




































{"id":1165,"date":"2026-04-14T10:48:53","date_gmt":"2026-04-14T08:48:53","guid":{"rendered":"https:\/\/www.tisoft.it\/?page_id=1165"},"modified":"2026-04-17T10:14:20","modified_gmt":"2026-04-17T08:14:20","slug":"shop-service","status":"publish","type":"page","link":"https:\/\/www.tisoft.it\/en\/shop-service\/","title":{"rendered":"Shop &amp; Service"},"content":{"rendered":"    <script id=\"ti-ss-maintenance-auto-496\">\n    (function(){\n        \"use strict\";\n        var issue = {\"active\":false,\"code\":\"\",\"message\":\"\",\"detail\":\"\",\"db\":\"\"};\n        var isAdmin = false;\n        var reportAjax1572 = \"https:\\\/\\\/www.tisoft.it\\\/wp-admin\\\/admin-ajax.php\";\n        var reportNonce1572 = \"d450073532\";\n        window.__tiSsMaintenanceIssue496 = issue;\n        window.__tiSsMaintenanceAdmin496 = isAdmin;\n        function esc(s){ return String(s == null ? '' : s).replace(\/[&<>\"']\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];}); }\n        function copyText573(text, statusEl){\n            function ok(){ if (statusEl) { statusEl.style.color = '#86efac'; statusEl.textContent = 'Testo copiato.'; } }\n            function fail(){\n                try {\n                    var ta = document.createElement('textarea');\n                    ta.value = String(text || ''); ta.setAttribute('readonly','readonly');\n                    ta.style.position = 'fixed'; ta.style.left = '-9999px'; ta.style.top = '0';\n                    document.body.appendChild(ta); ta.focus(); ta.select();\n                    document.execCommand('copy'); document.body.removeChild(ta); ok();\n                } catch(e) { if (statusEl) { statusEl.style.color = '#fca5a5'; statusEl.textContent = 'Copia non riuscita.'; } }\n            }\n            if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(String(text || '')).then(ok).catch(fail);\n            else fail();\n        }\n        function sendMaintenanceRuntime1572(reason, detail, manual){\n            try {\n                if (manual) {\n                    var ok = window.confirm('Inviare a SSSupport@targetinformatica.it una copia del problema riscontrato?');\n                    if (!ok) return Promise.resolve(false);\n                }\n                var fd = new FormData();\n                fd.append('action','ti_ai_ss_maintenance_report_1572'); fd.append('ti_action','ti_ai_ss_maintenance_report_1572');\n                fd.append('nonce',reportNonce1572); fd.append('mode', manual ? 'manual' : 'automatic');\n                fd.append('code', String((issue && issue.code) || 'maintenance_runtime'));\n                fd.append('message', String(reason || (issue && issue.message) || 'Shop & Service temporaneamente in manutenzione.'));\n                fd.append('detail', String(detail || (issue && issue.detail) || ''));\n                fd.append('db', String((issue && issue.db) || ''));\n                fd.append('context', manual ? 'runtime_manual' : 'runtime_automatic');\n                return fetch(reportAjax1572,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();});\n            } catch(e) { return Promise.resolve(false); }\n        }\n        function showMaintenance(reason, detail){\n            if (window.__tiSsMaintenanceShown496) return;\n            window.__tiSsMaintenanceShown496 = true;\n            reason = reason || (issue && issue.message) || 'Shop & Service temporaneamente in manutenzione.';\n            detail = detail || (issue && issue.detail) || '';\n            var userMessage = 'Accesso temporaneamente non disponibile con il profilo corrente.';\n            var infoMessage = 'Shop & Service ha rilevato una condizione di manutenzione o blocco tecnico. Puoi riprovare pi\u00f9 tardi oppure accedere con un profilo amministratore abilitato. Per supporto tecnico: SSSupport@targetinformatica.it.';\n            \/\/ La segnalazione automatica parte per ogni vera entrata runtime in manutenzione; il server evita duplicati.\n            sendMaintenanceRuntime1572(reason, detail, false).catch(function(){});\n            if (isAdmin) {\n                try {\n                    if (window.tiAlert) window.tiAlert('Shop & Service: problema rilevato\\n\\n' + reason + (detail ? '\\n\\nDettaglio: ' + detail : ''));\n                    else alert('Shop & Service: problema rilevato\\n\\n' + reason + (detail ? '\\n\\nDettaglio: ' + detail : ''));\n                } catch(e) {}\n                return;\n            }\n            var div = document.createElement('div');\n            div.id = 'ti-ss-maintenance-runtime-496';\n            div.style.cssText = 'position:fixed;inset:0;background:rgba(2,6,23,.86);z-index:2147483600;display:flex;align-items:center;justify-content:center;padding:18px;font-family:Arial,Helvetica,sans-serif;';\n            div.innerHTML = '<div style=\"width:min(560px,96vw);background:#0f172a;color:#e5e7eb;border:1px solid #38bdf8;border-radius:18px;padding:20px;box-shadow:0 22px 70px rgba(0,0,0,.65);\">'\n                + '<div style=\"display:flex;align-items:center;gap:10px;margin-bottom:10px;\"><h2 style=\"flex:1;margin:0;color:#fff;font-size:21px;\">Shop &amp; Service in manutenzione.<\/h2><button type=\"button\" id=\"ti-maint-runtime-info-672\" style=\"padding:7px 9px;border:1px solid #38bdf8;border-radius:999px;background:#082f49;color:#e0f2fe;font-size:12px;font-weight:800;cursor:pointer;white-space:nowrap;\">? info<\/button><\/div>'\n                + '<div style=\"background:#111827;border:1px solid #334155;border-radius:12px;padding:12px 14px;line-height:1.45;margin-bottom:12px;\">' + esc(userMessage) + '<\/div>'\n                + '<div id=\"ti-maint-runtime-info-box-672\" style=\"display:none;font-size:12px;color:#cbd5e1;max-height:240px;overflow:auto;background:#020617;border:1px solid #1f2937;border-radius:8px;padding:10px;margin-bottom:12px;\"><div style=\"white-space:pre-wrap;\">' + esc(infoMessage + (reason ? '\\n\\nMessaggio tecnico: ' + reason : '') + (detail ? '\\n\\nDettaglio tecnico:\\n' + detail : '')) + '<\/div><div style=\"margin-top:8px;\">Supporto Shop &amp; Service: <a href=\"mailto:SSSupport@targetinformatica.it\" id=\"ti-maint-runtime-support-1572\" style=\"color:#7dd3fc;font-weight:800;\">SSSupport@targetinformatica.it<\/a><\/div><\/div>'\n                + '<div style=\"display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:14px;\"><button type=\"button\" id=\"ti-maint-runtime-copy-573\" style=\"padding:9px 11px;border:0;border-radius:10px;background:#334155;color:#fff;font-weight:800;cursor:pointer;\">Copia testo<\/button><button type=\"button\" id=\"ti-maint-runtime-report-1572\" style=\"padding:9px 11px;border:0;border-radius:10px;background:#0369a1;color:#fff;font-weight:800;cursor:pointer;\">Invia segnalazione<\/button><span id=\"ti-maint-runtime-copy-msg-573\" style=\"font-size:12px;color:#93c5fd;\"><\/span><\/div>'\n                + '<button type=\"button\" onclick=\"location.reload()\" style=\"width:100%;margin-top:14px;padding:11px;border:0;border-radius:10px;background:#10b981;color:#fff;font-weight:800;cursor:pointer;\">Riprova \/ accesso amministratore<\/button>'\n                + '<\/div>';\n            document.body.appendChild(div);\n            var infoBtn = div.querySelector('#ti-maint-runtime-info-672');\n            if (infoBtn) infoBtn.addEventListener('click', function(){ var box = div.querySelector('#ti-maint-runtime-info-box-672'); if (box) box.style.display = (box.style.display === 'none' || !box.style.display) ? 'block' : 'none'; });\n            var copyBtn = div.querySelector('#ti-maint-runtime-copy-573');\n            if (copyBtn) copyBtn.addEventListener('click', function(){\n                var txt = ['Shop & Service in manutenzione.', userMessage, 'Info: ' + infoMessage, reason ? ('Messaggio tecnico: ' + String(reason)) : '', detail ? ('Dettaglio tecnico:\\n' + String(detail)) : ''].filter(Boolean).join('\\n\\n');\n                copyText573(txt, div.querySelector('#ti-maint-runtime-copy-msg-573'));\n            });\n            var reportBtn1572 = div.querySelector('#ti-maint-runtime-report-1572');\n            var supportLink1572 = div.querySelector('#ti-maint-runtime-support-1572');\n            function manualReport1572(ev){\n                if (ev) ev.preventDefault();\n                var st = div.querySelector('#ti-maint-runtime-copy-msg-573');\n                if (st) { st.style.color='#93c5fd'; st.textContent=''; }\n                sendMaintenanceRuntime1572(reason, detail, true).then(function(d){\n                    if (d === false) return;\n                    if (!d || !d.success) throw new Error((d && d.data && (d.data.message || d.data.error)) || 'Invio non riuscito.');\n                    if (st) { st.style.color='#86efac'; st.textContent=(d.data && d.data.reply) || 'Segnalazione inviata.'; }\n                }).catch(function(e){ if (st) { st.style.color='#fca5a5'; st.textContent=e && e.message ? e.message : 'Invio non riuscito.'; } });\n                return false;\n            }\n            if (reportBtn1572) reportBtn1572.addEventListener('click', manualReport1572);\n            if (supportLink1572) supportLink1572.addEventListener('click', manualReport1572);\n        }\n        window.tiSsEnterMaintenance496 = showMaintenance;\n        if (issue && issue.active) setTimeout(function(){ showMaintenance(issue.message, issue.detail); }, 300);\n        function isFromOwnScript496(sourceText){\n            \/\/ 30.9.1208: verifica che l'errore provenga effettivamente dal nostro script inline (pagina corrente),\n            \/\/ non da script esterni di terze parti, altri plugin o estensioni del browser - evita di bloccare\n            \/\/ l'intero plugin per errori completamente estranei al nostro codice.\n            try {\n                var here = String(location.pathname || '');\n                var txt = String(sourceText || '');\n                if (!txt) return false;\n                if (here && txt.indexOf(here) !== -1) return true;\n                if (\/\\bshop-service\\b\/i.test(txt) && txt.indexOf('http') !== -1 && txt.indexOf(location.host) !== -1) return true;\n                return false;\n            } catch(e) { return false; }\n        }\n        window.addEventListener('error', function(ev){\n            var msg = (ev && (ev.message || (ev.error && ev.error.message))) || 'Errore JavaScript imprevisto.';\n            if (\/ResizeObserver loop|Script error\/i.test(String(msg))) return;\n            if (\/maximum call stack|too much recursion\/i.test(String(msg))) return;\n            var srcText = (ev && ev.filename) || (ev && ev.error && ev.error.stack) || '';\n            if (!isFromOwnScript496(srcText)) { try { console.warn('[Shop-Service] errore JS ignorato (non proveniente dal nostro script):', msg, srcText); } catch(e) {} return; }\n            showMaintenance('Errore tecnico del plugin.', msg + (ev && ev.filename ? ('\\n' + ev.filename + ':' + ev.lineno) : ''));\n        });\n        window.addEventListener('unhandledrejection', function(ev){\n            var r = ev && ev.reason;\n            var msg = (r && (r.message || r.statusText)) || r || 'Errore asincrono imprevisto.';\n            if (\/maximum call stack|too much recursion\/i.test(String(msg))) return;\n            \/\/ 30.9.1739: un errore HTTP\/rete\/timeout di una sotto-richiesta non e un fatal del plugin.\n            \/\/ Deve restare confinato al processo chiamante, che dispone gia dei propri messaggi\/riprova.\n            if (\/^(?:HTTP\\s+\\d{3}\\b|Timeout richiesta\\b|Errore rete richiesta\\b|Risposta (?:server )?non JSON\\b|Risposta pagina non JSON\\b)\/i.test(String(msg))) {\n                try { if (ev && typeof ev.preventDefault === 'function') ev.preventDefault(); } catch(e) {}\n                try { console.warn('[Shop-Service] errore richiesta gestito senza bloccare il layout:', msg); } catch(e) {}\n                return;\n            }\n            var srcText = (r && r.stack) || '';\n            if (!isFromOwnScript496(srcText)) { try { console.warn('[Shop-Service] rifiuto promise ignorato (non proveniente dal nostro script):', msg, srcText); } catch(e) {} return; }\n            showMaintenance('Errore tecnico del plugin.', String(msg));\n        });\n    })();\n    <\/script>\n    <style>\n        #ti-ai-outer {\n            --ti-font-base: 13px;\n            --ti-font-small: 12px;\n            --ti-font-xs: 11px;\n            --ti-font-large: 14px;\n            --ti-btn-h: 34px;\n            --ti-btn-radius: 8px;\n            --ti-input-h: 34px;\n            --ti-row-h: 34px;\n            --ti-vh: 1vh;\n            --ti-shell-bg: #102a4a;\n            width: calc(100% - 16px) !important;\n            max-width: 820px !important;\n            margin: 12px auto !important;\n            padding: 18px !important;\n            font-family: Arial, Helvetica, sans-serif !important;\n            font-size: var(--ti-font-base) !important;\n            line-height: 1.3 !important;\n            color: #e5e7eb !important;\n            background: var(--ti-shell-bg) !important;\n            background-color: var(--ti-shell-bg) !important;\n            border: 1px solid rgba(96,165,250,.24) !important;\n            border-radius: 20px !important;\n            box-shadow: 0 18px 48px rgba(2,6,23,.34) !important;\n            box-sizing: border-box !important;\n            position: relative !important;\n            isolation: isolate !important;\n            min-width: 0 !important;\n            overflow-x: hidden;\n            overflow-y: visible;\n            touch-action: pan-y;\n            overscroll-behavior-y: auto;\n            -webkit-overflow-scrolling: touch;\n            -webkit-text-size-adjust: 100%;\n            text-size-adjust: 100%;\n        }\n        #ti-ai-outer, #ti-ai-outer * { box-sizing: border-box; }\n        #ti-ai-outer button,\n        #ti-ai-outer input,\n        #ti-ai-outer select,\n        #ti-ai-outer textarea,\n        #ti-ai-outer label,\n        #ti-ai-outer th,\n        #ti-ai-outer td,\n        #ti-ai-outer span,\n        #ti-ai-outer div,\n        #ti-ai-outer a {\n            font-family: Arial, Helvetica, sans-serif !important;\n        }\n        #ti-ai-outer button,\n        #ti-ai-outer input,\n        #ti-ai-outer select,\n        #ti-ai-outer textarea {\n            font-size: var(--ti-font-base) !important;\n            line-height: 1.2 !important;\n        }\n        #ti-ai-outer .ti-btn,\n        #ti-ai-outer .ti-send,\n        #ti-ai-outer .ti-help,\n        #ti-ai-outer #ti-sort-btn,\n        #ti-ai-outer #ti-show-sospese-btn,\n        #ti-ai-outer #ti-login-btn,\n        #ti-ai-outer #ti-logout-btn,\n        #ti-ai-outer .ti-lang-opt {\n            min-height: var(--ti-btn-h) !important;\n            font-size: var(--ti-font-base) !important;\n            line-height: 1.1 !important;\n            border-radius: var(--ti-btn-radius) !important;\n            white-space: nowrap !important;\n        }\n        #ti-ai-outer .ti-btn {\n            padding: 8px 12px !important;\n            font-weight: 600 !important;\n            cursor: pointer !important;\n            transition: opacity 0.1s ease, transform 0.1s ease !important;\n        }\n        #ti-ai-outer .ti-btn:active {\n            opacity: 0.65 !important;\n            transform: scale(0.97) !important;\n        }\n        #ti-ai-outer .ti-btn:disabled {\n            cursor: default !important;\n            opacity: 0.5 !important;\n        }\n        #ti-ai-outer .ti-send {\n            height: 38px !important;\n            min-height: 38px !important;\n            font-weight: 900 !important;\n            font-size: var(--ti-font-base) !important;\n        }\n        #ti-ai-outer .ti-help {\n            height: 24px !important;\n            min-height: 24px !important;\n            font-size: var(--ti-font-large) !important;\n            line-height: 1 !important;\n        }\n        #ti-ai-outer #ti-filter-ditte,\n        #ti-ai-outer #ti-ditta,\n        #ti-ai-outer .ti-in,\n        #ti-ai-outer .ti-msg {\n            font-size: var(--ti-font-base) !important;\n        }\n        #ti-ai-outer #ti-filter-ditte,\n        #ti-ai-outer #ti-ditta,\n        #ti-ai-outer .ti-in {\n            min-height: var(--ti-input-h) !important;\n            border-radius: 8px !important;\n        }\n        #ti-ai-outer .ti-user-name,\n        #ti-ai-outer .ti-user-role,\n        #ti-ai-outer #ti-company-sub,\n        #ti-ai-outer #ti-company-name {\n            font-family: Arial, Helvetica, sans-serif !important;\n        }\n        #ti-ai-outer .ti-ditta-row,\n        #ti-ai-outer .ti-ditta-row-main {\n            font-size: var(--ti-font-base) !important;\n            line-height: 1.25 !important;\n        }\n        #ti-ai-outer .ti-ditta-row {\n            min-height: var(--ti-row-h) !important;\n            padding: 8px 10px !important;\n        }\n        #ti-ai-outer .ti-ditta-row-badge {\n            font-size: var(--ti-font-xs) !important;\n            line-height: 1.1 !important;\n        }\n        #ti-ai-outer .ti-prod-table {\n            font-size: var(--ti-font-base) !important;\n        }\n        #ti-ai-outer .ti-prod-table th {\n            font-size: var(--ti-font-xs) !important;\n        }\n        #ti-ai-outer .ti-prod-table td,\n        #ti-ai-outer .ti-filter-input,\n        #ti-ai-outer .ti-order-filterlabel,\n        #ti-ai-outer .ti-order-filtervalue {\n            font-size: var(--ti-font-small) !important;\n        }\n        #ti-ai-outer .ti-modal h3,\n        #ti-ai-outer .ti-modal h4,\n        #ti-ai-outer .ti-modal p,\n        #ti-ai-outer .ti-modal label,\n        #ti-ai-outer .ti-modal .ti-btn,\n        #ti-ai-outer .ti-modal .ti-in,\n        #ti-ai-outer .ti-modal select,\n        #ti-ai-outer .ti-modal textarea {\n            font-family: Arial, Helvetica, sans-serif !important;\n        }\n        #ti-ai-outer .ti-modal h3 { font-size: 18px !important; line-height: 1.2 !important; }\n        #ti-ai-outer .ti-modal h4 { font-size: 16px !important; line-height: 1.2 !important; }\n        #ti-ai-outer .ti-modal p,\n        #ti-ai-outer .ti-modal label,\n        #ti-ai-outer .ti-modal .ti-in,\n        #ti-ai-outer .ti-modal select,\n        #ti-ai-outer .ti-modal textarea,\n        #ti-ai-outer .ti-modal .ti-btn { font-size: var(--ti-font-base) !important; }\n        @media (max-width: 640px) {\n            #ti-ai-outer {\n                --ti-font-base: 13px;\n                --ti-font-small: 12px;\n                --ti-font-xs: 11px;\n                --ti-font-large: 14px;\n                --ti-btn-h: 34px;\n                --ti-input-h: 34px;\n                --ti-row-h: 34px;\n                width: calc(100% - 8px) !important;\n                max-width: none !important;\n                margin: 4px auto !important;\n                padding: 10px !important;\n                border-radius: 14px !important;\n            }\n        }\n        #ti-ai-outer * { box-sizing: border-box; }\n        .ti-header { display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; padding: 15px; min-height: 85px; border-radius: 14px; background: #111827; border: 1px solid rgba(255,255,255,0.08); margin-bottom: 10px; position: relative; gap: 10px; }\n        .ti-header-top { display:flex; align-items:center; justify-content:space-between; gap:12px; width:100%; min-width:0; }\n        .ti-header-main-left { display:flex; align-items:center; gap:12px; min-width:0; flex:1 1 auto; }\n        .ti-hl { display: flex; align-items: center; justify-content: flex-start; gap: 12px; width: 100%; min-width: 0; flex:1 1 auto; }\n        .ti-left-stack { display:flex; flex-direction:row; align-items:center; gap:6px; }\n        .ti-company-sub-row { display:flex; width:100%; justify-content:center; align-items:center; min-height:0; }\n        #ti-company-sub { text-align:center; width:100%; }\n        #ti-company-name { font-weight:900; font-size:2.2em; line-height:1.05; color:#fff; letter-spacing:0.01em; }\n        #ti-company-sub { font-size:14px; line-height:1.2; }\n        .ti-header-bottom { display:flex; align-items:center; justify-content:space-between; gap:10px; width:100%; flex-wrap:wrap; }\n        .ti-header-left-controls { display:flex; align-items:center; gap:8px; flex:1 1 auto; min-width:0; flex-wrap:wrap; }\n        .ti-header-right-controls { display:flex; align-items:center; justify-content:flex-end; gap:8px; margin-left:auto; flex:0 1 auto; flex-wrap:wrap; }\n        .ti-hr-right { display: flex; align-items: center; justify-content: flex-end; gap: 8px; width: auto; flex: 0 0 auto; min-height:26px; }\n        .ti-hr-bottom { display: flex; align-items: center; gap: 8px; }\n        .ti-company-ref-datetime { display:none; align-items:center; justify-content:center; min-height:24px; padding:3px 8px; border-radius:999px; background:#0f172a; border:1px solid #334155; color:#bfdbfe; font-size:12px; font-weight:800; white-space:nowrap; }\n        .ti-header-help-btn { display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; min-width:24px; min-height:24px; padding:0; border-radius:999px; background:#374151; color:#fff; border:1px solid #4b5563; font-size:14px; font-weight:900; line-height:1; cursor:pointer; flex:0 0 24px; }\n        .ti-header-help-btn:hover { background:#4b5563; color:#fff; }\n        \/* 30.9.1712: nome ditta mai troncato; se necessario va a capo senza essere coperto dai comandi a destra. *\/\n        #ti-ai-outer #ti-company-name { display:block !important; max-width:none !important; overflow:visible !important; text-overflow:clip !important; white-space:normal !important; overflow-wrap:anywhere !important; word-break:normal !important; }\n        #ti-ai-outer .ti-header-top { flex-wrap:wrap !important; align-items:center !important; }\n        #ti-ai-outer .ti-header-main-left { flex:1 1 520px !important; min-width:260px !important; overflow:visible !important; }\n        #ti-ai-outer .ti-hl > div:last-child { min-width:0 !important; flex:1 1 auto !important; overflow:visible !important; }\n        #ti-ai-outer .ti-hr-right { flex:0 0 auto !important; }\n        #ti-ai-outer .ti-header-ss-reload-1712 { width:26px !important; min-width:26px !important; height:26px !important; min-height:26px !important; padding:2px !important; display:inline-flex !important; align-items:center !important; justify-content:center !important; border:1px solid #64748b !important; border-radius:7px !important; background:#334155 !important; cursor:pointer !important; }\n        #ti-ai-outer .ti-header-ss-reload-1712 img { width:20px !important; height:20px !important; display:block !important; object-fit:cover !important; border-radius:5px !important; }\n        \/* 30.9.1716: Data\/ora + ? + logo SS + IT\/EN sono un solo blocco ancorato all'estrema destra della Main. *\/\n        #ti-ai-outer .ti-header-top {\n            display:grid !important;\n            grid-template-columns:minmax(0,1fr) max-content !important;\n            align-items:start !important;\n            column-gap:14px !important;\n            width:100% !important;\n        }\n        #ti-ai-outer .ti-header-top > .ti-header-main-left {\n            grid-column:1 !important;\n            min-width:0 !important;\n            width:auto !important;\n            max-width:none !important;\n            flex:none !important;\n        }\n        #ti-ai-outer .ti-header-top > .ti-hr-right {\n            grid-column:2 !important;\n            justify-self:end !important;\n            align-self:start !important;\n            display:flex !important;\n            align-items:center !important;\n            justify-content:flex-end !important;\n            gap:8px !important;\n            width:max-content !important;\n            max-width:100% !important;\n            margin-left:0 !important;\n            flex:0 0 auto !important;\n            flex-wrap:nowrap !important;\n        }\n        #ti-ai-outer .ti-header-top > .ti-hr-right .ti-lang-wrap { flex:0 0 auto !important; }\n        @media (max-width:700px) {\n            #ti-ai-outer .ti-header-top { grid-template-columns:minmax(0,1fr) !important; row-gap:6px !important; }\n            #ti-ai-outer .ti-header-top > .ti-header-main-left { grid-column:1 !important; grid-row:1 !important; }\n            #ti-ai-outer .ti-header-top > .ti-hr-right { grid-column:1 !important; grid-row:2 !important; justify-self:end !important; margin-left:auto !important; }\n        }\n        \/* 30.9.1717: i comandi di testata sono SEMPRE su una seconda riga sotto la ditta, allineati a destra. *\/\n        #ti-ai-outer .ti-header-top {\n            grid-template-columns:minmax(0,1fr) !important;\n            grid-template-rows:auto auto !important;\n            row-gap:6px !important;\n        }\n        #ti-ai-outer .ti-header-top > .ti-header-main-left {\n            grid-column:1 !important;\n            grid-row:1 !important;\n            width:100% !important;\n        }\n        #ti-ai-outer .ti-header-top > .ti-hr-right {\n            grid-column:1 !important;\n            grid-row:2 !important;\n            justify-self:end !important;\n            align-self:center !important;\n            margin-left:auto !important;\n            width:max-content !important;\n            max-width:100% !important;\n            flex-wrap:nowrap !important;\n        }\n        #ti-help-ov .ti-help-reload-1713 { flex:0 0 auto !important; width:auto !important; min-width:0 !important; padding:2px 5px !important; min-height:18px !important; height:auto !important; font-size:7px !important; line-height:1.05 !important; font-weight:700 !important; white-space:nowrap !important; border-radius:4px !important; }\n        @media (max-width:767px) { .ti-header-help-btn { width:22px; height:22px; min-width:22px; min-height:22px; font-size:12px; } }\n        .ti-conf-header-right { display:flex !important; align-items:center !important; justify-content:flex-end !important; gap:8px !important; margin-left:auto !important; padding-right:42px !important; min-width:0 !important; }\n        @media (max-width: 700px) { .ti-config-comm-rec-grid-1591 { grid-template-columns:1fr !important; } #ti-config-comm-ov-1591 .ti-modal { width:96vw !important; } }\n        .ti-conf-ref-datetime { display:none; flex:0 0 auto !important; max-width:260px !important; overflow:hidden !important; text-overflow:ellipsis !important; }\n        @media (max-width: 767px) { .ti-conf-header-right { gap:5px !important; padding-right:38px !important; } .ti-conf-ref-datetime { max-width:150px !important; font-size:10px !important; padding:2px 6px !important; } }\n        .ti-lang-wrap { display:inline-flex !important; gap:10px; font-size:15px; font-weight:800; z-index:10; align-items:center !important; justify-content:flex-end; text-align:right; min-height:24px !important; height:24px !important; line-height:24px !important; vertical-align:middle; }\n        .ti-lang-wrap .ti-lang-opt { display:inline-flex !important; align-items:center !important; justify-content:center !important; min-height:24px !important; height:24px !important; line-height:24px !important; padding:0 1px !important; border-radius:0 !important; }\n        .ti-lang-opt { color: #6b7280; cursor: pointer; }\n        .ti-lang-opt.active { color: #38bdf8; text-decoration: underline; }\n        .ti-logo { width: 44px; height: 44px; object-fit: contain; border-radius: 8px; background: rgba(255,255,255,0.1); padding: 2px; cursor: pointer; transition: transform 0.2s; }\n        .ti-logo:hover { transform: scale(1.06); }\n        .ti-qr { width: 44px; height: 44px; object-fit: contain; border-radius: 8px; background: #fff; padding: 2px; cursor: pointer; transition: transform 0.2s; }\n        .ti-qr:hover { transform: scale(1.1); }\n        .ti-user-area { display: none; align-items: center; gap: 6px; text-align: left; margin: 0; background: rgba(255,255,255,0.05); padding: 0 10px; border-radius: 18px; border: 1px solid rgba(255,255,255,0.12); min-height: 34px; height: 34px; max-width: 240px; width: fit-content; box-sizing: border-box; }\n        .ti-hr-bottom .ti-user-area { flex: 0 1 auto; align-self: center; margin-left: 2px; }\n        .ti-user-avatar { width: 20px; height: 20px; border-radius: 50%; object-fit: cover; cursor: pointer; border: 1px solid #38bdf8; background: #000; flex: 0 0 20px; }\n        .ti-user-info { cursor: pointer; line-height: 1.05; min-width: 0; display:flex; align-items:center; height:100%; }\n        .ti-user-name { display: block; font-weight: 700; color: #fff; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n        .ti-user-role { display: inline; font-size: 10px; color: #cbd5e1; font-weight: 500; }\n        .ti-chat-box { min-height: 250px; max-height: 60vh; overflow-y: auto; padding: 12px; border-radius: 14px; background: #111827; border: 1px solid rgba(255,255,255,0.08); margin-bottom: 10px; -webkit-overflow-scrolling: touch; }\n        .ti-chat-box.ti-chat-after-ai-form-717 { margin-top: 10px; margin-bottom: 10px; }\n        .ti-bubble { max-width: 96%; padding: 10px 12px; border-radius: 14px; margin: 10px 0; line-height: 1.45; white-space: pre-wrap; word-wrap: break-word; font-size: 14px !important; }\n        .ti-bubble p { font-size: 14px !important; margin: 6px 0; }\n        .ti-bubble.user { margin-left: auto; background: rgba(56,189,248,0.2); border: 1px solid rgba(56,189,248,0.3); text-align: right; }\n        .ti-bubble.ai { margin-right: auto; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); font-size: 15.5px !important; line-height: 1.58 !important; letter-spacing: 0.01em; }\n        .ti-bubble.ai p, .ti-bubble.ai li { font-size: 15.5px !important; line-height: 1.58 !important; margin: 7px 0; }\n        .ti-bubble.ai b, .ti-bubble.ai strong { font-weight: 800; }\n        .ti-bubble.ai table, .ti-bubble.ai th, .ti-bubble.ai td { font-size: 14px !important; line-height: 1.42 !important; }\n        .ti-input-wrap { padding: 10px; border-radius: 14px; background: #111827; border: 1px solid rgba(255,255,255,0.08); }\n        .ti-input-main { display: flex; gap: 10px; flex-wrap: wrap; }\n        .ti-input-main > #ti-msg, .ti-input-main > .ti-msg { flex: 1 1 240px; min-width: 240px; }\n        .ti-input-main > .ti-send-wrap { flex: 0 0 auto; }\n        #ti-admin-ai-logbar-830 { flex-basis: 100%; order: -1; }\n        .ti-msg { flex: 1; padding: 12px; border-radius: 12px; background: rgba(255,255,255,0.06); color: #fff; border: 1px solid rgba(255,255,255,0.12); outline: none; min-height: 126px; resize: vertical; font-size: 14px !important; line-height: 1.45; }\n\n        #ti-ai-outer,\n        #ti-ai-outer input,\n        #ti-ai-outer textarea,\n        #ti-ai-outer select,\n        #ti-ai-outer option,\n        #ti-ai-outer .ti-in,\n        #ti-ai-outer .ti-msg,\n        #ti-ai-outer .ti-filter-input,\n        #ti-ai-outer .ti-cfg-filter,\n        #ti-ai-outer .ti-import-map-select,\n        #ti-ai-outer .ti-import-map-input,\n        #ti-ai-outer .ti-p-input,\n        #ti-ai-outer .ti-q,\n        #ti-ai-outer .ti-support-box input,\n        #ti-ai-outer .ti-support-box textarea,\n        #ti-ai-outer #help-bot-in,\n        #ti-ai-outer #ai-gen-prompt,\n        #ti-ai-outer #ti-kbd-prev,\n        #ti-ai-outer [contenteditable=\"true\"] { color:#fff !important; -webkit-text-fill-color:#fff !important; caret-color:#fff !important; }\n        #ti-ai-outer .ti-conf-window input,\n        #ti-ai-outer .ti-conf-window textarea,\n        #ti-ai-outer .ti-conf-window select,\n        #ti-ai-outer .ti-conf-window option,\n        #ti-ai-outer .ti-conf-body input,\n        #ti-ai-outer .ti-conf-body textarea,\n        #ti-ai-outer .ti-conf-body select,\n        #ti-ai-outer .ti-conf-body option,\n        #ti-ai-outer .ti-cfg-table input,\n        #ti-ai-outer .ti-cfg-table textarea,\n        #ti-ai-outer .ti-cfg-table select,\n        #ti-ai-outer .ti-cfg-table option,\n        #ti-ai-outer .ti-import-map-table input,\n        #ti-ai-outer .ti-import-map-table textarea,\n        #ti-ai-outer .ti-import-map-table select,\n        #ti-ai-outer .ti-import-map-table option,\n        #ti-ai-outer .ti-conf-window .ti-in,\n        #ti-ai-outer .ti-conf-window .ti-q,\n        #ti-ai-outer .ti-conf-window .ti-p-input,\n        #ti-ai-outer .ti-conf-window .ti-import-map-input,\n        #ti-ai-outer .ti-conf-window .ti-import-map-select,\n        #ti-ai-outer .ti-conf-window [contenteditable=\"true\"] {\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            caret-color:#fff !important;\n        }\n        #ti-ai-outer .ti-conf-window input::placeholder,\n        #ti-ai-outer .ti-conf-window textarea::placeholder,\n        #ti-ai-outer .ti-conf-window .ti-in::placeholder,\n        #ti-ai-outer .ti-conf-window .ti-q::placeholder,\n        #ti-ai-outer .ti-conf-window .ti-p-input::placeholder,\n        #ti-ai-outer .ti-conf-window .ti-import-map-input::placeholder {\n            color:#cbd5e1 !important;\n            -webkit-text-fill-color:#cbd5e1 !important;\n            opacity:1 !important;\n        }\n        #ti-ai-outer .ti-conf-window input,\n        #ti-ai-outer .ti-conf-window textarea,\n        #ti-ai-outer .ti-conf-window select,\n        #ti-ai-outer .ti-cfg-table input,\n        #ti-ai-outer .ti-cfg-table textarea,\n        #ti-ai-outer .ti-cfg-table select,\n        #ti-ai-outer .ti-import-map-table input,\n        #ti-ai-outer .ti-import-map-table textarea,\n        #ti-ai-outer .ti-import-map-table select {\n            background:#000 !important;\n            border-color:#4b5563 !important;\n        }\n        #ti-ai-outer .ti-conf-window input:focus,\n        #ti-ai-outer .ti-conf-window textarea:focus,\n        #ti-ai-outer .ti-conf-window select:focus,\n        #ti-ai-outer .ti-cfg-table input:focus,\n        #ti-ai-outer .ti-cfg-table textarea:focus,\n        #ti-ai-outer .ti-cfg-table select:focus,\n        #ti-ai-outer .ti-import-map-table input:focus,\n        #ti-ai-outer .ti-import-map-table textarea:focus,\n        #ti-ai-outer .ti-import-map-table select:focus {\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            border-color:#93c5fd !important;\n            box-shadow:0 0 0 1px rgba(147,197,253,.35) !important;\n            outline:none !important;\n        }\n        #ti-ai-outer .ti-conf-window input:active,\n        #ti-ai-outer .ti-conf-window textarea:active,\n        #ti-ai-outer .ti-conf-window select:active,\n        #ti-ai-outer .ti-cfg-table input:active,\n        #ti-ai-outer .ti-cfg-table textarea:active,\n        #ti-ai-outer .ti-cfg-table select:active,\n        #ti-ai-outer .ti-import-map-table input:active,\n        #ti-ai-outer .ti-import-map-table textarea:active,\n        #ti-ai-outer .ti-import-map-table select:active,\n        #ti-ai-outer .ti-conf-window [contenteditable=\"true\"]:focus,\n        #ti-ai-outer .ti-conf-window [contenteditable=\"true\"]:active,\n        #ti-ai-outer .ti-cfg-table [contenteditable=\"true\"]:focus,\n        #ti-ai-outer .ti-cfg-table [contenteditable=\"true\"]:active,\n        #ti-ai-outer .ti-import-map-table [contenteditable=\"true\"]:focus,\n        #ti-ai-outer .ti-import-map-table [contenteditable=\"true\"]:active {\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            caret-color:#fff !important;\n            background:#000 !important;\n            text-shadow:none !important;\n        }\n        #ti-ai-outer .ti-conf-window input:-webkit-autofill,\n        #ti-ai-outer .ti-conf-window textarea:-webkit-autofill,\n        #ti-ai-outer .ti-conf-window select:-webkit-autofill,\n        #ti-ai-outer .ti-cfg-table input:-webkit-autofill,\n        #ti-ai-outer .ti-cfg-table textarea:-webkit-autofill,\n        #ti-ai-outer .ti-cfg-table select:-webkit-autofill,\n        #ti-ai-outer .ti-import-map-table input:-webkit-autofill,\n        #ti-ai-outer .ti-import-map-table textarea:-webkit-autofill,\n        #ti-ai-outer .ti-import-map-table select:-webkit-autofill {\n            -webkit-text-fill-color:#fff !important;\n            caret-color:#fff !important;\n            box-shadow:0 0 0 1000px #000 inset !important;\n            transition:background-color 99999s ease-in-out 0s !important;\n        }\n        #ti-ai-outer .ti-conf-window input,\n        #ti-ai-outer .ti-conf-window textarea,\n        #ti-ai-outer .ti-conf-window select,\n        #ti-ai-outer .ti-conf-window option,\n        #ti-ai-outer .ti-conf-body input,\n        #ti-ai-outer .ti-conf-body textarea,\n        #ti-ai-outer .ti-conf-body select,\n        #ti-ai-outer .ti-conf-body option,\n        #ti-ai-outer .ti-cfg-table input,\n        #ti-ai-outer .ti-cfg-table textarea,\n        #ti-ai-outer .ti-cfg-table select,\n        #ti-ai-outer .ti-cfg-table option,\n        #ti-ai-outer .ti-import-map-table input,\n        #ti-ai-outer .ti-import-map-table textarea,\n        #ti-ai-outer .ti-import-map-table select,\n        #ti-ai-outer .ti-import-map-table option {\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            caret-color:#fff !important;\n            background:#000 !important;\n            background-color:#000 !important;\n            background-image:none !important;\n            text-shadow:none !important;\n            color-scheme:dark !important;\n        }\n        #ti-ai-outer .ti-conf-window input:hover,\n        #ti-ai-outer .ti-conf-window textarea:hover,\n        #ti-ai-outer .ti-conf-window select:hover,\n        #ti-ai-outer .ti-cfg-table input:hover,\n        #ti-ai-outer .ti-cfg-table textarea:hover,\n        #ti-ai-outer .ti-cfg-table select:hover,\n        #ti-ai-outer .ti-import-map-table input:hover,\n        #ti-ai-outer .ti-import-map-table textarea:hover,\n        #ti-ai-outer .ti-import-map-table select:hover,\n        #ti-ai-outer .ti-conf-window input:focus,\n        #ti-ai-outer .ti-conf-window textarea:focus,\n        #ti-ai-outer .ti-conf-window select:focus,\n        #ti-ai-outer .ti-cfg-table input:focus,\n        #ti-ai-outer .ti-cfg-table textarea:focus,\n        #ti-ai-outer .ti-cfg-table select:focus,\n        #ti-ai-outer .ti-import-map-table input:focus,\n        #ti-ai-outer .ti-import-map-table textarea:focus,\n        #ti-ai-outer .ti-import-map-table select:focus,\n        #ti-ai-outer .ti-conf-window input:active,\n        #ti-ai-outer .ti-conf-window textarea:active,\n        #ti-ai-outer .ti-conf-window select:active,\n        #ti-ai-outer .ti-cfg-table input:active,\n        #ti-ai-outer .ti-cfg-table textarea:active,\n        #ti-ai-outer .ti-cfg-table select:active,\n        #ti-ai-outer .ti-import-map-table input:active,\n        #ti-ai-outer .ti-import-map-table textarea:active,\n        #ti-ai-outer .ti-import-map-table select:active {\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            background:#000 !important;\n            background-color:#000 !important;\n            background-image:none !important;\n        }\n        #ti-ai-outer .ti-conf-window option:checked,\n        #ti-ai-outer .ti-conf-window option:hover,\n        #ti-ai-outer .ti-cfg-table option:checked,\n        #ti-ai-outer .ti-cfg-table option:hover,\n        #ti-ai-outer .ti-import-map-table option:checked,\n        #ti-ai-outer .ti-import-map-table option:hover {\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            background:#111827 !important;\n            background-color:#111827 !important;\n        }\n        #ti-ai-outer .ti-conf-window input:-webkit-autofill,\n        #ti-ai-outer .ti-conf-window input:-webkit-autofill:hover,\n        #ti-ai-outer .ti-conf-window input:-webkit-autofill:focus,\n        #ti-ai-outer .ti-conf-window textarea:-webkit-autofill,\n        #ti-ai-outer .ti-conf-window textarea:-webkit-autofill:hover,\n        #ti-ai-outer .ti-conf-window textarea:-webkit-autofill:focus,\n        #ti-ai-outer .ti-cfg-table input:-webkit-autofill,\n        #ti-ai-outer .ti-cfg-table input:-webkit-autofill:hover,\n        #ti-ai-outer .ti-cfg-table input:-webkit-autofill:focus,\n        #ti-ai-outer .ti-cfg-table textarea:-webkit-autofill,\n        #ti-ai-outer .ti-cfg-table textarea:-webkit-autofill:hover,\n        #ti-ai-outer .ti-cfg-table textarea:-webkit-autofill:focus,\n        #ti-ai-outer .ti-import-map-table input:-webkit-autofill,\n        #ti-ai-outer .ti-import-map-table input:-webkit-autofill:hover,\n        #ti-ai-outer .ti-import-map-table input:-webkit-autofill:focus,\n        #ti-ai-outer .ti-import-map-table textarea:-webkit-autofill,\n        #ti-ai-outer .ti-import-map-table textarea:-webkit-autofill:hover,\n        #ti-ai-outer .ti-import-map-table textarea:-webkit-autofill:focus {\n            -webkit-text-fill-color:#fff !important;\n            caret-color:#fff !important;\n            -webkit-box-shadow:0 0 0 1000px #000 inset !important;\n            box-shadow:0 0 0 1000px #000 inset !important;\n            background:#000 !important;\n            background-color:#000 !important;\n            background-image:none !important;\n            transition:background-color 99999s ease-in-out 0s !important;\n        }\n        #ti-ai-outer .ti-conf-window input:-moz-autofill,\n        #ti-ai-outer .ti-conf-window textarea:-moz-autofill,\n        #ti-ai-outer .ti-cfg-table input:-moz-autofill,\n        #ti-ai-outer .ti-cfg-table textarea:-moz-autofill,\n        #ti-ai-outer .ti-import-map-table input:-moz-autofill,\n        #ti-ai-outer .ti-import-map-table textarea:-moz-autofill {\n            color:#fff !important;\n            background:#000 !important;\n            background-color:#000 !important;\n        }\n        #ti-ai-outer .ti-header-right-controls { display:flex; align-items:center; gap:8px; }\n        #ti-ai-outer #ti-user-area { order:1; }\n        #ti-ai-outer #ti-login-btn, #ti-ai-outer #ti-logout-btn { order:2; }\n        .ti-shop-footer { margin-top:12px; padding:12px 10px 4px; text-align:center; color:#cbd5e1; font-size:12px; line-height:1.45; }\n        .ti-shop-footer a { color:#93c5fd; text-decoration:none; }\n        #ti-ai-outer #lbl-conf-save { font-size:16px !important; font-weight:800 !important; }\n        #ti-ai-outer #lbl-conf-save.ti-save-dirty { background:#10b981 !important; color:#fff !important; box-shadow:0 0 0 2px rgba(16,185,129,.35), 0 0 16px rgba(16,185,129,.25) !important; font-weight:900 !important; }\n        #ti-ai-outer #lbl-conf-save.ti-save-clean { background:#374151 !important; color:#e5e7eb !important; box-shadow:none !important; }\n        #ti-ai-outer .ti-kbd-modal { width:96vw !important; max-width:760px !important; }\n        #ti-ai-outer .ti-kbd { display:flex; flex-direction:column; gap:8px; width:100%; }\n        #ti-ai-outer .ti-kbd-row { display:flex; gap:8px; width:100%; }\n        #ti-ai-outer .ti-kbd-row button { flex:1 1 0; min-width:0; min-height:48px; padding:10px 6px; border-radius:12px; border:1px solid #475569; background:#1f2937; color:#fff; font-size:18px; font-weight:900; cursor:pointer; }\n        #ti-ai-outer .ti-kbd-row button:active { transform:scale(.98); background:#334155; }\n        @media (max-width:640px) { #ti-ai-outer .ti-kbd-row { gap:5px; } #ti-ai-outer .ti-kbd-row button { min-height:44px; font-size:16px; padding:8px 4px; } }\n        #ti-ditta option.ti-ditta-attivo { color:#ffffff !important; }\n        #ti-ditta option.ti-ditta-sospesa { color:#ef4444 !important; }\n        #ti-ditta option.ti-ditta-configurazione { color:#facc15 !important; }\n        #ti-ditta option.ti-ditta-demo { color:#38bdf8 !important; font-weight:700 !important; }\n        .ti-order-confirm-host { display:none; margin:10px 0 12px; padding:12px; background:#0b1220; border:1px solid #223047; border-radius:12px; position:relative; z-index:30; box-shadow:0 8px 28px rgba(0,0,0,0.35); }\n        .ti-order-confirm-title { color:#fff; font-weight:800; font-size:15px; margin-bottom:8px; }\n        .ti-order-confirm-note { color:#94a3b8; font-size:12px; margin-bottom:10px; }\n        .ti-order-confirm-box { background:#000; border:1px solid #374151; border-radius:10px; padding:12px; color:#e5e7eb; white-space:pre-wrap; font-family:monospace; max-height:220px; overflow:auto; }\n        .ti-order-confirm-actions { display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; }\n        .ti-order-confirm-actions .ti-btn { flex:1; min-width:160px; }\n        .ti-order-confirm-meta { display:flex; gap:12px; flex-wrap:wrap; margin-top:8px; color:#cbd5e1; font-size:12px; }\n        .ti-ai-response-host { display:none; margin:10px 0 12px; padding:12px; background:#08111f; border:1px solid #1e3a5f; border-radius:12px; position:relative; z-index:29; box-shadow:0 8px 28px rgba(0,0,0,0.30); }\n        .ti-ai-response-head { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:8px; }\n        .ti-ai-response-title { color:#fff; font-weight:900; font-size:15px; line-height:1.25; }\n        .ti-ai-response-body { color:#e5e7eb; background:#0b1220; border:1px solid rgba(148,163,184,.32); border-radius:10px; padding:10px 12px; font-size:15.5px; line-height:1.55; max-height:260px; overflow:auto; }\n        .ti-ai-response-actions { display:flex; justify-content:flex-start; align-items:center; gap:8px; margin-top:10px; }\n        .ti-ai-response-copy { font-size:11px !important; padding-left:8px !important; padding-right:8px !important; min-height:var(--ti-btn-h); border-radius:8px; white-space:nowrap; }\n        .ti-ai-response-copy:hover { background:#2563eb !important; color:#fff !important; }\n        .ti-ai-response-body .ti-ai-order-final-check-637, .ti-ai-response-body .ti-ai-order-final-check-631 { margin-top:10px; color:#bfdbfe; font-weight:900; }\n        .ti-cfg-summary { display:flex; align-items:center; justify-content:space-between; gap:8px; }\n        .ti-cfg-summary-main { flex:1 1 auto; }\n        .ti-cfg-summary-help { flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center; width:22px; height:22px; margin-left:12px; border-radius:999px; border:1px solid #475569; background:#1f2937; color:#fff; font-weight:700; cursor:pointer; }\n        .ti-send-wrap { display:flex; flex-direction:column; gap:6px; align-items:stretch; width:96px; flex:0 0 96px; min-width:0; overflow:hidden; }\n        @media (max-width: 767px) { .ti-input-main .ti-send-wrap { margin-left:auto !important; } }\n        .ti-send { height: 38px; width: 100%; border-radius: 10px; background: rgba(56,189,248,0.2); color: #fff; font-weight: 900; cursor: pointer; border: 1px solid rgba(56,189,248,0.4); }\n        .ti-help { height: 24px; width: 100%; border-radius: 8px; background: #374151; color: #aaa; font-weight: bold; cursor: pointer; border: 1px solid #4b5563; font-size: 14px; }\n        .ti-send-wrap .ti-btn { width:100%; min-height:30px; padding:6px 8px; font-size:11px; line-height:1.1; }\n        .ti-actions-row { margin-top: 10px; display: flex; gap: 5px; justify-content: flex-start; align-items:center; flex-wrap: nowrap; overflow:hidden; width:100%; max-width:100%; box-sizing:border-box; padding-bottom:2px; }\n        .ti-admin-actions-row { margin-top: 6px; display:none; gap:8px; justify-content:center; align-items:center; flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch; padding-bottom:2px; border-top:1px solid rgba(148,163,184,0.16); padding-top:6px; }\n        .ti-admin-actions-row .ti-btn { flex:0 0 auto; min-height:var(--ti-btn-h); }\n        .ti-actions-row #ti-help-btn { margin-left:auto !important; flex:0 0 42px !important; width:42px !important; min-width:42px !important; max-width:42px !important; height:var(--ti-btn-h) !important; min-height:var(--ti-btn-h) !important; padding:8px 0 !important; display:flex !important; align-items:center !important; justify-content:center !important; background:#374151 !important; color:#fff !important; border:1px solid #4b5563 !important; border-radius:8px !important; font-size:16px !important; font-weight:900 !important; line-height:1 !important; }\n        .ti-actions-row #ti-help-btn:hover { background:#4b5563 !important; color:#fff !important; }\n        .ti-btn { padding: 8px 12px; border-radius: 8px; background: #222; color: #ccc; border: 1px solid #444; cursor: pointer; font-weight: 600; font-size: var(--ti-font-base) !important; display: flex; align-items: center; justify-content: center; gap: 5px; line-height:1.1 !important; }\n        .ti-btn-ok { background: #065f46; border-color: #059669; color: #fff; }\n        .ti-btn-x { background: #7f1d1d; border-color: #b91c1c; color: #fff; }\n\n        .ti-booking-nav-actions { margin-top:10px; }\n        .ti-booking-nav-actions .ti-btn { display:inline-flex !important; min-height:34px !important; height:34px !important; padding:6px 12px !important; font-size:13px !important; line-height:1 !important; }\n        @media (max-width: 767px) { .ti-booking-nav-actions .ti-btn { flex:1 1 120px !important; min-width:110px !important; font-size:12px !important; } }\n        html.ti-no-scroll, body.ti-no-scroll { overflow: hidden !important; height: 100% !important; touch-action: auto !important; }\n        #ti-ai-outer .ti-touch-scroll, #ti-ai-outer .ti-modal, #ti-ai-outer .ti-conf-body, #ti-ai-outer .ti-chat-box, #ti-ai-outer .ti-cfg-table-container, #ti-ai-outer .ti-table-wrap { touch-action: pan-y !important; -webkit-overflow-scrolling: touch !important; }\n        \n        #ti-ai-outer { position: relative; z-index: 1; isolation: isolate; }\n        .ti-ov { position: fixed !important; top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important; background: rgba(0,0,0,0.85) !important; display: none; align-items: center; justify-content: center; z-index: 2147482000 !important; isolation: isolate !important; }\n        #ti-alert-ov { z-index: 2147483647 !important; }\n        #ti-ai-loader-ov { z-index: 2147483646 !important; }\n        .ti-modal { width: min(92vw, 820px); max-width: min(92vw, 820px); background: #1f2937; border-radius: 16px; padding: 25px; border: 1px solid #374151; text-align: center; position: relative; display: flex; flex-direction: column; pointer-events: auto; max-height: 90vh; overflow-y: auto; -webkit-overflow-scrolling: touch; z-index: 2; }\n        .ti-modal-x-red { position:absolute !important; top:10px !important; right:10px !important; width:32px !important; height:32px !important; min-width:32px !important; min-height:32px !important; border-radius:50% !important; border:2px solid #fecaca !important; background:#dc2626 !important; color:#fff !important; display:flex !important; align-items:center !important; justify-content:center !important; font-size:18px !important; line-height:1 !important; font-weight:900 !important; cursor:pointer !important; z-index:2147483647 !important; padding:0 !important; box-shadow:0 4px 14px rgba(0,0,0,.65) !important; }\n        .ti-modal-x-red:hover { background:#b91c1c !important; transform:scale(1.04); }\n        .ti-modal-bottom-close-row { display:flex !important; justify-content:center !important; align-items:center !important; margin-top:16px !important; width:100% !important; }\n        .ti-modal-bottom-close-row .ti-btn { min-width:160px !important; max-width:260px !important; background:#4b5563 !important; color:#fff !important; }\n        .ti-conf-window > .ti-modal-x-red { top:12px !important; right:12px !important; z-index:100001 !important; }\n        #ti-login-ov .ti-modal { width: min(38vw, 320px) !important; max-width: min(38vw, 320px) !important; padding: 22px !important; }\n\n        #ti-login-ov #l-db { width:100% !important; box-sizing:border-box !important; margin-top:8px !important; background:#111827 !important; color:#fff !important; border:1px solid #374151 !important; border-radius:8px !important; min-height:42px !important; }\n        @media (pointer: coarse), (max-width: 900px) {\n            #ti-login-ov { pointer-events:auto !important; touch-action:pan-y !important; }\n            #ti-login-ov .ti-modal { transform:none !important; pointer-events:auto !important; touch-action:pan-y !important; }\n            #ti-login-ov #l-db { display:block; font-size:16px !important; min-height:44px !important; }\n            #ti-login-ov #l-do { pointer-events:auto !important; touch-action:manipulation !important; }\n        }\n        #ti-login-ov #ti-login-form { width: 100%; margin: 0 auto; }\n        #ti-login-ov #ti-login-form .ti-in { margin: 8px 0; }\n        .ti-conf-window { z-index: 2 !important; }\n        #ti-plugin-modal-root { position: fixed !important; inset: 0 !important; z-index: 2147483000 !important; pointer-events: none !important; isolation:isolate !important; }\n        #ti-plugin-modal-root > .ti-ov, #ti-plugin-modal-root > #ti-ai-loader-ov { pointer-events: auto !important; }\n        .ti-plugin-scroll-lock { overscroll-behavior: contain; }\n        #ti-ai-outer, #ti-ai-outer * { box-sizing: border-box; }\n        #ti-ai-outer .ti-scrollable-plugin { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }\n        #ti-profile-form button[type=\"submit\"] { position: relative; z-index: 2; pointer-events: auto; }\n        .ti-profile-actions .ti-btn { flex:1; min-height:42px; height:42px; padding:10px 12px; display:flex; align-items:center; justify-content:center; font-size:15px; font-weight:bold; line-height:1.2; text-transform:none; }\n\n        \n        .ti-conf-window { position: fixed !important; top: 3vh !important; bottom: 3vh !important; left: 2vw !important; right: 2vw !important; width: auto !important; max-width: 800px !important; margin: auto !important; background: #1f2937 !important; border-radius: 12px !important; border: 2px solid #4b5563 !important; overflow: hidden !important; pointer-events: auto !important; box-shadow: 0 10px 40px rgba(0,0,0,0.9) !important; }\n        .ti-conf-header { position: absolute !important; top: 0 !important; left: 0 !important; right: 0 !important; height: 60px !important; padding: 0 15px !important; background: #111827 !important; border-bottom: 1px solid #444 !important; display: flex !important; justify-content: space-between !important; align-items: center !important; z-index: 10 !important; }\n        .ti-conf-body { position: absolute !important; top: 60px !important; bottom: 70px !important; left: 0 !important; right: 0 !important; overflow-y: auto !important; overflow-x: hidden !important; padding: 15px !important; background: #1f2937 !important; -webkit-overflow-scrolling: touch !important; overscroll-behavior: contain !important; z-index: 1 !important; }\n        .ti-conf-footer { position: absolute !important; bottom: 0 !important; left: 0 !important; right: 0 !important; height: 70px !important; padding: 15px !important; background: #111827 !important; border-top: 1px solid #444 !important; display: flex !important; gap: 10px !important; z-index: 99999 !important; pointer-events: auto !important; }\n        #ti-ai-outer .ti-actions-row,\n        #ti-ai-outer .ti-admin-actions-row { gap:5px !important; padding-bottom:1px !important; }\n        #ti-ai-outer .ti-actions-row .ti-btn,\n        #ti-ai-outer .ti-actions-row .ti-help,\n        #ti-ai-outer .ti-admin-actions-row .ti-btn { min-height:30px !important; height:30px !important; padding:5px 8px !important; font-size:11px !important; line-height:1 !important; border-radius:7px !important; white-space:nowrap !important; flex:0 0 auto !important; }\n        #ti-ai-outer .ti-actions-row #ti-help-btn { flex:0 0 34px !important; width:34px !important; min-width:34px !important; max-width:34px !important; height:30px !important; min-height:30px !important; padding:0 !important; font-size:14px !important; border-radius:7px !important; }\n        #ti-conf-ov .ti-conf-body { bottom:52px !important; }\n        #ti-conf-ov .ti-conf-footer { height:52px !important; padding:8px 10px !important; gap:6px !important; align-items:center !important; }\n        #ti-conf-ov .ti-conf-footer .ti-btn { min-height:34px !important; height:34px !important; padding:6px 10px !important; font-size:12px !important; line-height:1 !important; border-radius:7px !important; }\n        @media (max-width: 767px) {\n            #ti-ai-outer .ti-actions-row .ti-btn,\n            #ti-ai-outer .ti-actions-row .ti-help,\n            #ti-ai-outer .ti-admin-actions-row .ti-btn { min-height:28px !important; height:28px !important; padding:4px 6px !important; font-size:10.5px !important; }\n            #ti-ai-outer .ti-actions-row #ti-help-btn { width:30px !important; min-width:30px !important; max-width:30px !important; height:28px !important; min-height:28px !important; }\n            #ti-ai-outer .ti-conf-window .ti-cfg-sort-ind { width:18px !important; min-width:18px !important; height:18px !important; min-height:18px !important; font-size:10.5px !important; }\n            #ti-conf-ov .ti-conf-footer { height:48px !important; padding:7px 8px !important; }\n            #ti-conf-ov .ti-conf-body { bottom:48px !important; }\n            #ti-conf-ov .ti-conf-footer .ti-btn { min-height:32px !important; height:32px !important; padding:5px 8px !important; font-size:11px !important; }\n        }\n        \n        .ti-in { width: 100%; padding: 10px; margin: 10px 0; background: #111827; border: 1px solid #4b5563; color: #fff; border-radius: 8px; }\n        #ti-ai-outer input[type=\"text\"], #ti-ai-outer input[type=\"search\"], #ti-ai-outer input[type=\"email\"], #ti-ai-outer input[type=\"password\"], #ti-ai-outer input[type=\"number\"], #ti-ai-outer input[type=\"date\"], #ti-ai-outer input[type=\"time\"], #ti-ai-outer input[type=\"url\"], #ti-ai-outer input[type=\"tel\"], #ti-ai-outer textarea, #ti-ai-outer select, #ti-ai-outer option,\n        #ti-ai-outer .ti-in, #ti-ai-outer .ti-msg, #ti-ai-outer .ti-filter-input, #ti-ai-outer .ti-cfg-filter, #ti-ai-outer .ti-import-map-select, #ti-ai-outer .ti-import-map-input, #ti-ai-outer .ti-p-input, #ti-ai-outer .ti-q, #ti-ai-outer [contenteditable=\"true\"] {\n            color:#fff !important; -webkit-text-fill-color:#fff !important; caret-color:#fff !important; text-shadow:none !important;\n        }\n        #ti-ai-outer input:not([type=\"checkbox\"]):not([type=\"radio\"]), #ti-ai-outer textarea, #ti-ai-outer select, #ti-ai-outer .ti-in, #ti-ai-outer .ti-msg, #ti-ai-outer .ti-filter-input, #ti-ai-outer .ti-cfg-filter, #ti-ai-outer .ti-import-map-select, #ti-ai-outer .ti-import-map-input, #ti-ai-outer .ti-p-input, #ti-ai-outer .ti-q {\n            background-color:#111827 !important;\n        }\n        #ti-ai-outer input::placeholder, #ti-ai-outer textarea::placeholder, #ti-ai-outer select::placeholder, #ti-ai-outer .ti-in::placeholder, #ti-ai-outer .ti-msg::placeholder, #ti-ai-outer .ti-filter-input::placeholder, #ti-ai-outer .ti-cfg-filter::placeholder, #ti-ai-outer .ti-import-map-input::placeholder, #ti-ai-outer .ti-p-input::placeholder, #ti-ai-outer .ti-q::placeholder {\n            color:#d1d5db !important; opacity:1 !important; -webkit-text-fill-color:#d1d5db !important;\n        }\n        #ti-ai-outer input:focus, #ti-ai-outer textarea:focus, #ti-ai-outer select:focus, #ti-ai-outer .ti-in:focus, #ti-ai-outer .ti-msg:focus {\n            color:#fff !important; -webkit-text-fill-color:#fff !important;\n        }\n        #ti-filter-ditte { flex:1 1 0 !important; width:auto !important; min-width:0 !important; max-width:none !important; padding:6px 10px; border-radius:8px; background:#000; border:1px solid #444; color:#fff; text-align:left; margin-right:0; transition:none; font-weight:700 !important; }\n        #ti-filter-ditte::placeholder { font-weight:700 !important; }\n        #ti-filter-ditte:focus { flex:1 1 0 !important; width:auto !important; min-width:0 !important; max-width:none !important; text-align:left; }\n        \/* 30.9.1509: AZ + Tutte + ricerca restano sempre sulla stessa riga; la ricerca occupa tutto lo spazio residuo fino al bordo destro. *\/\n        #ti-ai-outer .ti-header-left-controls { flex:1 1 100% !important; width:100% !important; max-width:none !important; min-width:0 !important; flex-wrap:wrap !important; }\n        #ti-ai-outer .ti-header-left-controls > #ti-sort-btn { flex:0 0 35px !important; margin-right:0 !important; }\n        #ti-ai-outer .ti-header-left-controls > #ti-show-sospese-btn { flex:0 0 auto !important; margin-right:0 !important; }\n        #ti-ai-outer .ti-header-left-controls > #ti-filter-ditte { flex:1 1 0 !important; min-width:120px !important; }\n        #ti-ai-outer .ti-header-left-controls > .ti-ditta-picker { flex:1 1 100% !important; width:100% !important; }\n        #ti-ai-outer .ti-header-right-controls { flex:0 0 100% !important; width:100% !important; justify-content:flex-end !important; }\n        #ti-sort-btn { width: 35px; padding: 6px; border-radius: 8px; background: #222; border: 1px solid #444; color: #aaa; cursor: pointer; margin-right: 5px; text-align: center; font-size: 12px; font-weight: bold; }\n        .ti-table-wrap { max-height: 450px; overflow-y: auto; overflow-x: auto; border: 1px solid #444; border-radius: 6px; margin-top: 10px; background: #111; -webkit-overflow-scrolling: touch !important; }\n        .ti-prod-table { min-width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; text-align: left; }\n        .ti-prod-table th { background: #1f2937; padding: 8px 4px; border-bottom: 1px solid #555; font-size: 11px; position: sticky; top: 0; z-index: 20; box-shadow: 0 1px 0 #555; text-transform: uppercase; color: #aaa; cursor: pointer; }\n        .ti-prod-table td { padding: 4px; border-bottom: 1px solid #222; vertical-align: middle; line-height: 1.2; font-size: 12px; background: #000; }\n        .ti-filter-input { width: 100%; box-sizing: border-box; margin-top: 4px; padding: 2px; background: #000; border: 1px solid #444; color: #fff; font-size: 10px; border-radius: 3px; }\n        .ti-order-filterbar { display:flex; gap:8px; flex-wrap:nowrap; align-items:center; margin:8px 0 10px 0; overflow-x:auto; overflow-y:hidden; white-space:nowrap; -webkit-overflow-scrolling:touch; padding-bottom:2px; }\n        .ti-order-filtercell { display:flex; align-items:center; gap:4px; flex:0 0 auto; white-space:nowrap; min-height:32px; }\n        .ti-order-filterlabel { font-size:12px; color:#cbd5e1; min-width:auto; line-height:1; display:inline-flex; align-items:center; white-space:nowrap; margin:0; padding:0; }\n        .ti-order-filterbar .ti-filter-input, .ti-order-filterbar .ti-in { margin:0; font-size:12px; min-height:30px; line-height:1.1; vertical-align:middle; }\n        .ti-order-filterbar .ti-filter-input { width:126px; padding:5px 7px; }\n        .ti-order-filterbar .ti-in { width:150px; padding:5px 7px; }\n        .ti-order-filterbar::-webkit-scrollbar { height:7px; }\n        .ti-cfg-top-scroll, .ti-cfg-bottom-scroll, .ti-order-top-scroll, .ti-order-bottom-scroll { height:12px; overflow-x:auto; overflow-y:hidden; background:#000; border:1px solid #444; -webkit-overflow-scrolling:touch; }\n        .ti-cfg-top-scroll, .ti-order-top-scroll { position:sticky; top:0; z-index:4; border-bottom:none; border-radius:8px 8px 0 0; }\n        .ti-cfg-bottom-scroll, .ti-order-bottom-scroll { position:sticky; bottom:0; z-index:8; border-top:none; border-radius:0 0 8px 8px; margin-top:0; display:block; box-shadow:0 -1px 0 #111827, 0 -4px 10px rgba(0,0,0,0.35); }\n        .ti-order-top-scroll, .ti-order-bottom-scroll { position:relative; }\n        .ti-order-top-scroll { margin-top:10px; }\n        .ti-cfg-top-scroll-inner, .ti-sync-hscroll-inner { height:1px; }\n        .ti-cfg-top-scroll::-webkit-scrollbar, .ti-cfg-bottom-scroll::-webkit-scrollbar, .ti-order-top-scroll::-webkit-scrollbar, .ti-order-bottom-scroll::-webkit-scrollbar { height:8px; }\n        .ti-cfg-top-scroll, .ti-cfg-bottom-scroll, .ti-import-top-scroll, .ti-import-bottom-scroll, .ti-order-top-scroll, .ti-order-bottom-scroll { background:#d1d5db; border:1px solid #9ca3af; scrollbar-color:#9ca3af #e5e7eb; scrollbar-width:auto; }\n        .ti-cfg-top-scroll::-webkit-scrollbar, .ti-cfg-bottom-scroll::-webkit-scrollbar, .ti-import-top-scroll::-webkit-scrollbar, .ti-import-bottom-scroll::-webkit-scrollbar, .ti-order-top-scroll::-webkit-scrollbar, .ti-order-bottom-scroll::-webkit-scrollbar { height:12px; background:#e5e7eb; }\n        .ti-cfg-top-scroll::-webkit-scrollbar-track, .ti-cfg-bottom-scroll::-webkit-scrollbar-track, .ti-import-top-scroll::-webkit-scrollbar-track, .ti-import-bottom-scroll::-webkit-scrollbar-track, .ti-order-top-scroll::-webkit-scrollbar-track, .ti-order-bottom-scroll::-webkit-scrollbar-track { background:#e5e7eb; border-radius:8px; }\n        .ti-cfg-top-scroll::-webkit-scrollbar-thumb, .ti-cfg-bottom-scroll::-webkit-scrollbar-thumb, .ti-import-top-scroll::-webkit-scrollbar-thumb, .ti-import-bottom-scroll::-webkit-scrollbar-thumb, .ti-order-top-scroll::-webkit-scrollbar-thumb, .ti-order-bottom-scroll::-webkit-scrollbar-thumb { background:#9ca3af; border-radius:8px; border:2px solid #e5e7eb; }\n        .ti-cfg-top-scroll::-webkit-scrollbar-thumb:hover, .ti-cfg-bottom-scroll::-webkit-scrollbar-thumb:hover, .ti-import-top-scroll::-webkit-scrollbar-thumb:hover, .ti-import-bottom-scroll::-webkit-scrollbar-thumb:hover, .ti-order-top-scroll::-webkit-scrollbar-thumb:hover, .ti-order-bottom-scroll::-webkit-scrollbar-thumb:hover { background:#6b7280; }\n        .ti-ai-image-generator textarea, .ti-ai-image-generator input[type=\"text\"], .ti-imggen-wrap textarea, .ti-imggen-wrap input[type=\"text\"], #ai-gen-prompt { color:#fff !important; -webkit-text-fill-color:#fff !important; caret-color:#fff !important; background:#111827 !important; }\n        #ti-conf-ai-prompt, #ti-shared-base-path, #ti-shared-base-url, #help-email input, #help-email textarea, .ti-help-input, .ti-help-textarea { color:#fff !important; -webkit-text-fill-color:#fff !important; caret-color:#fff !important; background:#111827 !important; }\n        #ti-conf-ai-prompt::placeholder, #ti-shared-base-path::placeholder, #ti-shared-base-url::placeholder, #help-email input::placeholder, #help-email textarea::placeholder, .ti-help-input::placeholder, .ti-help-textarea::placeholder { color:#d1d5db !important; opacity:1 !important; }\n        .ti-conf-ai-desc-label { font-size:15px !important; line-height:1.45 !important; color:#cbd5e1 !important; font-weight:600 !important; }\n        .ti-shop-service-inline-icon, .ti-shop-service-logo-icon { display:inline-block; width:20px; height:20px; object-fit:cover; border-radius:6px; vertical-align:middle; box-shadow:0 0 0 1px rgba(255,255,255,.08); }\n        .ti-with-shop-service-icon{ display:inline-flex !important; align-items:center; gap:8px; }\n        .ti-ai-image-generator textarea::placeholder, .ti-ai-image-generator input[type=\"text\"]::placeholder, .ti-imggen-wrap textarea::placeholder, .ti-imggen-wrap input[type=\"text\"]::placeholder, #ai-gen-prompt::placeholder { color:#d1d5db !important; opacity:1 !important; }\n        .ti-ai-image-generator textarea:focus, .ti-ai-image-generator input[type=\"text\"]:focus, .ti-imggen-wrap textarea:focus, .ti-imggen-wrap input[type=\"text\"]:focus, #ai-gen-prompt:focus { color:#fff !important; -webkit-text-fill-color:#fff !important; outline:none !important; border-color:#9ca3af !important; box-shadow:0 0 0 1px #9ca3af inset !important; }\n        .ti-col-img { width: 50px; text-align: center; white-space: nowrap; } \n        .ti-col-disp { width: 80px; text-align: right; } \n        .ti-col-eur { width: 80px; white-space: nowrap; text-align: right; } \n        .ti-col-qta { width: 70px; text-align: right; } \n        .ti-col-tot { width: 80px; text-align: right; font-weight: bold; color: #38bdf8; }\n        .ti-row-img { width: 32px; height: 32px; object-fit: cover; border-radius: 4px; cursor: pointer; display: inline-block; vertical-align: middle; }\n        .ti-cfg-head-label { display:flex; align-items:center; justify-content:space-between; gap:6px; font-size:11px; }\n        .ti-cfg-head-actions { display:inline-flex; align-items:center; justify-content:flex-end; gap:4px; flex:0 0 auto; }\n        .ti-cfg-sort-ind { display:inline-flex; align-items:center; justify-content:center; width:18px; min-width:18px; height:18px; min-height:18px; margin-left:4px; border-radius:999px; background:#1e3a8a; color:#dbeafe; font-size:11px; font-weight:800; line-height:1; vertical-align:middle; box-shadow:0 0 0 1px rgba(147,197,253,.45) inset; }\n        .ti-cfg-filter { width:100%; box-sizing:border-box; margin-top:5px; padding:3px 5px; background:#000; border:1px solid #444; color:#fff; font-size:10px; border-radius:4px; }\n        .ti-cfg-filter:focus { outline:1px solid #38bdf8; border-color:#38bdf8; background:#020617; }\n        #ti-ai-outer .ti-conf-window .ti-cfg-filter,\n        #ti-ai-outer .ti-conf-window .ti-cfg-table input:not([data-ti-activation-protected=\"1\"]),\n        #ti-ai-outer .ti-conf-window .ti-cfg-table textarea:not([data-ti-activation-protected=\"1\"]),\n        #ti-ai-outer .ti-conf-window .ti-cfg-table select:not([data-ti-activation-protected=\"1\"]) { pointer-events:auto !important; user-select:text !important; -webkit-user-select:text !important; }\n        #ti-ai-outer .ti-conf-window .ti-cfg-table input:not([data-ti-activation-protected=\"1\"]):not([readonly]):not([disabled]),\n        #ti-ai-outer .ti-conf-window .ti-cfg-table textarea:not([data-ti-activation-protected=\"1\"]):not([readonly]):not([disabled]),\n        #ti-ai-outer .ti-conf-window .ti-cfg-filter:not([readonly]):not([disabled]),\n        #ti-ai-outer .ti-conf-window .ti-config-fast-table-507 input:not([readonly]):not([disabled]),\n        #ti-ai-outer .ti-conf-window .ti-config-fast-table-507 textarea:not([readonly]):not([disabled]),\n        #ti-ai-outer .ti-conf-window .ti-config-fast-table-507 select:not([disabled]) { pointer-events:auto !important; user-select:text !important; -webkit-user-select:text !important; opacity:1 !important; cursor:text !important; }\n        .ti-cfg-help-btn, .ti-cfg-pin-btn { display:inline-flex; align-items:center; justify-content:center; width:18px; height:18px; border-radius:999px; color:#fff; font-size:11px; cursor:pointer; border:none; padding:0; line-height:1; }\n        .ti-cfg-help-btn { background:#1d4ed8; }\n        .ti-cfg-help-btn:hover { background:#2563eb; }\n        .ti-cfg-pin-btn { background:#374151; opacity:.78; }\n        .ti-cfg-pin-btn:hover { opacity:1; background:#4b5563; }\n        .ti-cfg-pin-btn.is-active { background:#f59e0b; color:#111827; opacity:1; box-shadow:0 0 0 1px #fde68a inset; }\n        .ti-import-map-table { width:max-content; min-width:1400px; border-collapse:collapse; font-size:12px; }\n        .ti-import-map-table th, .ti-import-map-table td { border:1px solid #475569; padding:6px; vertical-align:top; }\n        .ti-import-map-table th { background:#0f172a; position:sticky; top:0; z-index:3; white-space:nowrap; }\n        .ti-import-map-select, .ti-import-map-input { width:100%; min-width:160px; box-sizing:border-box; background:#111827; color:#fff; border:1px solid #475569; border-radius:6px; padding:5px 6px; font-size:12px; }\n        .ti-import-table-container { max-width:100%; overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch; }\n        .ti-import-top-scroll, .ti-import-bottom-scroll { margin-top:6px; display:block; }\n        .ti-import-bottom-scroll, .ti-order-bottom-scroll, .ti-cfg-bottom-scroll { background:#000; }\n        .ti-import-top-scroll .ti-cfg-top-scroll-inner, .ti-import-bottom-scroll .ti-cfg-top-scroll-inner { min-width:1400px; }\n        .ti-order-modal-grid { display:grid; grid-template-columns:minmax(180px,1fr) minmax(220px,1fr); gap:14px; align-items:start; text-align:left; }\n        .ti-order-modal-img { width:100%; max-height:340px; object-fit:contain; border-radius:10px; background:#000; border:1px solid #374151; }\n        .ti-order-modal-caption { font-size:14px; color:#d1d5db; line-height:1.45; margin-bottom:10px; }\n        .ti-order-modal-line { margin:8px 0; font-size:14px; color:#fff; }\n        .ti-order-modal-actions { display:flex; gap:10px; margin-top:14px; }\n        .ti-order-modal-files { margin-top:12px; padding-top:10px; border-top:1px solid #334155; }\n        .ti-order-modal-files-title { font-size:12px; color:#93c5fd; font-weight:800; margin-bottom:8px; }\n        .ti-order-modal-files-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(92px, 1fr)); gap:8px; }\n        .ti-order-file-preview { border:1px solid #334155; background:#020617; border-radius:10px; padding:7px; color:#e5e7eb; cursor:pointer; min-height:96px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px; text-align:center; }\n        .ti-order-file-preview:hover { border-color:#38bdf8; background:#0f172a; }\n        .ti-order-file-preview img { width:100%; height:62px; object-fit:cover; border-radius:7px; background:#000; border:1px solid #1f2937; }\n        .ti-order-file-preview iframe { width:100%; height:62px; border:1px solid #1f2937; border-radius:7px; background:#000; pointer-events:none; }\n        .ti-order-file-preview-icon { width:100%; height:62px; display:flex; align-items:center; justify-content:center; border-radius:7px; background:#111827; font-size:26px; border:1px solid #1f2937; }\n        .ti-order-file-preview-name { width:100%; font-size:10px; color:#cbd5e1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n        .ti-order-file-preview-open { font-size:10px; color:#38bdf8; font-weight:700; }\n        @media (max-width: 768px) { \n            #ti-login-ov .ti-modal { width: min(92vw, 340px) !important; max-width: min(92vw, 340px) !important; padding: 20px !important; }.ti-order-modal-grid { grid-template-columns:1fr; } }\n        @media (max-width: 760px) {\n            html:not(.ti-no-scroll), body:not(.ti-no-scroll) { overflow-y:auto !important; height:auto !important; min-height:100% !important; touch-action:pan-y !important; }\n            #ti-ai-outer { width:100% !important; max-width:100% !important; min-height:auto !important; height:auto !important; overflow-y:visible !important; touch-action:pan-y !important; overscroll-behavior-y:auto !important; }\n            #ti-ai-outer .ti-header, #ti-ai-outer .ti-chat-box, #ti-ai-outer .ti-input-wrap, #ti-ai-outer .ti-actions-row, #ti-ai-outer .ti-admin-actions-row { touch-action:pan-y !important; }\n            .ti-ov { align-items:center !important; justify-content:center !important; overflow-y:auto !important; overflow-x:hidden !important; padding: max(10px, env(safe-area-inset-top)) 8px max(10px, env(safe-area-inset-bottom)) 8px !important; touch-action:pan-y !important; -webkit-overflow-scrolling:touch !important; }\n            .ti-modal { max-height: calc((var(--ti-vh, 1vh) * 92)) !important; overflow-y:auto !important; touch-action:pan-y !important; -webkit-overflow-scrolling:touch !important; }\n            #ti-login-ov .ti-modal { width:min(94vw, 380px) !important; max-width:min(94vw, 380px) !important; max-height:calc((var(--ti-vh, 1vh) * 88)) !important; }\n            #ti-login-ov .ti-in, #ti-login-ov .ti-btn, #ti-ai-outer input, #ti-ai-outer textarea, #ti-ai-outer select { font-size:16px !important; }\n            #ti-login-ov .ti-in, #ti-login-ov .ti-btn { min-height:44px !important; }\n            .ti-conf-window { top: max(8px, env(safe-area-inset-top)) !important; bottom: max(8px, env(safe-area-inset-bottom)) !important; left: 1vw !important; right: 1vw !important; max-width:98vw !important; }\n            .ti-conf-body { overflow-y:auto !important; overflow-x:auto !important; touch-action:pan-y !important; -webkit-overflow-scrolling:touch !important; }\n\n            #ti-ai-outer .ti-actions-row {\n                display:grid !important;\n                grid-template-columns:repeat(5, minmax(0, 1fr)) !important;\n                gap:4px !important;\n                overflow:visible !important;\n                padding-bottom:0 !important;\n                align-items:stretch !important;\n            }\n            #ti-ai-outer .ti-actions-row .ti-btn,\n            #ti-ai-outer .ti-actions-row .ti-help {\n                width:100% !important;\n                min-width:0 !important;\n                max-width:none !important;\n                height:30px !important;\n                min-height:30px !important;\n                padding:3px 3px !important;\n                border-radius:7px !important;\n                font-size:10px !important;\n                line-height:1.05 !important;\n                white-space:nowrap !important;\n                overflow:hidden !important;\n                text-overflow:ellipsis !important;\n                display:flex !important;\n                align-items:center !important;\n                justify-content:center !important;\n                gap:2px !important;\n            }\n            #ti-ai-outer .ti-actions-row #ti-help-btn {\n                margin-left:0 !important;\n                flex:1 1 auto !important;\n                width:100% !important;\n                min-width:0 !important;\n                max-width:none !important;\n                font-size:13px !important;\n                padding:3px 0 !important;\n            }\n            #ti-ai-outer .ti-admin-actions-row {\n                display:grid !important;\n                grid-template-columns:repeat(2, minmax(0, 1fr)) !important;\n                gap:5px !important;\n                overflow:visible !important;\n                padding-bottom:0 !important;\n            }\n            #ti-ai-outer .ti-admin-actions-row[style*=\"display: none\"] {\n                display:none !important;\n            }\n            #ti-ai-outer .ti-admin-actions-row .ti-btn {\n                width:100% !important;\n                min-width:0 !important;\n                min-height:31px !important;\n                height:31px !important;\n                padding:4px 5px !important;\n                font-size:10.5px !important;\n                border-radius:7px !important;\n                white-space:nowrap !important;\n                overflow:hidden !important;\n                text-overflow:ellipsis !important;\n            }\n        }\n        .ti-p-input { width: 100%; box-sizing: border-box; padding: 4px; background: #222; border: 1px solid #444; color: #fff; border-radius: 3px; font-size: 12px; font-family: inherit; height: 24px; line-height: 16px; }\n        .ti-p-input:focus { border-color: #38bdf8; outline: none; }\n        .ti-num-step { text-align: right; }\n        .ti-qty-stepper { display:inline-flex; align-items:center; gap:4px; width:100%; }\n        .ti-qty-stepper .ti-q, .ti-qty-stepper .ti-num-step, .ti-qty-stepper #ti-order-item-qty { flex:1 1 auto; min-width:0; margin:0; }\n        .ti-qty-btn { width:26px; min-width:26px; height:26px; border:1px solid #475569; background:#0f172a; color:#fff; border-radius:6px; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; font-weight:700; line-height:1; padding:0; }\n        .ti-qty-btn:hover { background:#1e293b; }\n        .ti-order-card-line .ti-qty-stepper { max-width:170px; }\n        .ti-order-modal-line .ti-qty-stepper { max-width:220px; display:inline-flex; vertical-align:middle; margin-left:8px; }\n        .ti-cfg-summary { font-weight: bold; color: #38bdf8; cursor: pointer; padding: 10px; background: #111827; border-radius: 5px; display: block; border: 1px solid #333; }\n        .ti-cfg-table-container { max-height: 60vh; overflow: auto; position: relative; background: #000; border: 1px solid #444; border-top: none; border-radius: 0 0 8px 8px; -webkit-overflow-scrolling: touch; }\n        .ti-cfg-table { width: max-content; min-width: 100%; border-collapse: separate; border-spacing: 0; }\n        .ti-cfg-table th { background: #1f2937; padding: 8px 10px; font-size: 11px; color: #ccc; border-bottom: 1px solid #444; border-right: 1px solid #444; position: sticky; top: 0; z-index: 20; text-transform: uppercase; white-space: nowrap; }\n        .ti-cfg-table th.ti-sticky-col { left: 34px; z-index: 34; background: #2563eb; color: #fff; box-shadow: 2px 0 0 #444; }\n        .ti-cfg-table th.ti-cfg-rownum, .ti-cfg-table td.ti-cfg-rownum { position: sticky; left: 0; width: 34px; min-width: 34px; max-width: 34px; text-align: center; font-weight: 700; box-shadow: 1px 0 0 #444; }\n        .ti-cfg-table th.ti-cfg-rownum { top: 0; z-index: 35; background: #0f172a; color: #bfdbfe; }\n        .ti-cfg-table td.ti-cfg-rownum { z-index: 12; background: #111827; color: #93c5fd; }\n        .ti-cfg-table td.ti-cfg-rownum.ti-instr-expired { color:#fecaca !important; background:#7f1d1d !important; border-color:#ef4444 !important; }\n        .ti-cfg-table td.ti-cfg-rownum.ti-instr-future { color:#fde68a !important; background:#78350f !important; border-color:#f59e0b !important; }\n        .ti-cfg-table td { padding: 5px; border-bottom: 1px solid #333; border-right: 1px solid #333; background: #000; vertical-align: top; }\n        .ti-cfg-table td.ti-sticky-col { position: sticky; left: 34px; z-index: 11; background: #111827; box-shadow: 2px 0 0 #333; }\n        .ti-cfg-table .ti-in { background: transparent; border: none; font-size: 12px; margin: 0; padding: 4px; color: #fff; width: 100%; box-sizing: border-box; }\n        .ti-cfg-table .ti-in:focus { background: rgba(56, 189, 248, 0.1); outline: 1px solid #38bdf8; }\n        .ti-profile-btn-eq { min-height:46px !important; height:46px !important; display:flex !important; align-items:center !important; justify-content:center !important; box-sizing:border-box !important; padding:0 12px !important; line-height:1 !important; font-size:15px !important; font-weight:700 !important; white-space:nowrap !important; border-radius:10px !important; }\n        .ti-profile-actions { display:grid !important; grid-template-columns:1fr 1fr 1fr !important; gap:8px !important; align-items:stretch !important; justify-content:stretch !important; }\n        .ti-profile-actions .ti-btn { min-height:46px !important; height:46px !important; display:flex !important; align-items:center !important; justify-content:center !important; box-sizing:border-box !important; margin:0 !important; }\n        .ti-eye-btn { font-size: 16px; cursor: pointer; margin-left: 5px; filter: grayscale(1); transition: 0.2s; }\n        .ti-eye-btn:hover { filter: grayscale(0); transform: scale(1.2); }\n        \/* 30.9.1609 - selezione e azioni compatte: nessuna colonna numerica Riga rif. *\/\n        .ti-cfg-table th.ti-cfg-select-col-1609, .ti-cfg-table td.ti-cfg-select-col-1609 { width:34px !important; min-width:34px !important; max-width:34px !important; padding:2px !important; }\n        .ti-cfg-table th.ti-cfg-actions-col-1609, .ti-cfg-table td.ti-cfg-actions-col-1609 { width:108px !important; min-width:108px !important; max-width:108px !important; box-sizing:border-box !important; }\n        .ti-cfg-table .ti-config-action-mini-1609 { width:22px !important; min-width:22px !important; max-width:22px !important; height:22px !important; min-height:22px !important; padding:0 !important; margin:0 !important; border-radius:4px !important; font-size:10px !important; line-height:1 !important; display:inline-flex !important; align-items:center !important; justify-content:center !important; }\n\n\n        .ti-report-toolbar { display:flex; align-items:center; gap:8px; flex-wrap:nowrap; overflow-x:auto; padding-bottom:8px; margin-bottom:10px; }\n        .ti-report-toolbar .ti-btn { white-space:nowrap; flex:0 0 auto; }\n        .ti-report-hidden-cols { display:flex; gap:6px; flex-wrap:wrap; margin:0 0 10px 0; }\n        .ti-report-col-chip { display:inline-flex; align-items:center; gap:6px; background:#111827; border:1px solid #374151; color:#e5e7eb; border-radius:999px; padding:4px 9px; font-size:11px; }\n        .ti-report-config-filter { display:inline-flex; align-items:center; gap:6px; background:#0f172a; border:1px solid #334155; color:#e5e7eb; border-radius:999px; padding:5px 10px; font-size:11px; white-space:nowrap; flex:0 0 auto; }\n        .ti-report-config-filter input { margin:0; accent-color:#38bdf8; }\n        .ti-report-table-wrap { max-height:58vh; overflow:auto; border:1px solid #444; border-radius:8px; background:#000; }\n        .ti-report-table { width:max-content; min-width:100%; border-collapse:separate; border-spacing:0; }\n        .ti-report-table th { position:sticky; top:0; background:#111827; color:#fff; z-index:3; min-width:120px; padding:8px 6px; border-bottom:1px solid #444; border-right:1px solid #333; cursor:pointer; font-size:11px; text-transform:uppercase; }\n        .ti-report-table td { padding:6px; border-bottom:1px solid #222; border-right:1px solid #222; background:#000; color:#e5e7eb; font-size:12px; vertical-align:top; }\n        .ti-report-table tr.ti-report-row-excluded td { opacity:0.45; background:#140c0c; text-decoration:line-through; }\n        .ti-report-table tfoot td { background:#0f172a; color:#38bdf8; font-weight:bold; position:sticky; bottom:0; z-index:2; border-top:1px solid #444; }\n        .ti-report-filter { width:100%; margin-top:6px; padding:4px 5px; border-radius:4px; border:1px solid #444; background:#000; color:#fff; font-size:10px; }\n        .ti-report-num { text-align:right; white-space:nowrap; }\n        .ti-report-flag-btn { display:inline-flex; align-items:center; justify-content:center; width:18px; height:18px; border-radius:50%; border:1px solid #7f1d1d; background:#b91c1c; color:#fff; font-size:11px; font-weight:bold; cursor:pointer; margin-right:6px; }\n        .ti-report-flag-btn.is-off { background:#111827; color:#f87171; border-color:#ef4444; }\n        .ti-report-row-flag-cell { position:sticky; left:0; z-index:2; background:#000 !important; min-width:44px; text-align:center; }\n        .ti-report-row-flag-cell.head { z-index:4; background:#1f2937 !important; }\n        .ti-chart-wrap { background:#000; border:1px solid #444; border-radius:8px; padding:12px; overflow:auto; }\n        \n        #ti-ai-loader-ov { position:fixed !important; inset:0 !important; background:rgba(0,0,0,0.7); display:none; align-items:center; justify-content:center; z-index:2147483646 !important; border-radius:14px; isolation:isolate !important; pointer-events:auto !important; }\n        .ti-loader-box { background:#1f2937; border:2px solid #38bdf8; padding:20px 30px; border-radius:12px; text-align:center; box-shadow:0 10px 25px rgba(0,0,0,0.5); }\n        .ti-loader-spinner { font-size:30px; margin-bottom:10px; animation: ti-spin 1.5s linear infinite; display:inline-block; }\n        @keyframes ti-spin { 100% { transform: rotate(360deg); } }\n\n        \/* GRID PROFILO UTENTE E FILE MANAGER *\/\n        .ti-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; text-align: left; }\n        .ti-grid-2 label { font-size:10px; color:#aaa; display:block; margin-bottom:2px;}\n        .ti-grid-2 .ti-in { margin:0; padding:6px; font-size:12px; }\n        .ti-cb-wrap { display: flex; align-items: center; gap: 5px; font-size:11px; color:#ccc;}\n        .ti-file-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: 10px; margin-top: 15px; max-height: 300px; overflow-y: auto; }\n        .ti-file-item { position: relative; background: #222; border: 1px solid #444; border-radius: 6px; padding: 5px; text-align: center; }\n        .ti-file-item img { width: 100%; height: 60px; object-fit: cover; border-radius: 4px; }\n        .ti-file-item .file-icon { font-size: 30px; line-height: 60px; color: #888; }\n        .ti-file-name { font-size: 9px; color: #ccc; margin-top: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n        .ti-file-del { position: absolute; top: -5px; right: -5px; background: #ef4444; color: white; border: none; border-radius: 50%; width: 20px; height: 20px; font-size: 10px; cursor: pointer; }\n        .ti-btn-catalog { background:#1d4ed8; color:#fff; border-color:#1e40af; }\n        .ti-btn-catalog.ti-btn-services { background:#047857; border-color:#065f46; }\n        #ti-ai-outer .ti-catalog-unavailable-1969, #ti-ai-outer .ti-catalog-unavailable-1970 { display:none !important; }\n        #ti-ai-outer #ti-activities-btn.ti-btn-activities { display:none!important; background:#7c3aed; border-color:#5b21b6; color:#fff; font-weight:800; }\n        #ti-ditta { height: 34px; min-height: 34px; width: 400px; max-width: 400px; min-width: 400px; box-sizing: border-box; }\n        #ti-ditta option { background:#000 !important; }\n        #ti-ditta option[data-status=\"attivo\"] { color:#ffffff !important; }\n        #ti-ditta option[data-status=\"sospesa\"] { color:#ef4444 !important; font-weight:700 !important; }\n        #ti-ditta option[data-status=\"configurazione\"] { color:#facc15 !important; font-weight:700 !important; }\n        #ti-ditta option[data-status=\"demo\"] { color:#38bdf8 !important; font-weight:700 !important; }\n        #ti-ditta option[data-status=\"nuova\"] { color:#10b981 !important; font-weight:700 !important; }\n        #ti-ditta option[data-status=\"sviluppo\"] { color:#ef4444 !important; font-weight:700 !important; }\n        .ti-ditta-picker { position:relative; flex:1 1 100%; width:100%; min-width:0; max-width:none; }\n        .ti-header-left-controls .ti-ditta-picker { flex:1 1 100%; width:100%; max-width:none; }\n        .ti-ditta-trigger { display:block; width:100%; min-height:36px; padding:6px 12px; border-radius:8px; background:#000; color:#fff; border:1px solid #444; text-align:left; cursor:pointer; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n        .ti-ditta-popup { position:absolute; top:calc(100% + 4px); left:0; right:0; width:100%; z-index:999999; max-height:320px; overflow:auto; background:#030712; border:1px solid #334155; border-radius:10px; box-shadow:0 12px 32px rgba(0,0,0,.55); padding:6px; }\n        .ti-ditta-row { display:flex; align-items:center; justify-content:space-between; gap:10px; width:100%; padding:8px 10px; border-radius:8px; cursor:pointer; background:#020617; border:1px solid transparent; text-align:left; font-size:13px; line-height:1.3; }\n        .ti-ditta-row:hover, .ti-ditta-row.active { background:#111827; border-color:#334155; }\n        .ti-ditta-row.attivo { border-left:3px solid #ffffff; }\n        .ti-ditta-row.sospesa { border-left:3px solid #ef4444; background:rgba(127,29,29,.18); }\n        .ti-ditta-row.sviluppo { border-left:3px solid #ef4444; background:rgba(127,29,29,.18); }\n        .ti-ditta-row.configurazione { border-left:3px solid #facc15; background:rgba(161,98,7,.16); }\n        .ti-ditta-row.demo { border-left:3px solid #38bdf8; background:rgba(14,116,144,.20); }\n        .ti-ditta-row.nuova { border-left:3px solid #10b981; background:rgba(6,95,70,.16); }\n        .ti-ditta-row.empty, .ti-ditta-row.none { border-left:3px solid #94a3b8; }\n        .ti-ditta-row-main { display:block; flex:1 1 auto; min-width:0; color:#fff !important; font-weight:500 !important; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-size:var(--ti-font-base) !important; line-height:1.25 !important; }\n        .ti-ditta-row-badge { flex:0 0 auto; padding:2px 8px; border-radius:999px; font-size:11px; font-weight:800; letter-spacing:.01em; border:1px solid currentColor; }\n        .ti-ditta-row-badge.sospesa { color:#ef4444 !important; background:rgba(127,29,29,.20); }\n        .ti-ditta-row-badge.sviluppo { color:#ef4444 !important; background:rgba(127,29,29,.20); }\n        .ti-ditta-row-badge.configurazione { color:#facc15 !important; background:rgba(161,98,7,.18); }\n        .ti-ditta-row-badge.demo { color:#38bdf8 !important; background:rgba(14,116,144,.22); }\n        .ti-ditta-row-badge.nuova { color:#10b981 !important; background:rgba(6,95,70,.18); }\n        .ti-ditta-row-badge.attivo { color:#ffffff !important; background:rgba(255,255,255,.06); }\n        #ti-login-btn, #ti-logout-btn { min-height: 34px; height: 34px; padding: 0 12px; line-height: 34px; box-sizing: border-box; display:inline-flex; align-items:center; justify-content:center; }\n        @media (min-width: 769px) {\n            #ti-ai-outer .ti-header-bottom {\n                align-items: flex-end !important;\n            }\n            #ti-ai-outer .ti-header-right-controls {\n                align-self: flex-end !important;\n                display: flex !important;\n                align-items: center !important;\n                justify-content: flex-end !important;\n                min-height: 36px !important;\n                margin-top: auto !important;\n                margin-bottom: 0 !important;\n                padding-bottom: 0 !important;\n            }\n            #ti-ai-outer #ti-login-btn,\n            #ti-ai-outer #ti-logout-btn {\n                height: 36px !important;\n                min-height: 36px !important;\n                line-height: 1 !important;\n                display: inline-flex !important;\n                align-items: center !important;\n                justify-content: center !important;\n                margin-top: 0 !important;\n                margin-bottom: 0 !important;\n                align-self: center !important;\n            }\n            #ti-ai-outer .ti-ditta-trigger {\n                min-height: 36px !important;\n                height: 36px !important;\n                display: flex !important;\n                align-items: center !important;\n            }\n        }\n        #ti-user-area { align-self: center; height:34px; min-height:34px; display:none; align-items:center; }\n\n        .ti-order-wrap { margin-top:10px; }\n        .ti-order-toolbar { display:flex; gap:6px; flex-wrap:wrap; align-items:center; justify-content:space-between; padding:8px; background:#0b1220; border:1px solid #223047; border-bottom:none; border-radius:8px 8px 0 0; }\n        .ti-order-toolbar-left, .ti-order-toolbar-right { display:flex; gap:6px; flex-wrap:wrap; align-items:center; }\n        .ti-order-view-btn { padding:6px 10px; border-radius:8px; background:#1f2937; color:#cbd5e1; border:1px solid #334155; cursor:pointer; font-size:12px; font-weight:700; }\n        .ti-order-view-btn.active { background:#2563eb; color:#fff; border-color:#1d4ed8; }\n        .ti-order-hint { color:#94a3b8; font-size:11px; }\n        .ti-order-table-shell { display:block; }\n        .ti-order-grid-view { display:none; padding:12px; border:1px solid #444; border-top:none; border-radius:0 0 8px 8px; background:#111; }\n        .ti-order-wrap.ti-view-small .ti-order-table-shell,\n        .ti-order-wrap.ti-view-medium .ti-order-table-shell,\n        .ti-order-wrap.ti-view-large .ti-order-table-shell { display:none; }\n        .ti-order-wrap.ti-view-small .ti-order-grid-view,\n        .ti-order-wrap.ti-view-medium .ti-order-grid-view,\n        .ti-order-wrap.ti-view-large .ti-order-grid-view { display:grid; }\n        .ti-order-wrap.ti-view-small .ti-order-grid-view { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }\n        .ti-order-wrap.ti-view-medium .ti-order-grid-view { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }\n        .ti-order-wrap.ti-view-large .ti-order-grid-view { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }\n        .ti-qty-stepper { display:flex; align-items:center; gap:4px; min-width:118px; }\n        .ti-qty-stepper .ti-q, .ti-qty-stepper .ti-num-step { min-width:64px; flex:1 1 70px; display:block; }\n        .ti-col-qta { min-width:132px; }\n        .ti-order-card { background:#06080f; border:1px solid #243042; border-radius:12px; overflow:hidden; display:flex; flex-direction:column; min-height:100%; }\n        .ti-order-card-media { background:#000; display:flex; align-items:center; justify-content:center; overflow:hidden; }\n        .ti-order-card-media img { width:100%; object-fit:cover; display:block; }\n        .ti-order-card-media .ti-order-file-icon { font-size:36px; color:#64748b; padding:30px 0; }\n        .ti-order-wrap.ti-view-small .ti-order-card-media { height:120px; }\n        .ti-order-wrap.ti-view-medium .ti-order-card-media { height:180px; }\n        .ti-order-wrap.ti-view-large .ti-order-card-media { height:260px; }\n        .ti-order-card-body { padding:10px; display:flex; flex-direction:column; gap:8px; }\n        \/* 30.9.1856 - immagini catalogo sempre complete, ridimensionate per layout *\/\n        .ti-order-card-media { flex:0 0 auto; box-sizing:border-box; padding:4px; }\n        .ti-order-card-media img { width:100% !important; height:100% !important; max-width:100% !important; max-height:100% !important; object-fit:contain !important; object-position:center center !important; }\n        .ti-row-img { object-fit:contain !important; background:#000; }\n        .ti-order-wrap.ti-view-small .ti-order-card-media { height:96px; }\n        .ti-order-wrap.ti-view-medium .ti-order-card-media { height:150px; }\n        .ti-order-wrap.ti-view-large .ti-order-card-media { height:220px; }\n        .ti-order-card-body { position:relative; z-index:1; flex:1 1 auto; min-height:0; }\n        \/* 30.9.1859 - catalogo diretto: impedisce a stati legacy della chat di coprire\/nascondere le voci *\/\n        #ti-ai-outer .ti-bubble.ai.ti-direct-catalog-1859,\n        #ti-ai-outer .ti-bubble.ai.ti-direct-catalog-1859 .ti-order-wrap { height:auto !important; max-height:none !important; overflow:visible !important; visibility:visible !important; opacity:1 !important; }\n        #ti-ai-outer .ti-bubble.ai.ti-direct-catalog-1859 .ti-order-wrap.ti-view-small .ti-order-grid-view,\n        #ti-ai-outer .ti-bubble.ai.ti-direct-catalog-1859 .ti-order-wrap.ti-view-medium .ti-order-grid-view,\n        #ti-ai-outer .ti-bubble.ai.ti-direct-catalog-1859 .ti-order-wrap.ti-view-large .ti-order-grid-view { display:grid !important; height:auto !important; max-height:none !important; overflow:visible !important; visibility:visible !important; opacity:1 !important; }\n        #ti-ai-outer .ti-bubble.ai.ti-direct-catalog-1859 .ti-order-card { display:flex !important; visibility:visible !important; height:auto !important; max-height:none !important; opacity:1 !important; position:relative !important; z-index:1 !important; }\n\n        .ti-order-card-title { font-size:13px; font-weight:800; color:#fff; display:flex; align-items:center; gap:6px; }\n        .ti-order-card-title .ti-order-badge { font-size:11px; font-weight:900; padding:2px 6px; border-radius:99px; }\n        .ti-order-card-title .ti-order-badge.product { background:#1d4ed8; color:#fff; }\n        .ti-order-card-title .ti-order-badge.service { background:#047857; color:#fff; }\n        .ti-order-card-desc { font-size:11px; color:#cbd5e1; line-height:1.35; min-height:42px; }\n        .ti-order-card-meta { display:grid; grid-template-columns:1fr 1fr; gap:8px; align-items:end; }\n        .ti-order-card-label { font-size:10px; color:#94a3b8; text-transform:uppercase; letter-spacing:.04em; margin-bottom:3px; }\n        .ti-order-card-total { font-weight:800; color:#38bdf8; font-size:14px; }\n        .ti-order-price-alert-1863 { display:inline-flex;align-items:center;justify-content:center;width:19px;height:19px;min-width:19px;border:0;border-radius:50%;background:#dc2626;color:#fff;font-weight:900;font-size:13px;line-height:1;cursor:pointer;padding:0;margin:0 5px 0 0;vertical-align:middle;box-shadow:0 0 0 1px rgba(255,255,255,.18); }\n        .ti-order-price-alert-1863:hover,.ti-order-price-alert-1863:focus { background:#ef4444;outline:2px solid rgba(239,68,68,.35);outline-offset:1px; }\n        .ti-order-table-price-alert-1863 { margin-left:4px;margin-right:0; }\n        .ti-order-card .ti-q { width:100%; padding:6px; border-radius:8px; border:1px solid #334155; background:#0f172a; color:#fff; text-align:right; }\n        .ti-order-footer { display:none !important; }\n        .ti-order-footer-grid { display:none !important; }\n        .ti-order-footer-total { display:none !important; }\n        .ti-order-footer-total b { display:none !important; }\n        .ti-order-footer-btn { display:none !important; visibility:hidden !important; width:0 !important; min-width:0 !important; padding:0 !important; border:0 !important; margin:0 !important; overflow:hidden !important; }\n\n        @media (max-width: 768px) { \n            .ti-header { flex-direction: column; align-items: stretch; padding: 12px; } \n            .ti-header-top { flex-wrap: wrap; align-items:flex-start; } \n            .ti-header-main-left { width:100%; } \n            .ti-hr-right { width: 100%; align-items: center; justify-content:flex-end; margin-top: 0; } \n            .ti-header-bottom { flex-direction: column; align-items: stretch; } \n            .ti-header-left-controls { width:100%; } \n            .ti-header-right-controls { width:100%; justify-content:flex-end; } \n            .ti-hr-bottom { flex-wrap: wrap; width: 100%; justify-content: flex-start; } \n            #ti-ditta { max-width: 100%; min-width: 0; width: 100%; flex: 1; } \n            .ti-actions-row button { padding: 8px 10px; font-size: 11px; } \n            .ti-grid-2 { grid-template-columns: 1fr; }\n            .ti-modal { width: min(94vw, 520px); max-width:min(94vw, 520px); max-height: 88vh; overflow-y: auto; }\n\n            .ti-order-toolbar-right { width:100%; }\n            .ti-order-hint { display:block; }\n            #ti-ai-outer .ti-actions-row {\n                display:grid !important;\n                grid-template-columns:repeat(5, minmax(0, 1fr)) !important;\n                gap:4px !important;\n                overflow:visible !important;\n                padding-bottom:0 !important;\n            }\n            #ti-ai-outer .ti-actions-row button,\n            #ti-ai-outer .ti-actions-row .ti-btn,\n            #ti-ai-outer .ti-actions-row .ti-help {\n                padding:3px 3px !important;\n                font-size:10px !important;\n                min-height:30px !important;\n                height:30px !important;\n                min-width:0 !important;\n                width:100% !important;\n                max-width:none !important;\n                border-radius:7px !important;\n                white-space:nowrap !important;\n                overflow:hidden !important;\n                text-overflow:ellipsis !important;\n            }\n            #ti-ai-outer .ti-actions-row #ti-help-btn {\n                margin-left:0 !important;\n                width:100% !important;\n                min-width:0 !important;\n                max-width:none !important;\n                font-size:13px !important;\n            }\n            #ti-ai-outer .ti-admin-actions-row {\n                grid-template-columns:repeat(2, minmax(0, 1fr)) !important;\n                gap:5px !important;\n                overflow:visible !important;\n            }\n            #ti-ai-outer .ti-admin-actions-row .ti-btn {\n                width:100% !important;\n                min-width:0 !important;\n                height:31px !important;\n                min-height:31px !important;\n                padding:4px 5px !important;\n                font-size:10.5px !important;\n                border-radius:7px !important;\n                white-space:nowrap !important;\n                overflow:hidden !important;\n                text-overflow:ellipsis !important;\n            }\n        }\n\n        @media (max-width: 640px) {\n            .ti-header { align-items:flex-start; }\n            .ti-header-top { align-items:flex-start; }\n            .ti-hl { align-items:flex-start; }\n            .ti-left-stack { gap:4px; }\n            .ti-user-area { max-width: 170px; padding: 2px 6px; }\n            .ti-user-name { font-size: 10px; }\n        }\n\n    \n        @media (max-width: 760px) {\n            html, body, html.ti-no-scroll, body.ti-no-scroll {\n                overflow-y:auto !important;\n                overflow-x:hidden !important;\n                height:auto !important;\n                min-height:100% !important;\n                position:static !important;\n                touch-action:auto !important;\n                -webkit-overflow-scrolling:touch !important;\n            }\n            #ti-ai-outer,\n            #ti-ai-outer * {\n                -webkit-tap-highlight-color: rgba(59,130,246,.25);\n            }\n            #ti-ai-outer,\n            #ti-ai-outer .ti-chat-box,\n            #ti-ai-outer .ti-input-wrap,\n            #ti-ai-outer .ti-actions-row,\n            #ti-ai-outer .ti-admin-actions-row,\n            #ti-ai-outer .ti-modal,\n            #ti-ai-outer .ti-ov,\n            #ti-ai-outer .ti-conf-body,\n            #ti-ai-outer .ti-cfg-table-container,\n            #ti-ai-outer .ti-table-wrap {\n                touch-action:auto !important;\n                overscroll-behavior-y:auto !important;\n                -webkit-overflow-scrolling:touch !important;\n            }\n            .ti-ov {\n                overflow-y:auto !important;\n                overflow-x:hidden !important;\n                align-items:flex-start !important;\n                pointer-events:auto !important;\n            }\n            .ti-modal {\n                max-height:90dvh !important;\n                overflow-y:auto !important;\n                pointer-events:auto !important;\n            }\n            #ti-login-ov {\n                z-index:2147483600 !important;\n                padding: max(8px, env(safe-area-inset-top)) 6px max(8px, env(safe-area-inset-bottom)) 6px !important;\n            }\n            #ti-login-ov .ti-modal {\n                width:96vw !important;\n                max-width:390px !important;\n                min-width:0 !important;\n                margin:8px auto 20px auto !important;\n                padding:16px !important;\n                box-sizing:border-box !important;\n            }\n            #ti-login-ov input,\n            #ti-login-ov select,\n            #ti-login-ov button {\n                pointer-events:auto !important;\n                font-size:16px !important;\n                min-height:42px !important;\n            }\n            #ti-login-ov #l-do {\n                min-height:44px !important;\n                touch-action:manipulation !important;\n            }\n        }\n\n\n        @media (hover:none), (pointer:coarse), (max-width:900px) {\n            html, body,\n            html.ti-no-scroll, body.ti-no-scroll {\n                overflow-y:auto !important;\n                overflow-x:hidden !important;\n                height:auto !important;\n                min-height:100% !important;\n                max-height:none !important;\n                position:static !important;\n                touch-action:pan-y !important;\n                overscroll-behavior-y:auto !important;\n                -webkit-overflow-scrolling:touch !important;\n            }\n            #ti-ai-outer,\n            #ti-ai-outer.ti-plugin-scroll-lock,\n            .ti-plugin-scroll-lock {\n                overflow-y:visible !important;\n                overflow-x:hidden !important;\n                height:auto !important;\n                min-height:auto !important;\n                max-height:none !important;\n                position:relative !important;\n                touch-action:pan-y !important;\n                overscroll-behavior-y:auto !important;\n                -webkit-overflow-scrolling:touch !important;\n            }\n            #ti-ai-outer *,\n            #ti-plugin-modal-root,\n            #ti-plugin-modal-root * {\n                touch-action:pan-y !important;\n            }\n            #ti-ai-outer button,\n            #ti-ai-outer input,\n            #ti-ai-outer textarea,\n            #ti-ai-outer select,\n            #ti-plugin-modal-root button,\n            #ti-plugin-modal-root input,\n            #ti-plugin-modal-root textarea,\n            #ti-plugin-modal-root select,\n            #ti-login-btn,\n            #ti-logout-btn,\n            #l-do {\n                touch-action:manipulation !important;\n                -webkit-user-select:auto !important;\n                user-select:auto !important;\n                pointer-events:auto !important;\n            }\n            .ti-ov,\n            #ti-ai-loader-ov {\n                overflow-y:auto !important;\n                overflow-x:hidden !important;\n                align-items:flex-start !important;\n                justify-content:center !important;\n                touch-action:pan-y !important;\n                overscroll-behavior-y:auto !important;\n                -webkit-overflow-scrolling:touch !important;\n            }\n            .ti-modal,\n            .ti-conf-body,\n            .ti-chat-box,\n            .ti-cfg-table-container,\n            .ti-table-wrap,\n            #ti-conf-import-preview-body,\n            #global-action-res,\n            #help-bot-reply,\n            #col-help-content,\n            #ateco-res,\n            #fm-grid {\n                overflow-y:auto !important;\n                touch-action:pan-y !important;\n                overscroll-behavior-y:auto !important;\n                -webkit-overflow-scrolling:touch !important;\n            }\n            #ti-login-ov .ti-modal {\n                width:min(96vw, 390px) !important;\n                max-width:min(96vw, 390px) !important;\n                max-height:calc((var(--ti-vh, 1vh) * 88)) !important;\n                margin:8px auto 20px auto !important;\n            }\n            #ti-login-ov input,\n            #ti-login-ov button {\n                font-size:16px !important;\n                min-height:44px !important;\n            }\n        }\n        #ti-ai-outer #ti-mobile-direct-login {\n            display:none !important;\n            width:min(100%, 720px) !important;\n            margin:10px auto 12px auto !important;\n            padding:12px !important;\n            border-radius:14px !important;\n            background:#111827 !important;\n            border:1px solid #374151 !important;\n            color:#fff !important;\n            touch-action:pan-y !important;\n            box-sizing:border-box !important;\n        }\n        #ti-ai-outer #ti-mobile-direct-login.ti-direct-login-visible {\n            display:block !important;\n        }\n        #ti-ai-outer #ti-mobile-direct-login .ti-mobile-login-title {\n            font-size:14px !important;\n            font-weight:900 !important;\n            margin-bottom:8px !important;\n            color:#bfdbfe !important;\n        }\n        #ti-ai-outer #ti-mobile-direct-login form {\n            display:grid !important;\n            grid-template-columns:1fr 1fr 1.2fr auto !important;\n            gap:8px !important;\n            width:100% !important;\n            align-items:center !important;\n        }\n        #ti-ai-outer #ti-mobile-direct-login input,\n        #ti-ai-outer #ti-mobile-direct-login select,\n        #ti-ai-outer #ti-mobile-direct-login button {\n            width:100% !important;\n            min-width:0 !important;\n            min-height:38px !important;\n            height:38px !important;\n            font-size:16px !important;\n            line-height:18px !important;\n            padding:6px 8px !important;\n            border-radius:9px !important;\n            box-sizing:border-box !important;\n            touch-action:manipulation !important;\n        }\n        #ti-ai-outer #ti-mobile-direct-login input,\n        #ti-ai-outer #ti-mobile-direct-login select {\n            background:#0f172a !important;\n            color:#fff !important;\n            border:1px solid #334155 !important;\n        }\n        #ti-ai-outer #ti-mobile-direct-login .ti-mobile-login-submit {\n            background:#2563eb !important;\n            color:#fff !important;\n            border:1px solid #1d4ed8 !important;\n            font-weight:900 !important;\n            white-space:nowrap !important;\n            cursor:pointer !important;\n            transition: opacity 0.1s ease, transform 0.1s ease !important;\n        }\n        #ti-ai-outer #ti-mobile-direct-login .ti-mobile-login-submit:active {\n            opacity:0.65 !important;\n            transform:scale(0.97) !important;\n        }\n        @media (hover:none), (pointer:coarse), (max-width:900px) {\n            #ti-ai-outer #ti-mobile-direct-login {\n                width:100% !important;\n                margin:8px 0 10px 0 !important;\n                padding:10px !important;\n            }\n            #ti-ai-outer #ti-mobile-direct-login form {\n                grid-template-columns:1fr 1fr !important;\n                gap:7px !important;\n            }\n            #ti-ai-outer #ti-mobile-direct-login select,\n            #ti-ai-outer #ti-mobile-direct-login .ti-mobile-login-submit {\n                grid-column:1 \/ -1 !important;\n            }\n        }\n\n        #ti-purchase-ov .ti-purchase-table-wrap {\n            width:100% !important;\n            max-width:100% !important;\n            overflow-x:auto !important;\n            overflow-y:visible !important;\n            -webkit-overflow-scrolling:touch !important;\n            touch-action:pan-x pan-y !important;\n        }\n        #ti-purchase-ov #ti-purchase-table {\n            border-collapse:collapse !important;\n            width:100% !important;\n            min-width:1060px !important;\n        }\n        #ti-purchase-ov #ti-purchase-table th,\n        #ti-purchase-ov #ti-purchase-table td {\n            white-space:nowrap !important;\n        }\n        #ti-purchase-ov .ti-purchase-row input,\n        #ti-purchase-ov .ti-purchase-row select,\n        #ti-purchase-ov .ti-purchase-row textarea {\n            background:#0f172a !important;\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            caret-color:#fff !important;\n        }\n        .ti-purchase-row-search-popover {\n            position:fixed !important;\n            z-index:2147483647 !important;\n            background:#020617 !important;\n            border:1px solid #38bdf8 !important;\n            border-radius:10px !important;\n            box-shadow:0 16px 44px rgba(0,0,0,.65) !important;\n            max-height:min(320px, 52vh) !important;\n            overflow:auto !important;\n            padding:6px !important;\n            min-width:220px !important;\n            max-width:min(92vw, 520px) !important;\n            color:#fff !important;\n            pointer-events:auto !important;\n            -webkit-overflow-scrolling:touch !important;\n        }\n        .ti-purchase-row-search-popover .ti-purchase-result-row {\n            display:block !important;\n            width:100% !important;\n            text-align:left !important;\n            margin:0 0 5px 0 !important;\n            padding:7px 8px !important;\n            border-radius:8px !important;\n            border:1px solid #334155 !important;\n            background:#1e293b !important;\n            color:#fff !important;\n            font-size:12px !important;\n            line-height:1.25 !important;\n            cursor:pointer !important;\n        }\n        .ti-purchase-row-search-popover .ti-purchase-result-row small {\n            display:block !important;\n            color:#cbd5e1 !important;\n            font-size:10.5px !important;\n            margin-top:2px !important;\n        }\n        .ti-report-outcome-filter-wrap {\n            display:inline-flex !important;\n            align-items:center !important;\n            gap:6px !important;\n            background:#0f172a !important;\n            border:1px solid #334155 !important;\n            color:#e5e7eb !important;\n            border-radius:999px !important;\n            padding:5px 10px !important;\n            font-size:11px !important;\n            white-space:nowrap !important;\n            flex:0 0 auto !important;\n        }\n        .ti-report-outcome-filter {\n            width:auto !important;\n            min-width:120px !important;\n            padding:4px 7px !important;\n            border-radius:7px !important;\n            border:1px solid #94a3b8 !important;\n            background:#fff !important;\n            color:#111827 !important;\n            -webkit-text-fill-color:#111827 !important;\n            font-size:11px !important;\n            margin:0 !important;\n        }\n        .ti-report-outcome-filter option {\n            background:#fff !important;\n            color:#111827 !important;\n            -webkit-text-fill-color:#111827 !important;\n        }\n        #ti-ai-outer input[style*=\"background:#020617\"],\n        #ti-ai-outer input[style*=\"background: #020617\"],\n        #ti-ai-outer input[style*=\"background:#0f172a\"],\n        #ti-ai-outer input[style*=\"background: #0f172a\"],\n        #ti-ai-outer input[style*=\"background:#111827\"],\n        #ti-ai-outer input[style*=\"background: #111827\"],\n        #ti-ai-outer textarea[style*=\"background:#020617\"],\n        #ti-ai-outer textarea[style*=\"background: #020617\"],\n        #ti-ai-outer textarea[style*=\"background:#0f172a\"],\n        #ti-ai-outer textarea[style*=\"background: #0f172a\"],\n        #ti-ai-outer textarea[style*=\"background:#111827\"],\n        #ti-ai-outer textarea[style*=\"background: #111827\"],\n        #ti-ai-outer select[style*=\"background:#020617\"],\n        #ti-ai-outer select[style*=\"background: #020617\"],\n        #ti-ai-outer select[style*=\"background:#0f172a\"],\n        #ti-ai-outer select[style*=\"background: #0f172a\"],\n        #ti-ai-outer select[style*=\"background:#111827\"],\n        #ti-ai-outer select[style*=\"background: #111827\"],\n        #ti-ai-outer .ti-in,\n        #ti-plugin-modal-root .ti-in {\n            color:#fff !important;\n            -webkit-text-fill-color:#fff !important;\n            caret-color:#fff !important;\n        }\n        @media (max-width:767px) and (orientation:portrait) {\n            #ti-purchase-ov .ti-purchase-modal { width:98vw !important; max-width:98vw !important; padding:10px !important; }\n            #ti-purchase-ov #ti-purchase-table { min-width:980px !important; }\n            #ti-purchase-ov #ti-purchase-table th,\n            #ti-purchase-ov #ti-purchase-table td { font-size:10.5px !important; padding:4px !important; }\n            #ti-purchase-ov #ti-purchase-table input,\n            #ti-purchase-ov #ti-purchase-table select,\n            #ti-purchase-ov #ti-purchase-table textarea,\n            #ti-purchase-ov #ti-purchase-table button { font-size:10.5px !important; padding:4px !important; min-height:27px !important; }\n            #ti-purchase-ov .ti-pur-name { min-width:190px !important; }\n            .ti-purchase-row-search-popover .ti-purchase-result-row { font-size:10.5px !important; padding:6px !important; }\n            .ti-purchase-row-search-popover .ti-purchase-result-row small { font-size:9.5px !important; }\n        }\n        @media (max-width:920px) and (orientation:landscape) {\n            #ti-purchase-ov .ti-purchase-modal { width:98vw !important; max-width:98vw !important; padding:10px !important; }\n            #ti-purchase-ov #ti-purchase-table { min-width:900px !important; }\n            #ti-purchase-ov #ti-purchase-table th,\n            #ti-purchase-ov #ti-purchase-table td { font-size:10px !important; padding:3px !important; }\n            #ti-purchase-ov #ti-purchase-table input,\n            #ti-purchase-ov #ti-purchase-table select,\n            #ti-purchase-ov #ti-purchase-table textarea,\n            #ti-purchase-ov #ti-purchase-table button { font-size:10px !important; padding:3px !important; min-height:25px !important; }\n        }\n\n        @media (max-width: 980px) and (orientation: landscape) {\n            #ti-purchase-ov.ti-purchase-open {\n                align-items:flex-start !important;\n                padding:2px !important;\n            }\n            #ti-purchase-ov .ti-purchase-modal {\n                width:99vw !important;\n                max-width:99vw !important;\n                max-height:96vh !important;\n                margin:2px auto !important;\n                padding:5px !important;\n                border-radius:10px !important;\n                overflow:auto !important;\n            }\n            #ti-purchase-ov .ti-purchase-modal h3,\n            #ti-purchase-ov .ti-purchase-modal h4 {\n                font-size:11px !important;\n                line-height:1.05 !important;\n                margin:0 0 4px 0 !important;\n            }\n            #ti-purchase-ov .ti-purchase-table-wrap {\n                max-height:58vh !important;\n                overflow:auto !important;\n            }\n            #ti-purchase-ov #ti-purchase-table {\n                min-width:790px !important;\n                table-layout:auto !important;\n            }\n            #ti-purchase-ov #ti-purchase-table th,\n            #ti-purchase-ov #ti-purchase-table td {\n                font-size:8.5px !important;\n                line-height:1.05 !important;\n                padding:1px 2px !important;\n                height:22px !important;\n                max-height:22px !important;\n                vertical-align:middle !important;\n            }\n            #ti-purchase-ov #ti-purchase-table input,\n            #ti-purchase-ov #ti-purchase-table select,\n            #ti-purchase-ov #ti-purchase-table textarea,\n            #ti-purchase-ov #ti-purchase-table button {\n                font-size:8.5px !important;\n                line-height:1.05 !important;\n                padding:1px 2px !important;\n                height:20px !important;\n                min-height:20px !important;\n                max-height:20px !important;\n                border-radius:4px !important;\n                box-sizing:border-box !important;\n            }\n            #ti-purchase-ov .ti-pur-name { min-width:145px !important; max-width:165px !important; }\n            #ti-purchase-ov .ti-pur-type { width:42px !important; min-width:42px !important; }\n            #ti-purchase-ov .ti-pur-qty { width:46px !important; min-width:46px !important; }\n            #ti-purchase-ov .ti-pur-cost { width:62px !important; min-width:62px !important; }\n            #ti-purchase-ov .ti-pur-margin { width:56px !important; min-width:56px !important; }\n            #ti-purchase-ov .ti-pur-sale { width:70px !important; min-width:70px !important; }\n            #ti-purchase-ov .ti-pur-iva { width:42px !important; min-width:42px !important; }\n            #ti-purchase-ov .ti-pur-note { min-width:96px !important; max-width:115px !important; }\n            #ti-purchase-ov .ti-pur-row-total-net,\n            #ti-purchase-ov .ti-pur-row-total-gross {\n                display:inline-block !important;\n                min-width:42px !important;\n                font-size:8.5px !important;\n                line-height:1 !important;\n            }\n            #ti-purchase-ov .ti-pur-dup,\n            #ti-purchase-ov .ti-pur-del {\n                width:21px !important;\n                min-width:21px !important;\n                height:20px !important;\n                min-height:20px !important;\n                padding:0 !important;\n                margin:0 1px !important;\n                font-size:9px !important;\n                line-height:1 !important;\n            }\n            #ti-purchase-ov .ti-purchase-summary-grid {\n                grid-template-columns:repeat(4,minmax(70px,1fr)) !important;\n                gap:4px !important;\n                margin-top:4px !important;\n            }\n            #ti-purchase-ov .ti-purchase-summary-card {\n                font-size:8.5px !important;\n                line-height:1.05 !important;\n                padding:4px !important;\n                border-radius:7px !important;\n            }\n            #ti-purchase-ov .ti-purchase-summary-card b {\n                font-size:10px !important;\n                line-height:1.05 !important;\n            }\n            #ti-purchase-ov .ti-purchase-toolbar-fixed {\n                padding-top:4px !important;\n                gap:4px !important;\n            }\n            #ti-purchase-ov .ti-purchase-toolbar-fixed .ti-btn,\n            #ti-purchase-ov .ti-purchase-toolbar-fixed button {\n                font-size:9px !important;\n                line-height:1.05 !important;\n                padding:4px 6px !important;\n                min-height:23px !important;\n                height:23px !important;\n            }\n            .ti-purchase-row-search-popover .ti-purchase-result-row {\n                font-size:9px !important;\n                line-height:1.08 !important;\n                padding:4px 5px !important;\n                margin-bottom:3px !important;\n            }\n            .ti-purchase-row-search-popover .ti-purchase-result-row small {\n                font-size:8px !important;\n                line-height:1.05 !important;\n            }\n        }\n\n\n\n        #ti-admin-comm-ov { z-index:2147483646 !important; }\n        #ti-admin-comm-ov .ti-admin-comm-modal { width:min(94vw,820px); max-height:88vh; overflow:hidden; text-align:left; padding:18px; box-shadow:0 18px 50px rgba(0,0,0,.82); border:1px solid #475569; }\n        #ti-admin-comm-title { margin:0 0 10px 0; color:#fff; border-bottom:1px solid #334155; padding-bottom:10px; font-size:16px; font-weight:800; }\n        #ti-admin-comm-msg { max-height:62vh; overflow:auto; background:#020617; color:#e5e7eb; border:1px solid #334155; border-radius:10px; padding:12px; font-size:13px; line-height:1.45; white-space:normal; }\n        #ti-admin-comm-actions { display:flex; gap:10px; justify-content:flex-end; flex-wrap:wrap; margin-top:12px; }\n        #ti-admin-comm-copy { font-size:11px !important; padding:7px 10px !important; min-width:92px; }\n        @media (max-width:767px) { #ti-admin-comm-ov .ti-admin-comm-modal { width:96vw; max-height:92vh; padding:12px; } #ti-admin-comm-msg { max-height:66vh; font-size:12px; } }\n\n        \/* 30.9.1960 - File manager compatto + accesso diretto ditta senza selettori ditta. *\/\n        #ti-ai-outer #fm-grid .ti-file-name { font-size:8px !important; line-height:1.05 !important; margin-top:3px !important; }\n        #ti-ai-outer #fm-grid .ti-file-meta-666 { font-size:7px !important; line-height:1.08 !important; margin-top:1px !important; word-break:break-word !important; }\n        #ti-ai-outer #fm-grid .ti-file-item { line-height:1.08 !important; }\n        #ti-ai-outer.ti-direct-company-access-1960 #ti-sort-btn,\n        #ti-ai-outer.ti-direct-company-access-1960 #ti-show-sospese-btn,\n        #ti-ai-outer.ti-direct-company-access-1960 #ti-filter-ditte,\n        #ti-ai-outer.ti-direct-company-access-1960 #ti-company-ai-search-btn-1522,\n        #ti-ai-outer.ti-direct-company-access-1960 .ti-ditta-picker,\n        #ti-ai-outer.ti-direct-company-access-1960 #l-db,\n        #ti-ai-outer.ti-direct-company-access-1960 #ti-direct-login-db { display:none !important; }\n        #ti-ai-outer.ti-direct-company-access-1960 .ti-header-left-controls { display:flex !important; align-items:center !important; justify-content:flex-end !important; width:100% !important; flex:1 1 100% !important; min-width:0 !important; }\n        #ti-ai-outer.ti-direct-company-access-1960 .ti-ditta-login-row-1770 { display:flex !important; width:100% !important; flex:1 1 100% !important; min-width:0 !important; align-items:center !important; justify-content:flex-end !important; gap:0 !important; }\n        #ti-ai-outer.ti-direct-company-access-1960 .ti-ditta-login-row-1770 > #ti-login-btn { display:inline-flex; flex:0 0 auto !important; width:auto !important; min-width:76px !important; margin:0 0 0 auto !important; }\n        #ti-ai-outer.ti-direct-company-access-1960 .ti-ditta-login-row-1770 > #ti-login-btn[style*=\"display:none\"] { display:none !important; }\n        #ti-ai-outer.ti-direct-company-access-1960 #ti-mobile-direct-login form { grid-template-columns:1fr 1fr auto !important; }\n        @media (max-width:680px) { #ti-ai-outer.ti-direct-company-access-1960 #ti-mobile-direct-login form { grid-template-columns:1fr 1fr !important; } #ti-ai-outer.ti-direct-company-access-1960 #ti-mobile-direct-login .ti-mobile-login-submit { grid-column:1 \/ -1 !important; } }\n\n<\/style>\n\n    <div id=\"ti-ai-outer\" class=\"ti-plugin-scroll-lock\" data-ti-direct-company-access-1960=\"0\">\n    <script>\n    \/\/ 30.9.1462: area\/barra laterale dedicata sul bordo destro, solo su smartphone - richiesta esplicita\n    \/\/ dell'utente dopo aver notato che lo scorrimento touch nella zona di testo della risposta AI funziona\n    \/\/ solo all'interno di quella zona (dato che cattura il gesto per se stessa), impedendo di scorrere\n    \/\/ l'intera pagina toccando in quel punto. Questa striscia sottile, sempre presente, traduce qualsiasi\n    \/\/ gesto di scorrimento al suo interno in uno scorrimento della pagina intera, indipendentemente da cosa\n    \/\/ si trovi sotto.\n    (function(){\n        try {\n            var isMobileNow1462 = window.tiIsMobileLike ? window.tiIsMobileLike() : false;\n            if (!isMobileNow1462) return;\n            var strip1462 = document.createElement('div');\n            strip1462.id = 'ti-side-scroll-strip-1462';\n            strip1462.setAttribute('aria-label', 'Scorri la pagina');\n            strip1462.style.cssText = 'position:fixed;top:60px;bottom:150px;right:0;width:22px;z-index:2147483000;background:rgba(148,163,184,0.12);overflow-y:scroll;-webkit-overflow-scrolling:touch;touch-action:pan-y;border-left:1px solid rgba(148,163,184,0.25);';\n            var inner1462 = document.createElement('div');\n            inner1462.style.cssText = 'width:1px;height:4000px;';\n            strip1462.appendChild(inner1462);\n            var lastTop1462 = 0;\n            strip1462.addEventListener('scroll', function(){\n                var delta = strip1462.scrollTop - lastTop1462;\n                lastTop1462 = strip1462.scrollTop;\n                if (strip1462.scrollTop <= 5 || strip1462.scrollTop >= strip1462.scrollHeight - strip1462.clientHeight - 5) {\n                    strip1462.scrollTop = strip1462.scrollHeight \/ 2;\n                    lastTop1462 = strip1462.scrollTop;\n                }\n                try { window.scrollBy(0, delta); } catch(e) {}\n            }, {passive:true});\n            function positionMid1462(){ try { strip1462.scrollTop = strip1462.scrollHeight \/ 2; lastTop1462 = strip1462.scrollTop; } catch(e) {} }\n            document.body.appendChild(strip1462);\n            positionMid1462();\n        } catch(e) {}\n    })();\n    <\/script>    <div id=\"ti-ai-loader-ov\" style=\"display:none;\">\n            <div class=\"ti-loader-box\">\n                <div class=\"ti-loader-spinner\">\u23f3<\/div>\n                <div id=\"ti-loader-title\" style=\"color:#fff; font-weight:bold; font-size:14px;\">Elaborazione AI in corso...<\/div>\n                <div id=\"ti-loader-sub\" style=\"color:#aaa; font-size:11px; margin-top:5px;\"><\/div>\n                <div id=\"ti-loader-current-item\" style=\"display:none;margin-top:8px;padding:7px 9px;border-radius:8px;background:#0f172a;border:1px solid #334155;color:#bfdbfe;font-size:12px;font-weight:700;word-break:break-word;\"><\/div>\n                <div id=\"ti-loader-tip-keep-active-1458\" style=\"display:none;margin-top:8px;padding:7px 9px;border-radius:8px;background:#1e293b;border:1px solid #475569;color:#fbbf24;font-size:11px;line-height:1.4;\">\ud83d\udca1 Per una generazione pi\u00f9 rapida, tieni questa scheda attiva in primo piano: passare ad altre app o schede pu\u00f2 rallentare notevolmente il browser durante l'attesa.<\/div>\n                <div id=\"ti-loader-progress-wrap\" style=\"margin-top:12px; width:100%; display:none;\">\n                    <div style=\"display:flex; justify-content:space-between; align-items:center; margin-bottom:6px;\">\n                        <span style=\"font-size:11px; color:#cbd5e1;\">Avanzamento stimato<\/span>\n                        <span id=\"ti-loader-percent\" style=\"font-size:12px; color:#fff; font-weight:700;\">0%<\/span>\n                    <\/div>\n                    <div style=\"width:100%; height:10px; background:#111827; border:1px solid #374151; border-radius:999px; overflow:hidden;\">\n                        <div id=\"ti-loader-bar\" style=\"width:0%; height:100%; background:linear-gradient(90deg,#38bdf8,#10b981); transition:width .25s ease;\"><\/div>\n                    <\/div>\n                <\/div>\n                <div id=\"ti-loader-actions\" style=\"margin-top:12px; display:none;\">\n                    <button type=\"button\" id=\"ti-loader-close\" class=\"ti-btn\" style=\"width:100%; background:#b91c1c; color:#fff;\" onclick=\"window.cancelLongAIProcess()\">Esci<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-alert-ov\" class=\"ti-ov\" style=\"z-index: 2147483647 !important;\">\n            <div id=\"ti-alert-modal\" class=\"ti-modal\" style=\"width: 300px; padding: 20px; box-shadow: 0 5px 20px rgba(0,0,0,0.8);\">\n                <h4 id=\"ti-alert-msg\" style=\"color: #fff; margin-bottom: 20px; font-size: 15px; font-weight: normal; line-height: 1.4;\"><\/h4>\n                <div style=\"display:flex; gap:10px; justify-content:center; flex-wrap:wrap;\">\n                    <button type=\"button\" id=\"ti-alert-copy\" class=\"ti-btn\" style=\"background:#2563eb; color:#fff; flex:1; min-width:90px; font-size:11px; padding:7px 8px;\">Copia testo<\/button>\n                    <button type=\"button\" id=\"ti-alert-yes\" class=\"ti-btn\" style=\"background:#10b981; color:#fff; display:none; flex:1; min-width:90px;\">SI<\/button>\n                    <button type=\"button\" id=\"ti-alert-no\" class=\"ti-btn\" style=\"background:#4b5563; color:#fff; flex:1; min-width:90px;\">OK<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-admin-comm-ov\" class=\"ti-ov ti-admin-comm-ov\" style=\"z-index: 2147483646 !important;\">\n            <div class=\"ti-modal ti-admin-comm-modal\">\n                <h3 id=\"ti-admin-comm-title\">Comunicazione<\/h3>\n                <div id=\"ti-admin-comm-msg\"><\/div>\n                <div id=\"ti-admin-comm-actions\">\n                    <button type=\"button\" id=\"ti-admin-comm-copy\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;\">Copia testo<\/button>\n                    <button type=\"button\" id=\"ti-admin-comm-close\" class=\"ti-btn btn-close\" style=\"background:#4b5563;color:#fff;\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div class=\"ti-header\">\n            <div class=\"ti-header-top\">\n                <div class=\"ti-header-main-left\">\n                    <div class=\"ti-hl\">\n                         <div class=\"ti-left-stack\">\n                              <img id=\"ti-qr-img\" class=\"ti-qr\" style=\"display:none;\" title=\"Apri ditta in nuova scheda\" data-no-lazy=\"1\" \/>\n                         <\/div>\n                         <img id=\"ti-logo-img\" class=\"ti-logo\" style=\"display:none;\" onerror=\"this.style.display='none'\" data-no-lazy=\"1\" \/>\n                         <div style=\"display:flex; flex-direction:column; align-items:flex-start; min-width:0;\">\n                              <div style=\"display:flex; align-items:center; flex-wrap:wrap; gap:8px;\">\n                                   <div id=\"ti-company-name\" style=\"font-weight:900; font-size:1.1em; color:#fff;\">SHOP & SERVICE<\/div>\n                              <\/div>\n                         <\/div>\n                    <\/div>\n                <\/div>\n                <div class=\"ti-hr-right\">\n                     <span id=\"ti-company-ref-datetime\" class=\"ti-company-ref-datetime\" title=\"Data e ora sistema ditta\"><\/span>\n                     <button type=\"button\" id=\"ti-help-top-btn\" class=\"ti-header-help-btn\" title=\"Aiuto\" aria-label=\"Aiuto\" onclick=\"if(window.openHelpModal){window.openHelpModal();} return false;\">?<\/button>\n                                          <button type=\"button\" id=\"ti-reset-layout-1676\" class=\"ti-header-ss-reload-1712\" title=\"Ricarica Shop & Service\" aria-label=\"Ricarica Shop & Service\" onclick=\"if(window.tiEmergencyResetLayout1676){return window.tiEmergencyResetLayout1676();} return false;\"><img decoding=\"async\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAIAAAD2HxkiAACAAElEQVR42pT9d5Bl2XkfCH6\/c81zaasyKyursryv7q6q9mg0PNDwoABIICmSIEWRM2KENLuamJg\/JmJnJ2J3R7E7sSNp5HaW4oxEkSMStABBEQJAgN1Ao72rNmW7bFZVevf8u\/ee8+0f55pz7r0vqxeo7s7KfPnMveecz\/0MaPQhYiIwSP8v+W\/xb2x+BULyHRR+izh7MHI\/in+L0x9y7jEofAnrdZOnZtY\/AAMg\/f\/kmdl6JAHZX5myxxXeGpV8eFgfkDn7gMb3kL1D\/QOYr5NdBs5dE86eqeQyWhe9\/PowW49KPikz67ee3KLk7UC\/Yc6uV\/rd9K9K5V6H2bpeKLmt9gXXr0HmXWGCeaGGLA\/rpnD+I8fvI1mr5XfQXFnZUtEvhOyaM9LFkr2UviwYcguY7EdnuwCIn5Bzt4jz9xDJcjG+6dp3ObcDWb+rkpWQfUAk95g4fjAbrzd0RcH8jv4VxNeJOVs5ADEz9AsQzCdB4an06xOXvDaMfYls+cNYV\/alyt9gtg8LmLsMw3dwycYCbbMDQcRDrrh5EZFbDMMeEH9tHQDZ2rEPwvSF9X2I70LyhoqHI3N2PWDfT4qPgCE3vbDhYLwSW5eY073B2T4ZdmXNBWmFDH0smVfeCDkMNo4oDD8B2To6rNvEhSOUt7l7+bUmjIuI7CS13ypQ3Dfm3SCOD5t4LxHS6IEhgTQLM4TkV3QcYS6elZzu1fRSIndQc8lOsU9l87jOFgnnNjXK7615WBR3GWDtz5KFEX9OQrrKrDPMvri5VylZdTxsqRjvMLtp+rxA8ur50z+L4cmdNC5FyQmDYixkIk5fm83XZ+tcy++U9AODjSzC2EXpjorfN3Cf7EUvBs5tgnRJljzYvLDYLjvKngLMSK5W8QKw8U1sd1wkjxK58MvpWjHPaza2e7JvCmEz9x2UvziMBA\/3O9CSfWcHXhByuyD\/blF8a8m248LNAJekidbq5PItYa9B3u5Kp0ssjcpMhXWy7cHJw4\/X+y3LIaGaMHRtFuOVvUo5WXPMua1c\/vZgfoV4qVjPyuYyh51pcnbXkdxGDL0XxXCH0lzVWLRZwOBtY5l5Bm8b6ZAPedveaohtKrb7Fij2m+f7BGPYRZa5gbj4G+DSRWMl3bDrRravVvpiYM4ibfl14HzBGMfnknvI2Y7iZCFut0XsC8LldwT5G8zWrwDZGceFD8D32ZCII40VxoygAgzLaGEHtPSvMPckl4W77OKbsShLGZiIYZYDyF4p3qhsl1YMLkttiyWcUZ4U7zcKNS2SzBelV+J+i3LYMYBh15WLtawoT31gZ+cYfouZ7ns6F7\/OLfjSQ61sB7BRXg9bP+YFQ66rkmyi+AplSWKSpZqbAcM+oZWWo+wGYOiNGbpHUbgPMK+MuZZRSI\/K3pgZCFHS9onfKYBiY6wQ38xTwLxmabbLxvVA8d3BXpVxbhz30+xqMw5ObKY9yTMi\/scquJnLz\/vk0cWlxLmohny7YUgEgRHLUZqHJQ9hpG0F3HfbsDAqeOasD1ZWoAKcT1StFZSe1bh\/RMj\/rfBW40SH7UWcxN0hLVdjtcT\/ZSM34azJhuxDp\/2RwrUZ1j9lNp93aOf3AxxYGLKPUShS7UiKYqfFKsHsFYZ8fZYvBLhYbyJXSxWPMuPXYa+1fDoRbx4uidn5pzWTgPRATLYic0lLL9dDZ7pfTmKkAYUCE4WgaWRZbBwt+sCONxynx1namtZNPyYryxvSRmMWTAxm69As9iCGnCC5O212\/Mz+Cm9bUfF2MZWLRz0P706nPwbbgYoLmUS+FZ4WObkXLXud7RKD\/GonI7MorN60TY6SDD95x1yWVeQ+nJXPc66pRcU0LjvNrKMOhTTKOg24\/AaiUPgVjyZQ6ZYzNl3pX1GeeJt1F9sxA1SoJ7cZYsQ5EQ9LJEoCGZc1aoyKjNODi+9\/GgytCcv3Sb4WTkN9cWqBrBeC8vr2fkHCKojYTErYOH7ZbFfZaV16SsXvCcb6QnGWidLPe5\/DFEbmuW2nwMqdkOvCouycS898mOfOkEQC+ZzLTAiHZOz57W38CuvNhlzLd1j8zr0q7PoO6fFTPADKFgKXtR3YOLqQFY1DVmlap27fsbJPLdyvf7nNDDc+tdJQxvmiumTmaYXgeESBfJVdfsSzLvCz3YeSojd+\/TQgDR1SsDn7KC+u08kp4krdOsbSQiHbnCjZKiW91OR7Rk2Yb90WZkYo22plqzzX+rPLHgzNOs3IBipLE\/Nz+XzX0r75923lF1qfQFn0AcqWLoqTK+tw2r6nh+EtJKM+S7v+WcxLcz97XIHyrKE0\/ber29JO2JDqgIfWEekELC55mJOdzeXTpfhOJj91OX8DYQ5ZkBQh6aQOiP+VtpWyyJvb9zEKx8oQuPz0sgfUMHtRhU2M3N+y9qLdY4YxnUdJ69YKibhv77nkTCJ7mp1NSnMftnRCSsWurj7gstInl\/7jA\/TFkJujY7vmaXadczAQ+37kU6skt2AjcWcqy+XKB5nIYkt+8Fpa0jEXG3R2VgoiFuWRFeXf42H3oLDUrJOPGUg2CLIGSrq5YL493qZUYWMwABe5\/Hl46QQUWjFGgz3tPCMbD+efgVn3gmEWdmVVqznGMd67AWrgYu2K8vduJbFA7qIO23M87CTlYhHK+Sab+c0MdFTat7CODqP5AAyd83D6bDxsg0Ekr8zlqyyPdEneOptHVjJeLRkCpTkOrOY9l4+400Oa80A73HeYBi7cpOTFOVtKJq7LuHTg4ekl3+\/OcvmRZCxLLtvRXLhV2x7iAJHIdanYSrjsA9DouOj+T4xQJLaRGMUGRTqIoTJoKJX2wc03YcU3mNcSw6fNQDFC53ee1e0HUFbwlA0RtpvCmAWBOZ8s7lUuiZNGBx5Wzz6dJmRVFgjbjMaz383NOmDl1WyUz0xgZOAxZto2RRiGzbBS\/HjZoGSbMuVnsmUbhoFc3g1YZW1ZSQ8My\/nzZ2wugUdpD4zJbjIMWRJlg\/RhiZzxP9e825wfnCDtiHN2gCBX3dtzhhjJaqAceJvWQtkpbsU14xhNR6zgQsMDhe3PeeR11kSBkQexkf+V4R1zaRBKU7\/7tba2BdHmfo2HIwrIBFnSfZLMoe3jbTpwyGNVrBiI+2BazZhhVZlcGo9hn6dDEbMAl5RVheKGt7m+GDqizl0loKQyskET5VmX+RQp+BkYkmgZRUeyCS2oKLM9ujSSx4SzUHJJQWBwbrZjZA+8\/RFhlERGDWlOluykyT42E5g5mwsp36ouaZ8w2z\/CfQpALpsXGmsU5dkt0\/2ab2XnNMjEl5ttfyM8lSRQyGVt1taCXRFt00KEkYqyVWrGaOqh6UURZ0PmtYHVZcpnc8ixa8zZkvHmk6CKXKIMa70CxlHMJSUNEqZHcrjGubiBQExWO5A1rWFf3eRotlKBBAGPXGJbPNqIiIR5wbisOM7NqTjJNLLcCRmVgq2sP9lFjCEN6HzbjTltC4Hvs1jNsRU4bUiVPK\/ZJQeVZDLYpvNhDLy374swbxPfymfytN3kbWihVbiXyCWfKB\/5D4mOBpLKTFOZrO9YIxMUh4Fm14aHTfZwnzY\/kpl3SmLJZg3gfFyzqyZrKmP1j0p7vrn2vNXOhAU\/hXUC5nLUktZhllYB2yOCs0gIO7YxzMZw\/o6nIOi0FcM5zAInJ1QuhHLpSZCvlmGcLen5wsZJw7nKuzBnNnpWGLYZMlYGrNmVfQPYBvuitNItOeTYyBZKW008ZOo\/7LcwvLk8FDYAsmKFHX+GnBRcfndQ3DFM9x\/DsUnxLPaG2SpAeNjZxSbBCMy6O2ncDR7SQuMC7zJduFROdsu\/vFmk2PvNRtOWNLyRrNnyM7RwE0Q+V+TyK29EVmOfmdveOIw5JSXlBjDYhtshEoiuwbQZksZuFyR52Pzd5Jwg1zyzo5gxvAS2mb\/aOCuDzMK56XS+q4CSM5LzDRoMqephNuh425iLYQX30LCdm3tRKc9rCIfGnu\/jvpU\/LNwQcjGK7LF\/liQbqG8ur91z1JMUmAk2CIt59EaxRkQRHVjoJ1lQsW2aeGWNNDZqwvy6yRXmRbSAQbAsOSTZ2EPmlK6s2IdR8PKQCMDlw2MupShbTSa2ome+8wUTrWdRxrMDk6yZG3LlOZOVaW+TNsd32xyRZVxoM00oQXrAqkSsKSQY5UlOoUfF9iXNpaf5cQiyji4+wBlo9uvL2z9cWrNaeQEKV1NHPSptlLF1ENmRMS1ak4hsoIrzobIA\/0YJ5JBQNqrMBfdhoBrrOUvRyEzkFnp8Zg+E2Q6fKUM5zjez3kGR0Y5CR75wWjFsrYuSTnNyRuT6MTBCPoZkVsnIBSZydAjRwMLDFeCXhY9l7CUewmE1GOs2kdBo\/7IFLjV6GkzDBA9QsviHBxyzm51yKouMSh46r+PS5CtrRfEwEML92uFU1tmOCfRGH6nkyprpi7GTNWgkrWPSbLYEsIUEUZtLKXibrDgntYBthrTD92EiWZAn\/gs78MOYHrGB\/bNiNGIOHXNhKlbG9E1\/rfieLZhuMb8p58kjxwne\/uNznr1vvdUirBPleHOg8InyZ5YVcWGSl4tho4h3Q5YbZXh842Gcz5NRKl+wTRcom\/LATgqRB7WW9cxiiATSRZ9\/3vsNYEqHmSg7VswDBoUjyR4kMRuDKzMlHs4dK+3eZcQjY4rKQweifJ9WS2m\/eejIVeSvzJB6BpYyS\/qEdiLMZYm8OQmCPU\/FNoAJNvSSigVQToIJOcBknqCmB5gAD1uupR0OtquXRB4inp2gJMG2V1I6KdlmRAG7kAZTKXe1VIUAhRdHnugD+66ymVTArg7LeQtWycqpKg4KvA1sewJsJx3CxeaQge7g3H5gsxjKpjZcwlkrOVqQv3YWy5GNdrrd5TUovyUFCBcbxMQlokWlZH1AD+utgRZgy0qZfHbr+purkIszQ+RG5\/m5Uf5JUrSABduzPngaqTCk1i3cy3wf34bbWP1PlFakVvsurSQBFBqzZRV4Ou60Xo+HDucoVbcyYYglQZjZ4qwMzYiSLQMmU\/oMbOAMyQKAWW1t4xhPRmpkiW7ZeS8ska\/7Iga2+YLzyQzMI2Q4TNsCKFp9cv0RuJRuwGaXgssHv1wcrzKs8ah1GnHZkJmH9LfdQkcHbGdyuayuBHcEW8iqZIaM7b9j7xxzcFogEtgpbjnQFXlcf\/oDtict5fgYMNl9pcJCYR7epId5ZOgSIIdD3D6NNroR9qGbpQ1civMYnhMx58mqnNarWdVtJyEFWEJaY5sILrsmLPbJUL6XP1gVUQZ8twmFGNoRS9cy8nkr2xD\/Qv3LhVdJpi1FDCsNabSUAWPT\/gTbRyQTwSUaBtOhYZl+3B4FD23CZrKFJfpHDNwnSS+b9aCQ1xVaF6J8\/IUMZG4MGrfJ5MFDUDRmPEyfKbeq2JzJITem2r55lp72uVcvqGzm4Ei5Riuo5NTdTmoVhTnSfYocHoqa5OJyyEanMDrDzFS6h4xVmoVfUInqiJUHcdn01VK3LG1B5W8BD515WscgZ7Pyoqgo3XcGaR4jDE4jYalkEnNp1Q1LuQ9WRGIaEpaRF7oyv5FW11zSjrZCMQ9J4oYMo4yuSZFxmKmklmM9UYBeMedp6PZ80fgIZVpbsBKNIYd8cQfBzorz2nAWbKpUu9QuCQzG8FCuDYacE6UzwPtAmxJWGw8ZTgwbsmj4GGwtXxSiENu5Yk6AV0sOD4+YuWk758ZgXDY8xzbn6Pa9ay4NdromZE77tiXPygW1gCQJRVqoF5L0QgGcL95QlADlXJJZqLXY2jM2rxSlqoXbYnSG4Fc5xu7kwBDgcjRDvgmOuNguJC9MJjK3XG6Gh1PbShKdJDnnYfvCLntyDL6hos\/ljdViv6v03g\/v1Oag0ObToFCUgGzJ8JJsLvvgnIdkmUGPPwjk3J4I5md2yE9soTVhhit9lc9J4x1jILbin7tmXYec8EG6oLKMolj7FTsrKOXdFeMAlw++yqaFpV042D3SsgFJkbNkD7vYJjzlRq5l05HsIpbPb5kS+Hy+FcuczGm4kL\/mWKpDsG9DThaUVgUwRl\/Y\/tQuSUJhs1hQtrFz8kvI37PyXDMXqxklUIQ8bNKqzswCO3siDCPzb5ddlxDvUJq\/JX0AIF9lfKCwaHWms8WTLE83uxYld4qL6VtWFJQ00RK58iInqmQpIDfILLsuwyQ0QNtOUpJVAGSSfAasILt9sGwZzFEv0xAIX+6Wo5zwXxCGN9qdBaYyU8lL3F\/od5vKo8DwN+tKbCPXxeUKuDwkphWXf7JVOB+fYPUmyxt29lMW60CwvduRJUdDGxucn+5ZhduwJiLbCXB69HIJ3clu7TMNfcrS4EQmn9BMvQ0YiIGKyapp5FYX2EaAGEWVSXPOYK3GjmAu7cIUi+9yKRcmaJ4rrD4\/EYGElfTYKAyT9GaVIjk8LOfyFQzzwmAqkqktwZSc4UT58hv+LZQMeTIjkvvNxs1xFYbNQy24H3IhGeVxE6XvlwuJy3Da5dB+8TYnXR6CwGU\/RwmO22j1bqtANgz6iiENGI7zRBSZeyYAqLz\/4+beJ5cg9sGlOXuZvw\/n2lwmCbVULCIfN3KDB+RRb\/kJYSpemyalKP1FlIhaFyLPMBeJIYAN+2PEQTU3SYuPJuQHCkNTmfyBfZ90ffgORGFzwJKIzY3UiMrcoTJiTdnuxRCsMnLaqCgZKvC2VdSQj2MwZnNZB5fOvEqRvSbZj4pqz5wPAJaTkJFHwPpEnE\/YhtmWcH5YHaejJU3GErol5fV5soQvY\/XafPMhczGUtBbNBIPKisB8Xgpbq02km5BTTWnLacCYACTWYciYGsp4SGFiUKTKcq63n6PLFvW\/koIIJREzz4cBlye0242Ncu1rprIU0VqUhv4OW1NZzg4SlE7Ht425KJbxtq1TQaSykF\/bbyD\/gUEFGAPT9t1cKvDQOUN\/2135klIWJZMfDC\/Z718sIKd\/lI0o4saM6UdVqtZKFskAsBRsY2JuTt2Yi6uhtEE8DHdSwi4x4x4IIgENCiIAgpGYGcDQaNHdkhjFzMyKmJkVWGXSWUkjqpCUprUijMVWFNy11k5Bz8E4zgwkHhMX6jQMHboUqjTOU8u5JH7C3t48LGBSmQL1B8l02VKNyilc8P3WKuj+Pe38LrBr1txSRZ6yaAdjk+nPqQ4wl6VsXKitE01dmNZ2WboALp\/S5XD\/VjqaRW7Ol71pT49KAQuF0xz59IhLW+flIz9YuhooEyPPeehAy4qBIEg4BJBwCA5BkHD1zgQECxCJ+PkUMzFYsVIgRUpBSVKSWBIzsdKGSUgcLcm0QSiZFZQOFIBh6USRXAAD5TkUJWHXSDAfHwcxttUfcnkXcijCUmQLF0ED208Ay+Z+QzyBABtZkOuMWGM5FGT+c\/116w5Y5p\/52QYPS3uzGoHtyFgOITDbcZwEKwNIkK2HWFEOQxpftgJfVse6ObhfgZmDoUAC5DYdcsQyHtYZh11Zwmhpozh7SI4iwI6ESegDSLgkHIJLwmHHI8cj4ZLjQgAQgCCRVGmsSClWTKyYFViSjEiGpCTJiFiSkmBmKJ2jgu2qL42N+W1oHW+8XSFchvYoiyDDMivjBVHUm+ESoKk5H+Ihg3K2WwDbSpVyWZjnYekYSlj75qfKtW0\/ED8IZguTh04q05kaclzxzAIAmdRXpj7LKK1a4wMONoVqm9qPttU7NH7XNQ6WfC8xD7ZAnuhlvqCdqGNYfl3ARRg9R2DIPCzbgZyZCYk09OmNB8djx4frk+O51drk\/tmpQ7smd0+MTk\/4o1UFUszRIOqstTrLWxt319au3+tuNFlFFIUcBYgCkiGriJQES2KlRR2RNqbNS2JqyoHLGzZUHB9zyWh\/O40ZS3eraEGUgcO5HCqRcuesHhmbU6H7avkYFUradiqO\/u9z0KCM8MvbYrip4MduKlVZwlVl4mlMOS0c2MaVRgJRMhUrEXtku0jk+3gpW20YHjK8TG\/E2Jny5kki+GhrriHRic4rW6MIDcvnZYYhMgrIiUIAtD3uwCnvLS75BIRDjsuOT44Pt0Jexa03po7s3XPm6M4jc\/XxURVE7eXN1nq33+kH\/ZAEudVKdbQ6MTXSmB6VYdRdby5eurXwzo3mnSUOBxwNKAxIBVARKUlKMiswEyvjXnCh517UfvwA5Trfb3Sen3OUN9YxLMu1\/8PmAAapAgzlO788pFZnKqZEhqEMSkYRdpBCuSghtlnHKMo05Tr5bJwzZqZNVH6PzEwlc9Xl8jKJy01t2IplXCqkmh0ORQkc8x1yStUbPZPftABt72sDID+9KGuRFclpjO1see1mpp1MJT1PCAIYDhwdAH24VfKq3ujozOlDRz9+bmL\/7MrN1ZuvXl+7sRQOBioIWEpWOrIxCQcCQjiOX6mO1\/efO3TwkUP10erN165c\/en5rflFHvQ47JMMoEKWIdJfTCRkmFMadtrCYev68vb9sSSucFnvjobBFEtYGFwyfygOj4ev8NxByWznJqb\/OBWmOHnaz\/Z9Gy6ZW2\/3G5xfZShrwA79TIUtZPOI8ttv6K7L7bHCcJ+zqVT+9DKkFHIHJNvpcNzF15uwrCl7vzQDJSVenjiQa8galCIubTygoG6W7UACCA4JQcKF47FbJa8iKrXJA3sf+vondhzc896P3p1\/81pvq0NRyCoiKUkGSbGnCKR\/HXDIcUi45HpOtTq5Z\/qhz56dPLTrwg9eu\/7cW4ONTYr6CPssB5ChLhQ5sydhpCCmTMCEy7PNkgWHIQMGDFlN1mCTP4BOWGETDpNjz2Mmh2FOSkgTPHR+vv0+HAJCYFMLnLNmI+KuZep8UKBGDUfusO12bm48U0eM8wN0tp2ghoRELnm8nR2g7J1QmWUL5zYhaBjuIN8HQynsAjbwBiizdkHOlM8C2pgNGE7rQMSTQMFCkOPGAdCveY2RU888fuyzH7r44vUbL17qbWxwMKAoiHstSpKScW4ZVwRgIQgi3syOS04FXtWp1Sf3737kq486vvvy735\/\/cpNDnoIexT1WYZJiajvWfqFga\/Zpl3KXDJgKEsrjcuQOGBZ9Dsu9jS4bELOBewRsoYcWxpW93fyK\/vR0FJ2+B41lCp46HCi6KGeL1JQVrkMl1jihPuskOUy5lY0vmkYDCb5jbVvcz6teULLUOQFZ09V3qpjInJQmaG8JMX9VGtKrFsNmQBDXsUgOlldVOacagtyFWDW+aRUT8Uh4ZDjkVshr0aVem1i\/KO\/+XOTx468\/Cev3HrtatDcpH6HBl0K+4gGFA0gA0Qh6XRUSVKKWIH1WCIiJaEklGQllZS9zc78u\/PCcc587SkpaeveRmJczLD9Y0z+e6oqAEtjpyCYC+T1YIv6MsX2b8nJiCImpRjW8u8h11QtEQQyxXnvq56P4b5mOaBS9lkSlALKGjGGOkl601NDbaMTDkAfxIBg4ZBwIFwIlxyXhEvCJTjkuAQXwmHhgASJ+LeoABgwYoQ1UAXA5bXSkLzZbsqVKktRIUibDROHKjMFgzxbMB33Q0XkPcSRmfKhTLwFZi2N8spQCMMdPJkEOi7cCrw6qvWR6emP\/dZXA1V58Y9f3Li9yP02BV0KehT2SQYkQ5IRKalHf8ZyYGKOx4N6TM96WhixilQQrt1a6zb7Z770mNdorF5fYqVIn6MFhzLkHBKNlVg2dIYt32SurVIweqLAg1IkGsqADcisHPMMC\/PlilA3NkLNMK1xlKMIkChmw3KWL0LqYepW5c9fu\/in1Jg+lbQSEHrU5BAcEi4cl4RHuifn+HAqcHxyfNIDKseH45Fw4LhJ\/SKoqJ2FHEAPZGoZ5aXPClJlBdg9AAyFpFusF9i8iDgS5jcSoVSB2z5OULI4kOHYgKHgC5QcmdnwnZHlnwRBJEgIFi65FfLrqI7Wp3d94h98tdmSr\/75S921Neq3EHQR9igKoEId5Yhl\/ErCIeGT40E4yRmokj+sv0DybyZqrXa2Vjpnv\/hIFPLmnVVWiogpSWmKok7WGDO\/GYsbJveRsa0OkjkULU9VYOydTAOyzO8aQwExVtQ1DNJQuN0lkKayQaax4beDtlojX07MW2GioEgAgiAYjm6Gk+OR65NbgVclrwavRn6N3Bo7VXL1JvTJrcL34fokfHJcEh4jfh77CDDPPRQF9Qhl79beBciBKFIdfzPZZwxlr8ZzwhjrwPYAlG1PgjKr9dL6fhhEwH4EF4eH1rKCbbEg4jTD8cmrVcbHH\/n5T\/cC8dp3XhtsblG\/TWGXwwAyTIYKiohIOAwB4ThetdoY9fxqFPZ7na4MB0wBqSjZfvHgPgmbxISlC7de+pb66K99oru+de+Ni8xMLIkVM6cNDAOrl8zv88x9LkCWyw62Eqt3lJEnCgxXygBNedsWq2gsXHPw8J5KjAc29FZS+SkuQxNTifIZcL8uFNncAhhD\/dRNOstCGYLgsOPC8Vl45LgQnnB9f7TRmJoYnR6v7hivjNZ8zxHMkZKDftDf6nTWmq2l9d5mU\/YDyIhlQHIAnSVBT4MVkWJStrp\/0XUAQxz\/EHc\/7RF3XoUkryLFBbRKSuolEA+p0GGKpRWn8Pme+TZqHSXkapRYT2dROBkJkoh3oPCrxz79aGPv7mf\/1x8EmxvUb9Ggg2hAMmQlwSq2KxAuOb7renP7Z7\/wc08\/ee7QeKPWGwRvX1789refv3blRjTocRQg3opJmhon7JJUtPiefOmPX3ry1555rtldv3KdVcRKklIAx7ct23rM1g6z13ieoG3fRgvewFQmJDlko5iaF0DWTjAgqRiGgyvOLwzAefG45kQ5EUzliEh7EMfMRRn\/kvQWhZFDDhElWOgWmqcDILtV+BV\/pDF1aM+JZx4d2TslgNZSa+XaUndtq93pEZGo+u5ofeLE7ImDU\/URT3Z6l1+6cvvli53ldTnocdSjqE9RQAihIo3bZ9KjYOS7ThaPaxs4Wt70quTCMg9pdOpzbuxsyc4vQ7iwlToX2MhkuwuAywHZnFUfeV8kLdYU+w0AujKEIOGyTkQro3sePvnYr37xJ7\/z7Obtu9xv06BN0QBpL1Q\/u+OSU\/XrI9\/4xid+\/uc\/6o\/WLlxeWJ5f2zE9fvr0XCSjv\/zzl37\/P3x\/0GlS1CMVJaMbQcIh4bLrkVulyogzMn7u558eGan87F\/\/edTeoqBN4YBUEA8P42mt\/ofBZeEf23Y4hg3ccyiPbQbzRR175g8ii4xiv7wwWLdmXNhu1nifHh6XA0kLR3AyiIqzIQHhsND5Z1Xnn9WJ8VOfeWTuiZO9ZnD3rRvL15a6qxtBuyuDkJSMP7sQJAQcx6tV6jtGdx7YNXtybteJ3ZsLa29\/+4W1KzfVoEdRj6IByTR70shhhmkokpttkE73mY2jjkvUtGAYrBonk2WsnRv5sIPKbL4AsaoNyusRolhwlPU581oveftZLkHJJKQksyGm+zGOT36jOrnzyW9+\/sbrt+68dZX7bRp0EA4gA46BZhzjSN2qW61\/\/Ruf\/C9+83NvvnPnX\/yr7\/3xHz737LPnf\/LT91559Uq1Xv\/qlx4leO+9d1tJmYBIrWQteaNidX5j\/9OnQdi8tUSsdFKaQZW3Mz8p9lQKTjKFqhi5yoqGN2LSe8GFZY3tdx+GYsRKt9A2L122gYc8idWOYsPwVV9nJmGUoCLpw3nkVcmrk9\/wRsePfPLRx37xU8KpXPzRuxf+8+tLF250l1fC1pYadCiObwOSA1IDivoc9dWg39tqbcwvz799c+HiXadWP\/KZh3ed3Ndc2go6AeXY2WwJGxlOmZagEUqKxmF2D7gP09P4u4PK7ryRMsxwx5ZKMYSNS0SujwQT5Zy2FJDr+5jiC8jzkpLGDDRAVDgkPPaq8Osnnnli4uDe1\/7kBdltY9ChsJfM4hWxnsULCI\/8xrETh\/+7\/\/Zv\/+yV6\/\/8X\/zFzet3w84WhW056K5tdM6\/uzA+1vjqzz325pu3V5a3iCMolRAMzTYIEUFGHIXy+KfO3nnzuhwEcSHBaggFpCRBp0LbhvMa+SAM2auUs7ZGjo1+n6xvG3X8nFy8vUWNpnapGdMH7AigxIYJyBZzVviZRaCI57euT16NvDoq9cmDex\/+hU9PnTr03vfPX\/j+G5vzi7LT4qBLod57aT88IBWSDKF0bzwkFVIUcBQOttrL7y8uXVqaOTZ37JmHo5CbS81MlNN2MODCVNKu3Ysq3hgieDvsNuRvpd6EOfc+k0MBzkzPBOVcWSysWYmXQBo587Wt6aOQWk8aPpEJPcJh4ZLrw697o+MP\/fynLz53afPGXdI7MBro\/gpYISb4CziuV63\/yi985tEH9v2Tf\/ad+Zt3VdClqE8q1Hl\/JMXicufLz5wZGW28\/PKlKOjHHRfTryh7+05nvbfn7KHqaH316l1SITT4ZjvDUxQ6yCjrUlqN8iFqK9uUU+CSBh74fqEwaaTDOv7y1qKMD7KWzPMAVNiupRWg\/alTgZJ0GYgkBrpV8uuiUt\/70OFHf\/nzzdXeq7\/\/3MbNe6rfpqCLqEdhHzKAPoVlRCnyXulet0b\/xhhgPZeKuv277853toJzP\/dEbcfY+q1VGaoYgGH0xGAia3NbMYs7xQmSoddicJpL5UcAaz2IXLM102mybZ45SU6GdVyQn3+QDVLY\/k4azjOZhJ8eTjgkPHIrs+dO9Ad8982rHPQp1LCYeP6umzF6dEtCjDS8D3\/oyKXbm7cX2nHfRLd2hEsEUtHC0tbPXr528tTe+kiVHI819UkTgolJKZaSZEgypChQQXT7tevHnz7l1WvkeAyXhcNmC9fQj8+x6ZFr2eeHE0bRvT0OjUtRZyWsE8A2zyi75kzbiUghdm4axmDaJgBiyHlfTIARrz3oRFSwHqabO7DSEJXGoScffOJXvnDl2ctvfusng40NHrQp6FDQ5aBP0YCjgOPtF5GKoEKSIamQdWCMQopCkgHJgMIegg4Pmqq7tfDahWf\/1X+aPjL3xK9\/sTIxQV6N3Co5XkxJTSb7mcGzPVllyzSUSxrdOR\/50vtpN3h0JDQYIyjMngHkfaqy2GUe5jaeHiXutgkcCeYkNC0CjamRZsdDz4W8mlMbfervfX7h4r2VS7f0UB5ZIsoEQHjwqvDrwquwcHoT08\/95PL87WV9VYXjCLcivKrwasKtMPP71++9+vrVhXurrCEXcYsl7pQmObSAcBhuvxvtf+LY+o3F7lqTVAQVQROdsngXQ4CQFTtlXtwlcWKbuqu87jZ2F9tDnZyep\/miJXZF+a9A5Rp2sQ1O6lNkyPkMrTNLR8xmTQLLW0r\/R+j6X8fAEVEbOfTU2bM\/95EX\/+DF+beuqH6bwi6FPcSYRN2JyWa8KbYJzNA3kRlIT3dFSiXTYxX2woWLd2cfOjT3+PGFt2+qMErnxsimPoy8TiDKsDEo3EkU7bYK8\/DcnNBOLDhvB4bMUaToDJF8zqJEbkmFhBzABGX2o8bH0QekcOE49cmR8V2TK5df5ZiDG7HUdHgVl\/KO59XGP\/LRh5947IjjO+xXTuwa\/fiTBxGP+JKNT0ISRYqZpVD0pc8+HEX8yqvvv\/yzt4KuFryIOMYcMikdDweDza07794+\/pmHV67OU+hmM9\/Y0TwmVMT\/QWmKkoNLZioEeeVMLiJ9DeKc2QrHMIUklOGz85MPtlWWDRRlcSZJ5SgBTp\/J1KTJwRjy740TXSYTCMqxBoIDR9f\/td2nDp35+kde\/P2fLV66xYMOwi5HA5IRpzIImRiFrbZkiHYnH1CxYkJKSSMm6q2pN771k0d+9dOn\/tbH3vvjH8kEHsyKIYiU4kzywk4GUGT92qzbTK+kIMyU19uPod9u\/gUyU7Ksj2fKkXNenxtmuC7veVveDqCCiHnpVEPHIhaChTu2e+fGcmvz3qrGoyFuK6fsJNf3\/V\/71c\/+2q98otOPWv0wYI6YQeQmh69KXi5ilkyC4ANgrvjOZz9\/7lvfmvm93\/lOqOvGRHuGWJGK9CuuXls49AtPe4160G9xUlMhCxHMuQCFgpLgkISch+GhUYJpNkAdTNvmi\/ZIkXJmS5ofzqVjkRJ4ky2Gy7nNiJz5dhHvyPH7RYolhpWQg0gwHBIeOxW4tfG56Ud+5Zk3v\/vW0sVbHHQo6rEMdemRnFYOIAyWGZVOCzhNTZAogOl7GvaYVW8N5\/\/wp5\/6R1\/sL61d\/dEr8R0nRYoZ0MJlifOoWYPz9nMf2xjaVi7NRopZlYZM\/De+vpweH0Z9jhwVkYfyo0vXRC4JMYa6lmkzF5FBDBBcOO7EvpmVG8tRr0dRGDMkWMWcAAhy\/Nl9s1\/9+lPff+7i737rhU5nQEqyDIgVwFqILSF+cTzYgwvhKuZqRfziL3z0S3\/ryR9+76X5mwNmBRkQkdah4aS4by61hO\/VxhvButD5c\/6exOW0gavOk1rLrg8KbIISbOcQqOd9mqEoSUNQLGUK0JyCS3HeTAgGZt3UJE3kHoBMnGiYtqcBeQf09oiL\/6o\/OnrmKx9eurR455WLqt+ioEsyJMWAww4ydCtbCqcx7Mue1lqZc2KTyyxJamtfp7288fq3X33o555cubGwce0WWGr5LyRg+8QPo+BYbMXIbfjcKBVczEGMXFNyvHS2nJ4Fw7sGpfpiZTR52\/a9zLEpBYBxPDMUjvCrO04fmj9\/lxTHsGzdj9HLAwKOv2NqanSk9txPL965cVuFeqNGWb6aU0GgpBUOB271hecvff0Lj+w+sPfOnUWSIUmw\/i1WmmPBSgXtfr8XVSZGNCBYB0PO6xzCEGW7b5ezTFHGmlVxqnlaPgCh7cmx+ECnZf6OlbnEFMRLTKn+Eqi6TaZh4xNwlhiAC8hEOD65\/oEPnRrbP\/vK\/\/u7Ub9DQZeiATFDuPCqnu\/5vh8TI8yQYCLsmTiFUtgsKBmFg06Ho0FcTMqQw\/6989enT8898PWPvfgv\/0xKqZMssMp06XMiGNYVs+RChsQjDNOPSl3qXDszMs+uUiOkITLsxorJ1LVzurnAsJSVhzm+A4BwK5Ude3de+ZvLWqApq6GZY6CKfpgGZktJQZuiAWe4FrbxxgZRw6mwWyFyKqCK7xOcFEbIMc6biRUpKXuD5dtrbqOWNFFhluIpNqmg8zjMIKEwDSpuDAzxmkgs2m1RCTKMQmwh96GDD84Dx0rKemvzlOSswDZTQuua53sYyDrMQsMSPXYqjcnxIx87e\/7bbwyaGp8UD5aE6+07sO8bX3vqkQdmhSvMfkWW3yQvo+KhLxvyViDg7krzT\/\/shTdfvRgOeqxFvcKBgrj0n17\/6D\/6wuzZ43dfeYfkgBAQZApkKxU+QAaZQWnvv1SYlE3vW8PE1M11ezJV77ynDSiP0OXymzrM\/I\/Tub\/p5cxljgQJPxGCSTiuI1wnbHfSvRcrC1ACp2ZmxVHcTVEsI4oGBriM2Ww7JW0AYpfgatRSxCSVsj6t1nhKnlNFYXtl06t5evVwwhKJi22jL1OOAStmiUNjJYbNcjJ7hBLrG1sFHcPbM5ahgXGco6Tey1Nu7M\/DwwbToG3lG8EWcCPegeTW4FePf+aR7lawcP4aB12SASmlZ79z+3b9k\/\/bz++cHH397VuDMCSBuAsKEkKkkqGat6wTGY17ZE2NARiYndv5P\/w\/fvmf\/k\/f+fEPX+ewyyokHhDQX9u8\/vzlB7\/29NK7NyLZJzkgFREJIs7A+Wnine18WzzZ2Kiw5HryMRR5GzZ2iyvFgvei+B0MZUxgm5iZo46U1DBMZQAOEARYQEaRKffCFqgcTJBErCLiJAtVkdG5TptLCU8KTCSYFThSKoqYlS4W80qPnMoEq37gVryEgGvqoCSaZyjRQ78Pkr30opXLCtrG4fcZ5g8ZNtr7uaShWk57MOy7851wHgLPsrujabmY6tVnMypNkfHJq1XGxmfPHnv7L96SYR8yYBkSKwgXTuWRR0\/s3T353\/2T7732+mUV9uNbzCrPyYyvqjJaYnpI5UKI6V3j\/6\/\/8e9+9atPvvzy5fZ6jzUOMRLsBHfeuLbvqeOTR\/asvL1FwmU4gIzn9nGoZUvJnbmk9WVtzTIv4zzLhEwF7oKVYVGvg82CeJhUtuEPPnRxsK0MmT9nU463eShzBg7i\/OeNJzNJnRBHyyRr1ZcvhdQaYBFmBaWS8pIsxq1Ja0msUiEEG3O5+PE2uqhMAZm3w9Uw55L\/fNM75xppao2WmStZiO4h4\/UC82bI9i2jiFOp3c2Q7V6g94ish4W0Y6lxFB4cf+rwnl4zWLw4zykIhhUTkXCnpyeDTnDr7noYhjzokUzIaCUJO1uOWtDprkeuv7aC1krr6L6dIw2\/vc4xkQ0RR4PB+ubd168d+fxjqxevc+gRAoaIpdkzW1wuVHq5LnSabxp+CuV9GVPjlN0Pphtk+fAg6xqA+QPirUpGnJyl9jBBH2zr5ylFYHY8P9a3p5JaJsZ9pys7\/ZPq3ueXpqYdKjP5Tf8pTrgghDc+Mlhfz5uApywiSyDYVv4jo6uBkvZjIeewm9qFh5T1XLNMkk1dyrJ+Kcrcp7mUPGPJfJdqn1kYEGxnu56RXjmxDIFujwmHHE+4ztGPP7h8ZUEOBokqQnrRhGLEbBeh73oyJdZ3QuWOpNxucXTlxU4FJJw4S2JiZqUACRmyDFcv3zv+zEPVyfHuoENCQCEz7ykknJSPdOXmFCizqi62ZtztkyfkPVGY0kIoTdiAXPmfKoRnfXsqUcsqv5tG00F\/LaWiUHq1KkEgy1rN\/qFililqCxZmjkvMX0uPbqMlgzywQ8BxRnaNr74TUsbf3QbYyeXSZshRa616q0zRncrlP0rTDJSqJhU2g\/H0dnWfqsqXUu8pr7BUIiem7HQsp\/RkHzXZCog5E36jPn5o5sJfX2SpQdiR0W2BZBroVaGB3QRK9LvKxh+28Yvm1jgVuL4kRIpitQT9iZVkFUGG7aX1sDUY37Ozt7TIcAyxaUNbtdTn2PIFst7GfQzsE99715paAakYnE31toVAORsIcWmsQ04pF3nqMaziBJmLreHtGddjrIJwc6lZHa+lba4UgcUZri7bg0wljl0mM9JsoRhhmTN6OqdIjpjQ6FT86ZnR99sdbWeRwUXt5EebFXAxXTER3VkWkebhJrXcxkHR9rh8A8iUoo45Nwoqs+6Gje2B7dllqsLlf0tXcQnaM\/6Bxo6BWBGUjTsG2y8Ua96lKD49nBBOY3rccZzOypYGgrLW4EoG+kLA95zZmbGqB4pCjsIYtEgpsz1m+hmqxtkcn4UQXqVSHx2peiRSBSMdLhQpyUqGnf6t19+fOLZ38e3LsSxD1vcuzdxhdWXMO27Rrnl7UHBSE+bs2JGLuBi6CGKwb+mMuLQ9aFpvZjVVkkMbPZ+ky0wsZRgtXrjVmBoFEQuHIECCIYy3KywonAl\/heFRnBz7gCgBQsOGCugJsm4bQFQaVQgEmy1dajJnhGnLgrFwx8pUagEbcW2hYPIAGhghC6WQlHjXC7I1SUy9Lsv2DJRaaVsuWVYSbFgisCl8ZFZxwiEI1vg+FbCKoDILznxqlKq227NEACwECbexc3R9sT1oD0hKyIg1KIpELAooMDs79k\/\/+6+wUnFfLlkhKiEPcKGbASLFFDExkSvgCjG2o3Hv7ga0a1AaxVlqaFRzfvXAZ86K7z4vB4ISjY8Ef8r2WKko3limh8BUUO0v2dJuacltkYQ5myrmNcdgBNGhvuDpoNw0qrVqwmLPXf887q9IuTm\/cvAzj4tKVQZdEi6JkJQgw59X2\/KilEeLYTMAmIWKMPzeMhC5EFq0a2x2MgzC3lZH85j0mMSargxJ5FEc3aAsQMOMweCc0Edi2wgzniSjMC4O8+z2qt1TT8fBKCBEYeW1mQRSgliM0bwOOVV4DXLr5HqQIYc9DttE\/cRYRVFZ+84uapFKKGi6TGNqcv36sgwGWigongMbKq\/Njd7v\/9n5VqutopClVEqlewgEbfnDSpl6+IDQPCUIF67nOOLnvny25juslKHjrFhju5Xsbvb8nSNOtSJbCSmIzTecmS1yPu+lcjFZ5JyebNXY5Ca4ZsBLdrQpZWR0MrkIEc5FAtq2W81lom0oI9QxKD2oJKmotbg2sWdidO\/U5tUOiT4jIBFBCS7pVOSw\/0XfYZNbFH\/ivIoroEWikhGWt+vI7Ma1RdkfGKjx3FgbOQSv5URoRiiy3FTJVhlM4QRsss7SJQArVCVHNec+CAouT6YvIWc2M2wGVi7B1Gu4lEihvInYT51qO2ePHTl47uDq\/NK1l9+T3UTDTqrYw5vzw5b0LTDyVTcc0di9Y\/PWRsqN0CLLiEFITMytZu+vfvDWwsISBT2SUTwMJGVhP5J0JG4Yihh0Ra4Pt+p6\/mOP7D9yYGeqp86s4mOJFbMMuwN2HKfia3EjS0DesHa5H0atxNBie+0Fl\/KofTMlNDD+hRtkA1VtawKUNuRzhvXYtl3CccNFKZJhf70VrG\/tOrF368YCuz5FA1IhW+ieROoYArE+lyBhVEkw25XgWEk2XsOKE9BFTCcj0vKyjkdetTYxOvvgvlf\/w4\/Srh0nEmvmteDM28vupyFtSQJW4zKnD5pX4MwCICyOCZVEORNGztlpANMvw0DsMpvgYgNeY6fx1jvRAz0PbpX90erUni\/\/48\/uf3Rua7Xzrf+LnH\/lTRY9VgFBgFXMk+AMgzzUhESfd45Tm6itXFyIUdrMpBKUL7OG8UpiFfZZkwlVGO8H7dsT3zgHgI5sTFrw0oFwWTgkA0QBixEP5MW5OVuyY8zESgUREzm+p1uABuw87yTA1kSqZLI6RF3O7j4mX7uFMrHUFOqDuLailD5eTMAKzhRlw2K9K2IeQ6QGwa0XLx546qHrz70XhT1yXJJOopIRX1QVgwaJNRSYUng\/yqD\/SCWcFURIrBEznPTQIRwWHrk+PH\/m9JxwsHVnJcY6JWTCFL9mlWDIua2yOfZkU3M1Y1fm8mcg04HPdSZz68FCP5FpA8R2kc\/2AA2GnBEMWIJ5YoqkeNTSr0jyAq\/mTe3aeerQ+IEpdpzxnY3dx2bnX3sbcIgEpyVnmg\/AaskkEtewIJgAeY4MoxzMMDPNZJJMHHdEFYTwfSccBErF40QSjnAd4fly0CcVEYdEgAuv4ktJUkmigGTgEIs4S7LdlY1IDSHSYgz2CJdNMDgXOqTZG+Y8gpfLQRiIWRSFQa8VvNhSwLH3vu29DBrK9TD9s5jz0qjWkAuZ+WyC2yQZcBjMv3xl7pPndp87dPeFNjs+OWHcFofQA5\/sjBIu+XWN8Ca2XTVT22idAQqXnAoJj5miKJVdA0Gw45LrkVsR1dr+J09eff5y2O3G42PmjEsXU0htRhJgS65ZAjycaV1nOWe6QNniN4usCQwUFICQx2RkmEOda5mWKMl3mG3gf+whnmDPGakLXeqCTC5BCM916g1vdrf3wMmo67R7fOPKxpmp+r3rm1devsGkKFHOZhYEPQc3MnAuymJliTIrJQchBGfYRoA4GUfFcTFx8oSYO3P46d\/4\/Pm\/fOny955XKiIIp1o7+rc\/u\/P0wbf\/1z\/v3LnLUpIQO44d\/vBvffX6y5cu\/PmPEywbUEY9SnT6hBKCFXMmso4URpXXrigBxsDMOlBKmjHMIVM4pZvfyfaIhe0AxfeD7peNIwtztSQ4wezWpMkcGzFE70MZUtQLW+3bP313\/8cfWHrzehiFpCSBSEl9g1udsDcITzy4\/403rgSOD72AEtgapyWNNfsSRMKt+A8+sF9Gamtli1kSU0yodzzyavBrBz500hvxb\/70HZYBRWGCr8+KKs6Ia7aLaGZ9nCqSIGcCFzfrs30lYl5P7IKa5NWU2FGR4cqQgBxgl0OprDglXJAESKQMR1pO8neGOU1lUx1AABCe6x7Y6+6YJHZVL5SdcPDiFal8Z2zs+SutGyMb61cWWqN1YtKiafH7Z4NTkpOpRm7kzUTMUrXX2l6jbpw7Ih5BA\/lUjnnm7JHpJ04cZ1z78ctB0CMIb2x0zxc\/XN+9c+R7L3Xu3CEATmXvU4\/u+NADTeGJv3hORpKsNc5sjYcEhBC+J5hkENnu9ZzXfyoOn4bJuJro0eE8TbckUbQiIyyDimFZJlDssBVMP3KTcZSxeWwEHCtSEohI9jns3P3p+T0PHtz\/8Qev\/+AN5ogCRaRR9vLO3aUf\/Oitr3ztyTNnDkbdgQASgGlmMqsXtpkDMQMV78iRmZ8+9969u7HiPUNoKCP8RmXnjgMfP\/3+j94O2u2Ux2guiDhwZ5QWqzfLWevXCmKwOkPxLISzyXU8v2btgZN6SMHR85JYFZdEOuuyRu6sOIVWJsrilCoMJCERxKmmeFxMphIdSvkTI5WpSarXpV+R8AcL63J5jZlj1l9lxDu4f\/2tO826krfvqrEa1aoUNAlgEoAy\/c1ysAzOIUqZNG63s7hemZ0m4Wnbc1JC9zXTZDabS8K58dL71ekXbv\/0najXJxUBCDY2r\/yHvxqdm968eI1kCFbE8uazr7sj7uL5a2oQkiOy+8BstVwSYbFKzaV+JPtBwZzwA1lWZYOLUuwOD\/tFdgn3IZwZtxcfCCi8XYTkwniMS0aLVrKilbMCivphq\/3+91976JufWbl4p3lLswpZq2j32s3\/z7\/8s9u3V86ePex7jtLpLFsjERBI5QZ6POj1\/v2\/e+f7f\/lSr9Miinn67NXgj4jG2Om\/9WR7oTn\/8hWOApIRyDAMzepCpLDUcpwgbMnN2Oc0yTYhMqVNJKWXcFi40CaK2mwIDoTruK7jOo7nOJ4HzxOu6zhxI4aZZMQcRSoKZRjJKJKhlDECUxJrp1RO42TsBB5\/QcQKDsRowx2tVevV2o7x7upm9+Zi1I9Y6bugI6oglqjVIxVF169HBzwSgq\/exr7d3FojOJkUaokON5gKuFVmUkxKtVe2Djz+gPB9GbiAw5l6iK3HAjCr9Ss3X\/ifr3M0YBmCFCvmQffeD18g4VDUJ46ImWTYmr\/91m\/fTfWADHeUrPJk4xZUx6qte+tRP0iyBrJnr7ah2tDteF\/RLqv3TJSQegGzpQoTD1jOG7bSL9s0O+fUWwpjsiIgW3CRXBWsFJEkGQF9Ft7Ku9dvPXv+3Dc\/9vK\/+t5gIyJWHPWgIlaD9lbwx\/\/Hf\/72H\/sQbpwLwUg\/OC4n7FOZWckoCJVeqSQgHHYr5DdQH9v7xMmdx3a\/\/G++L8NBInbIaeiwxe6RCH3YLZNMzjjF3+ig56S7DkKwcLWiFDkOCQ+OR44Lx3MrVb9Rq4816iPVkYnG6MzE9J6x6ZmR2ni1UnXJddlxGFCKJZECC8VCSkQy7EWdje7yYnPlzlZrcbPX7nbag26rHw5CFUlWilNou5LkkluvCp+cuV1yIOX7N1tLS1sXbrCWF4itGgw8NBTt3RFdukmqgvUWzU7Q6oY4ekQtTvJyD3FvxpoyG+tPwBTLZwYpbcPaXuuOTtWrY\/VOt81wUgBG2h9QiS+GBpoRh5QobsX5tgwTaRIQMakIUY+Vw+SQcKEPOEoZ+BwbaKY5P9yxg7s3L9\/mMCAlkekgmiWfKmt5GLgNHpalboOqZdcwoGcD24\/i2LeURAhbRMXaRsk4ikvZO2wP+XIUj7hboH9Psfb6DPtKuLeePT9xcNeDf\/ejb\/\/+c+EWETGHPaiQWClWgyhMmX5W8zi\/N9L0wcAiCEfLXaJS33ly38Nff\/SV332+tbSVRA9JpEAqzTsNgFsekk6ZtZBIIIgaT+CQcJCEOxIuOx45Hrs+hAfH9evV+mhjcm76yLm5uaO7KhN133MrDrGirXa0uti89v5me70bdMIwkGFEiqEYpCRxJAR5nlNtVEYmquPTjfHZnYfO7B+pO8w0YIp64cZK+9rFlfmLy51mPySWAmLvBHmeurUiV1fC87dUrx9LxOvLTsru5YEgMDlGwqX1DapPkO5mVSrq\/A3sneLVxTihTet9pu0TLWatJBIN1lthKEf2THdXNrSRK3MGqEi6yo7+JccV9fHJfrMZ9hQcl5jheF5j1KvVepttpi5USCA4TmNyYtALgiCedurZh1EOaQaOy47nNypz5w69+e9\/oEXZOFXF\/wAhzTAAzn2r1OQAtsAL3OwZhprplLtaso1CtrCr+fQsNzxOUEyWTEIqxyByHxP6SJYR0YBCETbFe3\/47Id+68uPfOPDb\/zxz8LN5JKajmiZISuXYThh9UjgaJ0vcivs11Fp7Hzo0IO\/+KHzf\/nu1r69PrmD184jbdUyw0I8mF1lGPADwZpEAwexLxdify\/hsdb2Fz65nnArwq9Xx0f3nJw9cm5u6uDOsYm6VFi\/u3XjvZXVxXZzrdNvdvvdftCPwkGkkSIEwfH03GHhQClK4JSZhqArfN+r1v3aaK0+Vh+brIzPju4\/M\/vgZ4+zpMgRSwu9yy8sLr93L2oyBy47DaqIpOOUyubGznAp3Jr2zfGV2wRBSkIOOAgxs5Nv3KCOS3t38a15wCFw0sFKwMYYQuYibYkVRb3e1tWFXadml995P66BY\/ZDPHX3QUI4RAyO9nz03Ln\/6hvLP337jX\/9R2G\/D4I3Nvbkf\/PN6aN7f\/bP\/mT5jXc4YoD2ffTJR\/\/BV2+9dPHN3\/5zpQNv3CURWU0eZ\/7+2L4Zr+53Flc5VpTmhMbBpQBMexRclO5BqeG2HX\/sxgxQwvSGZS7PaQvQPPw5exhiOj6bGTTSzJStVu9wKBmM+TvSfi+DJauIogFD9FbWXv2d\/\/zEb3z2oW9+\/MIf\/nSwSiwcigbIVC2UYXBdyp\/Vt8HR4ShR2m+I6siBD5868rkz1\/\/63YWlbu0fflTdXA3efZ86y6T96\/MCVmzODMi0VRTaztIjPS8GoA3ehK+\/L1x\/bHri4Jn9hx4+uPvgFLvO2u3N919fWrm5urGw1VrvRP1BLAEW05QVGwNu7YkpiAFmxfri6LpQvz8JEZHorid4ZSkB8kfq47snduybmjsxM3d08sgvHG5t7Lnz\/vrNt24tXFoM2j326wg6FA44GlBm9pgg0fbOEBwKiLwakaAwRC\/A3ARf7fONLZyeo9UGt1uAMmUV7WE9svIkXuWKOGIZ3f7ZhbN\/+2l\/pD4IuiS9JPvQlSj5qTS7cP3x8ZG9O9p7Z+DXKWIiiEq9tm\/G3zPl1CoaVEBAdefU6L5d1etLul9FMiJmoVvNSM9K7brn7n7wwNqVe0GznTAVlT0SYOSQopzukQRMU6aVlYtQyfOwOb9yjT2Lkkk9F1gAeTqEMWvPc4MN3DCXWFcOYQZwNpDJhhmKFIEiAnEEJrTvLb7wb7578pc+9fhvfubSX7y2euUuD7os3FiVNF06SYVtA6gSoSfhJbaSFfJq\/sTY0WfO7X740KX\/9Pq9129gcix45WK41GbHIa8G4lg\/KuwRh9lmtlBmIlVMgVNht8JuBW6VhEPMDAG3AscfmRydOzl77Ozc7pOzQmDp2sYr333v5qWlzcVNKVWsqqokkTJgXGz4RerEDI2ZyWNfedgbr9386ysr52+QDCnKgHXIoNqJBCDQ3xwMWu2Va0uXf3KpUnGm90\/OnZnbe2bvwV9\/vLvam39n+ebb91auLcpum4I2RX1SAamI4vAL2r2bLtwl4VC1TmHEoeLlNXKIOCKleGUTh\/fSO+8TyWQRl6tHpVsU+nBhSSpsza8Jl+YePXT9R1ssPOKIVMrf1EY8ioRLXuPuS9de+b9\/a+XifBgSOVUmGrQHr\/6zPxmZGV95+yoJQaiwcG4893bYGaxdu6MUkXCYpJSKM\/snfZZ55HiNXZMzDx9+\/be\/p6KQVARlSZsaSgt5kkRZDThM\/KUINctMQnPjDBtjYe+srOEILjO7hAHaKAMAWHhvKmGslsHnODbIY2JJMon9zL1V+c7vfO\/UF5988tc\/deW5S3deuthb3+QopCggOYhFmhWn6Jss2ArEAdDxyavArTr12tSh2VOff5hd5\/Xf+eHW7UWWirrN3r+9xWCanqFN5iiCcMivkFMhOSAZZvO32MdXo+Eccnz2qvBHUBmtjI7Xp3d0uzzo9hyoyd2Thx6YO\/2Rw2M762u3N1\/5T5evv3Gru9mR4YBN44REHQcx5IDt1A4kFDnezNm5fZ84SQBqtY2Lt6JekEhTJ4cuGydz0o\/laKCDdq+L+c31Oxduu98Zndg3dfojh089vvfMpw9ffWvx6vNXV67cGTRbenuQksTA4VnaOUP+OmSfKlUebPIg5FYLrkO+Q4OQlrZorEFTO3l5KW5sWN6NuSIjqUH0IEqGUbdz7cVLcx85efulq6EMSAUEqdOMrWZPVLzxiZGl5QozggHd\/OklZoZXQ5yeYOvW6tbNZVKAVwOIIKKQb75wgeRAeD45bq1RrY1W76w0e91AjzpICHJ8uJU9T5zobbWbt+7EKyfVaysQcM3vFznamZJzGeVweGMmP9InSrRWUKKcgIyRZ0gwG3R0ZHwSLozoc5NIDFPkywkSpXx5IqFIRcl7VlFHvfcXz9977\/bDv\/zJE584ffl7b919+0Zvo8nhgE2d\/FjiPqEjxnZrHrlVb2RkfN\/08Y+d2nVi9sL3zt944b2g3aKoR1LGCYyKKGjh4DG6c4+7TfS3SIXxIIEccnxyHFJhrMynZaRdH16dahPVyZnP\/OZHTj6679p7a6\/\/5PaRh3Yce2xP2AwvvXjz8ks3mivNqN8jGZEMOYVfKZmrnlOBd6NJJiDAzCqKIsUKkDIiFcTmRMm5UxDlFUQSpr4zgeGwikKlVq50fvL+3Vf+tDFzbOaBL5z++D\/6aGuhdfH7F+9eXu02Oxz0SBDN7OR35jGzj+\/dpUGPZMBRSAoUhjTSoCAgYr63RkfmaH2DIxUnxcZIIMOWGzxILXbOMqBwcPeFS3OPHjvw9KlrP3iNZZgYlPJ7F24NwvAf\/tYz3\/6zV7rdkGNNkkSjmSiBZ5juLrqQV8wSAn7Fe\/TxI\/uO7P5X\/+w77c0NVkzC0TtwdPfUgSeOv\/m7P1D9buoyRMxD9xFZOMAyKUNLg8YEByLfmdT7YPwR2Oj+UsBNJkxgz\/FB4EKSatEh8lP4nEpCQbISBX9w5HSBkmJauOz45Prwat7I+OwDR8995XFnvHHjrdu3nn+3u9oM2l2WUUrDZ6WIFCDIcZxKtTZe333m8NGPnayM+LdeuHzt+Qut5XUO+xT2SQaxvrBSTIrgUK2OwyfoxlXqteFVKRzoJZIMmgDhEByGQ24FlVHUxqi2Y8+Dh\/\/2\/\/VT9bonmDtrvdX5rVf\/6srdC3e66xuxmUkGAFAWqMW6+ZyxK5NNSI5LXq0yNXng8496MxPz33m5dXU+qQlVTC1mzoAB6dlpjr90USQE4MaAdeFAeG6ttmP\/zKnPnDz91IF+K\/zZ96\/dfO1GdGKXakZ8ZYHGRmn5LnW3KOzj9H6Gh06Xui2+c4fkgFjS9DhB4O4CqZA5QlLX5TOjdFgqXBIuHJ+9Oipjex4\/\/cA3nvrZ\/\/PbneV1kn1SIQGe6z75xPF\/\/I++tGvXRKin+IYxCzLpErYQMRxfAgFygUE\/+P0\/fuHb3\/rrTqtNAAmP\/IZTbTz5m58Nu\/3X\/7e\/UIMmhZ3YUtu6HWz0F9ho+5ENHMyhc43OvFEVmk6jyZUYfyQXgIbq1iJn6wyrRkSZH302sMhttrIK0eQWsNGYzhkYJp3GtPoixyenIry6PzY2sW\/3zpNzM2cOjE00Olud9uLm5nK7t9WT3QCC\/NFaY+dIdXq0MT3mONi8trB64c7qtYXO2iYHPY4GsRlTgjKJBx1aa7Tq0cEjPH+H+iEclxyXoh6H3Rit6nqAS47HXh3+CNV3OAeO7nv0+Fe+ecSrOL324PnfffP9V+d7W23ut5J9HiWkgUzKMdfSR4IssycugIhJHsJxAKggYFZIxvEG0zFBwBHp0ksrABqXOzGmjhP12JsaTsWt1nYe2H3yY0cPf\/LQ+mZw+Wbn\/WdXIwhqr\/L1qxR2qNehBw8ReVhtwg3VtWsUtElF5Ao6fgg37nJ7i2QAknZ7zERoCc16iUc1bpX8MacxcexrT47N7nzzt58NO00K2xQNSCnHcaanJ3ftnnJdx1jNyPDu2ewhlbnkNAmXMtpcX1+4txoO+syS4JJXQ3X0yKce3v+hwy\/9i293lxYobFPUh+7AKZUBJ80xPbMtGzHE1jfde7lbag79YUTCsr4qhpEkjP6oOSFETkLC2oFFN9k8tQUozEgyYGQmZhFnHZxaWMXtTSfdinA8cjx\/bHTHvunG7NTY7kl\/tAbfESAmKKnCdn9rYa1zd621tNFd3WTdTtRBKd5+CTYtnhQlYEiWqDdo7iCtN7m5SSy1LTM7euLnw62RVyHHJ7828tDps584ffLo6PJKp9vu33ln\/tpPr0aDAUcBhYPEzUvfaUUJ+tyG2ZpgNGVIV9liflkMYFs+BMlAUhAJYhl3lWJzxRxtKdFTMS+pcOHXndrIrhMzpz976vC5uXvXuq+f31p646raWCW\/SpurdHyG4OLmstg\/Kl9+hfpNkhGBaHwEu3fxpasUDcCx51EC02eDOyKy++i47FTIb1BlvD499cRvPrN2ffXiX74pW+sctCgKEklscw7HtnhPTmEw+VoI0hQnGVJ61rg+3MqOowc\/9I+++Ma\/\/\/7Cq+8YOzA5HMlosJvnSImfNuUDYwlQgSzAjTHfcguspfIQWCDsm2pFMObeZSLdQxWdLNZvYdOzrThsIHHMo17FhQFUxHLAwiPhDYLu4voqv+sBDohIKWtqk6Ir40aINpeUpDRDQqWykrpy0ZwLhqB+n+7dEQcOMJRqtUlFLCNAUHWcq6NUn0B9vD4xcuDJ\/cc\/fsRd7Tz\/p+9cf3cl6ra516Sgw9rKJs0\/lUTsT6oMPRhr0hhX3rGeKhvycHl0tCVCoXeg49dmZ8ZPHWzdWurcvMuswDLpdFmksdQ\/jZkBxUrGOb9SkYwW3u4uX1m89ejhRz5\/4pkvz7xd7199w+tuME+P4eAUrW2xWhezO5TvceDFiN9mlw4I7JzglXVWAMWUF5TNrPUVgFIkJFTEKuxu9d\/60\/NP\/oOPdlr9W3\/9hoxCckBqEBfPmrzPdkhhNpsZbLAQACdOffVg3HHJqZBXGT+w+9yvfOzyd15ceuNS3GmLIX4WLNGccVqNyqGEwRwmjAtEihxGmhxUZws7DqUIyNxDUsWlHEAyXxDaNPB8NQiUwOFSDBjKZNQNhivSa60Sq7rYwiUkGSEKWAas\/y0HLAccDVgGFA30H2gHSRlBx8PY7y4VCGcLCSMEEbFkarcxM03skGRdkZJXJ6\/ieM6eI9Of+XtPHjw9c\/H7l1\/4\/ZeXri3IXou1uWzYRxTEhrJKIhZH4iTepqDLeAQPt1LbMemNjUUhJe6zMp8CUdKz0Y58SaUHIUh43vj4yd\/6yu4vPDZyct\/GW7dku5OBuVMOdqaTypmMMWUuYhqTqoJg497W+6\/d67b6Zz9\/9NiTc63lXmcjEE\/uF1VXvb8sdvq8ukmDkFJniM0m7d+DzQ4phQzPb7rBm5E4MSoUArWGOHZ6QNW1d2+f+NoZEk7rziYrECloMqEJTE\/+DdaHqeIErY5EEDHryGvmmleHX588su+xv\/\/MvdeuXPv+Sypok4wbAUiVFNnQmObkImNIkZaLivfHUVu7pGwT2icyk+25buiymDJheXyT3YnhPEsTBbJ1CV4HVOJVk6Kms9Eo238SOGKyG0PL0zw2NI9IhVBRHANzVXhiV2t3lZIpvGLu9py9s\/AbzBUa34Pqjvrkjkf+1qNP\/uLjC1fWn\/v3r956\/WbY2aKgQ4MOhf3YV1jbets9GDDbfHpAuOTVZh458eg\/\/vLBT59pLXS6SxssA2IJUihggLJWW2o4D0HCq+zYufeLT6BeU4rWX74abm6RChG7i5u6G0ylMiBxOqKSzDmSQbR2c2P+rcWxqcZjXzlcmahszo5Gh3bytQ2+vUgVlzpB1oiWTJ5HO3fQZjOZc6qSszg+dWNQEYhodj++8DXya\/3X3ly\/MH\/sc2cmDsxsXF9WobSI8LlEjwtKNvGlcDiVKdE2stWR2SdOnvu1T80\/+9bVv\/qZHLS16z3inIgzwBonrqPD4Nd24bCt7noua7V+w0F1D+XtVQGjRIHlDJMtFc5pHKKw1QoOtChX84NtjWLRb3OWpfaPshojR0FESt6JNbbTE05HywSGQtkAwEblwSaQJSWo8GIDExIUCeeBB2himgaYPnv007\/xod2Hp174gzff\/v6Fzsq6jn6kOz2cwqCSd5VEMKMXkx5pgtyKqI6c\/vmnph455E423Kq\/+PJVDnuxzCab79byvMsiDQSEKyNE7dA\/OLP0w7e2zl\/jQBc8yjjjYVb3qXMgTIh+0joCK+aIZTho9e++t7i12D3z8UNzs6OrP7nbnW\/jxC6xc5zvbMQ2BHoRd3s0O02dPoWDNOBT5gbtUEzGF6neD1yfKmO0uEA3rvHWetBsrV++O3ty7tAzZ5pLzUGzn0gtam0nkRm2xjTLVNxEdwpcjSsi1ye\/Br\/ujU2c\/tqH93\/4xOU\/+cntn7wu+\/EOJBnpHRiDAljZJx2X6yaVILFwv92Yl6xAugktzQ+yNLGM0xIZ3bjMXtlsmrJpUgLThBsWSyMLacXAyHlvQyqxduIcXzT9ePr01buOEp6rUhkdyQC1wVI8SzQYUs18ZAor8ZTfr1N1grla++ITJ546+PDnjm4ud5\/\/o8v33r4VdZo0aFPYpShINGlUYvETV3hW282cSWgojOejOrLr1L7pk7tDxQvPX157+waHKRSGswMxxsfp5WhIJ2gpQUJvo1M9smvtr98I1jdIBuCQlAags3XcALAEXbPmR0b51VdPSVKRCoKNO827F9amxvyTj80MJG89NCcOT\/OVVWp34\/6WhhNFIXbtpPVNJDx9rYIRt7g5k3shUvAbNLaLmuu0fIeba6QGJIOg3Vm9chcQx7\/06Pj+Xe3VbtiNCC7BJeHGAt56bBvD4j1y9L99cqvkVsmrwq16I6NzTz344C9+jMPwvT98duXdqyroUNQjGUCXgrpJluYmVj0HyotmcSFvyMVLDM9EOaN2MZXUhACKpWBSahhe85nwV0bTAhXUY0rso5FLaFGyA8t4GkactuaZqWoSTIvhrK5LJ8LItlyOspkdMOm74iwGkqY4EVyCQ65PboVqY6hNNqZ2ffgzx08+Mnv5zdVX\/\/RCZ32Lu1sUTyAMZ1kignAqvj8+KoMUEp0lPEZCAIJDbsUfa+x5+FB\/vXfruQs3v\/eabG9RlIwuU+UWISBcOD6cKgsnq\/Qy1zYhPH\/H40fb790ON7f0aos1ArMcOIkhwsl2YCqFlDquZb0KPQjRAoGd+bfvuUKc+8xRty3XyIuaRI5HnS7JKBYE6AdUr5Jfo36od1qS7cd0qjSXQW2CxqZ5a5mCLjgiDqBCcAQVykGwcXN5\/erSzOm5\/R9\/qDG7U0YIe0qRq5vhyZ8k6LlV8qrkVeHX4NcbM1N7Hj916qtPTR2dvfmjt65892e9lSUKu7oOhIzi4sWQHciEQmxPRnwQlm958YehD9LdUUs\/gMnSfk2HdUPsY7PCAvc1xkTp17z9Hky7vYDd8LE68mndbDYbwGXN2qHS5LHILjMZp0qaiArN9yWvzn5DVEemD8184ptPjEz6f\/3b5+fnW6rZpPYm9VoU9iiKs764HS8EhDvzmUf2fPzchX\/+ne69hbhtoFR+iqTVJQSd+vTJRtV54X\/5YdDZ4oEelIVIGnexPo1wRa2x48kH6\/v2Lv\/4jf7de6x0tNSdKiYpSUWJ9FKmeYFY2SFRc0uw5klPRSJG7aSUmIRlw0xQsfm7kizDQTR4609ead5tffzXn5jyKy8FvKWqfGg\/3ZK0FWtp0717dGA\/bayRJIJIMNkwlftR30mNKbV+i1RIBGaQ0pc9IuGQiFhFWzeD1\/6\/i2P7Z488c+6R3\/hUe7G1dmlh6+5yd7UZdnoqGKgwIlZwHOF7TrVSHauPzU1NHJ6ZODwju\/35n1y498p7UbfDsh9jAGSIBGOMWEGPCxxCMpm2Bcu7gsBMDh\/KlkQ+5zPVeNLpkq1ia0mEGZBR5HuvbDqLcFG5EKWelAU7iu10A3LitIZYZi4n5UT9PFUxilVUgILoaPID4zOyua2THc+Jc5AWGoNLwiOvSpURMTa179TeZ37jY+1m\/9v\/\/Kcb97Y46MT5ZzigKDRpBwQBInJcb2aHNzvpVNy0l2S0WDjRjCEC4Lj7D03fvXgvaG1w2KOorwkcsUhm\/D4FCa+2b3bf3\/uiP9YIW917dxfIlFfQwnOaEZjI6RrLKdW8S6REHZ+EIClJhky6T0iGnwcSmnSiDhTv6kiyuvbCpeZK+9P\/5Yc+\/bcPPvc7S2s3ujR9gKprvHiTBkwh08oW7dzNK3dJ6fxWskbb6u7C2DS7dVq9ThzFp2iqtsiKlSQhSUhSoVLe1vXBm\/\/7oj86Oj63a\/9HT+39yFFV8QiIAtnf6pJUXr3ij\/quCwqjcKN779Ur1\/\/q5d7aphz0WPb1cRYTYqTkrBeqkoWQkII5Fo9Eua6EvSbLGkSmCF4phj3dzC7lmTkfSLmCU67RfeItiolurpYsmGYPAe2YPQiLAVwwO+CM68+xXU0GF+ZMNjBh\/iL+JRPklRBKRUa9dStUGUFt7PRHTn3ilx6\/9vbCT37\/xe5mm6MAUR9RSEpyLOWirfOysSQptXn+xvix3d2ltTSvSyRobbECAIBP5CoJFbAcUBSQipB5mKZqdYgCFXUGolLpLawli4nS7i6xVlEj1m2V7OSK1R5iQXuv4o6M7f7MY+5offGv3+ovrMSWElnanApDxcK6CaVBT2iJWS1fiv7yf2o+\/fc\/9Mz\/+cM\/\/Z3X7r5zj9mnuYO0cJt6A+oT7ZikRpe6TYYDzZAiRQAm93DQ57WbSIfjEJlWpWLo4Kkki4hUyHJAUX8waC9vrCy\/d9Wt+l6j5o2OePUKhH6fHAVR2OpGrU7Q7XM0IBVxjMQIKZnFa9h3Uh6nKvGco0qgdPJesLAuMbROTUVNSlSpYyqTa\/hfDeUN58HYzJZp8zDEKYqcYBRJH+UiQNsN982\/sp0YZEwOWBh3HRVNq9UMLps6oaRGJUwxLTDW4XY8cmvkN0R17NyXHvnQVx99+9lrr373rf7GBoc9kiGzJKl594lcKqXqfSo+0YMQEWsHt3Q4wWZSnaowKWVo4EpSEjGKgC3\/CaUGS+t3\/uynYw+fbL77fuaOqksvDVJRUkllYT6YM\/UvEIRDbmXP55\/Y89WnyXPcqbHr\/\/q7Sg30XB2miFumV6GIwCzAksDEgX6h1p3gJ\/\/muUe\/8fjnfutDL\/7h+Ut\/c0Gt9Wh8F006tNGkZod2ztIgIgSsGdgCNLmPO1vc3aC0WxYHQKnjbpwAEwhaaiiCcAhhrMYPJxyIsCloUWjly2y3pCTMjJ0cJWeZzBSukv6cecDHdSCTiRS1wWCcV3Rluk8ByGV7N3lKt+yXUHSDNP0q8xyJYn5YLPJyfHarUcT3k44qQhBgiyOa+5cNUlUqUl14fP6NmrYwqdygA93j9mrwR9zG+Lmf+9C5L5976S8vvvPDd8PWFgddigZQUYossws8w+RNa72DYjUnsvR2E0Z0Ou1LlcU4UWhPnEzjzy70LJSjKFxvR82OCgYp3DFpo8RjGCVjVoXlmpoBqACIyq5J4XsKVBlvQDgZCZDZXGW6RZNIV+iVqrQzC5RkGXWX5Sv\/8WXZDz\/xzXNKhVd+\/K7q9Kju0\/Ruam2QX6XJXdTcJAgSoNEd3NqgfjPrJ7FWOkxp3OYJriBBkKSEJbJeAvpPQ7ayJeeS8b1mXaTzTE75EGyLrHH5INK6yVwmf1bwqEhtJ7g8uLgFMIwNIssmeDAaqwUqbq53wlyAxaSCAiLWjmKCBbQzS0sMxc7BLm3TRQJr1DhUkZ\/zXVz7h7EAIWJ713gHUmXUG508+4VHH\/vy2ef\/6PyF5y7KXhtBV8Pt0y6fPfbUUnqpbq8QQrgOjB4WJ1pymbhrahEoHAAo1voJK0CBBCcTUaGUGUiNtaKI2YFhdM2x2xxnVkPMrJaee2\/s3KHBZm\/px++qKEigJwwTi1hETWSxQjELXXkO1vnVP3o16gVP\/\/KjzOr956\/JwYCCNtUb1GuJub1esDNa25BRxBv3KOqTEJRm2lkYVOX3kaGTWGM55d4VDAC3MnaalQ7YaqullpG87Wxv+yIM+aDH+XWck0l0C+ovtlQfGUOlXDLIZNP6KS9VasG1oYMA66lO2qzTPQxD9hem4JupQ2xHTkPHO+MYZ2R+lCbhGd43dcFlczRPif9ePOf12KuiMuqN7jj7uYef\/Oojf\/P7b1z66SXZb1PY40jPl5LaKVMW1f5OImESxysGghxwku1k4GBDzYNN4SikoECYDZL0E+uhlooxNDlWtXGoOMI4GWNZbhVPHxJ4Wn+thebmnf\/w4tbVOywDUiGnOZuZpwhBcPS4XOfDGfmVOVbdZhVuytf\/9BUBevqbj8P1r\/7kquwp2mpR3a195vGxUwe6L1zY+oPvaMtPIplA5BOtUiktNDGz4TjASW4oC1ZCKCigMWdgDFNNI9t+hhWAIQdczj82Wyecm46bJxWzOQM0NF5sU57UAJkQ22VnyEWrV8KmJVR50svWuxo2DEnldCpwfBYuMUOGLAOiAAzWQCpwoUNU4v1mHVqWXSxsiiKbyuG2LWeKxrPtjzOGm0NCM2tGRGPyzBcfe\/Ir537wO69de\/Wq6rco6CEapC3QpD\/FMQvBcUm4iDt7EWnMdHaLZCLozgZwNDngk+ZKxjfS6z1DM5orM2EMZqq+hq1NiizNCGiUSjYleB29gRVAVZcpHLAaQCYcf21+nIzyWTjkVMitkHCJFaKQKSSpMmcOJoYCK1YqUuqVP3q5348++UvnPNC7P3qXlYIkZ2REVqrRWM3GP+qVJiy7RDaUpDPyARUcbVN8qGUSCZvZZJGPkiZzMhLkzL0j0XBFjl+Q7BmUpKm5\/JTKWBS8bcMTbl56wiRMwCrgeOgkPbMczDcsYYzanAr5DXdyurFvb\/fOYrCxRmGHIk6Y8ipnHFaYYHC+lOMiYM9Q9ipLGkqZ\/JyypUDQ+mWOp7NQUZs487nHHvny2We\/dV7vQA57JLUhpmKyAwUQA693T0+dPbJ1Y6l59RaH\/QTLn2juZagXXaGpON6xYIM\/ktX7ccc8EQtLm8oZXNSE5JsohRzKlGHgjJkUSMSiwMSe3swq4nj7KUslEoDjkd9ozO3Zde7A2qV7zWt3adAmFSUlVWLFCqUzXtmhd777Rq3mfujnz3Rb\/esvXOEdOzo\/erd\/\/kp05x45IKUSAI1K3rwwFjobDUNkrjVZ5WOFnxRGnK16LhN6YcOlkYzrzZkytzX2ztPthmJCh4Db2JgZsrWjDIK8W2qnXKa8VA5HNUZsXACXpdFVa1p53o6p0\/+nX546d7J56cb5f\/p7g+WIWDIxFBuElBIRjvt1bsoaqTwEAWDaASdIoLgpGg\/lXThV8kcxuuvYZx997OvnXv\/+5Ys\/uSj7TT0MhIy0fm7m7aN7rwAJx6tXTv3qM1OPHG0vrL31P3+7M3+HVBQLH2YTgpTIm4wBWBguLoniZhzyshqSc4esfk1XpK6biUId0u4fG4e9OdPNtCFYxvyMGFWbNQ85ww855FZqM9MP\/8PPTT00tzW\/\/ur\/+KetG92kgaA4bYCxluJiJpJtev1PX3Mblad+9bHNTrC+Hsrzl6QvqKJo1xSFfeozsWLFoIiUJLdCYZdNQFa6Yzh3qLKBKimqTLCJac8BNZCPXGxuWhT303aGZ8UAVZCSsVZ0bmIYfwKR34GZs08+xb5PAxPlI8sknwcgqtM7xh87JcYbk2eOVvfvh1slRwtmp6YLogj7LtKdSngXsKHexr2xHBfzKO2EFwuQQOwD41bIr9PE9NRXPvrErz556eU7b3\/\/gsrIEAnjiVLWjEpsLxQp5Y3UqvunSYjGron67p0GXsCM2CkFyRS3zOxrFEFlujhp1mo2Ejhjo4jUp8T+KUyIX2YiaoLmUmF8pUcjGdEpXZ1ggByXXL+xZ2rs+CwJUds9UdsxapwpacNDxU4YKiIZcNgLms3X\/\/i1pasrj\/0XH66HbZIhDUJyx2lxHQePUG2EhZvo\/CoSDkjZAH429lJ6sexdxOb3bdp7ZkRlJ\/NGjZ1p7m43HKMSAdvth+Sm63OhE5\/7nxhS58Vng0XmZrKcGLaPyznSMTMr1VtcW37hne7qVrcb4IEH6cBJTO6h6ihrOWptipJ6A5h7q+jGS8WXI1vqo\/gD08QT1uBEpA6YPvl12jXbePqRT3z51Or5hde+82bU3qKgRzKI+3isEo10zUtisIKSUBE4Gqw3V9++0dpodTba3eWtGNKq+xhKWRx562IysRknU4S3ShNLJPBXGNCqxLs9045h2wMI+aKCs0WbXRNWirPhpN3XAwQ5HtyKGG90u\/1Os7d5ZaF9b504YpU4gnC6A1UG+OaQo353ZePlf\/ditd175GvnKhNjxIJCJuXz0pKYnSInkVyByzK6H4w4vYOcNVpiV4KMn2ki47UzkNGJYSMdJUMUn2D2b\/Ib0LZ9pG2WH7Z96yUCaJT3JyzJA5HhJADKSwrkuUkWQyONR\/rSqDDcWr\/yr\/7A3znlnzjsHt5X3TM9aG7Q3hO0sUzddR60EAacRolk4GUk6kUdZ9wPQ1uYEGaTjsSWLOYiuOT45Dew94B3\/ORTZ2Yrzd73\/+OrvdVVGnS0zAnSEzfLEg1WkGKSUdTvX\/vd781\/9\/mdnzg79tDe7vydxKOCldErT4HUhn53to2U6S5odca5AFrgeIJoofitQ6ggyG7Gw\/gXY4tVW+pPZwksXLiV8WN7d3\/y+MV\/++POnZVgozNYXdcsWE7FqjMZ6OwqkQo56LbmF1\/8N89+8b\/\/Un\/l4Tf+\/LxUTCOjtHqdUcWuab4zH1MiODJOXrbWH2y\/QzaXLGeQYDDnuuicFdG2n12KkhoumrYNhfA+q46HfpPzVH3SBh15EUIMM7KwFjcXAgyXokH1GcMSKkTUk8213vytrZ+9tvnSe07YHz9xiLY2OYrIrWHHfuw6iOoIHJ91Kzz2iNU8MUCIAiej1L6qmK+CrRlhloVyMhJkx+dKA6dPY3L3Q4cmjj+854f\/7uXmvSUKOhT2kWWhqbl7wioghlZnUFJbKUatrd783fbr7+46NUOObn0pUpHK4GyANUjl3FkWMalsVpbPezijXIAsChJMOzbr4AUVzbb1b3E+dU9Z7qk\/qXBrlWO\/9OTy31xeeulS6\/r8YPkeBU2SgS4mmVN6FMPS5tKInwGH7dUrd179P15\/+Iunjz51CEGPpneQYF5rEjyx\/zC5DXLrMZYV4Bi0ZBCsmAs323DmKWjZIsUdkulvGPerOOvbcAntCMXhMbYfHg4PfSVPDsOEXH84N68FBbtPirLuzLboMhigSaTYm9j4uh8rDkWhWrzT9fyGzzsePLTx1gUZBNRvEZiqdYzuJNej9QUOeqBcOWQPUHh4+IdZqaYrE0azQZAQsTeL49PoBI4d483gwCH3Q58+8eJ3Ly2\/f4+DXgyetuo3A9duQM\/ATCqiiMlRWtrcFRyXjopZzyrSRa7\/CGRqqMmih+b5sCHXa\/A8s8lFrJJGBqs1BglwRi1PJpdCQ0xSB09KrIigIZpR9nKJ+FIc3UAAXKEEmjeXORpQjCmPjPQ16e8TQKnJkUhkmiUp4rB\/+W\/e23lwx6N\/5+zipdvN9XUe2UntJi+3ad805vby4mp8UzhzOMy6vuaozTiz2CSqszWlMJWyQGbKYoW+wmwQ9lwhpw2Tw4cNCXtZ7C0d3yNT1WUiZDUh212DIh7u\/8+ozAb\/NjO+DiEDivoUdvjuTa6I9uL64Pb8wQcO1BpVcjxm4k5LbSxQe41qI2LnHkzPoT5GRlSMie0kLB6qGVpgTxORquLF+isMsKYmQYOzK7Rnrzh6lBY7dXI\/\/POP37i0\/Pb331bdFqIASqVOriTAQmjjrgRfr2B2TVLIIoHhKlaxnLMOKHq3C4eFyEw\/tbRZbACabEVTM1tow1CRiqCRcOOrQQJCK8roeB4\/BvprTYVkirnI8UdIOsDCSTF0uiTkWJtcsL4s+oV0rc4cRpLDLskBcYRkjIG4g8lxHhg7C\/hwPOh5qe4aEZMMZKf1+h+\/vLHafuzXPuy6Po3PklslErywhqlxzO5IWgOIEba5pVaGJkMW91I2YDGYcS44IcsR7qsMw1TCXLfj59BmZbETA0u7LNnq7v1JtNtF3lJ0WIqWhn2uKFJEHJFIfCqX7mJqd\/vmbSfozh07uHj9Vns9iBP5bjt+vcYY6qOojXAYIuhyv5vkwpzTJLdBqhRDNK3ujqGDoP0AhSCvgn37aWRc3dpwvfqH\/84Tbr32wp+9HLWbGSyGANerTO0YO7yne2+lc+MORz0tv2L4mybGznEkcZggmVlFcWPDqTiuS14VostwSDDFqJokPxGCnFiUQTguHIcgyHFI+UREcDLqZbaNyXEc39M6yA6xm5hewPA\/1C40sfFoDHTW2EuROrQJIUCuT45HMiATWa77VUCkFMtAgwpYCLAgVpZGZsJI9sYnxk8ekEHUvHhD9frx\/ENFHPW6K+tvfuu1T\/43nzn2yVOXLvVUc4M6axQE6uZd58GDamONmyFBMNLZKVtjNR4CZiQeXpOkLq4F+Jn17HbyaNEJuaQ0w7AysCxL3H66SOzS0L4rhlCEkbeNycndY4gPXYLYgEqcylcWqVrjkerm8mYwUPuO7V++rjaXVtm8au1NxeuAoPo4du5F0OdBj\/ttCgcEZc4pkQPK2dLgnCWBAlryWbhUb4hDB3kg1fVFVEb2PDR37OkjP\/69NzfvrWnyC7RQpxDOaGP\/3\/tb40f2Dda3rv7LP+jdvJ4wXVK5wMRqN9bPdZkoYCLHZccht8p+TRI4nYKwy4rMFQTtkOH55FXh6i984ohApLwEoENMqZ+2S15F+L5X8cjzKfKTcydZCsIjv6YcQcQkBLl+fsQNxPJHlYbnOcKrkFchjijm6af7yiPHIyHgeuRWkhmsYC3eoUDat0Vn146z61OP7\/vaJyIpb\/z2t9dfeJNJo88VlOLIWb5w5\/JfvvvE1x9c\/Oc\/Wx8dp+46AdQN1cXbzpH98mKPuxFlWJgMHlwCIGMuupxYiH6+7+ChlGNORcguhvDu7tOV4fs+CkzsAjn0P+ebH3niHpfoapcQKPJ+vUaebRBMVxbo4HFqNrubGzfPNw+ePug4WFtYSc3xErAxUbcpuy24HlUa2H2U2uvUb3PQg4ziNgnn619kXZksBsbpnHDFxAQdPapur3CnD69W2zH2xDc\/fOHVO++\/eo3DXqyPFg+vyWnUnJmdSggaH\/N27ujfuqVpbwSHiQHBjqPDHQmXHAeOR46QEPBrJCrwKuR6gWSA4Prxr2aoxSR9Fw78OjwvAKTnwa8KUux6iIGaMp5aCwE47DjwqvAryhHwfKHqMfhGTwuIyK2iNsJCMEsSgF8lruZF3V2fKg1URpQQ7Aj4FYBZhmkBysIj14dXFcKBX0N1jMIBOwMOA6DPMiQkCmW64HSEf2C3ch3HE9U906QkkfbTBQmH5EAF3cs\/vnTsQwfOfOnYz\/5IhusLMXFpq6s4EPv3yms3SSvdCzZQ69b0rIBhifkdZOpuF2l2bIUEbL+PkG31JJaW7PkyLhMKgtzI47ntb7jM21EOSwaAQB6kZvZjMIyDiHzcZEUK1O3Swl2qN2hrLVDOjfMX9x0\/MDoxdvvydRUxS8vSDaQ4lAgH3N0kv0Z+DY1x+FW1uUyDDilJRRG3NCFJzEC17YHYN4vGmLx0naVAdcRpjJ\/58hP1Rv2tv3o+6jZJFz8qpNhZGuHq5soPXxz\/8NlwoPp9JrdGHFFcLeoBoye8Sn3nxO6HDk0dnKrUfXe8Wj24a\/bvf1K4PoRwJmojh3ZO\/PrHhZLCkD1I0WcE0l55LDB1bHpk19j03lFSETSQRim2ZfDhuHAcsWPE3TU+\/Rsfd5RKpoCafSjI8ZTr1k9Mz37jSer2nbhToruZiuKk1RF+1a1XJ\/eO1796Nmr1nJgVqZRiJibhwPXgueNHpqd\/4an+Vq+10lp4+\/bW\/KrstSnsIhpoAiQDEB4cp7PRqq2t80Zr87WLDILUPWE9h4847HVXV5\/9tz\/95P\/wpT2PydtLa7x8g6M+Kak2OqLmeyePhBfeN7oSyrLj5AJ1zYRspacuWy1fNtThLWB0uWdbYWjHBSQ3bxM4iwSo+7RVgfFHh+SjKPB9MATCQjZrKWf2klPvNDGlgrV00r7jtHgbMiKG6zt7Du8Tnnvn4vthECRqvJzAQbIWS4zxq42QXyO3SqSo2+Rex+TzJT1RxELrwoXricMHSDlyfpGIyKujNj730LGv\/7ef\/+v\/+PbFZ99RvU09moeK4tFzTCx03PFRVWnQiZPq+m26fY3UgCHg+qjUJvfteuiLD+8\/d0D4Xnd5M2h1JDMT0v0WMQkBj5UgcpJLo0i7N1uSrEwcMTkg17L3iAs1lSDPHQEQDRSHiiogJ3kVxawHOkSImEPFDpEv4hfVDXpllEtCAEQREzE70FbxMGSY4AAKkExgcqr+yO6JWsW7e3np7e+dv\/vm+6rXibWrSYjqqPf4Y6LfkteuqEEomz3WfPZUVk\/XpW7NqY8\/\/M2P7P3YyR\/\/9hutF39GQZuiHnGfiGuHZwHRu3JD\/y4SjTmOTRdzPVLOUjdmKxHNmfBxzkCCyd68yFGVTDuX8r3E+U4pU+Elts2Ek0e6QwBiKMNGD9uBKB+JlIOmmTIDXiZSFAW0eJNGJnltiYAwUPNXbswdmdt\/8sidqzeD3oApNsGGKR6eKsX02tTrkC4aGxOiMcFhyEGP+u1MQwVg4UA4YmTM2b9HbvXU4iIJh1yPXN9v1B7\/4pn1e63rr99QYT8WiUn16oliPkRIYdAnZxODAT34AAcdWlogxxWV6sGnTj31d5+SzO\/+4J1br99o3luTg15m3M3K6OaxRnamkKREXAAMYdxOZYz7YKpTGdKMiaI9GziKrKeKWLqXjckhZ2eZVRlm7HkRt9S0K7CeNBjjE+F6jZ3j+x6aO\/HJU5\/+rz\/7xnemL3339bDVoqhPfk08+kTUbMo3XiPZpdjUjBM8DTEAxSBiGaigf+kv3z3x9NHDnz7x9qXLvNon5ZAUxHJwa6l+4oC\/Zya4u8CkkaWcUSMy9gQSBgWXM2zK1mrq6MdD3OFzCg3bFXbW0C5nQz+kGYN8wqqvu1vgrdPwgSCXwTh5yPsiWw8GJpA9llNJjjfqtWliN9XGqLdFUiqF+Ss3p\/bN7Tt17N6VG91OhxQRSQsDy6mhdtIr6ra414YQVG3Q5B70tPSgJBbkuBDkjtTcffuDO4tqc4sgSGjKfOPQ2cOHHtrzR\/\/sp\/3mFmmOkkpVg5WVVKiIVMSrS\/RWiIdOMZFo9w8+dezpv\/\/xxXfnX\/y9n7aXNyjqUxTGbCCydCViCThmynFzTH5qvpYYcieRy5fMA1GUD5c5RwiigkhRnDhwhhPIuLMa4K6E2+w131tYvPqziw997fGHvv6YqPjvfOtnHLnOuTNqbVW++zbJHskQZuVhOJfEev4y6q633\/ve5eO\/9NjNR45v\/WiFVEAsSCklVffa3dEzR6nTCTa2WHDc99FJAOdNYGDqk+QmCkMbMwYdpeA6eL9isXSXlAKwi48vjiYBYrdkEjIcIl7QlbEFUVHAiad6LigI4VMCgyDFBFq5TTv3Ub8Z+ycDq\/N31KB77Nyp99+52m01WSHj76UAKSsUK2KwVNTZpM4WvApVx7DrIAWhOzbiH52l9fXuuxfUIEqoVQ559crY5JOfO3P3wuri1SWOBiQjZGTWzBwmC0aKiRVtrPJ7F8WnPrZjq\/nYNx+\/8cq1l\/+3HwadDoV9wyRYkelWyznDIIMwV2x5FwW+SlS42LrZ8cOFHQGM7IrLUG+U58Wy7pzF38jGPOnYg4VLwhsE\/Tf\/4KeDXnj6G08113p3+2509aq6eFF\/\/NgTIpHtSZs8iXEikYo47F\/6wXtHPnLwzOdP\/ezld1VzQCrQoA4eBN13r049dGTl\/FXZbmbJZSaflQquGBTa1Ewcdl2HIb1\/tpufQEk\/n4tLnAsoMs4zLVLzRKsVwsNmng6qe1METVZx5VHStp4vFdqnKDywBHiNEkXFjF6lqN5AbZR77UQiFv1e0G11D5w+Ouj0giBkw1KPrUzJLoJTDJdi7g\/I8ca++rH6F5\/c+quX1dYWyZAgyPXJr6My+tDHHjz30ePf\/d03t5bXYslQFWbaJAbcHuagVwhi4Qb0iX\/4SdHu\/vRff6+\/uU6DDkVdkgPE2l4BVAQZQUVaApRUhNgGI\/2OFtKNSAuQxa4P6dcRYkeNxDkj+T6pCPFPZfzN2H5DUvywECqEtnNKvkMyIk7eg1ZA0t9REZRE\/KNQW9ak+kjxqyRi+IlWkmTG+u2NHbOTZ77yyPVn3++\/d4nCDmScAoASEXRKCsJMZVjjLiAjKRSd+8Kp29c2u\/dWwRGUBClSUoZh0O40jh+INppKqsKBATJZ6Om6hK0ljWJ6x0VVM1jPDhrK2QFgLHgUhvIZExL2vjDgP2XoAAe1PakZRNHOs6xVQ9upbJRsQgNumvj6mkCyjBc96GJkknrdeLwLIlAwCDpbzQPHD8lI9XuDmGln7ODcjTFGdg45rvD8yvG56O5K59n3opUmuS7qI6iNElzyRypjOz75Kx+av77x5t9cVmEPUZApZ2dIfBNnkaRnwiOvsnN28qNfevD1P3n97jvXKOhQ2IldDdKdE0s7y9T2EIkNhmUtFPu0Jew+ZRr3yuSPJq3LTFJRW52xbfRLklThm5bpTap9pK25k2cmw+Qo82NIuVoqJSuw4dmkyAl79MgnTtx97cbG\/CprVU82GCGpsRZShFDiqwMi4uZKZ8+pPdMHd9585TYnSQSzJJaqH7ig+sE9\/ZWtNPPUKH59+CZE\/HQBIS9QVOY4lCfI87AE8L7E2mFoHsunExlsNffQ1Ac3M4QpsV0qAFKR31ug4dw\/FLxckqI4RfhabrJJSjG5l9obQEYxD8OotdHac2S\/63mddp9gyK+kJkQGBwqOC8eFcN1atXHiULi6Mbg+r7baFPQp7FPYh1\/B5JzYfeDBTzxw5NG5v\/mTd5pLa4nOPJuwcNOZIsF8CopHZ\/7eh\/bPPbjv5T94qbe+RkE7sX9Joke2plNBndSSiWGrD6Wqm+A8mwkG6892vCl9TCrLm1B7iEmpmAZVZFGZbyMhJWVu2+k7JzLcEZODSYAcb9Dn3Ud2jcxO3njlGkcxpBsZ\/iBxehMuhEeOC+GSk8DTIKRyyfHOfvbEjdfu9TZb8T6MT2GEnQGNNKozO8K1LWQwxEwaL41NuSW1vag7CqVdWfFoaMsPA67kyLbFncN5JZyCuD1zYghjegzCxj3nQhxyeCBknhQ0xJXe+k6qqoQ8KxdERGGfag0o5igw5HdIKtpab+0+OFep19qbbc7ugZP0IVJUpAfhkuN5UztrRw\/2b98LlpZjERdWJAQ5HokK3LHq2M5nfvWROzfabz97nQddkhGIoIGXEECGn06eWQAOOY62+BHVxqFPPNDvBZe+\/wb3WxR2DXutJNTkjV9SOV0Fy4uCDZw6JT7BafDJEXCLfyzIb8JyJKstREl\/P7OjsTekSW5MZFHjP2YbKclQ4qmPcBU7tanxg08cvvzsxWgQIZXSjYG+DqA3nk9OhdwqHB+OD8dLGWS9Dh16dN\/IRP32+TvZJkwEwqOtTn1qwhmphZvt2BiDYELe7cLGWEtly5iJSrVPsM0gISdUZB3Qw0JiCXFiG4SprgkLpwfsrDoX+HNxbxjzPV9AosR60OQ66MsqQ5rZR63NWDY32eySaWt1Y3J2ujY20m12OM1tROrO45Lw4Hjk+pXdu\/xjB7sXbkVb7dS2EsLR2k3U2OFM7zr41PGzT+55\/gd3NxY2qd8B0+jhmUOffXRkz1R3taOkHg9q2TWX9PnteuT45NepOupUG0efPtFZ2rzzykWKuqlYve12GHeSoP2hzJ0WyzQVKfM5m8TcAwobJuatkv3ItDhhFJ8ha\/kW2fqWqzPSHoMhTZfccUEx2dcf271j\/6OHrzz3fjhg42GChJfguSvkVMitw6uPnjq093NP1aZ3dJeaLBUBMiJB4pHPHb\/80o1Bu00qivPheF2JwWbb2buLCdwfpCb1mZOUOY6HHXhQQiQqLFQwCLYBZ0Gjdlu8dq7xgQIZKmfHhDw93c3vfVhvOEPLlaIMLC3+7Qj\/vL0YgKlFGPS4uUaNSbRWDRsORSqKQp6\/dG32yP49p44sXLsnJVuyGnq1OE5t\/253Zrr12hUVBiQc3c8EMRyXJicxOSUO7Pendz\/68QP33l+\/d\/EO9zukpNuoHP6VT0wd3eMo6U2Nrbz5vpAhsgxQ51ia\/lUhvyY8tzpe6y2uxua7abGUma6otBlouZGZHG3eFuq7LdfUbk3zNlNhpE6TzDZ0OfFRM5immXyeHhhyUidocwA96mfoGTqriJUiqXzfHT2yFzsmadBD0KcoZBmBde8sTkfZ8VGrzv7Cx8YP78Zg0FnY3Lp0g1Sowt6t87ef\/MZDex+cay4sslOJndVi72TJkepfvV1\/9GQvjORmM+bva40s\/QCliBRDUCzbNwwEA0MbOvH\/iW1xjDEDm5YNKWyebShYTmWKh80TbAZTCQjWEHrK39n0P8NJtPnthbLKMF8Up0YQnLJJYOfWIGqtY99J6rc4HKQ\/0mMiFWHhxsLkoQPT586sXrkdKZccjwBSkqIAiOon9qlu2Hz9KksVFwuuh6qHHRM4cUKudrnL8srCSJf3TZ78q7+6GiwvUL8DGRG57LoBEYQYO3uwsndMgAVIxN558dAeCQ3KccTYwanNK\/Oc6SnFwpscb0ht9EOJLGKiPMHp7cgGTEiP5Lw6xdCqw0KOoIzrY65B2HNC05g0gedm3X4F08qeGbGPDnRNKBIlKF33RlDKaVR2ffxkrRNQpCCVUIoj1mWjiGt4Qa5Qru\/uHI8UK4AcSTIgYhJoLW299f1LZ77w4I2XL\/fWB6Qi1uZQMd+fuD\/ovnXVOXdavXOVO70kw9fycBFRRIqIFSAy2T5rwbExxIfJUYTFUUXWLxk2RTQuOVuTi8R\/ASkqICENZzEGXACja\/XVYVpmXBAs4+2SZ3ABZ1PWSuKcA0Vh6siKpKTVuzQySRtLhv5KnEQpprV7G6OiMf3IQ2sL3YjqEI4KAxE2Kwd2BKtbwd01ggOhMLNT7Jggx+HegJst9foljlzyR0StfuSxvb1A3bm4yL02hX1WMtqK7vzpc4MPnx5stBd\/8GawvpVVd6Sycw+CXZfcqtuo7\/oHn3LZ7CIm+Sel7G1O3nKscm9OpzLxBUO2ly1QVSkWEShOrDgvyJc3V06XQ5FqkKOnGq4JehYbw5djbXZO8adZs5RYbfVu\/t7zrcUlHvTTKUWS9yZcYccj15947Njkkyf7t5c6798iGRCIIqhI3nxz8dzPnZn58Nlb529we4NW7lAQpRNLAKof4v3bIw8e716al\/2QQKRCjgYUDUgO4oNYSdL7MH8hgFxAydmCI\/YRKui0oECsjb9pm0SkWvf57WnEpCKQIN7yLlvcJNhCpR9A89uwSfuADA8uNQZNJUT0Te+0aNck1cao3yJSzEwwmeZorXXlBO360LlDcxMzUyOX3t+4s9HuXLvLbuQePUSqDxUqYt7qqaUNlhFIsXDIqxNU7cDMA585\/taz11pL6xT2KRqQjDiktVcubI35FWAAAIAASURBVLx+hWXEMsyGB0omNzWl2LrkRwCUjBLDA1NzzYh+BjiJTZoXWyctLNOVtJ9dYskT36xSzhrD8N+4rx6zAQmwax82ypCUKJbu1RQrFiMHExFxh1mFgRx0qd\/R2jNkChbHMwmHhLP+7MbG829yFLLU4uuCAJaDzYWt1t2tYydnbr9+j+o7eIaov8lBn\/ptdLtEIOHKZhCs97yTJ9StdYJDQY97TQpaFIKigCggIlIqHjunegdxwg0LugCwJVmEvOi1tbRtlj1Zm5OphCNRSFzTM898aPy1O6Qm4aImVHlrx5CUH7r9Snn5oKERWMeQ9UWanKGgmzgQiFhFX\/NQ\/Wo3qDx6cOYLXz\/kOTj05Ozv\/cWtQc0Xg97g2m159Q631qEUwdNgzeTJJUarU0dmRqGuvXRNDXokA0QDVpG+AyoSsRKHsidsCQ+D2CGiZJ6uhElKyUSyC2MAW08hy4IoXekwbz+Mg4lzuAc2NrUx+EFOR2iIADLDhE9R5lVij65yMh6xjkbaJ0gEk1O9QKGlPeIrloIQVKKPLWKrRggWHkmHNDmLEjp01A9bW2\/\/+Orjf+fc2GRt69YqdTY47NBonfbso26HggjsMruD1YE3VZn40LmdirvrraXr87LlEkDUoYg0hZOYQUk8zLwobYEJNuTmze0Du9KGYY\/CdtZmYm5pWAwkMnN92KVp8rtukYBEnPMIzcVhq+rjQtGXIQbi+wQLWYVtB6MpTJcURSE5jB27eWuDVESgxM7SI9clr4Lq2MzMqCcQEchzaLweXF7le+u01YUgch2SREwQLkvJxBAuV6pidu+hqZFos7+xsMEypChgGZDehOmSjnV4Zap1H3crBWcfX7iO4wig4LaTqoNo1Fsa2DLdL1s61MgADdwfJ4JwJdAJzhaLqUdtI3SR7sscxjn1c4BNnzNSU87MwThmpiPu5BbUO9N2lAyR6eFl5D5iYq0mGlcVUXzkJbw6EBH6FPp33rr10V955PATB968c49cQZFAs0VbTXJAfpVmZsTsLG90qaU+9fOHn356v2r2f+dfvHD5VU514jiKPzEnZsOcWSwiM9QxE\/5UYzdnKlTkOSFXxVuGcSjqElpIVFMkJ231xN48pfIWQ4Mg833Kw9wUI+ciivwIsTSV5bTwoLVl3nec2n0iLSbvxPJBUQgeTBysrrFqNiPp0qXF3sZbt9X8EqIAxBgbpZ3j8CvKr6m1dWy1SBL5NXH6uDuoHD0+9c5rdwbtHskwAbgoxMIwqSO8k9EYk\/KA47FhIvTiOpo0xDB4nLHrUaY5n9qOIJdIgoy2JPLTpizxQb6YQNbEtAARzCUVvBEZjfWCHNIYRqLEWW\/U9CRILNHShWwsBqWL9nSmykLrrhEL4\/05EC5z2vZU2oWONcCIZacZbt7Y2PfI\/vPPXpGDLfJCjoiUJCaEkhaWeaNN9ZHRIwdPnpoebXhOwz388IGrlxZU0CEZMEkiRZJISQKgPVszw5x4XVkRzuyEFtO5NOYYXTRs16rOUSjMgpLNjlAqIKJvrjucGbgtPK0ox1Z4Bsb9jXwNrr4JaGNiRYJIStpap6lZWpknInJcEhUSrrtrhze3a9Dvvnl+5d1XNyoj0erFG\/zwQWclku\/Nq34PYYfUQPfmyBFUGaFqjfbN0c7pPWOV6tz4hX\/3kooGpGOgUokDkW6oOsKtOdVaFPRjCEgqQ6HFkdwKaXY8SJkDEmQpQFpdGEo4uS4mDFIRCnQxUy4VJW3R7EUK9Gqj8cX2qJZze8+oSzij+SczYgO1ZJDy0sYMGx25ZBMLAcdnxUSChDIiEAAB13MqjWgQctAm7hsqw4pIQUUqDBffW37g81OVPXu6zbU42EcBEZNTget447XKwV1wsHht\/ejekU6oljvByMnZEXens7W2fuFKsLYcDkCIiIWeWMRnov4Cqe9AFgwL1oGwDD1jl\/AMqGAZghRSoOL30yqAeWhYc4eOHcuB9pRVMUOn80R5m8GihVVSByNn7EUJYN+J3+LWOlXHqDJCTOS4zuS4c3iOt1rRyoZw6735C+w0KrtrgwvzbtAVDUEHxuTNAYcACY3GZlboDzA6SbUKv\/7uzM+dW19vN5c3MsC04R1JEKJSn\/3yJyfOHlt98Z3W9dsgmeQGDG0v5VXIq7q1qluvstn31tNEo2BnonIZolJrVBQvZqIWZ1EpkaVPtmCD5RbHqXCodVstuhyz5Vucfcn2gkhDIxeFIvSjhOc29u\/msQbJEFFEUqZnvRZTh3AnP3a2cWRu5cdvrvzwBY2DSncCWOlW57X3Fk5\/4cT49Ei\/c0TduU28Qip0J0bcfXuEUtRs9y5fawXet0PM3+vV9k68\/+p88\/a9geiNVMP6eH1y5yEICKjW+mbr7lI0GLC2x0qwfpw10ijOtiwpXsudjlIJiNRaNJtiDKHWF3ofzNvIIsbfdu2xiXmjSueHGAI7yC+jvE1ZGRDO1iiMcYAxZUbr\/+nI0+1g9gj6XX+qoUbrcn6F+j3vxP7Be1fZqZPboPE9rGR4YV6cnqV2lw7P0GqN7y1T6h+oIt63jzcCV4mZo7vuXd0IOgOKNKsgA7iAiCHcicmJD5\/19+ycGmvUb+\/TumQJvYQJpISjHCE8tzI7pt6zvGxhyZIzyvNykyJTkiAkFm9gG6JlNMATOmXWH0EGFAZZwStBluQ5p4l0CkzJvPzcn7P8hLmM9Bif8mKkOv2psyOdAVSshKBb2qnKq\/ArlQcOo+I3NjurP3qBSRIZets6z1dy6fbG6mL70FN7Bqd3d3\/syK0GqEUso6VVeXeRlSTXo8rY+mb\/+R9eGTs+SV5E3Wa\/t9Hvb1HQETJwK9XxuV31yfHR8RFIKYMw6A9aa1u9ZovhGOB4zsykTCFgWLhoHUVZxSbkaW0Pu6KwD10LKV4y4zANoQBicm16KPIM0eFUQ06TnWIIzdv0FptKKIfQQKvHOlpXgR0PboVcv\/H1D3tVv\/dnz4XnrzoNv3Jif+\/tKxwyuX1Cm7sjFHWo3+ULHefIHnX9Fp0+wdUK3bwBCZKSJid4Zi9dW6\/PzO7ZM3Hj+ZvMMhVTS31dGACrcHNr7bnXRh84uPSXL3au3tKWOVnHRQhyPHZ9t944+V99VljOgUw5xR62c27KMyC5kIcm\/4cBbY+PAaOVw0mCo4zUN39UcgI85xiya+E1mJTZGkoJClmAZTObsfJmRqFVsdW9\/R9\/0lpepbBPkYyh8OmyhiPqjdm\/86nqwd3Nl85z2COODL0vQUykQlZhFKqFa5uH\/u6Dm4QNGax9Zy18\/x73mnHLmhRFRBXmTmewtbo1rbyKcioy2upQ1CcVKaJg0F+9dksfLp4nRnZM7Do8t\/vQXGdto9vpdjrdQbMTdPtKSjJ8Q7MbpzmZECxEbDIpI0JEiqAoqWMp3xfNjexzFP9c8MznmOwWJAwN+8ztZBnzlUapVKIZXtnqzZTZvBAS6XtOofei3nAPzlV2NsJbK\/35BbcqGsf3tS\/Nq15AYJIhKeLOJIIWB10OpLPAtRNz7dcu4tRxsX+\/ujnPbg1HTgv4ND6668RuFli4vsxyQBym5puZm58KaNBc\/t6zKz9wVBBwRiBIVCQcl1yfFCvHkWHIylRjya4LjElvUU7Psr\/MKzbCorRDMCXcn6T7klqvgMCs4kmzOXA3bINji08IMsCWnEHM9eJCvLwK3jqxfgFQIAckhSExQA6RiiIZBDEn0+JGgyBU2L37e38BB7LTJtk3bSeQygXJgIPWytU7p+XpflNt3GkGCyukmIBYbE6\/ifoobS2rsB25U+rt92vTI+17fVaSSCVgOo0ipIESweLKxtIqgSrVaqXqjeye2v\/IA73V9dbiSr8fDTqdQbefxDbEHXBth+r4BIdkSGEPUY8i41ayyrddSun2Vj5hyoEjc3nP0lGr1QWUUXmpDHqdpf1l9g92aGfkPaKQR4FDgIR2qYJw4Lj1udnK3Fzz2t31\/+XPsGtW7Jn15ya6V+Zlp5MRXpRSgxbJHkU9IhosrKpG3dk3Hb13hUbrzo6dMgwpgnrnfWdmx5Gzkxv31jfuLVFkjCUInHALWDJYKRkinoyZEz\/NNJcEItfXe1NJlXThOJNBKQrBMg\/XT2AjK4u9HxImhxbedgFHZwcxu1yHBY2ZhKTU5zgbtSOW99XD1VjeW3AsIcOap8vQbclYM8JotRk25ZwK41BmqyKYyeR8pYwqSSpkFZDWyFIqtTwhFaion3CjYpFyPb5n4RAAZlYhhf31O2veamfwn+4Ga33s2sHtdRJuqhZFJEhGtLHAUPARdpW\/p+qMjURr\/cRwQYIlaztepRgxtb\/XDnttsbW2uXDxul+r1EZqtVpt5vjB2mh96eqt1lorCGQ06DNceDWujovaqF9vRJ1W1Frj3lYM8JMMM28vlZNJnAhgnbYGRgOMrBhnTkYU5tCYyqaERTxrJi9gmxUXqVxF5TXYHVSdL8UEM83ZcxuN0QdOBFv9zbcvy0BRjWlrzfulz\/Wfe09t9SgMYikEImKSSjJnmi7RrXv+yYM8WZWrG6h4ePws396gIESzMzNZmb+ypMJIa10mTUoLhslKZXYOWZJp4Jx1riU8x\/Xy4EK2sQ5W\/VAED9mMm0SBDvHmcdnRvJAKCZ+Em+i\/aFePgGQAhKwAipgUsQDYwufHIldOKk1Pwo23jgxJ9iEDJj3LlMh8i4xGWV662mbzpPFQa8apUJuBx\/4cyqi0STHr90kWkA1ucsSI5HyRW6vt1dube0echa0+ju6j5jovajSMICJU69zfoqhLjksra1Rx+zfv+ft3ybWVrIHL2XwIbEEbmIQUot+K+q02EVZuL1VGR9ya35io7xwZHZ2eavbl2lI3oJHHnjnzyCdOLN1e+8+\/8zfte9dJBrH0m1QZPd2c6VuDwUSp1AaYArnUPh74usURnhXNuLTjatR2GDbPMLug6fFMhjZ2ug9FTErSfg2eO374gKrV2tfvhFtddnxyKqDQ3TcpX7uq7q3SoB2LuLAiARIeMYMkqwggVor7HFy6jgdP0ECy71GgaGSUon697k\/tbJy\/vRUbelLioKKPZK0PTzkVpvQyxDEqU9rWqGTH0THTdA40knfAloVFqjubO7CQ6LjEr+KS48Gtktcgv8FOhVyfhQsQRSGFfQp6FHYp6oI4MbhXVp85CYPk+uTW4TfYq5FbgXCIiYMuBk0OOvEvKua4\/86WLxeX5NRGdZFwf7XRsoridC5Wr+Bc5cTWQeNoxwto\/FOCyyFC2FcL1zf2Htr52nfX2R2hU4dpbYuiHsEhkjwySmt3iCNih1bWhCvDe8ve5Jw7PhJutZCKxWhx9hRynG0IRUokwGmKIhVthrTJTTDBaUztrswerB46tPf4oU\/\/0tmxnbXdJ3e9+\/Kty6vLPNhC5BA5ujQE2xOALFMoNkY48zjN5ZVJ7uJSHiRnyBrnFgqXSQbYdR3nJDh0MiBsghdMcke8ppkAIWqTY6N7dstIbr53VSmlN5jjUOPAVO\/addkMaGon9TeJQI4Tv6gQUMyQ8TEMYiW5p\/jqLRw\/SV6d7zZJCszM1icdVJzNhY2YKZOi3YUnKlUlFctUx0EmbUND4kJ3ax2P3CoJTwshkjAMjOzWIUqQhGzYitsupYl2TeLH4pDjk1dHY6oyMeM1GlypkFch4SDoc2ezv74Rtdeox4YpJ2eDo9RZSbjkVFCbqO2YcUbHuVKHVyEmbq71l+5FmjqsJEEBzCyLIEMgjzjO+b\/qj+5oU3vhwvGZNdswsxxNCd0xAljoHeg5lerIoT3kuK2bS2rQiw9oxavz6\/sfnvVlr39P4ZE5OnWE3u6RknAc1geQDuerm6hViCRvtCfPnFh54TzLMCU0QqUsahMSrchALhEUBJHw9InQ6cnORggR1fdEoedKgJhUrUFebAfCOk9JscSchy3Z0NAsXTBEJ5N7zlmp6LIlXjPM0BcFJlM5VQIoMPENRyQ24GzGPBAE4deqY\/t2u\/X6+pXrYS\/gGLOiBIWN\/XvDxeVwtUUgahKNjFFrjagSWyZo7jmEJhMxM6CYBbV71O\/T3n10t0cEXlkZf\/zsVjfaXG6yUpmRJdHI8SN7v\/FM5\/27qz97i6WM4b9K5fVb9VtyK+RW2HEdz2EHkVTEhb6WCWQxQ6BpNgKyz8mUqyogHBY+3CpVRsXI9Jd\/+eMPP70\/cBwF4YA8VhyG3\/2DN1\/5z69wgtKEUoRse8QgHjgkPLgVpz7+i3\/\/mRNPHowcxwGIadAb\/Md\/\/teXX3kDKmQZEEtG0pjhHGuNC6055KyYmRV5bmX3ropwKOiTlKQkSZmm8dbIHwJCMFwId+rph3Z\/6SkQ3frTny3+8GWwZGaSwebCunRFdcQfrPT4vWVx8hDPr\/AG0fgIdbYIiKviXgfjDYLbX+s6uwJnclwudxNhRRO4S5lGE4lEdVr32CoMN6FfgKUUvXbFD6SrXnnu9qG5+nJzcPvCbeyYpME6qxAyIkgiQaSYRKzEo+8d5yQGs0EhDGZ0CkcxCCrsmmTDrJkJE6qTnyizBYgrjYqZSDay9oDIaP5x+Sd0460xPbnjyNz6+\/Pda7eVVLGUCxPA9UOzg6Xlwcqm1vCl5hZN76Nuk1jFNmD6LHc9wEmALxRTbKTD61s4NceXFsDR7kl3bb7ZaQUaXKgt2sEYfeT0yJljIycOjD14kFgS2Ca5ctyFcPQ2ESSEckXkCO\/QjvDqbXPolCsPc+rMKB3hEDiWvU5KQXjk+Ow1UB0b3bXr4Y8c2n9oIhGogAt2iT\/8ydNvvXwnCPsc9mNAgtET4jjB1sZvVVEdnZybOnh4Z2plFoZyZHqGKmMctkm4UIEeabBVgWR1jtlB5xSMmnxexRyO1w\/\/0ke7vTAKQ1JMUhl2jHFTQp9CTizFLch1\/L0zTr0Wsaof3YsfuRxFpCIK+73VTccR1dHq5mKLllZpR939+Nnor9+kqUnaWE5yGMWhJL9KJJhVb2HVO3dC\/ngtFoaLg5WWk3LIrZJbJWYKO9qUm1hROKBooAXBSPhwPLde3\/3h48227K+svnF78fmlbuXAjmBjUa0ukpLYMUtBjzYWKOhy0k0wHLZNYf48DpTYZE3kZDLgptIAjKJSVdIRi9s5bJ+Fw+S6zUMztoNn4Wn2AyDiBhMEMblVb+zoAdnuLbx1Jep2OTUL0Dvw+OFgfT1YWo2julIEQZ1NGt1JrVVipvoYEzO55FeZWrHbnu6h+R6vrdL8XX7yURyYdu+t798\/sfD+hookKZWpawux8dJ7RBjcW2tduh0LAXJKX4r7v5xaBepPVGm49caRX3\/aQ4kMpcnz42yCX0TGGA2qbGYt4ozXq1N1fN\/xucnZEUXkkD54iQkKeOjszOGHjlx6YQ2DLZYBdPs+ZV2lBaFwyatRdYRcL6GZapAYtJkHCZ90cojEVpGKQJxS3GT2\/gFEG+2r\/+7H7bUWD7oUasErm7jDRlyFQ44Pv77zyQdnv\/JkNIg2Xr5EGiGoiAj9Zi9SauTQXmwS9Tp8bR5TR0Y\/\/1j7J29wFCXaqg5HgsdHAOZwIFf6TnjQOXxM3pqnaEDRgGNhBEVKUdSjsBsPk9IBQ9w0JmIWQjTmdlf37Vm\/eIP9GsmoeeUuM2RviZwBBT2K+txZhevQyCRVZrG+wIMukUmbEta8Mb1ayPCpyJ3PSZbskgmnQEGT2ZjYMsyhnykSY7OZYLjkasiL45FbI69Ojs\/CISKQQhSM7p9yRuq9u6v9pRVSUaLuGtMHxo4fDpqtYHEl\/kRRQKRIONRZp137qeOQEDh0mPbvx7XLFEVEnNweQXBpZoYWF4hdunyNn\/mYMzo6Otm4un6XErhwKsXfv3174fZtYsl6RKm0zZAyRPuypiULQY5Lfp8GAxGEbmYNXTKNZbNjxjkmTO78Sl\/FYeGRW0Wl4Y+OP\/mxw9Wqow1BdRWhw3JtzHvosT2X3xpT3ZF4+ZLK2rz6XWlnQscjr+oIR6dQmnYEokSVxyE4SUqClDNhrKe0hCEUPRmYiEhAOJKD9a1gdZXDPmnlyBTnlR6rKQNKu9M5lcXvr2+9c4Gl6i2ssiZnkmAg7EeDldbOSe\/65hYHTQq7tDiy47\/+\/GBxdbC2RF1FxPA8JvBoheoeNUNiFTUj\/8h+eeu2thOGCo3boEyQEggsHMAlxyFmr17dcexwwM76W5eIeOLsqebl97nTJxVxl\/zHTgT37nEQkgw4GFBHoT5KI+NiYid129xcixtB4By\/YaiNGkxmG4hYe77CHB6z4QplkAAKOBCgjCBhWucKbTHJbg3VMartQHWMhGAV+VXRmKlzt7l54RoPAo7nsA4JQawAqh\/eF7U7\/TsLWf6mr6liCpnWF6gxTmHkHT\/kfOhMsLFBHJAQsVsKCTQa3Nykfpeq49Tt4+qdyt\/9RHW63mn2mKMEzhbTcJiDWPAvEVnilL6UdZxFUqYKIkXS1Yc9MvSrrYPAFlCGOaMOsXUwGoP1NHbpM6syPrVv9qGz007qW5tcb8UcER15YKq6Y7rb2aCoT2pAKgQUGx0vxGrZbjreSAwRkxaCyLpiyfeQsHHiEIjcYIILzK3UW0pFHA0o6mfikQYehTNVAOi7yXLAodO53iQSRAylGKSHFhxx505zdm7UoTDsNilsR+8Nlr8zrRyHZo9Tp01bdynoUNDhKKB6jTbaREq9fZ4e3C9GPNmN4rOYDTmDrF5OZGmFA+GMzu6qT+\/sLG+0VprkOI0HjrSv3wzXVjRCgImwsemO1cNuMzm4mTtN6jTJr2B8CpUaBX1uabadLSGJAqM29TlMIIf6cHONRZDodqbCRHFhrdLfyMOxUUa8SHOhxDETXo1qE1Mnjh37\/CO9gbr96g14aF28HCwucWToncTkVnj7dslBOJi\/yymsSW+bNDEKApraQRsb0bvvy1bAmx0xOUF+nQZdYgWStHMHLd5L5A99Wu\/X2332R9utAcf60Nq9nY1qh2NpXau6S5E+EhBMikifFExwdHgpWDoYhAkmG+ZFScfYYLWkMZDASeOevCrq40dO7p0Yr4hUbTpJJnUtMndg7OiZA++srdCgxVpwkSVSY3btIB9P6kUqg5P5oIgkH6MUE5d1BMCw51lpuQP7eKF0UoFEcoY4gg4+KYaBDBv5RHw2TghjQztdDwkSYJZKqtU7zQdP7haQpEKSgWoG3b982Xn6NOoeyzHqNbm7QTLERpsadRaCVETBYHDhinP4EFbXOAZ8MnITosSfGHDcamV8357\/H2P\/HSRZkp13oue4XxEqtc6sLK2rq7Xu6elR6JnBDDAASJAAl1wsCWLJJddoNFuzR67xj\/fM+N4aV3C5giRIglyAAAkSA4BDAKMwWrWWpasyq1LrzMgMfZW7n\/eH+1URUQ2O1bR1V1WqiOvux8\/5vt\/HS+X9u6sijADJGStLvxNsbYKU8YFpiZVtd3JEbEWkLyk6\/BwRQk\/trSG3cGyGV05Qq6E6TYh804PtmSgkySlag2+US6RPwpTawIHZgNzcy0jGvOcEEtSTY4DYJyIX42R5tEyr3Smx4ujVLz518dUrIQDa7rX\/8KZsRVpyksKnkQGz+PwcOba\/cD8WVTFDDUXMIeVqOzAwopaX4KDOyw6fHhNSAnKAEEpFEgIiBXYBeAHLZXZ2lt\/dhKvloOWZnZ4x1LpZ5IhIpEAGeqqMOSd+wihJfk6m6zdAjpyxNPa9q9ygPnimnC4wA+czQ0KOqJPDHHBK7uDwM0\/POjaT5uYBrbZyLHBc1EOfSom\/+OLcnbfvi\/YB+A4wKzbLxi9aIlqiDNUw5qbFTKJUp4r9GX1d4sQ8HTm+AbPkjsIYKE5MI0J1N4ZMOx67obuU9jCRkqktECnR2WuUyhbHuGyxXGi31Nv3+BPn5bVVijxETm4J9g6wPJDEB5DHuevgzES0sQWoA72Td42MDBA5Y1ZpbHjg5PHm6mZ7aUtf2O2CPXRmvvr2NRBhSschks0mmxlGRiRiyLKuyPTZJgXtbRC3sDSAUyepsQ+dhgGUIWbjdykVc6h4QAgx3sKUJRZyF+wicBsISEmSIcowlUFkMEGUGWebw51zYExLjdEqYKHCKiPkVpRQFPgkApKR54cCwCaQAxV4\/jy7EcJylfT+wmygCEjxuSkaGhN37hmBWKx4yshj4x\/Db8OxWVAMgAHjaPP4tOQ0Mgn7u8AdsBwcH8OLJ9TqJlejTJwJ215SrZFloe0WJ8YJ0N8\/pLAFyPUPm3QReqZmDLgDvEBWARhX8S26K3EuTfH6M2g7pneYqEMJOXAbeAGd0vGTY489MqL17ApAAvz4\/fpQmX3sySF9oDGAC+eHhibHq7VtsFyIbMAIUKX1cx5kQUmGSlwpmhobkqUKMbiTMnLkDI0ytf5myy1CBIsxsFzkjpFhJRZNosTAmjV7xPdjhqZoVKQxdqbwVe1WR3HkTiyscSvgHdKhhI0NdmxANqvk20BStQlHbNRCIg3tvrtcODUjtvdI6nhICboZa8oNsBxr8vI5ANy7uRD5gdGXcxw5MdO6dVcFXqbJDKAIBImgY89PB\/dXDeU6xlvFZSWCDFXzENo1LJTZ1DyFIdX2QURamp6mbWckfqBkkn5lxeEKFtlFa2h87rMv8oK7+e13woN9iloQgQHg6U0OGVgOK1SgWAFug5AUeSbDRH\/nUpAiajVUq55Oh7hDEm985fUmkdjubFV9qNfo6JCVh6BUwkIRIh8O96xzJ1UQyXsLsX6f5fWlia1Gb8cKtrdh6iTUQnKLUCiZH3NwBLlDioNls9lpnJ9VC1sgyZ4fQqlUGBm+DzK03NnPPD\/3088JRWv\/+bXae7dBBZgjFJnVSFnoLbPBKYJbZq4jCSJjwoDeUEgEoj6O23Q6H2t5WbZMAu6AXUS3fOHSpF22YpQ8+L66cfOgVGLPPTZgc\/PSTIy5jz018\/3VZbILENogLdDB1Dm0GGnZWD5qOr7l5uHo0O9Mz\/NNKdsBSJSjETI+MMg7IYQeSGHoMil3h3paOubr2sNDAxdPtVY2vOUNgmRWqUQYKACr4CB3idnAGIgQyBe3F6znHmXzc7QUUacBjbZlTYa8AMAhkkBKeUGkAOfmaH0dWOwdMSUoVsYGR4\/P1DZ2mntVfeMDAmSqMj1DSnqHtTSkwBz\/CkgGq+vs5HFkFskMyzw7KNU\/kVTUaUi\/jYUyDExAoQz1PfTbhGRuGRBPOJUAwJhgpMtRM1ayhp+8MvfXvuTalqqMrX7rbexUzWuq2WFKkJAoJUhJjSMQkU53IB1YpdXGmMUZADJO3AbmEEL7oHHvrQVxc51kyEZdNjqo1neo2QLWZCWHP3oFnrgiv\/06DA9Dsw1SACpABkog40aThdlBJSMvBIugiMA5lEvgVkAEMDJGOwdgFfHkLNmOurMMvIiOa1uopJSRTCTFaLsDj56FkWFgOPMLL08\/d45r1iVkQihVbJNIdH+IknFlWwqZc2pSLG0YdT88xHbSB\/+BGTV9ehtH08RywCkVR0auPD4h0cTrcoD19fbyg8NyhVdrczPjLtM1nM2ef2H69e8Mec0ScBdYEMujKbOFxcruVLqIeZ4b9gZt5ltwlFV+QA6bCgCoAMKh0om\/+EroRyAilDrdMUPbyQaNxZYFBQDI7MkR+8xs9cP7G\/\/k31PQNk0ckiQFB3LLZbBLiECtvRiuBbSwaD\/3QtgOYKMDxOxCKVKSkINTgaAJMhIrG3j2JGy7GTEd5647fOGkDbi7sOI36iZrABGArFKRD5UOby3EiZQpMNZM6HxFocBSiVrNDOuD8mQ8ikWaEvw2+D6UBrE0AANDEATk+WCXkHEkoUIfhG\/KUlSQ4Y4SEhDjgjGGrHxisjIz7N3dEYc1kBGowNCOdedQ6\/cTgaWpIpKYiYSzwuLihVCGrITkt6i5BzJS9YhNTbFT82r7gPb2yLGU56l\/8x9IKRwcxNFxUGMQhSgFNWsQeqQVRmn4Xjz6392BmVkKQhgoQWEQhytkM2CIp+aAO7S6DbwABQvAdYouECgzoCcAIiFqt1ftkzORUAdfe7t9cwkpSoJZKEEIphG2hptCAGA7vFi6MPAxK4ORpx5CaFY7jD0TVMoIOOLBugN2EYuDlx6ZO3duWF\/wGQAC3VloeS0\/9OTmRuvYmKsVuQpgdn5g6vjU6v428RpwB0hpj2Ea1QCApmqmnHQkIY1h18ghxjWlB18mXhlTp32y2zLGWMvb+Np7ncMWiQCiEESYCbHJwqRSeJTuGznjQ86JCW9tl0Iv\/TskSUkH0SkNQLGtl5+BbRPI\/RpfW7auXIj2d8nvMMbZQEUeHQBIsF2QgtptaLfx2HHarZKKQAl3bKAwMxm2\/KPlTdKXf610AUQE9+Rce31LRpFmN+czm3QHnFMnZKeOq5u3iTDJX0HoxwpO3Gd+h8IAnQKMTOFIwXKLx195vDQ7vvon32\/cvKGDg\/SObJkXS0lSUf39W1v\/4Vv2YFluVMslt\/zkFW91w68ehY0WiZBkgDIkJeJiR2UQYVomK5NJfgwCUKCkNmVZg9xQIpUCBLWzA80mv3CWJoZgwJFvvw1+B5hF+7tAEpBhaRjHpvnwhGodqnYdIo+0GgOMvAsYB1+ARKgMkuViqYSTk7S6jmfmQSEtbQAAoIlTtwtFi9DsILokiLy9b73ZvL+poshfWiEZgJLxVEZlhsuQ9o0Rte8GuG2VysrzeJe2Idd76MvryohF00gTrWewwHLQKfPS0NUnZgoFSz+xEjHw1e17RyrwFMk33q0+fnnEso0KeWDAfuSJmfU7S7JTAuGZizEofd2ih2MoifpRTzDPZeziCGOeP5z2WZkrZLiz7+1XSQQgQpAhajQ9USYfPa+2AkaI\/jbANUVKICZzSxM7yRjykguVQWrsZ0g\/CEqJxWX37Glx7hzdfaAsh08Oy8YhSAEyBLsMUIRayK6cVz6i9IsTA3bFad68p7xAh64Z2iIQIBRPzquWFx4cZeJD8hJ8\/feOGjA5gZZFkSTdRIwT2zPWkHg2jpYZNTllKAwRFNEdGHz58alf+gxnTA5U7v1\/V6TwQZrnwYpx4hEITx7ubv72fyJm2eXK8Ol5b7cqg3ZpfHjq0TNHdx94ewdCGr2CKUgwE9mT1Ubmw+VBCYo8ijy130QRkDaro4RGoNbX2EvPwf0lVETcBeQISJGHaJHXkev3FRIwBKcAg+NsfJIaNWgcUSiAOHAXnCL4wK4eLxQH6NS8IsFOz8rdBu3upbxQUsAsi9vM9Ai0FSgCJZWS7Tt3gRQIHRMrKeeRpywhgvSkXgczAepQeyKl8WNISN1gEMqP5DF7nULAxPxuIqW0baIwMDwzcfHKmALggIQkAT5caCwt7lCngYzfW6jv7PszsyXUXxXh5ZdnX\/\/O2FFzn4KWAe8CmOkfsEwLKHdTxHzKLFKaU5Gnm2J69GnoI3b1loAMfxVAhhB2dOQ4xRQJ6hOwEU849L2UYrMdKQQLuAXcAVaIbEs9ew7ad+FoBVRISr8kAACqEwavvcu\/8Dm5u6faPhuugF0AxkDnnzoVYoOF8eGRv\/6r7e\/d7vzwg87KCgUBKD9efhohS7xSoIFB\/\/Z9REz82VkwZ0o1lEoe1KFShnoEaBtXJ1KOAKq36Vinhwi85LDRAX72ohoalpw1251y0e2s75NSGUw4WfESkqhCiBTJABiPonbt1tHwibmA7PriprdzWB4pjDxyOvT86uKS6Hjx9TTj+knptZjRjjIDFFIRhL7a2clkjDMcKuNwRX7ta7w84Fy+FK3vqWYLwAIlySqA8AEEAQOF4HXA86HVgWIZBkaYxWF4nCIETyIvnpsuP\/+ZcztPHHvnT2\/X3l+gZgjM0iQ1BA4Wh4KjCrbSLs+kVaAPDUM5MDIaTMKxYwQQJV4QRAROuv1IBMiR8RRR0aUTzeyiGfR\/Jikck5hFjcS1gDvgFLFQeeaZubnpUvJpmKJr72z51QPwmoBWY7\/2YKk5O1tKfLhTU8WT56aPNrfQq5Hwgcl41s7MMsVuSkVGSJ79tgl7FPqEXT6QbNgkGvuTkubBJYUaK6qH9eb17O4J5akZsVogawliNjCbR5LW9nHEgVNT4Pq0sQGCkgus2q\/jgyX29IXo7iIbHYTCEERtEKFmdaNtlS6eGLow1\/rTu2GHqDgGjENrFykEAGAO8AI4tnPpdHD7AUVhDlCSUO4x3\/tut\/HMBbx+nYhieaNpyWLmmWcWYqngnDrBLYdankAVLq2yiU5Q4kv\/8F\/ZZbt1b0UFHVQyiVewjJhVAUBCUGYALIq8o\/ve+JmTxWNj+2vbQXW\/bkFlamz8zHFLydbefn2\/FqOs0gCGPJkkpyYlbpFQhFy\/0nxkgM9NRgv3odORfkTo8DOnWaMpNnbBLoIQaLkgA9LZtxrHJwS0W9hBBYQBwMQczo3Pnpn54l94dHJq8PyxgY0Pdw\/Hp3BoCNo19OuIQHaZCmMwMCwdS4JCEwOaaboy28hxSKLSN2NFGaNApt7XC4mRid1jjDNmJGV5nhPm2tcZInb2NmiWB2rjErPAcsEp2wNDjz06adss6SAFHbGydEhBB4I2AVPN4vvX9p95etwtaBIPFlz+5LOzN959EDWLwDugBCmKufjpL8qqN\/tDKLGbBoeYS+9JrsTdKCJUQKaO0NcEAiRJWt6QYoiTmoDFBSlH5hC3gcAEEpu7InJuOYC4ukf3Vqi5i2UHz55FBrR9QPWaXjPy2rL1K18E31cKYGACfAfCNojQnR2DmZn6999vr+8H796lThXCFkgPCIgXkCFwl9yK+\/Fn5V5V+ZmpIOS2gvyupcD30A9pZAY8D6VPwgcZxc4I5OWSPTVOjClE6nSig1ZQa6kgRLfonD8Lqu2\/t0ydpnFjC5\/MPkVA+iTU4mwldUM2HvUy6av9xeX5cyenj43srmyIUNXWN+sky4PFsbmZoenpTsur7+6FHQ8AiGQsqMBUXIoxzNKyCBywinqzxKJjzU+K+6vk+QAMSKlGnZZW3ScuDf3si\/7ybudHN6jThE5gGj9EBvoAAEBsbAzHJ2GwzIcrlcnhgUpRVxnuxBhOdWh3HRo1tb8NioM7BCWB5SiYLQoYA6bbSByYhQBgO5X5eeB2a2OHAkuberKuiJwaU8N\/uA2WHqhyxpAxZuC81EONzV0qMVOtm8tDDKHQ69ACywW3Mj49duzEgEqInIj3Vtt7ey2SAoQAAIq8uwtHGzv+6ZNlFle+Tz458c35yc3DHQpbJiYxJwmI3xXEFG2UX269VP2YcNh1EczMHMEAfxkz2dfmp0AGKEhlX8lsEcziyoIDs+yh4dLMZKfaCKuHIGPEMyAiRAyEkuB7EETUagMRjA+w6REaKigvgGYIkYL3F9wXL8uthtwmaBYwPHKmBhgo\/9YdFVK4ugWWA8KHqKNJUCbiLvL4UAGLVrSxA3YZuGvG4CIyrHdSJHxQgrIDVGZB0yufuRAdHIZH++jXmQV8sMwstIoFkiQjFW5uURABkR75om3b8+MIneCD2xCGoAQqSSqKecc6Qg+s+DWS5oqBSFqegoyIZKDWbi8cv3hm7uz89tJqFAoi1aq12o0Htm0Pz03NXz7v1WrNo2a7VpNCUup1jDEnWglQGQBC4DaoCEsl59yJ8O4itT2DUSEFIqAoAsTRVx9vr9X8W+vSa6LtEBICMcdihQIrFsG1sVyU41OqrdTOodptr9TEG2fHT54cbJWLW0sHdHcdo0O0XTUyDsQBi8RsUFHQ8SRnzHFNoihYwPj4s49c\/NXPWZa1+OXX99+7QyKIu3AGwYbZFClE4By5RdwFu2gVXct1HpYgmAQQYEbGFhcuSMAy7Rn9KtlguVgcePzp+cqwK+MVK6X64Rt7HS8wVkYAAui02otLjXMnyya2jaAyZJ+9NLV5bxC8GggfSI9DWa72w7xSpQtmnxluYgYA0MNoTtnymM214dweHnRCCSIEITEjkc\/HAyZdLk7cYrZ99pc\/PfnMuf2ba3f+76+IhkwXIYOQYejYpiUDBErSXk1uB2ApPD4Hx4+hh7Rbnx9wLn3uSn165PrNLY8Fwd0HYm0NZABE0PBxfJo0PlivIo2WddCaGgv+6OsURTHoTQAioIXcAWcA3ALqhmJMUSG7iG5l4ur5p\/7Wzze2Dq\/99rf8Rp0XbWrVxepy0GmTUnE8uH5hFGPcOTMHNguu3SQVYZJqrqSBoMb9Pysj9U87skaiiaRHZWt3FmfPnjh5+czKjbuRBABGBGEQ7i+tVVc3ysODxy6eCdr+\/uZOp9GWUaSn4bGA2wLLZTMzgBahhSXOH7kQ3rir9CkHhJyDW6TSAIzOhku7h7\/9nXCvWbh0MhofEOsrrgrcyQkYHfIXVuVRXR01KJQEW8As4BxLFTg9+4Pfexc6wvqpi+7ZUX6\/JO4sQ+sAkKFbhHIJBgeAKGQcbJsXisg4ISIydArjH3sMxkeI4alf\/tjsS+eVEqQMe8a0CwzXxXwEY4wYSkTijFmscnK8urhCmRSImBhI0Gs4iOs5ivVkZnSHZkaPTqk0PPL8s1OcM2Wsd+Q1xNq2D66D5Qo4BT0dUZZ9b9X\/aUFoo7ngM\/boE1Ovf3c4bO1D2AaMAGQm6SH+whniPebpi5SMqYi6dNf5GLuU\/BwnTZEiwuHShb\/y6bYXkpCcFIOYeZG\/ZMbHPwJDiUxaTunkbORYpYvHi9OTzVYLSCAiEDKLK2ZFM9M0tg0cIHRNmx0cYAhNBULAxGjlifOvXp66enoILw2O\/WjwP\/3Gm7IF4I5A2AIZQNgAEOA60O4A8nhyw50rF8TeLoUdoz5TKibuCZBEXgQeASUeIA4I6BSs42fnvvgJZ25seHyoMjXWvrckWlWIPJBBGgWHDIAD48zm7rkTikR4fUEfsETS7H9GRaQSkLmVVhppxgAZuaZ+KVEpUpuLy+Mzk+eeuHr\/xt0wMoFhRCCFbBwc3nnt0C2XisMjx5883dyvNnf3g0BSUmU5JWv+uNhpssEh+8xkuLBOAQAvAip0CjQ0DmGASrLaDlp2\/a3beP6UOjwCGeLJeXH7XnRnTYWSRKilbYAckECFoLAwO0OH+\/56HewCfC8ILhxzHpuVG6tkcWjWKQgg2IdmGwZGhB8BAnedGFtGIKW3vkf+mRBg+5vv7v3wGigBUmYi5ql7\/KCho8wCxqyCM\/vfvMJ6oFjY\/ehl\/F8p6Trm+Wo3PbPAKkBhYPbExNRMGZPWFeBRA4aGh93ToIIAlAJEtC1WLIVQ2DkUM5M2xZroK5eHTl2cXKhuQuCCDI1tCVN9QMYVkmjX0n0h4Sn29ytlUV5IuaaObpTUO\/e\/\/EbzoEZhB2VkrEyU5eEmhGdm7sPM5qWBs3\/t1dLZGW\/7MDysJ6AtVKHroBMIcXMHOgSBwNAjikBJ4Ax4mawyWgXyEJfroyVL6jZfESH0QAQQtsFvQtQBGdDOGhQroAiQA2cA6B6bAD8Sm1VjiNE3GYZJ4Ju51ur2WcnBQpGfPUPMoVp74\/u3KrOD7dX92of3VKcBwkfpA6kMEIaQMVYoDjxyztvaCje2SYbGZ6xl7hDnx2ayyq3Y+gQpWR2TxMoEREmk1MH2Lklx9rGLD27eDz2fdHpujM0NWp2gE7YO6+WRwdETx4ojozsrO52GT26Zl4cLE5NBnZynHmvdewC+wMoQjk5Q2AbvyB4Ca2Sa+1J0hOx05MEubW9REEEU4kCZj01DyYKNVVARgIwbfQqUtKbGZOiHy2vAXXDKsE1ytAx7R9bLl6KvvQdD09DYh8gDkqAo6kgAdF3bqCKUoAg2vvZG\/d46SdFcWJGdts6lMD9UL9sCGTCGlgvcIW5bBSdq+2D0yXlVWu4OlA\/FQswotpNiwQa7yMtDjzwxWyhberCg47bn5+y\/96tzUs0KMtNlC9FCBIaWg8konxBKZfvqE9OL7w8qvwGRj9rZHk\/au+AKsTsUCT8i4KTLqJxGxUAXRQeASeXtVTs7u2ZEEfsJ87NIzAF1kKNduvfrf1ScGfW298PDAwOhRAUqKlTsUCjZ6ECkwOtQUAcZAulrp4BAkBdYI5Fz7OTijj8+Ujg46Lz9wY4zU\/KrIWmVDONAFvgeDI7EZ6DNSwU+NOTfXdJCfAO51RG\/yWXYYlgpF06fUIyJo5pqedGdRQoV8OK+Ktb\/3m1ZPxCNGggfTBMh2WwZMOQFt\/ToeX9lNdje1Qo1TGS0qWYo63JO74Rdb1R2WKQQDZuyulcVUp26eHr9\/lqn2TJkpKSHoUD4Xm0nqO8dVqY7zvi0e3LIGhh64qcenXr0xOKN\/Wvfvk9z56yL58BrYuipo7ZStqx15PYhtTpECKSAImPPRaSGEJ0ARydh9hjsbUCnAdwBboGSbKACIyPR4hpEEiwBoKChIJwQu002UGCPn1dv30O3SCC0WzdQFil0S7Y2baCSBFLUD4\/ePwSN65ORviundt7sUsLYoUcSSe8FriSSZjKOfSf0iH1S6DFn5OXJcGJoYuS5ZyZyvmggsNC2GAAmjl2Ghtkg8\/59hXDlkYlvjo21OjUIWqRC1EoZzM67MrAAhr1xWKZxRH0so2nEmsnGyfyBUkoRkACpWyCB8fjnh6WZIDHjYyIlvFW\/s7qSEOkpZhyXx8v7R75IHvEsOwcIQRZPjbHhofrq7n\/+T8H7x0erH64erG6yASyfGuMNq7m8oSIGzAKSUCjDwCj4Hjq2c+VisLCkhAIE4Lae9ZkrXLHozs0oi5NSKgjD7V1RrVEQmSsVAjCkdi042ADlgwhQPzPZ\/YVxPjBQuXiyvfgg2j8AJVBvK2Z8kFt4lHFWWBmzDuZwKNkMbq1jUkgg69UjIDV\/Zn7jwWq7Xov90\/onkaRMoGRrfx\/qHh+eOvvZM1d\/6hGrYBdKxZXVtljfpO0HcmWZDquk9MxUAYmMFy52OzL9R5L21tB2cGIWRyeo44PlsqjpnDsV3FuiSAERyEgLKWhtDafm1Hv3rVefpLUSrazgwCBwm1QUBQIjMTDo6IY76fsxhJg0Qo1vSyYhu4bdBgiEwDDhNZBkYClAzhiPLS1djY5sPkwuSCmj4Qbjo+c2WC46pdNnxqcmCiy2ozFAhqCSyVkuXCmRPSZ5X8QRT85XLj5+7L39Heq4IAMAhZjWo3HjmhAyQW5d33wak9JLv39IphYSIUVKkQnojfkgaV+UEvhCEtgBxIARSQIZ6tQ0Yw9Ajb10RudHDlZqyrEAwQAZFBIwYA4fGbanx0iF7ev34fgx2Wkthe1wcZn8htprdFQ4eGJq8NLp4Kjpb+0RWuAO4fwIba45xybEQVu2BXBbo6iQMxybYY7NChYjIIBofVe1WrFHMubWadJ0eRD2lkF4QAJ0+8DEeGl5JrNHhgqnj7fv3Bf1GiqRaDlS\/W6a5UqZeHSyzG9l0pBTkmkuKFiB3pCB6od1BHby3Mn1+w8aR01KS39NWAIkAYIBC6TXObi32d5rlqeHGrvNaGMPl7eirQPyJDAXmDabKJCmNM83xNFwU5AgIthZg5mT9qdesZ89Q2\/cCN\/4UHnSsJn1nVgGtLHJJsZVx5M\/vMafPCmqO9Sq49QsFCsiCHwvLA+5SdaFJkYTqYyuWudOKMrc4vL4iXjAAISk9IgiAxfpDhxAxK5k7LyW2yAJwSny0uDVx6YLDlPGuYuIYCEggUxN7phqechMy1WcJIFExQJ\/7pnZD18fFM0CCJ9I5JBSqRRNb8AqzZROrLnJdkGpkBSSGMU+kcrG7yKBQIXGysh47D\/NLvJkZceQddN\/SMRi2ugAhNwqlkbmx5a\/vaLCAFwbnCKENjCJHO1jk3xiLFhYVe0OnjhFWzv8zATtrFN9C2QIIlSk6vfXmMVKp+cHL53yGyIKWfHkCTYyShW7\/fZ1sB0sMbCKaHOsVJBbamNLbjUhCglUAm4yMdugSEWADJ0iFStQ30MwYiBzh2PmnlIcH3FnJxvXb6tOh0iPnU3WbLL2kKivxNjKrMgepmieQ53gZYmgVq1GoX\/i0tmNheVGrUHaQWM+lSJCJAkyoqh9uLL2lf\/pD0cvnTjaPGrc3S7ODbtTp737S\/JAqSAEpUCKlGmffh8MGAAxje5Dqwh2kY6aVLLgsTmxsatuVDAQ1I6fL0NqQPLaOF1Wq3v0dtu+fEpeW1KtEAeLcmBkpxaWpoeBW8llwFSeCX3YVA4yBWZ2LUKmKUyO6ZjpEZn+wO5Hs7syTfUzkGN\/oO1CYWDi+NTlR8Zj7icqgHZb1PY9UipSWoFJLAMOUiYMkE9PF12bMSQAlAAnzgwOToweHu5C5KEEo3TNnkd5ll6\/aC\/q0tRgjiOG1C9FymaI3DI8Ie2XVz2HodldGSS9MaVfbcJUBM+QsUK5UB4qdA4adLgPbhGYC7xgVVznzIw4OPI\/vE1SQWWIjo6g3bGiQX95CbwakNEwE4CU0Lz3wBoaL129Mnpi\/uoXrvKC\/f6\/+XZnZAiGBwBDWHtAhzW1uaV9M\/FQSqXOEX08GHARUXkAazukAsoh7RgiQ8YrsxOFqfHDD+9ILYXRfPe8FjxpR6eE33gdWl2g83xuMqaN6cTFp7RjmLUbrQc3Fk5eOGltWUf7NdOhiYmDoG3BfkvRzs611u6dpcL5Y9H+Rri7zmxljVVKj57GMOrcWZJtD9KZiYqrHAkSTHIdEkQt4i4wR77\/oX9UU+\/dBr8JwxN44iTsbVO9joUSACcRqd0mu3ycHqzSTscaLDiPXmjfO6RqQ1F5c827cHHcKbu+rw89A3IlbhempwZPzx7dXpVRJiwt600y+CkdyeSCXWAFlxBENpIJenSSWW8sdXVKWYLAwkLliafmp6dLCpIMKPrR6zt\/9MeLFHgQBiT0JhXDgxgnboFTcIaH\/vIvX3zxiTEjvSMYGneuPjP7o9V1CppAEmOPbgYEj+kuQaq7CZwJw+whN2YlNfnFq5RtWVZliJd8iBwgBM3qT52WWdURAjBeLNgTg97KmvI6qET6FZEDs8rDBRcgaAVIRCChVCqcPM258O8+kLUjIAVuGewiVLeQM\/Q6qnoIFKVjWSPKsWS707y2dPK5y+MnRiNJxz92Zf+tO7RwBzo1Mys3qRhE2VAgw\/sSKSWPMbQdONxEpcxpqVUWjCOzRi+cQMet3liQgYemTE0iTJLCgjJVJSU\/r\/6\/lVlkGc4o5RFbmfwKQGVmYQqCTmflzvKJi2csy93f2VMqBkLqr6EECR9IgQwpKkt\/mI0V5eae8lXYbEbr2874gHNsHPlUtLMnqkdEytx90iDYTMyRinB0GKSU33sNiyUSANtb0Gji8CCeOe389DNwbS34xg+h1VZ7VShw8KW3UnWem+KPnJR3dqDdPFiqPv3iVHmk5B8x0ysnJORoOce+9PHpzz9bu7YUeL7SgXvZFBdM5CegU3u4YzOLuWenopWtxE+Yg7NSt3kindJhirsnbqFTsMtDjzwywZnp\/Sugji+vf7DV3tmkVh0iH6SAbAYbMuAWuGWvOfnOW0MvXh1Bm2l7ScFmLz838\/a3hrzOIckwXv\/6MM1cNTQ\/UqsUIfP8Ze+GCZ+JEuYM9iEeAihSNFQ89Zc+VW8FIopQSEaEipKZWOZcRVKIhNbYAJ+f3Pxnv9d878P4mGBGy8CtgYmhSEDHk8Q4mxjAkzPi3q3g\/gMKOsZVaI\/CwSaQAi5l4MUkZ+3HVaBhaoSgBDjWwYF\/sFIVnO0uH1EgQFLcUY77t6TSmQ1iouNP5Yaj0xAFyTkZk4E4s+yh86eI1NHNeyrUK1Bh0pHCLG+PsqRWzO6IYOC\/1K2dSyCVmLNVZ6HAusANfG\/p9uK5K2dtG7fWdhRxyEZeJzGdBGJtg81Nw7rUjV0KRbBWA1LWyFBpboqPD0bNjndQV5EytzUlEYCY8RBiuYQT42ppGcKQ2ocwOIauRY19ajU4oTM5EJ6YsidGxWGN6m04MQsLG8B4uLhvPX+Vd5TaaTT3G4pBZWr4cHWHGKcYLkFS7vz4Wqdab95aFX6Q2uH1Rs4yGCuM47Kdgu1Yp37pOSup3rAnuUqTVZCynVNKc8Bi6KBTmjk+Nn9qSG90epEs3a8v3Vyj+gG0DkGzC7KnllbYuBUAXFscqdfPDo0XAFEf7qfmK9PHxlaq2xS2EzeD0opYNHxMJCCl4h6moswnR+jJH8kTn7I\/LcUoDdH0N799o1FtUeBR4KEIgCRBPpKFFBAQcATkg0V7asx\/sBonDqB+cTRnfmRutOHa4WPHrbESk75Y2pRrOxB6oCeQAyMQtEF4wC1WdIXXiPdBSkJ5AZA4A86tydLejYUf\/fh9dIAcZ+DMZOvmvgq0u4YylXB8czM9gkSBgQAMLJt2V2LKvWGRWI49cvZYJML6whJpvVuSMgTdQwgTyYp9IlaTzHrM1BoIvaFMaU2fmeXqolmJKISFGwunL5+emZ\/Z3thTxNDcXA0QB5RAEajqEU6Po21R5IEKYlsXieph8\/CIu87g+dPu9FTnoC4O66LdSjQlpBTanJ87LVe2wGubcrG6RuPHoFAEz5O7u53\/7fcpVNDu4PgkyA7MT8HmEUkOoZIfLvPHT0Iz8JpeqyVGj42tvW8bnrfJNwubdxZbd+7Hp4HKSiQzViYExtBywHKBu1GxIL2A5TwBRuGftMJStnkPmdSsOGYxp\/jcC8eHxgoxjo8YwcL1be9gH9pH4NVABEASlaSUg8qAOwgEXqG6XV14UHtyfDqWacPQgH350vjq7SIgkgYoKInpQZgIkkWSq5NPremJg0XsDXQzzyhp4x9nkfQ297zdKgWdWKgp88ionDwAAOA2pH1UM5lAYtxyrJmz49Wiq37uKv3um+F3r4NtGY88SSwPEXLoHAFjQJzPTqmjA1ACuAWK4oQvIqcCtutUOLeVd\/uWkKCv+mxmqHx61rsfCE+fDSK\/2yjoMYhioUhBG\/U0AhEZB2Zx1xk5MyfbnfrSOimRUFEoxSBlMUUpV6B3TSV+M+qm3acknz4dsbjRpilpEpUQUbh0a7FQsudOz3PLAWbpcAhKmDa6img2rNkRJIlJWLxSIAUpIfzg6Obi0Y17IMLRJy+WTszaQ8PolMkqo1NwT82rzT1qtICEGSQQwf46qBArZegcyaUFOtynVkttrFKtAa2Afe4lNjQIQFQ9kNfu8MtTAri\/354\/Nc5sFywb4h4pKAkiJOFD5EHUgciDyAPRAeGB8ED4EHmk\/0X4FHkUdkj4JCMlpVIU2wpSqW\/WcUfdfl7KBcQClsqlq1cnESHuUaDwxeKNTfIa4DchbGPUgbBNUSf+3nwUAQifog75jeho9zvfvtv2BJnWGRDD55+bqVRcUARSao8fk4Ij6CgTw1SVIYjAcJBBkkGA5dcKYpZI2x0Vm6pBkQOCEhS1IWqAaIP0QWoGqWd+SR+l\/s8OiE486RbmPDJlAgPGK2ODM+cm1t86sA582mmAkNBpAAMQAXJGhUFoVGOfqsSxYepIMBm6BMjRKVNlGgDtAiscPx7cvAOtA\/Br4NfBq3WWV6P9\/YnLZ5xSRT\/8qY3SjJvS0E3U8PiZE9hpUNKtYdwqlUYfPd+p1o8erJMZL0tIQ1EhN5PKwPL7CiKSk\/AhUJQssy8L1jQ+TzTpmigBSUS0urg2e\/r4mStnl+48EBHFL4022UtSgrZ33cunBYl4X1SYouAUKKF85W1s+du79vCwOz\/nuKXIE7zoUKuu6prHmi2aCI62YXAcxybpaJ86DeQOSAntCO4u47njMDPCLU73V9T+gVpZxdMX92rw5PkJd2i447cNElfb7c1dLOnam1B4zGHq9d8SiEzn4zKGQIoyEUvGsUDZD8Os7lLvdxhTQkBFc+PW\/FgBIxkCKACb6N7N3ZV76+Q19OCb4oc1rUWJo\/ZbIYM6rH5g7axcOnVmnCEqhIBofr48P1u4vRKayr99KDttjARDFIQhkQgFBS2IOijDFIWspyx9\/PbZ\/m5sI8w\/KAx0anJkKEbZTiP1\/FN3PuJWVZI5p11d43Ojluts\/mDBizpQLGLBpaMq2A5wGybnYW\/T7CREiKDabVXvAOfgOFgcBMGI2RAKq1JxTp1s3b6nggCUAAjiqQPz96q1IBy+eKp+dzFo1AEpqWAN\/NKwK5CQgVuCKIDA1713RHQqxcHLZxsLy0H1ECg5A1V3MFr6w2I3\/rRnOVrdf4R9S5LkXk6GDJvSpLW6DQhQRmJraX325LELV84s3FyMROZuS4QkVKeDBwdO2Q2bUXcr0WDklEa9R0eNqCP4yGjlb\/xiQYjOH\/0gdIrKk7kgKv3It+uIFpueU7sbJAKwHACbmh5tVZUXQr3Bh8o4UFFNiUW2LtxXxivHjg8v7u0Qs4hZGaWocdkk5xmkTIccJJtYPCpEZJyhJrWm5r3MwAcpY3OKe42kQCGiAhlB5Fe3tv7ZP\/kOlQYFoIwCLvyDjcPO7gYEDYg6OpvS0IqSRYgKAEAYEFVrC3\/n\/\/jW8OwMc0sEpIIOdBo7D5Yp7IDwgHHRwT\/+j2++9voGFEqKUIYeefXl6\/chbIPwyVxmFPREfFNP8AhlEn2yMEVJClSApOLQDgSQGQlu1qAYEz10NHxCoNSkcG6NnRqrVzve1paqVXGQ4\/wEVbchjHD2HNT2QATx8SLR5lCvURQAt9hTz9LHPw5f\/gqsLznj45XPvFT\/0zeV34ll3xDn+jAg6R2GMuyMnj5W32DewSEYcLmJB0iDHgigOAD1KukJFmOlocrIufn9O4tBrQEquwIpAbr2DH3oITe7tAFm9d3yqOdjKLMM86epAUPrb0BGsLm0PntCnL1yevneahDoekPf+yUABI22e3IuvLGQExWbJzTVHxBjoCRHqX70\/uHSll0qFC+fitoNsbyqOn4a6a47RJ0GIOHoGB3sgkRwCmBZ6vYSDJRoZ0sUy9iOYHoWAmLnB2pD7uSZ0cV3UfPhdTCTIUAidFXzlEvzRgA08AVuAzJEYIxleUpJaAD2vPqY6fGTxlaoiMLOwerawUED3EEANNWvCCkKIGyDCOKzJUl6MfE8cTNQ6qH70vs34e4GOGUgBUEL\/DppKbMS+kF\/cHPhwf1tsIsABJEHYRuCDkRtkgEqkeTAIebGepiLPEDK5iwkkjQiJOJJ7gizwNI37biySDUAmKoUwGRy5fq9nDOLz56f3FmthfUaeA1qduDMLB6fp1oLuE1BmIlwJeYWMCTgHAtF8CLYrEIQ8sGBgScud4482WyYw9nwaUzqgd5jwnpYvRcNnDvNGWvvHWgzd\/e9zHFgdBJW7mqKwsDk6PCxid0bi2GzlXPWQ+bV6HPW4UMr0fjPrMxUOtE09cIMkihu7IfFQ3MkKkUIEmhzeWMe1dnLp5YXNzttLy62AUCJRrt4rsQKBen7SfMDuwLEkAGzLLcweGy8fv1a2AxDQGTEZ8adM8eV58ujtqq3THa0fhA6TYgCGBwCXwBn4Ldps8GfuiCLBeAOBQoOGsD2lQi2sTJ+cdpy7EhYIDkoDsickYo7MujtHlEuljDF4Zr2HWDsCylw1yHGVCaEnuJhokl\/RIQ+CgkwsS5KAgqUHgQAKqROzZxBmn8jQ6NlNVR5lbkJaKiNzognAoCQSAqIOsBtAAIRogxBhEl0LpAiGUJQNyFEui8qAhCeZu0YIlMK9U0jmLC3LMKuHZ2IJDLGiwNY9JAjKhUPTRPMDCBmpdvMKrgDZ4611vb8g0O9UyCzyXKH58ZGj4\/d\/L0bIAKIfJABLa3jxXNYHKT798EuQ9RMpYFTEzJkODhBIqJb1+DBAybDwcfPte8s+NtViAIEIi3fAdQMobSjgTzqePW7i7NXzjil4tH6rmliZf9XGYH6gd5th+amKlMjO9fvRp6v+R1IyevWter6eKbzlFZ4SDmazfQF6stEp353yjx+RBnAGsLa8vakYKcvnXpw877naSGYAgAVCbG+VRga6gSCEEhjtokom2YBjFv22JUzra2t8KgWQ4xRrKxLRDYyyM+fhXqLqjU4OiKlgFkIDPSOPD5O1S0II+AF7HjWsQmxH+qgeQVh9U9urrbPPHlipDg2LAKf0AIUwNnMn\/\/k5KefbL33QIRh7vwDnSCMyBAIJBERKsaY7ViOVTk\/U1vbybbUHlr5Z0+ChM2uhBkHyQhinL5pFKlEMyBNoZ5CwWNjLdNB2cYUgtIj8xmIDF7WbAagIpRJ7Re\/WYZ2JZJYYiLqm\/zaFcfcc+cBBRAOFCd+4cVSOwARolAcgWvNsdK6XIWAyJm5ZyssDJVGnruw8ZXX1v79Nw1IkttoF449ckIh27y9Q5pFTwAigiCA4TJwhCCKfaoAnLvnT3rX1ynwQUbAGQ\/rw+fmOyub\/u6B3sVICQCGzCJnEPwjEO0MyUIBCBni1u2VyScujRTKteU1pbO9kqStkXHY3UXbHZkddUcHdz64LUIf9fKLbzFZYWdXtUndCfJp17xrTVrdTN10xA\/ddCDsTsxGyn+gbmboF17B3vpWFIanr55fvH4v8INkWiLb\/ujJea9aIyBU6TqM9bucMRg+PR1UDzpbe\/qJjC+jDBDVYU29cw1KBX58Dk\/MycOWaobgBxA0odWgwMOJCTqoAnC1dug8dk7sHQICkMBR17+7tqzk1f\/mqamz0839GkQGeXB4bTnsyMYbdygKcltXon\/HmA2jJ+xuxSpXzo5WEIH6WXfjBIZ+dDPzWqm4AiJQEhiLoVhJFZeE6XUFbpn4W1KEuqmgFDCZFsx6DJ2Zkptc5OybqD+\/0j09hRSvwN6uTPf8s7dbjoQsaHoH3\/6gXfNAhBAFIMNkkm96roowEesBWhWntldtvHMbVGTYZ8xmdnH+ysz+yqHfbseGeoYTw7Sxjq7NZ4bkSgvsEiIHzrFUYkC0vwkCwSpwmw2fngsPqv52FbVVTUWglAZFgH8EMkJmAylKdjcEACUV7d24P37+xPil8wd3l5RSwC1gNo6OwMAg7u0Pnpzjttq9dltFIUihPxwzHe6eNHnqFxWaowvkT0eyEPrl0fftr+ccGKmQP1OyJAEgqHexo92DKIzOPH5x5eZip+0BASEL2hFUKs7AgF9vEKM0RwoR0ALGirPjilR9eV3LtTDWWJNpCUpQEhq+uN3GkXF85nkGIT5YUnsBRARK0d4ujk9DxJRyIreIw0WqtZFbcHDgjBb8VrR+e\/fiJ88uv78qQg9kQCJovnWt+daHwFjcmEg7CpgmN5q8ALRccFpWqRy1PUaQz2XCh3Wa09DMtIRXZlmhRGIZuJDCJM07N\/DN1rSZ6G3tNcmMADNzyqzwJ0MPI9MSxLxgEvq30jGbRNmdxoXIkblKRdXDYK9GUajLSFSyZziGJg4REEi1dN4BcmA2cAu5XRooTpybePubD5RSQAIQcGgYwgj2d4hz6+IJGCzKkBMiRJFlAW0cqlACs5DjyLm5qNlobVdJhtpBi8iIMVISVZCUGGTYdjYg0y5+UlJG0f7C2sCJuYlnHzu4viBZAawSTs3A5vLg2WMkZHVhUUVRolvCTOwk9UlAw36K3J5LSQZ4Z3X\/7d4e6UcCZBHzSqf0RVdavtM6rK3fXpg\/f3p3fa922NBVz9H9dWd0JGi2SLG0X4EckBcnRkrT49VrdykygslE\/Y+pttshtACRGk36\/vfQAhwdss8eZ3Yh2j6Q+1Wqd9jcSVAuVQU7PSuvrUKxYHGLFYvBTmv95vbLf\/Hq4MTgUadJJgBdJjGx6cjeaJcoB0dhUvu7KGJxLDv0psRRl84SUxkTYnaRqFhWozKdD8qz3qjnTTYeKTKdeiTCTAQzZlXAOZBh9pYRJ+lRbN3K32Cz8NiH7CuxBIQhOjpEVYZ6rIIyIiX7fUJm4hIyiWEm5oTzuUszkvH1vZDGRmCvDRRByaW1Va03iJY37JefpaqiB8ukQmtgiDoE9gAyGDk1RaHXXNkAKWKkAKNEvwpK9xo1dIeIkIRW\/JsAabSUhMbqrhBs4Pnngs2jytRkOFTBYTfa2u0sLVMUQRKb16fo6bl3ZHM8CD76f0l3lLp03h\/hIEvSDR6iq8mQukDpSVvrqL5+9\/70hbOS2c1qDQCDVlg4cQw3t0goMIcAAWPuQGno9NzBtbsqjBIZPiaZUowDc4DZBADSN2k7ACSY3I1ktWNNjrOpITZSVj5Thw04NkcB8VJJjYzzs9NciWBxT0Vqf78oXWfqwtTR2lYK54wbaAiZmF4zXNLnsE4QkhBHbZtWZbobImYxa8mEO7sK8m9XmsFJGQMwEfXCMrCr5U2JSz\/RGCZHLULOEkg5HnP85mnBfSwrw4c+LPkbIXbNbIwdyahqY11LP4Zy4sRSiMYUnLaymGUXC8++evFw8bC1tAcooVzAizNWvaEcLr0I3IIqDlNblqeH2geDFPlW0ZHSxsrEwHwZlHd0c1lpPwTjRpGnHaoIQCzRMkHmtQNAJEmEgDZym+xSu4FDbfbpv\/OluSszB9uNH\/3rH9S37xhot9aHxK1QTDxD2KVyR8wfhj2i20SplUhVycr3QjMlTB\/wQdda7Q9FyM6ZSOmkLuk1Wxt37o1duii57VVrSihu8eL0ZHvnIPlsls2HT83X7m8IX3TbargNaBO3NVE\/nhOydLClJMhA7OzAzjYWC+zCRWt+VB36MD02cWp6+Ox8q1jc\/t4dKNo4abeHKqu3D658+uzyG7eCkJPmICgTUkL6TCbSrztlPAWZ\/BbEmNaeycDJzhX1U571UeRU0WlKRy7oIU8Lzl4l0ni7eEWlhzBl57E9TnnKWOoxpaSlBsgupRX0Pdszmy7mJ35IRBERSZG+LywDZDN5jyxhjZNOJtXfhRkP2kPTI1Onx979rfeodQheA2QLOlWw0b1wSh4Oi04kOyJa3Bn41FR4+XT4Tscemwz3guFzg4y3Dt+9F2PdIQ0CMKwunUzIjfLTbK9opBqMmM3BsaBYgYFxHJksnZife\/yYO+BOFyxXz58MGS2zfrt12P3ACtizBKl3EEgxbS2lh2TmE4h9ClrMZfRgP98TplG0RlJD2mSjIGz7+7cWxq5esmze3D9q3l+vHJvu1CNSCpRCkONXTvpHR8FRI2k4oU4atV0CBiKIlx+k6HhkqbVZVwvMJsHlwpYqt\/nU2MTFuU99\/vzEaGF\/1\/va+lHj\/apaOZLr7fud6OrffnryzPR6s4VSmDkhKWSIrkuKSMpY35wxxaHh1QOzdVHIMpAIhFyuX9Yci1lRfbIUMRu7kivmMZe6TZnJuVZBYQaqmHnvMJ+mFH95zDEHM\/GUGb9ptjXalYiW87JgwixO\/CUIyISu\/ZDpfMsYmAD5kxCBceQWMltJAhJAANwC7qJlz1+Z6YTRxt018hogPRibpNXFSEZie9caGy6fnI12a0EAtQ9WrM8+U+4EoydnS4Ujjo2Nt1cIOTCVBC0hA+OEYczIfm2bOzZzCsgRSDCLsUKBDwzhUFkWi5EXRp0AIouCTmd772i3Oeaww5Xd+uoaRR6YxyNvC8xRKDB9m\/u1YjDzvufe7WREkdxeEPK2id6GD\/XmZBNkI4DTKjk26lOSLKRACRH41VuLI5fOYbHQOvCssWmrhpHnoQiGzk+HgV9fPyAdD8ot4CVCjjICKQEi3ZWOPfdoYkNIB2YS2ha4BbAYMAcHBuxjs2x6whkemRkqjBctBChVLD5UYPMzJEBJ6+DAOzzwLrx0YWthX0gZS1LY6FOXjn3xpaM7G1vffhuiMO5eJOlCQPo5swvMdmJpJXbdpikjuomPnu7hBaY5SZTuXJCTHGZL2h40dHIqUZyyRlk5WbLiTbWJveqN7LaQafHlskGxa\/dFyMtiTTwPWoxx17UKRbIYShH3tro2f2SOM\/Xp50qnZtf+4Cf+5iaA0nmMpZHhRz535e3X11oRQqEArAC7e6AIgBGwqBGKO+tW0bKmZ3Fo7Ayoz\/\/9z5U4f+OHGz\/+8o8kFgAD5ICOjYyIBCOBjmWNjvDJUas4iDKUnof1lmo0pJCkUASS2g21c6SEMgMgHTtZHm6PTXz7H399cMBqbGy31lch0DBlhTlMMnXfL9KgtG5\/JmZdNV0jjKQGzMj7Hzqmz3d++q1PyGjZkgCRVHlJBihMUgR+9d7K8JXzxdH50B0qPTLRXFgvjDhUcmpL98kaAAzBAYPWkoKQoWZUAyBjHJFx4BbjAwOFsUFrZAQcLkMhOn4QRFEkpQAACFe34MGmh+6dgbEhFZx++sS9e\/vt9xflQQM4xyKPhq33H9Q+8cLJmz94sHPX13FZVsGe\/YVPDl49W3nkzPgTJ5kMLSNQyRDkESSiQsYsNnputrm5m+2GYLbSSPdAQsyJcLKxf5gRO2F359NUkNnOCvUWnPFf62rQYYIcyWsw8pNgzDb6ssFpGVIbYo7dCNl0NcMdHStf+BuvhmHISTEiJFLKfNn47qmR\/UV+8oRw7PFIbfzL\/wRgoV3EQuXY1ZMDw+UH722pSECxYqCptgUkwS7AzHGqDEVFB0vl8szUx185e3J+kANefGLqvfWLcDhKzSZ4LXW4D74PUQBCkZRRtRnuVCEMSSoiBmFAIBKyY0z4ZIAcGUMFBBbOjYh712u+rBFR2DKGKSUghhtgxuOqdz1zWUHoriby9Sc+VDqTGdYnGo98lBzCwy+GXYdm1x\/n9d7xm0wKSCohjh7sFh+fLh6bvnhprnN1fr0a7L73QA0dA1aE1iEGDQbEygVnoGgPVgpFR1\/RQJJLpJT0QiGEjDqhX9+KvEC02jIQQGRkU4wZEoxd8Dz\/x7\/9vXf+eMD3QjgxSn6NDj1gFtjO6n61cXHozNPzu\/e3yXJBSaXA2zkaOh827m1sfuU1EpHGxqNSZokwrR1lxC2rUDz2i0VSRFmAZ2YFxjTr3IUwOXUI+iCUKONX6I3sjNcWdqWRpkFPfUFMOQ9EZuCSVUdQV1e1qyWTYhoNKzXb+kVQpPyGt\/anH3oND6UxTyWp7qlDiHFnaHj6iyWYGvaXtxGBmA12sTA0\/PynL+7drTY2DqHTgYIDu6sQtkB4UCjgzBRVBiCUIHz0oTBBFcdyAIjIa0Xh6n60tU2He9Q4Aq9hgEOadaRiyzKzwClpmFjmXh2bwvQeVXRgbobWVqDRNLwSFYGIQIaoMg6JfAR9XgSaL0MeLlXL9E3NJ7HS1xv7Gcq6UBfY78Le1c5OTmfzvGB2jqF9k6RUsHrw4l946YVPnvIU\/OEfLx\/4yGoHrOm40YBFIY8CIiWJUIqo0\/ZrjU6tLTqeVggTQjZPNx3CkQAVURInSIKUEFGnVa8CEBxu2RePK4Gy5gOD4NC798ba4y+dvv39e0drDUKgSKz++28d\/PhDb2svOKglDdJEcJgimS3XKlfa1cuUlZXqzniS7Z7epeNJeG6tIPYpa7KoNuy6miHmpEyYs5NkTf2YP5WhRwSFPY9FX9Ma5kWvGGvPUi27thdb3OahaC5sNg8bICIQIUiZweDHjSvGkRfqS1vWUKmzvAXANJ391OXZY2dGf\/N\/\/4lo1cFh0D4E0QEZQrECA6N0UIetI14olOdG+ZAtDne\/8xUpPnfOP2y\/986m0252Dg7Ia4EIYneFSrZ7AwUtDsLwMdq6iUqm9PAUlqDALcKxY7C\/B4cHiMmbTobSQhK7s9Cp\/8QuN1DvevcIMqT2nF6G+gm4H+rufOjMCPt8M9ibcRNbrEkBSUQYqTgSwbFwbMzhXiPc3ZHbG1GrDkGLooCiSO9ACLGqA7KIgH6HNLLUgIscSKFSJHxASx+S4vYyv3QaVYeaAVnuvR8vP\/7CyYsvnXpzbZ2QEUVRrVY7OtSa6QRtHMsJtJuWg3IAOUVB1AncwTLaDkUWMAZSe2Ew\/+ND0jQxG0UfqFYXFyNz2+96xTMhEXo+SDnfbWYfzqZAdck3khgyYpj6RRCzSoCEaZHOSOPlB0igg\/i4brQUhyoWMFJkBJ8iNLH1pmFkNgVCRlwE22GwgwQMuAOM26595aUTD5YPd5c2QQbALWjXgHEYGgdmQ73GSgVndqw0MQKeV792R\/LizY2ZtWqndWtNerWxk0MDU5XWUlWZW71+hbRnwDiMqH0IUqAMUognQmLIQteB+eN6BRqzQTJcTbSvqQ+Leh0MidUEHy4ZpYTvjQa1nVUWWz3D\/ofIB3vmgtnIy7wkADNMDMr3dSgx0apO\/fqPbg9PDahI3v2jd7zbS9SuglfHyKPIBxVhLMOnWNnYtcqzXQvzn2QsTuY\/9HYo0XD4mA1E4s4Sv3BCiZD8llfl139y\/9xLZ67\/6QetPd\/E+iYUYCUxq9s0j5MFyEBJRayx17z88vnC6JAXtE3ODGmfkf4GelKNspqTnNIIs3RO7MdBo65rPuTZ34iZfixmQgXpI3Q8afgBpQHQWYFqSjpK+qExiTzxTCCjkdnhxn4r9EKQkcZvo5SkFKY\/K6KWy+gnm9vAHGAMkZ1+7Nj8lenf\/413ZRCxyQk63IdimYoD2G5a5Nlzo87xGX\/joHbjnooEIALzrMJQZ3stPNyAqH1wbXPwxNTIhfna7QUpM7hxopwBL6YGpy84MgBE28EL52h1gw4P9V6f2LkMDY2IEospdOEgc3znLAYGsJsxh1147VQ9RQTA0Z3L9zp7y87euQV2YzAw+yUQuotbTPbDuJJBUrSzvH\/z9YUPvnPtYHGZmnvgHUHYRuGh0oV4nPYKCkkhEMaDp3gIq2JuHGVYShnzGkFG+xLz56SiWgOPT0AgKVT1vfapF06Xh8qbt7ZAaVmz8dchZamYGRCQZhxw1ykVrn726saNlcZWFZREJZI0sUxqpG4sMZNKi8lYJX6akSX93uSfmHyUhgBnwLgmIBEYMP3XWCz+Tj4biz3xacp3+p9M\/475a2T+AqPkN7H7W8L0G2OUpik6aBfBLlQmR5\/7y5+89u2bW7eXIdSWeQFKolJJ\/h6amJP4xzfkyIJTKv3Ur7x4uO+\/8901QokWACgol61ObfjYwPDZGW+32llYjqqHJExqHZJypobC+8vk1SHySIRB9QhlOHbmWHBUk0LGhXpme0JEu4DCjx9QrWVn6Lhw9hysrlLtUNeu8WMGKf8g08vMNsEzTcf4uO\/xCvZspIm4N1ONIACClZ2uY16XC32UqXlWysOaN\/mrPWEmE8SkZ\/tAJEVQa1URgJSM3TdRYvTW\/aikbqa8CiVRHWTmZbq9xAxhSTML47oNlIngBVLgCbq\/wq6cp13RqXmLP1h8\/meu3vvB4uHaFsgQMAIQmZ0049EFIiVRcZICIn9\/aXO\/3jn9qatb1x5IGcdrSQlKUGqlyyWD0UfW9tnuP\/YMPPKj4O5bet7pmc8+w774xbwy52FlPqYPUGzYNaRGckrolk6\/cMkeKa\/d2TQ6FZl0ZTIaLmO\/Stg0DLiFlnXuhfODZyb\/6J+\/K5HB1ARJHy1ZGEB3bDzY2Kvfvi8D33R19E7EbGY5tgi82oHOI9FforPTUp3W9KXTh8ubrXrTZI0CoRbxEJCUGGtWzc5YKOK5M7S2TvU6xC2cRE\/RrfAkyAKzsZc5kZ1M9GRRPez6lNzTORZm+xvqH4IT6XOf+ajCNdPcTk9DvSAlKF29aBhJiDLKohaywHB4uJI\/31PIlHyZFAaEHl6fAmp08MQ0kNXe65x4ZHby+OjytU0VhSZkM44fzpzjZtysfb1oO3T1HBTsS8+dDRt+dXmXEmp6st+bmi3\/yxwmDE0vN8nfMn8Bufl9NPWepfmWce\/X\/NKzmvQzIEfO0XxU9gvpT24Bt+JPwpKPQmZlP7P+WnGOKgf9nXAr\/k5s4DZwB6wCOCUsVuYeOf3yX\/3U\/Vs79xfr6ugQQtPQz55C8XGqrRIcmYW2C265PDb+6q99bPHO4d2lNoyWaXIUR1weNNXWVufuUnhUoyiAhEWkdYKMl6dHmIqCgwNjtoxRGsIPw1Zn6sy8kirseBkJJyIgWC4ogRrfDAjFIp44STu7+h6oKx3MXsfz3u54VGCeB8j3xvr4aLoa0zltf\/ovcWSzvhP2zhq6gymwfxsGe26nXcjm7sWhNwwJCogUMImxuibXh4QcrLKPKJ2S2GaEZBBHSbpsRqOQbm2xdUj\/hmLQ6dD9ZX7hbLum3v76nc\/+2nOzF2fX3m8Tj3SWlRk\/JFIGjMH1lstKA85zV2TBufeb3x31XnrhL72sovDBD24KzzMIIyVif3DPrZlyBHnqgZRm0rXzQsJsgdE1ssUU1Is5tFl+18KHzapyv530wExv06S4GaMZcActlxUKM1dOfepvvFrfqb\/7G9+QPmGxDJ0GQQCMp99tJuc43hFssIu8NPTE5x9zKsXbd3fKv3DVHinWvnNXfLAiFhfJO4IoQQoYnIwp5JQYPjFVW1jW4mxMnJlAAMxvtTfuLM+cPV5wsLq5K3VnzjgqELhNRIgKbJsdn6eDfaoeIGj+b6+YIm1dZlV+0LUC6b+gp4nd2OReV6YFfRn48dWm58sCfgSxJquf6VqFMco0LhwloEJiqSc9noenVmXK3aMzUI6uyXNSX8U1dCIJ65IJGZwUACDKiIBBq6XuLcOli+trRws3tp\/\/5WcP1g7auxGoiEBhtjrRxw5yYAyL5cqnnwHOm3\/6GqH15r\/7sfLDF3\/t8zMXTtz8+jv1rarw2iQioDiPBXLM8zztP5dXkRFkdlU0WTkbdnVbcnpUo1PL8mfR9I0pl9ubnz\/mPqmJcU7McowB4+bGyCzLLVTGBs+\/eP6JP\/fCzoO97\/+zb7R3qyAC4BYWB1AJkmGco0I6dDXOWLWAOWQV0ClPnpz+2OcvfvOb60dSVUZc6fvq7eu0tgZBG7QGNeuciaEynIPyw85ePD3SJpI4uoVIRp7cvL04c+HE1KWh3cV1KRSRQBkBQ+A2AIBl4ekTan2Vaoc6iQTj5mfXaZPSsjMdeTIZIIB95uaZN5HoI8cLlFe1IeLwM9Btisso5XvOWOqyp2bvL9ini0O5bg0m7fWkeQ7pPh5Pjql76A\/pgsAk0Rl6BQmQfHuYtiOTKTMY4TUwRowDd4C7YJdheJxfvTyI9s\/9rRdvfOPW+195W3XqJupVaSU+A9tBp8BcBwCKn3+JvKjznbcobAMpYNwuFo8\/deGlv\/zx0miltX20sbhb29hnJBljoOPblWIm7Y0kKb2Da04UAJIOw9GBoVqiGkdXKC03yb1hcXiZ6QODIiKlA0Q1\/06BUrprQ7GPH5ElSza+KWnFHyJDZvr6yYFDyfhZaaEStxAZAhZHB4+dmxo9NoKMvf2Vd299+4POwRFEHT2WQLsIg5MAyrIQAKNmC6IQVKTVTsBsslxwy4WxiS\/93VcrM8O\/9xsftqVi\/hHUq3L7EGrboCKQgYFuUDKFIUAE7hRHB0vTM4d3HpAyR2UaOq0ZTciBW8x2huZnhuZm1z+4L0MfRIiOQ8JHp4AXL9DCXaodauYqZuJys1CPRHSZ4OtjeWDXJIC61lbP8RirCnN9Gur6p9UPHJLrx+QWdjp\/oMx3RAj9Insw2wuA3qg+zHeRksEJ9lPKZVQn2Ns6oO49gLKyLOoSn2s3OkQADNCHVl3dX2k8\/fSbP157\/otXdxa2N68FZCiDCEDALVasTH3q2ZEXrgZBdPDOzeaP3ie\/ZTIiESMZLr9+Y29hY\/bK6WOXj42fmznx5KlCwSkMlTr7zUBKAWQX7OLIQLTXFFIqJXXAC0uvrcbNpIAE4uDkoApV1PSVksoIwLTPHLXXQ1DM3Sg4UC5Ghy0TFaRfBGVWFzBmjQ34hy0II33N5pkZSEyzRYtzPjXU2W9CJFhMbdCqX6kAGNoWtyYHg4OG3wqP1vbv\/ujOxq21o8195Xcg8kFf3vRuIsT0S49f+NknZShv\/D9\/Wr+3AoJMZKfloF1Ep3DxhdMzp0b+4B\/\/pH0gyKvK\/U0IGsA5kADRgawRKX1qGaiwND7oV\/dJRQbazWxtR4qdEyaPSElV29wPQyo\/frm9sCq9iCxEZeP8KXqwSq1WWo9QkprU5YWnLFsCU\/wZPbyKT2ZSub4OPtRuRHnuKPbqQrG\/Kzi52mHm6KW+oETKlpI98T7pBBPhYQapzM6U2hep7wUVu41Xugjq8h\/rF16ZIlshYASSQeTBYVXdeXB\/5Mm5hnzsF5463DzwDhSRAuETKUBuDw\/O\/vSLhfFxX4rqN14jr40iIJ1HiwBKkhKt3XDxsL74+i27XHEK9uCZqdnPPnn3X3+foggQhs\/Pnvm55z785z8U7ToEHZBRrB8infdEaGkgJ7OtF3\/tMwcrjYUf3FFhGyLf5PvEu6IWDREi2tbQpfmx564u\/+6PVNAGKdDESykAAsu2BioX\/+rHl7\/8Zmt9z8C2uyQBjKPt2iMjl\/\/WK4u\/\/UZ780CfQiYzQx+knDsD5WO\/9onNf\/eTztZh1GyB3yIZkIx0GjsoCUrHtSuGYv7Fs0OXTyhF40+ea9xbJcYRlA7SwUJ5+uKJ5770+Btfu71dC6hRhcMtiNoQ+eBHUBmDoKmBIwiZnDZkgIxZfOT4zNqP3wUVYIruTtpglqGqI0fOiaCzd8AlFc+dc47NOuODzYWVzvW71G7HeRWUhW72MekhZBGsaThF38tftvykj1S\/UK\/9N\/UTYs+nxT4tgawngzBTafYuYMzpPhLjE3Udj73feuoxwJxqv8u78dABZrYvlauvDQLHMBoBEJQEiFAEFHVgZyt6x3p3wP30J+ce\/Zmn3vny20oRkQIZAoAKQ++oVZwYszxPtTsgIxBRPBg0\/DLSiEvuhFEQcs5G3I7Xae\/vkwKw3EJHyihqH+yLRtxFJMIkx4oxk9NkuaxYQaFku9Pe31WBBh8ap5V5JfQ8kHGwHHduLPL8zv6e8pqgpBlCaoCK5VjBqIgiv17r7O\/p+WcqrzFf1wLbtZWUYRjUa+39PRAhKAkmDpgAECxHiEgK6TU74dERhS2IfJBam5ajBpOSFPmdgxoBUST8g4Zm52h9DDql8vjYi7\/49P5u+8P3tmV9H\/ZWQHogQlN\/ejUoDEL7ADJxsYk4zh2otDd3RKdj+G6ZdFddRqAKARlyV\/eBidsissK2PPEzL7ujg4cz46vvXEfUehroZQNlNdbUw9rRSbm5ZJEufsifoS7D3jB1zJajXTBRwt7xVR+9cELhfogJOIHBm4ZJ11USM2bTrEcm87ew58qXlgapb7ELOpX9KOzC5mBu7gcKTI5iCFEHggasr9XfHbo+7n7sk5cOHtQevH7HjCsAokZ75be+1nnpkdbieuvBOpn8vRg6qIExSoGUxCXwCC2HkXIISCmSEpmFJFEI8BsQtCDyzemReEz1cJxzAAIq24AYBeS3INT83ywdHEyX0nKAMSSiMKSgHS\/sDKhbSdB0MBmB0EWjzGuNkZgFJCAs21Jh6IFZ8xnyHzJQRaCyi8CkgLCDYRtESDKlbppKDQlIURQufeXHou0FTX\/37buEzGgGrSIrFJ\/46Ucqc8N\/\/NsfhJ0m7K5A1ALhmy4oEXgNGJoEuwxRK8GC6a0CmGUPVNrVGpnNKAeX17reGI+giCSijYhYKtoTIyoQTCrmBQikTPBG\/MhhP4Ag9bUtYLfZrNuf23VLJOjmp0HfFWvwFt1sPsLeW1ffWQh2qa96v3NKIlJyiJQu\/37OupMhBHSXoqlQLp389WiQkfIFKuXl6Zid72j2lkIQAYgAmE\/37i0rNle8+tIvP7G3tN3c8IgkyAgUeSvrq0vLQJJEBFK3BLLptrHZXQ9aEEEpTojASEbEQiUCEpGOFtImSTJjjPh7YgzIAi5ARUgKRQAyBClAivgxVYmBj7RKhgikVCICRaCUKQ61a0yXZ3q1KBWLgaJUjG6CZRRwC0iSDq4QEURhTFvU11ALmAVKcSIQAYkAhDBWibiiM2Rr\/fNL4e3sLfzON4FxYhYAQ8sBuwRO4eQL5898\/PxPvrd6tLRJ60sgPJAhmJDteHzUqsLgNBz5QCKm5SMgQ87Y9Hj7ziJlIuAJTFspxYvoUsIp8pFRPjWhRkaD5bW1f\/77hfmJ5od3KN6niJKsqC5MC2HXksmMCh+O8HrICuy1wVD\/VWL1zN\/6fpWHjea7bBXU07ylrKUns2wy\/iZEyBOJKXvaYu\/ph10TesoxF3IflROgGFpM3hita0IlQATAXAg6Ynnp3a9alV++\/NyvvPijX\/9+cIQGFy8iczAqAUqmga3Z+D09AtE8OClVEtAnBWj2kZKgyIy5tGVb31YRgZg5vmSklFQJYocUSAkkkumdueyapB2BiT9eLzNQoPkRSoIUKma8m1BkSsKSEDkH4rqSlHpDUQSkUBoYKSED4DpVkCmJ8ZEVQ8ApA2aPX2wlIQpIa2I4kOWSXWDFobHTUx\/\/lRduLR4tf+tt2lyFoAlREG8KyixpRJAByg6NzkB1C0DGfArk5QKfGJHvBcnENr4rck0fMnI823JGRipXzgf1tr+9Gy0sg1JiS3Vu69RaH2VEht\/Xl5LUXT32mVH3DN8A+yDL+yxXeug5ZRmHTF7e1I2ceWilS93phpmeTX4+0fUj54w+2bUdVyBdXVeMBzSImYsf9TZpMHMjNXUCpglnmJMLmfpfKQBEJUkDbJqivcjf+Kr1mV99+slfePrd339XNIhUBBpHq5SpnbrepKxfSNdg3MY82izl9sYemfiyB8BYnOFO5nqZvAtaVKVUBlzLzNpWAklypttjMgn91FWZPgB1SChmGIfx9s9AMeDm7BakQb3x5dYk\/mVmPECYxqEmOLl83Bsl2XJozFjcRrswODny03\/9xeaRf\/t3fyw318BvQqRbU7EgJo2OIWoewugc2CUQHQAEzgHRrrj+wooyb6pRuiLjpmRFjrZdmZuqHJ\/xdqqND25FjWYK7dHzQKWQJJnhh8qoQQgpJ3noiXtIiE7ULXboZ7CGLhZwcvfp\/SgTa01Wd6HZfx7fg9x6GJQNHy6Xy6\/qLo1GPJ\/OzfcwjXqPsVyZYWPSgKFuPV3mJMQ4aTb30qQlcqw5VZT4JyybartHN+x3fzD96VcvhHX\/wz95V0Y+cGGe5jjtFru3QY0GdsAugFMizpWe2sWMDJ60JnUXXmXKKnO4mPGJQbulTugM9N64us0tFEHpcCggiZBRkMSiGYbxga+PMA0dznbJCUCRkjpKlDKC9VhpiCYnFZkRi+t3Ju439+Q0GXGfA1YR7GJhaOBjf\/Fxe8j54f\/67fbyBghfOy1AGdthBhYQQ1\/bdZiYh90Hpv9EipXccOfQEPf0bwLXyxwtXjhxzB4oYatdfe9m1GyRUaKp9Naj17leh6RSCzw9xJOeYSBkXq6HlKPYNQDsrVO7MrCzvlETEtqDtuz9\/Ji948FD8KYI\/ZuXfdnqaWkYgzep64jDHtlqYheMXyhEfR3PLM6ssy65sHVlQXdPV\/U6NFIPAlDALdU4XHlj5cOK9dQXLzcPG4s\/upXMZ5BUzH9VueoBEdBCu8SHxgYvzFfOTLX36iR9IAXEzEOsL3KZpiJk\/PLJpIszYMgyVW4qo828bAZtpPShqp+teA6TfBRLP223Fw4NwU9X0ZnvitK5PqGpH5AxcEpoF0CEpAQCIah8OmqCouP6AAR3wB4ceubnn5y6MPHNX\/\/hwf0NitompsaIQjXkPwMm0vtO6EGnAeVRCH1gnDvMGhvvLG0DIqCNBt2rrKLtTo\/zSll4fuvGPQp8IH2MK+h9x5PLJOXAu13zCezW21N2++5PqegdrvftpjwEJJpNZaK+q5B6NPZ9vizif4kXOMfgwJyZI+6cYGbqh5TxkuqnABNDTRLeZHw33MCzzbYd80IpqQNjlChBwrrNE7AUKQUgARUAgbBQeGp15f1vkWPD83\/pmaAdrX+wYlKLdFmoRPzKZhhQjKHlHHv12WO\/+HEvlA\/+j\/9AUpq1wOzYyaL61S4EacK7dsLqIlMbmlVX5ZOOeoz8RUHO8ZyehAryAKIMey12JRIQMaScgC472SFVGCkVRwYnrp719lsi9FFGhAqBgWGiIxqbL0PkxCzgLjhlq1x56guPXXr5zPf+9Y83371DQQPCDqg4FY+6aAJEKWROQvsQZi9CswZKOsenoDAEvAQQGUhpueCMDhbGB\/3d\/dbNeyoMTPpSQhw21+nsAkuUMZDP\/KE+sukeYsVHSG372eupe8PvPYkycjer63DIfa6ka0Lw0Wu1z6mI+LAPwT6\/n3HlGO82ZsZ9iXqY5fwBmBgCLF2lpJuxUnFStIrjFvRxQaBUbFPUs3JMEK5maSGADCBsAzKxLt7+TsGx3S\/+rVe+9k\/56rVFUBEoZRpmSmjaZa5BizhweobZjsNV+dRc\/cO7BAjIMcl7oR6ZRU7+brYbTCAM+VZ3vhBJDISpxpx6L6tEvc9P5lpM8ddkuS60kYiQXXSu\/NWfGpqfefRXx6Mg2PjqPhmQh0LgMUhMW42spBpnbuHJn7769Ocvff933nzwxl0KmxA0tNsQlSClEICIIbNIz\/1ylBsCAGjWYOokto7c2WPe5iENzqLftBwxeukEMFZfXD9cWafIo0TqnYa0ZCKHu11IBPleJuZ1Hd1NToKHX71yMtE\/Y0zf52hL3V5Wz8ruHayZoQL1dlER6KG6nC6ffmb0gNmyNjueT3LXMWNDYaTb92hsNWAMNXZq5+E2tx1mcWSxK1opGYYqiuJ7jjTdSBVpv1+Sb9zd6dIwfBHXLMiieu3t+5F92nr1v3vhq\/+nt30zNEe0wK77NgADQIr8nR+9Vzw2FjY6R2\/dJr1iiYCIhAIZGX5pLAPtDSrAuALMtrCo9+03vUFmjllmAUaAKm6LZK3buZFSXhxCMU81NpvHSYXpoNAtFMZHCFDatlUumMEdIgCjrE2WMeAW2AVwB6zS4KOfe\/SJLzzyk\/\/49p0fXFNeDcIWCD\/Oe4sR5gBxSZtAa7i5+FlFQMuenD714qXBycr1\/bvW\/JA7W8C9ncbKZrBfpdAHGVFsQEUigpiBkiJAKF9wUOYOkghGCPHhSwuzML3eg4qw6+aH6RGa32kzG33cC02+iPXRCBmCbAsDu0b92HspTSxF+YWdWclJnkaX87fLpx\/nFSeiJJ6Y2RzkDlqOVS6Nn50dOzM9fHyiPFRhjiWFFJFEzizLYkHYrrWP1vb3HuwerOxKP9DJuHFXwOzHOVuD6YuYCRgyRlYBRMu7OPbaB5vBCLz6N1\/+\/m\/wtetLhAygHeNvMbZIIRKRjA7euta4v0oSwloLRASAwG2pZKQ0wkSfXSw2amDPC4sqMSFnFfNJrUNxA5ZZuoYGywFmAwbUcxXPVFUYd6gQ05aDVqQyru9yestLJzgKSEXN9tJ\/fmPqY1fae4e7r11DreTUZTASmfGAFa\/Ail0Zfuyzjz7\/84+99uV3bnzrXdnSwATfjHaUIspfUDGJqSJgNjCbuAO2y4oDLz498+m\/\/FRENDQ28Mb3FoP7S3J9hcKmTlbErNswvv\/3o1bH5r2cRYmyKbX40Udcn5Mu5yTErPXuITrp\/GmHmVv+R4CeMDca6cZkdLU5u0vLPuqZfj9tTysWk3Z4vAKNCc0BywW7iHaRu4Xx09PHnjg7eHyyUHTb1dbB4s767j2v0QlanowEt1mhUqiMDg7Ojs6cmz39zAXPC3fub6+9\/6C+uq0CT4\/mSXLtcDCILozXkp4KoASlUAo62FV\/8p12I3yrPFz60qUv\/I2X\/\/S3nKV37sTyeIYSiUQqclcCAhlu+5QqyDiQsAoWc13uuNILTGhFHugSk3IQACQRJQkZmN2LKYPG0HU4gsXRconbwDgoFvdvcoSG5DPnYxIwCWnhWvAd73oYO81JCfI6q19\/ff07b1EUKKFAKjPhwFiawyzkDtgFckpOZeCxV69+7M8\/8drvv3\/z2x\/I1hEETYh8UiKOBFbxKIO61VFmOq8QlJannzg3WijbFYDjo8UfPtgRh3sgApAi9u9LNBCG7IWYsoOHPo3KvDQMoW8k2cMFLvgRg4mH\/sHDxvt6rVi9yhvIWwIx\/X4x07aN5dXpYJC66RM5OXU+5Af7NT\/zTBpATnG1CZaLTomXBibOzZ976cr4qZmte1vXvvx6c2NfhBHJCKQgzdsiw9Pa1a4Wp+BUKmPnjp392Pn5\/\/bVjesrq6\/frq\/uqqBjjkRj5weTbJF0dglMPH19n96vg1P2RsLvf7X8yheOf+KvPc9stfTGXcksCD1CBImghLFbpbBbQGDEGDAsDJfnf+5j7tnjkx9\/YvNrP0n7L+mLEvd1TQdB+yrjDrC5epIG1WDcmuJFd\/D07ODUiDtc9tq17LQAs6swZ\/BNrt66+ckRuenJIwLnyK2kVgcgVFKjXKSPueIq3Qs4cgfsIhQGC0NDT37+kSc\/\/8hrX373va+\/Kzv6DAxIRkjm2pbcyjAH7MeUahPnN0ohrr+2NHZyzEW8+fqqCtooA1IRxqqXzNNEsUKf8h68Prhl7Eqk7s+DgS5KWfegLZ\/3mR1V4Z91N8y3UTFdhP0VNRkOXrrTpEq0rMGKsqg9QuoS13QLR\/MXkzgjJ7b766ugOQAdsAvoFEoT44987pnjT5xd+NGdd37vjeCoRpFP2kwUm18yibg6+J4r4fl+a\/OouvXezcrU+OUvPfux\/\/6Ld797c+WH16JmEyIfzBLiwKz4XVPaggxuERp7wDjYRQCAetVjxe\/+fvDsT5\/45K+9XBos3f7ebdGsmxmJZJQYapLATdRtGOUMlgvHptBxh6+c2frGa7pVixl7pFY5YxwbJlWcOaGxTvEYBs3fRH1uj189fvEvfcp2Hf9Lz9\/5F3+gDBwtjVhLQhApn3VHhkDFkXFinAAiAuIcuAMsAIz0CNy0gpUAkPGrylKZBOPALWQ22EVwy8Wx8U\/90jPnXzjx7d9+49a33lN+XcekGddfugIhE19FmSxR1FFN5rlRkoL29e9fe3BtBRlrHbVU5wgiH1SUefX6NBzxYe196IdV\/ujeCXatXugKi8zQRTF7V+hrGvyISfzDylHTNaCHfoeUP5i72zndX64nELjHu5F7PoBZwGywXHBKrFiZOH\/82b\/y6er97T\/9n\/+guVvVhFnSEyeSqFTahTc3YIM2I6Gbflwxq7nWfvtf7g4en7n8516ae+xn3\/u3329t7RGzjIuUmPawgYrAdqlQhtoWaDyJDCFEUAhRGAUTb38fOoAv\/5Xnx6dHfvzlt8I6Qsi1sQCVICW1ntv8qIoAVWtt9\/5vfXPo8unNP\/y2CjxMki0S9o5Zb4ZlJgAlmcDGxG4fG3NjAQNRaXLELbiEOHTxOC8VVKeRy2GLzec95q\/Y3KzHCcxCxiVZUKyAXSQtowXjGI4zqTCjuY2BMeaOUEKnWJoYefXXPj53cvyrv\/7a\/TdvqaCptX7JtQ0z01pKS45sEYSpyJcUyQjCpiLR9BtACmRg9L3aZxhT7BNNfspszBTg0I1jwgQZbYYk1HfI0NVMpi5hZ08oPX3EJ+g7VEz3RCRIQU99z0zMVyDYLUnB7MgPMx30nnkEpWjojNEeYt1zPGUyIkB9BtpFvQLPvvToc7\/48evfuHbnm+94B1UIOiA8MPrmKKb9CEy1XclsTcbpn0L\/k2QU1Fr7d7fsSunKn3uxXe20awEiNz+Akqh8sF1wK9A+ApIpHZAAVAQqABHQi5cOzp9q3K8\/9\/zs6LHRndVa5BtvXmbwS9nBJwnZXto4fPtGuH8AIoyFbxmkBWPIOFo22AUslE8+f6l52N5f2kUpYidHmm1kylTLUYRjl04SyQdf\/nHt1oM4\/Vsll0ZWKI6\/dLV2bSWqNXQvKn5PmElQ4gWrXDnzX3167LHzA9PjtcWtqN4wvg2jGoxDb5J5LLPAcsBy0S6CU8HSyPSF45\/9O5+kkvOtf\/nj9Rsr5DcwbBt7hOZHapt8HtgJGSUhdqMWU3EsqMQCEsTUmZzOIaOgSspN7HLJUdYCkNmKHtaNhI\/Kr4beJYi9RWzfSR51Oc7Nf3MszPakTmtelwAAV\/5JREFU82I6osuWxXHR2PPzYI6PEm+XeeEMYnbp6mFgip\/IQso4cAecArhlVqpc+uwzl155\/O0vv7723oLstCDyQAQo4uWnxbhmycUTgyTpmghNvLiKuegKgEQoj5arIsRHfv6ZwFONnRopQCSUAbglcCrk1YEglmhxQAZWwQxIbBeLZQh49cbe+odrV14+ee6ZU42DoFH1475C79YIWpZNoWZyGrhlTLXPCE0sB5yiPTZ65pOPBQL3bm2o0AMZJr6BjD0EASCstXbfvr35vferH96jwIs5cXHKAndYoTT+wuXajZWo1kDzp+nsB5gFdqE0N3Pmr\/yUWy4VJoeaKzvNxRWzZ6V7teGdGjycVYDCALgVdMq8VL78yuWf\/tXnd4X1gy+\/f\/DebRU0IWhC5KVbJCkEBd0rMJnvYzbfDmNQKiRlqoo302QcRLn6MMt8wVywd\/oYd3NhehZVjmqBea\/8Q\/srfWVm2LUssidoz0De\/AtHd7a\/rbfbzpTPKce+izD3reTNQ5hZjJgKsgEzrFu90dpgu+CUsTh44aeeOfPS1bd\/98fbt+6T34rfWoFKYjY8Nf78lAR3UhePk3K1OhEpqm\/Vgrp\/9rOP+fVWe79BVhFtG6wCeHUEhlYBzK8iAAMZQtiGsA0ygr0aLWxSu90KcfPG5szpsaufuaCAH+60pMxkhkK++0DxXpCJ0shEO6A26bJi+fIvfWr2lavlU1PBYbO+sALCLC3s9ZgpGTVb4VGNQl9DU+JsYwTkYLu8ODD14uXajeXwqGGMsynVgiHjyB1eKk89fdEZGujUWzvfedfb2gEl4m54wg7mwCxiNnIX3ApWxnFoamBi5JkvPfrUF67cv7b9gy9fb1cbtLdmbPIy1OWJAQp2hR8CpiMoyBKHORoson4SspRkhMzdOEYw625WJn0oQ9fM2ta6DDf4EEtQP+98XpP8UbDPPi7gfLxq\/7ZLqh3NOuUf4uzoVuY8XKSGvX+p5+ePg2\/THwwpoXpaLrql2SfOnv\/EY+\/+hzd2765Q0MLQ048RkSSD09bPbnyQ5iqKDMMjG8pIBCRQEoUKSG68fk0xOvczz3U81hg9A0rQ69+EwrDZa8MWRG2QEpT2BzHgDkQ+Uo0iD\/xDiqYO\/PFv\/PpPHvvsped\/4bGp85PvfuXa0dquYjaEHRR6miwA4l2cVPp9UJaclgoVOLdGzswS46zIhi\/N4Z\/kLig5NYxK1OSpTCQWoiEgQ2axQskpFJhjQwx1yvC0AEiBDP396q1\/+dWJx08fLawfXbsLSsUPMcPE18s4MQe4TVYBnQovDx1\/4vQrP3OODznf\/70P7r++KMMQZADIUYQkwsyZnILf48YFppCODI9cU8CJcWCctBwq15GCuEukzGxQKSIBJAFj2wdpR2\/cJU2JcakmJvMKInQjYbJGiq6XvFtl2EeClBG3dLdvHnYCxxkX+TthahTqWz1Tl30B+9nec3l4SYpmho2f3jSSg0uPiw3a2QW3XJ6bfuGvf+HWN26uv3eXgiZEHqrIuHVMTcyQW3pqz2wXbQetAloF5A5YLuMO6tkGMzxcs22ax4ESmmVrt10YGjz\/sy9sNgpKKFhfBL8FYRuCJsggZyBKzliSQAJAQejDQEki276+vr1UvfyxM1c+daHVFM1DXyo9wk664tinqDCLITkJGTKukLtjw5Vj40G9vfLVt5tLGzqdK+nlxPkQ2as1ZnJi4vsbt5A7488\/NvFTz1GpVH\/\/LoUBKJFJ8kheDxlU64c37nsbO6BJjYmuliEgJ70t2iV0SuiWS+NjT3z+0S\/+148eNsQ3\/p\/31j94oNp18JsQeGC72KmDDIEEKBXfBSCNtDCTEdOIwvQCovtwjr5tgu2CXdRdcbSLaLlguWi5aDmo\/47RTlkpbTlTasXVflJmaFksYrYB2NOr6ne09RkS9lefddnFU0UK5ArwfqdVt2IG8\/fKnuES9g+o7PJPUG87FvNyGMzdydPeNwdmg12wK5Wn\/\/JnVt9ZXn3jJmkYRBz+agCYjAOzGGOOU6wMDEzOjM7Ojo6ODFRKBQASgjp+cHBQX1\/bre7XOp4nokAJQVKkAAgTcx9S5C9\/+8OhycHzo4XbX\/8eBV5qXMgE9IJWhwEHgHgUgQAMNpZhZlbZ7ub1ta\/8o\/r5j51++ZeeeOTjZ976yo2dO+uqYxPGvgEUiIyUQCUBMVbLUDakk6SAwLv\/B9\/f\/MkNktTZPSBljpRYWZO4t\/Qi15JUNELZhPyvZ45SWgPFiPPi\/CRzXdVI4FqYggCUNO77rsaEDl1CBsxG7pBdAKdslSonnjn99M89Wjw29rWvLCx8eBjsVMlrg9+CqA1KgjUIrgthU3usUq18aj4EgjRUwzThkBstFHeA22hZwG3mOJbjugPFganh8mjJLlhEFLTD9n6zvVvzWy3p+0oIc\/NMMhT0xNjoCTXYVgExUx9kiQ55\/UpP\/kDfgTv16GLSINcul+x\/6SgkYcxkB9QPqVrxIzXk1KPKpowQpF8qV4YOmqSXEOPAbbScmUfPFoaHH\/z2j6Wnr\/gmI80knluu7ZYuXjrx5DPnr1w+NndsfHCoxAAiLwyCMJQSEQtFt1h0hZD1o\/bW5sG1m2vvvn1vaWFVhEGsNiQgBTKCsB3V4M5X33zk73xpcLJcazvA9QSfAYg0706\/1MTNMJNxkBwgBADY2oSJKXLczu7u9T852ru\/9\/SXnvjS331l4a3VD75+\/XBli0xaWEAyRImk7fPM3A\/TqS8hKAUilO1Ga6mNCKAUyoiUIsq38szjaxl0KjIQmhMRAUkTzASEJA5eey8Skbe2K2p1iuvDbmOlZguketTkmNWFSQEslzul6YvzT\/301akrs\/eubd763upRxNXeNngN8JsQeaYX2vB13GoiV8ipKjMtAGKcjBrRiDHAKqLtMscdOjYxffX45IUZt+RSO1CRFEopUojIbW4BoG1Jm7Wrjf27m9vXlr39KkUh8RCiADEgDA0QBBBAArA0ZML497Af2D3\/m0QPb+J0o+8zFSw9DATz0cNIxKGn8pQWTIvmh4VZ5OCD2PWd5FCHicAfMxK6bMiW3hQZJz0VtMvFyYlP\/L\/+qxtfv7759k3yGvEilACIlmMVKpcfOffzX3r2uRfO79X9B4s7yw92Nreqewf1Zq0V+KEUgiEWSsXh0YGp8aHj82PnzkyfOjvtuvaPf3Trq199d\/HeigraJEMghciIW2AVsVA+9vnnx8\/M3fidH4rGEWjTjVECyNgIk8YAojm3LWI2cAecIszMQcuDkLA04IxNXvn8o4+9MG+R\/OAbN++9ttjaO6TQM8EbMlb9G3YtpfdlRGQs7RtrH5Z2hGRHsloqbRV4ZWj40Yt2pXL4we3w4ACEBzKI3QEsDqvg5oxNGzOYMmaSkCaIhQGMITJiFjAbrQI6xZFjExc\/efHyx8\/XdtvvfWdx9d0l5TVpbgiEhI1tCAIIdax0BDICpwJhB0Q7HsGnxXes\/I7nHDweBdsu2gW7MjDz6MljT512hsrtg0b13nZtabe1dSC8QMUTHURAxpyBYuXY+NiZmdlLc9y169vVtbfu7t9dl74HkR+ja8zsStOBMQWNmpc1USf1eCa6F2GWKJUV41Ifnm\/vbZD6XgWzX4WAEIafwuysM\/EudTOukfr9Zxwlma5MyvZLc9AX6GqKxnIQFm+HRXQrJ15+8uLPvvy9f\/SHYa0KfhOEbx4dbluFyqc+9czf+ztfrLX8P\/z6h9\/97vXDw7qSoZIRaY92XDHo9iAyhpxxyx2fGH31s09+4dVHLc7\/t3\/yx2\/+5H0ZdrShARknqwBupTA19cLf\/8Ubv\/Pawe0H4B9B0DLcsZiul0vqTNxJjBNawGxwXDh+Eg6agBydCkzNVmZnn3x8+MIrp5r7retfv7n6\/nL74IiiwIRVSJFPO8mEqORGUJr9rHnvZnKntUTolMdefPLsf\/8LzLK2vvn22r\/7Jnk1iDwyvJbEfmmE6XE2BsZvWbze4sqQ0OTP6Ekgc4qDU2Onnj712BceiUJx\/TsL915bCtttCloQtEB4cGIaGIOVXYhCiNogI1ARoAWFEWhtmSIi3tu1\/i7+KnH9aRfQKVrlytSF42c\/8UhhpLz84zurr98NG02lP1saNpoIPTX3yQJuoe2WxobOfOLKzOOnDpZ2l757rba6pfy2mWPJgJJ1aKIBYkqiEVJSP+8v5H+z5+7X6w4n6AL+drmiMEe4BspFOCkC4FiYy00He7Fk+LB2bB4umHPkQvcizF0tE3NAqj8EboNdsCqDj\/2FTz74ycLh4hqEHY0GRCBEhpZz\/tLZf\/gP\/uLS2uHf\/4d\/+Obr19u1Qxl2KPJMOaRFFTIEGaIKSQYgQ5KRlKLV7ty4uf7G28tPP336lVcuv\/XmQqPeyEwLEJDLCJ2RgcG5sYNbK+YWF7fX030Lu9R\/8bulx8rtFszOQKsFUQQdL1Swfm1raaMzfHr8qY+dPPvC2TBifluJiAjjMyq5FJk+Icu2i3tkLvGQXcuJuDv23CNDj58nRABefesOeW0z38NML9CATCDORUqu3yYjSUvPyHLAKaFTBqfMiuXhuZlHPvv4y3\/1xdGzEze+t\/iT3\/rJ5vUl0ToCvw5BE8IORAEcHoFr4\/gQVA9BqXgqKAA5gAKKMt97krKou98OWC44RXRLlemJx\/7cC+c\/fmXhh\/eu\/cfX9m8tiVaNAj0Qzr2tKENUIcgIVUQyBBlSFITN1t6t1c33V8aOjT\/5518UAht7LSWy0BroilIi\/AhHLD2kjdkXf\/uQIX7iWqKHDhUzDhdEAI6FmXzHrhveCV2AsoeGh3aBHrKsl4wkLe5tQjzoiUUYLjrFifMnz3\/6qWu\/\/1rUNIUoggQiYhwt5\/NfePHqYyf\/P\/\/L11bXdlXYgqgDSld3ESqBJJEkKqWjxjEJGDUXEtby1cFR8AtfeHxlef\/uwkYm1geRMULLr3vnvvjU\/rWVqNUGyhGBMI7OwswFJ\/lN884qCX4HZqag0QLhQxTC6JB\/0FrdbN\/\/7j0VRc998ZErn7pYnh5u16MwYmRyyOLYs3SFMN2XTFuy8cygq6OoBA6em1Oh2Prj19sLy6CCTCcpSbdOa\/74q1jIbbAc4DZYDloOWS7aRSwMOoOj46dmnvnFZz\/2l54dOzn23tfvvPm7b62\/\/yBq6hK9DWEboo4ZAyoJjSaSwNlJqB6akbp+GIpDEDTjbyIOOdVVtL7HOkXmlsfOH3\/pVz\/TOei89Zs\/2Lu9JDs1iNoQdUD4KAPQeDsdGqHHwsY5IYEEKoHmei+FH+4tbu\/d2zn7+ceHr5yqLe8JP8qrSbNOwuQR71VMY49ZCPu3SfsNxLuWQy55AfNitQyyk9LuaFfaBfWueaI\/y4jU7\/6IfTulkHH4xo8aJ+6MXjq5v3XkH9VBhCgFkUld1s7RYrkYIQoVkvQNZJp6reP5gpkAlAROwDnabqlcKFjMcd00uhkASIIUIEJ\/vy6CYOj0VGdnl4xos\/tNoFxFoWtyCaDMw99pwd4WjI3Dzj40I1ayFbnyCKqre7Wl1YWfLJx49PiFT5699OKZ6srR7deXV96779frFAmUunmbmMRlwubIBifkbE1KtJc3bv+j32U2D\/erJALN0UCGQIxyvRDIDcRZKlJF5gC3LYuXxoYvfOzC2edOVqYHdtZrP\/r965u3t9q7e8pvgQhA6HMpw0eL9cN0cABhACfnYGUFyNIMOJACuIsqMILEbPebu+CUmFs6\/vylCz\/91J1vXl97+55oNyA0qXLJ+w6gNHojw1oyuqs49BcTXI1SUXUxeOP\/PLrws88\/9zc\/\/8G\/\/V59ZTNtapoIXpn4x7JDwjQxHFLyVk7DnQv2i\/uk2Ot8yPVsqLtj+lBbVTInxIfkhGZ4gdB3wgJ9a85cAyDdMmKAWgyPAYZJ8itzyxc\/\/\/z29fXDxRUjjkna7sxCt\/zMs4+89PELY5ODS\/e3m\/U2MQtYfPNhLAu\/MHcGbiO3kFtou3Zx8Mknzv3tX31lZmbohz++e\/vOSnzbpES9CcArJyYL44MH11d0s1vL4ghUToaYF5xjLk6EIAiBMxgbhUYdRIQjo2ADtNvU6QQtb3dpf+nt5epmfXBy5PIrZ0997NzI8QnHLQaRJSUDywVmmwkYj3+lAaNxMnbyi0D5gWy19XwvPv942pLRn8fS3X8XrQLY+lcJ3RJ3KoMzU+deOPfYl5545peeOfbI3N796rt\/9OEHX72292AnrFepUwNdcQg\/o4NJNIDS1OGdNsgQJqchVCBjCJVTAenFb0qS71sAp8QKleMvXj7\/2adv\/P7bG+\/eU55Re+uuFeoRvJF9q6RBHSc3GxoVxSQhAJUckiKIDhb33KHy2VefbGwc+o1OIldMezNZkBNlwjofOlzAHp3ZQzqsGTZCn1iWnHEhd1JZPb\/VNW\/ojmf+CKDTR8w5sqCUnsaq0THalQobKO3cWKaMZZPiaCREbjEetsNjsxP\/8P\/3X3\/7mx9+8N6DldXdZr0OMiTQ8JiEXQY6lAgYHx4pnzpz7PkXH\/mZVx\/dqwe1TiRjspgZ3GsapxKgor0PV0585lHGUTKeihHyfu1cmZEYuBAI42FmdR8cDpPjVG2CjMAZxLFBOjwgRGDMC6z7bzSWbuwNHZs4\/pmLc6dnLjx1Unpyc3FvfWH3cG2\/tnUYNNpAAqQifUqTyvjHVcYoEMdQm9j6ZECUqWMZR8YpzfG1i0Ol4emRydOTx85PTp+dRIdtbDWuPWhv3N88euuBahxC4IHfhKCJUYd0NIXucGg8D0DucAYCRXB0BJLY9DTtt6jTAulBoQJWCVVESUg915aL8twT5x750rNv\/9ZP9m8tU9iKr\/SGgJj+sJlbN2W84XFGfCxUVslQVwIp2cGFr7\/DAJ75lU+\/9k\/\/uLMjKKGZpMok\/ZkUwsNdgPSQZziLG+mbQoFEvSrRrux5yulprL6Z6R9BlSLoGUbkANvUpYbtHhV2R8tg0isvz45z1wmP6sY3nYueA1ISSR3tNP\/x\/\/LNV1459ZnPXP3Fn392aePo1rXlzY3dWr3TbodhKAiAM+Y41kDZHR0pnTgx\/ehjJycnBrYOmr\/3x++\/f2P\/H\/6Dz0nTljRBiGhUnZKUbG3sW65jDZRl6BugWzbCgrrK0pgBj4AkjUNHR3Tt7MDxkzg1Snt7QAwmChC1NCmMlAUAEnntkDWuL9\/8nY2hE1MXPn5xZmrwmUdm7AI\/2m\/v3NmqrVYbe63WYTNotCM\/kFE8qMjgEhMnVOoqMGpMMElqnFuOZRfdwmBpYLw8PDU0enJs5sL04HAx6IS19cN3vnZj+dp6q+GrUoU6dWgcAkkolMFyUNqgbFRC97dAScqkpmlossn3099Dq0lSwtRxtDjVA\/DqUBiEqKXVeMA1DL80dmb+sS89d\/0P3tm\/vUxhGyIPIh9kZFZ4nFWW6xJnpEKUsz4l5QmZ1x8RREcF7N63r1uDlYu\/9Ikbv\/n1sCa0zE2nL8e1C+X5K3+WKRf\/y6Z\/mMVIPOzA6la0WdkvQbmJH\/YVquJHTx+zWPQsXzdTXFO3Sk+3DVh5tEKRlJHMbYSJ+0xDuSRtbOz+0\/\/7xvBg8cojp1555fJLT58sf+qyU3ItzhkQRyDEiDAUMmh6fqNz6+72P\/9X3753d7XpiWPH5+McP8o8UikiUfqhXSoUxoaDajXfHqOsrp6yL2Xsy9VtHiRhRlpbW3DuFLQlbK\/j3CVyLAglaKY9+oAOTLriJx\/g0Mght9\/8vTeZF7guGxovzz1+\/NhTxy++fK7IkSnlNYKD7frO0lF9+8hrelEQhoGMQqkipaSM8+GJMWScc9tyHMt2mO3yQqU4PD8+e250fHrArrgSIGoHtb3m3Z\/c37y+1jhoBh1PRcLgkg6lMeypCOsKlM4gUlAow+AEdhomtExEIKIMNSXZIwmQKIhgZ5NNTQEfp9oRuIOEDFRgbChOsTg89PjPPbv23vLGe\/cp9DKuX90oZIRgBC4aspO5ZVFv\/y8R9yQxs0rH+3iqY9\/7xvvP\/90vzL\/yxPI331TaEqWtGBq1k0M5YVYR+FADU57z3FMtUr+hBnUJXrAXR2MWYR5PneFApr76zL8S9neF5GxdmROwt5tD2Idgj1bJEV6ghIQEBU2U2Ch1JRKClNITUXiw1\/7hd\/df\/8E7xaJbGhislIulou3anDOMJAWR7HSCZrPd6XT8gKTenDgH4YEiRA2MAMzOGEgBKRIRV7JQcuq5QzvbZDPi63S2SpmygBQhoB5shgEtrsCls7BxCF4EVy7AtUUAAhIgBc7M09o2Tk+ACOm9N0mCAiZsuxNUtkP88EcLDlGpwAcGnaGpwYmT4yefmB785ClusZBhBIyMNItUHLjL9C9CjsSAOBEJVT\/0DtaqD968X9+tt+pep9nxm20ZRKAi0rN1lZgtFZBOehFEEhUBSSKJfh1qW+ZuiRaUxqA0CJ0j7ByBIhJSx6QaMr8SEHhqcw2n5nD6BNWa4A5C2ADGwCowy778+SelgNvfvKYCL7326ydNUwUyDGQz7s9QlDDTP8mAC\/WtIlEjChQBQSussmu\/+YPn\/7vP1Jd3qjcXSWrQnkRQ3RAMpB5KIP2ZB95HVKxA\/VxL1N+mAXn4L+aFZ30ibjO3oj6XTchp0jJJND13Tuqm9wEAMJtTKGI7aZpQl+WQS\/3QG2p9GEUy8puN2iEgR8wjP\/R4mpQWQILtIrfMBYolrM401cXIYqREIRhnSf57EhgQB5tSShgxvOuErZP5URUQRhAiPFjDc6ep3sSL83RnUz92bH4GCiVwB2n\/kHa2QUUwMASujcjIa+DCgZBSILYBDgAQGeojzrXsgmuXC9x1LMfiNuOOhZzpzVIpICFlIEUQRUEo\/DDygtAPRRiRlKAnPYlNVndiE9MzmWCcpGzLtkMACFUEERAQeEfQsJBbwBk4FeRO7DhpQxjodQvAaH8XZ07h1Cw1OmCXgDEoDIyenpm9Mv\/Gb\/1E+G2DPyQFCKjja7iFlgtopdU1ZWez+eopvVkRAoESerhvKPcyAkAKrcbq9tpbi+c\/+8xbD7ak1DPGGLEHEg3KOa\/26n6eP2o1IuVaqN3nJvaVv1HP1RCsHBW+e4CC6SFIee1nFh7X3QzKxCCl6zGNScuNQzDzahIxzG1N+vSjxP1DVKq4o+Mj1cMmMAkqNK2LbIeLCLJua\/N1OCBHqzhzbMIuOcrELWR+grTQYIyxbrF8Xi2ISYOaqGdgarrhZhMHBh2ftg7g7Bk6bMBAERoSR0bpiUdg44iWNiH0sFwEXiEiONgh3wPGMoxCA3RSiBJZmAgbUutW4gaixBcDyWzDLDCZJkzoUlwpo0GnLC8QUnmX6T0mHSDKNkdARCT0l28CEVgFKI6AMwBWCZT2lzBQRDsbOHMSxichikBE3B248nPPr9\/eqa7uxXprAUSIDLnN3NL02fnTj58Znx3hnGHKyEmvh9TDINei7NALNu5v3X\/vfnNvn4QPKorLDZ8i+\/63Pnz5f\/jS3BPn19+4RiLQgnhEBcB0RM\/DHEf9opb6jdv6kiywyzCcP3QybZk+LorMKZUO76l3QIiGcYy9y6\/\/9DC7GvP1REatF\/kBc23kLPZ6YgamahBm07PDf\/tvvvrP\/sV3lpfWhS8BAKR+NZPGiTKVBtOmeNTYT8ctXrxy6m\/+9U8OjpSU7rt2v0IIyNCywLGjSOWTGyh7B+oVImV3qLhdI5EAlCAZwMEBFCvwsSd4oYgPtuhzz6nDFuxWcaAAZNPmOvgemvYdoVDU7XzFlFqQM7Yy6t5usvdblVl+SSiAZn9QJiRY5fqcqekhVVqm+QxE+cE3AiCIAFp7KY\/PLmJ5DJhDkujwEE+Nw6ufh44\/uLo6MjN07Q\/eARGiiEAJ02hlllMZfPbzL7z6Kx8PpOzUO5i+1Bl1e1qJxhkG8fbvlJznf+6ZlXvbX\/2\/\/nj73jJFhCQMrFEEUbO5+e7imY9f2Xz\/now8EH4WNA796U8P02B3mw8fut6oTy5vZgbfTTW1ehLRIC6\/MBPb2zUziQ\/x7vzPLqFAHuebr1PzOTUEpLx6Bwsus20V8Nh9n5vTcADRDs8eH\/sX\/\/Mv\/c5X3n3tJx\/s7hy024GSESiVAhGMu5wjd5njVkr2zMzoy594\/Be++Ey9I4JOlOn2QALY1WIUbjuBVJ1aE0GSQWfHL0RS\/GTzIzLjgvTEN7wwBUyAQlA27NWcnaPJv\/ozGEQHC7vB\/V2KOrC7TZ2m0UbqQCUNINPbG2RNmInCIQkIwG5xL6bvGWTSKbJTteygjJJVlyoBKI1AjH\/2ZNH1oXclYuhE1EkIUQfqATEb7DI4A2DZOD0NIpydxZX31hrrO6T5y5pPiQy5\/dgnHv35v\/Gp9390\/09\/76127QhklBRjlMB4MGtSj60QyACZ7RROPnbqs\/\/tKz\/3P\/7iv\/97v1nf2aGIUNfVMiIRrb52Z+6xk5Xp8fpyC5gFjIFKLYeZHgdl8EAPvRkiZtKxMi7l7kEi5SVqlMWgdTO6rT9LAfPwMxm7TlikDJLyoYNH7G0kKZ3H0t49lEpyx5GMU3KIZaaojKi+0\/h\/\/6NvvPjC8S\/93BM\/+\/NP1g7bK8v7t26vLy\/vNmrNMFKgiIGyHV4ZGThzevaxK8fPnZqojJbrgfi3f\/DuvXsH\/9M\/+BxPCRQx2jOe+DtDFemFYbVmOtqUArmSYCPM9IGxqzOcq26UqUhJgpIlbg8XS34R7Ttv+G9+AF4Vwjaq0KQCxjFo2PUmZpPh0mBLTNOMM7PctHmmW0fZ+KFMJl42IDUGj8XoMVN4Eub28+TJ79peifpgFGLhCQkiARur8K3vOKPDs3\/+wvXf+IDC2F2pP5RZlbHRl\/7ci3eurf\/hr3\/L63QobKMMYrsmxrB4hT3dQ\/NNMO5x9+aPm4EI\/uL\/+HOXX3n8rT\/4nhIhEQFJUhHK0K+1DjcPT3386rXVDWKcgHUJTnLnUGI1TGse6uI6YQaTgr0Nz3RKQV2WJepPXSQLs1\/8IXEvmA3RQOzfKO5iiuZdvvlhdxoDGhdOCkgF+0fg+aWZibDRABbXXZSaepRSUqmNzb1\/9W9u\/fEf\/eDMmWNXHz392CPHn3n6FNgWAEghkQgYA86kosAL97eqP3rz3q3bGwv3t\/aPvPn5WUbEkUH6TmAahMDY+MU52QmlH8bfVRIglEkSIurrMOtizZv\/IElKoPD8B6udhRVFFNy6BUGdRBBTYWJxlvkqWYwBdlUhmCZ950AGyaLNrMOu8oag2wWQg3RjOhSnbI8gzw3M1uPZGiWjWMi1DhQFbbh7s3zltFJn6xt7hnxhhFCIyGZPz8ycnPxP3\/i+1zjSED3TOMGUWgKZhInEiWCOemTAI0ly\/dZqY7fx6MuX3v\/q60HYNuAvRA0L3r27ef6zjzPHkQFPsW7pyZcloFJPS\/NhN788pAIePlDPLAXqct5CJp8wvXqlOnPql+P0UVbefkAZSgAjiBlfOMSRGGhiMUFJGcjmQWPmydO1hRU0h6GM73gERJJUoKQQ7dDvrK3W1la2f\/T99wcGiyOjQwNDlUrJKRY4AkgFHV81Wn7j6Kh+WOt4UjEHGAKzlOiIODE39gemlDdkfOLKfH1tnzTxNkn5yaqdiHpegMwAgzCjKwRSBIxAhRQ1g5WFtf\/1XyKSqNfT2HqSoFQ+sgtjtHn8CmGX\/j+9JlDP25mk6vb4brIxCFm9BgGlBOK0GM3w4buSQrD72chszV19RdLNs2BkuhLsNsKmn0xEEBQBB2RuweWI7YZHSmDkg4wAOXIbGQKz8hMLSre\/uPlESoIUxKLIjzqNoFR2GedxLaCITGZ4c6PKi44zUPDaHJBTL27ko+QylGvSdl8d+5rpqe+yoIe4Da2H6rAzM3Xq7rHinxGO1qUqSaYQ+spPGROi6QQY+d\/BvfWzn3n6nltQURsZJ4WZQSpKglCRSTxWEpQQkTrab9YOqjoaIc4iZ4QWAZA212hAk11CtJSIQkXSbKJJSWMCZ9xKcXRudPW712K\/X14zkNmMsfs1yhGek+a0SUqQ2s4XiYOOnumnyPAkyDpeWClpV7e+YkVO\/tKfqV1zTQRzL8wsqD63CcpM19K2Uz9wQ16XQnkKRO+MKvfBSClpsjI1uP3+GgmRxoPqL4mAANKU3VzvfWjhiafOn3j2\/9\/Zl\/Zacl3X7VX33nff0COH7iZFcWzRHERziCSSJiXZim0hUmw6spUJSAzbMAIEQRAHyE9IkA9BYiROgnxwEngI7NixTSuQZQ2WJTu0RHGmJJJqstndHHruft39pjtUrXyoaZ999qm6zwQ\/sJvv3aGqzjl7r7X2WvcKssbSqzkPq3a2YCayc23rtS\/+1eTSevXXSlRXbS5VIvJ86\/z6tfPXlg+sbZ\/NpIkZbuAusmv0nf1+FW30RQyFJtxKQ56Q0TJzY3ctl4hgO\/R\/owzhtUULarqiflbK+fG55LP1Y++uPPX4nsP7r2xdqf2n22VwbWN7Zc\/yDYcPXF5fFw5rUz2SMwo1sQIZNMPpkNJlJMuy0QdvvRnj0dX1K5LPpE1EGWAwlOHo4F0376xvr594n\/lMONdjoOEwGK0IlxoTCw1Lirp7Z+naBgpRVLAkahsIu88xLuebza9QJ5H53Xp\/awea\/HiQClukotu0U1SAlcPXNreMDQPCu6W0qkmFbDxeOXLde8+8wFoTX5lfMKuOS7KtiElIcctDd973kw8XxAyVILya0meLjGUik2tbJ\/\/qu5OLF6sgyqKCk5oPUDKfLObFzs6105dXPnjk8hsnQudCduvTyAbmcM\/KGjSOtdWa7Uws4uYSDhNnmuP+5oE30algXKV07ga1mKYFcSrynbkUk80z58+8\/NZdn\/zwi++eZj6SYgbWmsli\/vILr\/\/s333iF3\/50\/\/pV79w9szFIstkPqh8dfV8jYAoSm5QBmW8QTbIiruO3vTLv\/hj779z\/pUXX5N8CtaxXtmQg6XBeHz0Mx9959k3phsbUszQpi5LEJ9m07aD3Eal3FNkbRnLXhpjN\/uOGDGqc6NUK15o1AAwkesM4kWaYtYsbJ2wRr2GGQrT1Ux2c8eCesyrzGi2qBZGWVpdXrl+72Rro+qB2zTPOlCpkCKv7YYhzOXZ3\/raK3\/8nAzGIhlrfwqGdttSzIvp9vali2Rjss46H4C1+TSlKMqiZrK+efD2I6chAc4rqHBph3EnqOYPVRHhdI\/0hNUpMbbOPEQTEkrPWNR1oFJQAWJNju0Vkpoe7aYoQikKFLkUM86n7zz7+mP\/7Gd+8OXnN96fymBWdk0iheSzN77\/9n\/71T\/6lX\/5uV\/7d7\/wu08\/+\/\/+4tULF65Od3YknxT5VFrqrxSzDGWwJNnSyji78bo9P\/rpR3\/6qUc5nf3af\/j9C+cvsjRmLxXVwyUZjg7efnjPDfvPvvJW7VCSs5la0NPZqkoHxRA87aNYF2x1fViAMCvOJrOya94bQeCOmUxRAx2Nlt7REzIkhlqfFRi9Fc3cTKojattYSPgGCrPNxgPJkE9moTZAdaTlOVcKaEhKMd28Nt3exmCpMsiRQgWJ149ePpV8R4q5YFAKfQpSp4WzdQYppMhnm9s3HD0UnPNtiBOhcSYGY3wW+Q1IPtrGkpGrN0wQY50QyTaodKhYkZDO18atusCUCN1BYpO0idnlY99WqI03I0mUHXY+vXz8vVMvv\/WBTz547A+uFpURSyGSs5gX0+0\/\/\/oLZ89c+dnPf\/yf\/Pwnfv7nHj1x6tKbb519\/djp9947t355YzKd5bmMhoOVleG+A2sf+OCNd995891HD33gluu2JfviF5792p8+e+rk+7WcrfJ3k9HyaO+ee37qseNfeXHr\/AXOJ5LPWeRo1mFVr2nDH5oAV7sg9QwAbVIrXZanRXQa0FzZVDRokphQdOplAsSyDep6EQn9lKNrNA+RAYO9bQNKGlUfGhThbJYX87zprMEakNP4XTlQ1vTeRU7MGoCrERLXoyS55DMppiAlq4OQ85YXRVNjV0wjWRRltnctimxVp00ULsOuWcL9K+l8IcmxJhMXk8odHSI0UKFLFRIUN0upNSALuTI94hQfslamXhpSsJjLfJJvbx7\/0rd\/5Ff+3oWXj196bcJ8KlkhLPGM2Xyy8d1XX3vzrXee\/sPbH3zorvvvv\/VHHj\/6qc88XAyyyWSeT2eSc2k4GC8POcim0\/mV81dOnjz\/tW++9sJzb5x88\/h8Nm1WIJAxG8loGaOVmx+5e++R61\/4718uZo0LU16nyrCRtgUPLmPAgnHSJFqMu+H94QnbHTFfUGcyOZjdRHuHkomY4khMqmr5qw866O40OICBUNMPg+sXpVoV1cRjawrSWCJI7XTSQBPIhoPltdHeNWDAbCSCKsqiRKry2WxrY765wdZ5pCb2Gax8s21kwwELWhLGdgOEbe09ZAWhJsZlMsgwNxjuOEZ5VYedXH0zQ0ICqZ80bx6sQ01vwLT8jQypnK0sUMxZTGW+vfnu2Xe\/8fI9T33suXOXJ+dLbVqp+it9OOdbVycvPX\/lpRdfG42G+6\/bf8Oh6264Ye\/a3pXl8WiQZXmeT7Yn61e2z124cuHMhc2NSS7CMkqN85KaIDIOlmRpGUsrB247cu+n\/8Z3f\/8vty9frpJDqUPtibjDZlvXaaoWYR4xqDsmapNmGpLV8P6dkLMSW9HUhQmInEGVoxR4CAb16Iy+tDsHoxEi1UIawoLt2HsxnUNkOB4Cg6ppM1HwlRdxVr39YHD\/5z5x799+lMS8EtwLUc\/uFjz9+qnnf\/V3puvTanKy5kyKKu+mULqGMlshAzBeXSo2t0PZUMzjhZujfYSdQhQ+tsNYIeMLXiAiGEa3MLkWJSKKwnnnDggHxkgqmHdAbYhQ5MjngimnOz\/40rcfvuvI0c9+7I3f++Z8W2QGmRHFtGLVOC8wFexMZoNz29fOv\/+eoNxSA3FLRbir0c\/6LMtKs1CM18YH9j\/4+Scv\/uC99154jfOdxsKoKY0qQE5Xm9QYqRaJqPXAJvUAWgONdvTf4J\/enWe\/c0G8AzL6bHHlFFaPXr9O1beQDl3cqMnaM7QZem+mU0lyujXZXt8YroxLgYR678oHp6gTSyUbsCiEcu39y5ffPldQ5vNcgCzLKMjL+GIp1k+cyacz5QaTNU1pUWsq2vVdJ14s7Vu7dOq8VSOQ6ETEAqiTthNhE1dt1dvoCNw2l5tKMYM+\/VoAvlCH8hKMiMGI1KBq4DWM0LxyUcWV55DZ9nxz8Oqvf+nRf\/pTg6ce+97T38oFwpyzQjBvm3sUIvOmFmALz6lqpOmYTPTaaFnGa8O9ex\/5hz\/G6eyVP\/iLYrJVzdfkVRozGptK1gxeZxA56pQXzaw32hQ952kOTAefISXdYbQ6VX0YIsAYbBsSD5QFlTURo\/YB9BpmpEhIHurDo5kOKstDFsX2zvb7F9Y+cN36sVPNxGB1Whb5fDqdiGCUiWQyGJWoxYlnXjnxrVer64nKig4k80k5hMXZDMgqRU02wGAJo+XR0rCYl0SF2vyzAbMM49HqTdedfe77Si7byvEkFEkjNWKvk+H17qnma0ADTMcvRcv8VwHF\/UR\/WhbQOhnrHw5djRmlZwuNiUijm5FiLvmEs63tixdf+o2vHr7n5gf+zuOD1TUZrcloRQbjSoNbNqPl+VnkkueSz5HPUTsgSvmXCosDKm9FWVrFyt6l\/fsf\/fkfHw0Hz\/\/mV6dX12W2LXWcEFoYXX28tLtrs6lHwtiAY4RzAQm1ZUA0wqYjMcKrWjY3OihTMdTSDEy0g9HtS2vtT\/Mv3INXK1RSj4NSeAdgbLV\/VZdx++z6Bx++QwaVw2oZCEMRKebn3z138eK1Wx64ORsNZGlVllZlOCpYFPN5ns+LeV7MZ5xNOdvJZzvFbFrMp0WRS5bV0TGrMt4jSysHDl935NaDb796cj7ZqcZHSntbQLJs5bq9+w\/vn1y80qgRm7IoZDndeM+QGLZjSaquplbA0RtKZPgWtUxBxjfZthzxidlm3gQ7HxJxbo3Sv62i9ECAHr6ACfzVe8xkY+fSOxePPvnh\/XfedPHti\/lcqvwdGwUVWpS3gz+VLLvKexqMZLQsSytY2bvnphsf+6WfyOb58\/\/rzzbOnZfZVpN3XcbKNjQ9SBMLbgtIX8zXYNC21lSIMzudaOmWqKm8PIh0EXnmAYJdXXDdTGylFbg7EApiitopCKpQ0cF4sLp6+yfuO\/XMsXxnR4rSN7FCZabb832HDtzzqQeunt+6dGab2bIMRtUQ12BJBktVSCuGyEaVf0DpmzgcY7SM8V4s7d1\/5IZP\/qNPXv+Bg1\/5z3989ewZyadllB2zgQyXZLR8\/T23Xn\/PB49\/6dliZxP5BLUmEYFJghGIR671dgulX0SKSErfEA0ale8+RAyVB\/K\/eJBXBaLVlnEtgNbmwEiizmWo5GA4C1VI0Vjyg3NcPv7Ot379T+7\/Bz\/60C\/95JtffP7yW+9yOqrs98qMCn1qKXhB0JagzAZ17MFytrxy+IePPvDUY1feOffq735969Kl2u2rtD+oqKqawqL3iNPubqqUAT3lvGnyyEDeYLZMJjk5zwda3ZI6lA+R+MXWt7RvSg0K0H0oVKqRo8BRQ+\/NgV5KcPPZtXfPz\/Niz5GDl66sSzaQPBOUdjvzfLr9nf\/zzI23HnnqX3zmtcdPXDx1bjadTWfTKVlwIIXMZ\/PxUFZXhsPKx6BgXZIjG2TZcHnf2p0P37bv0J4\/+x9fPXPsRGkPVyWQZkMZjDAc3XjPrVfePjvf2W7wNm8KUE+vu\/0b01hZePvJxDaGUIDVjL\/sezi9f7qbbJTLi+D4rYWh8I4sRGy9qLzo1nmNVSTQkgzHGK4MVvfc99NP3Pqxe9\/+1psnnvne1pnznE2kqLiEmgVmq5wsg90rl85BafycLS3vvfmGW5+8\/\/BDd5786kvHv\/Fivn1N5jtVFdoUoqJsHcSd8OQC+KWhdBg9sD4dBytjQ8dbUHGtzbVlkq1N4az0hB2Nd4ckZFPKZhZNqnatIMoyYMAybmlpD1YO3vv5T3LC159+hpOrMt2Q+aQyp8mGGK2s3XjkI5978o7HP7R2YHXGLL9u79asuPLelT0H9l5348qgmM4vXFkqOBRBq2OqOI18ll88deGFp7\/95jMv55PqlZENWHf+SwcOPv7Pn\/re733j4qvf52QDZdRPRUHV6XfB2JfbDMcaNBcjiOVKCYRG\/ZxahPExGPJJNoNJorpUe2zHLsA25kmxiNUKzKgDm5oacrAkw2UsrR2845YP\/9zHlw9dd\/zPXz734rHN8+vFdMKikDxHmcxcUEfAVvby2WAwHq8cOnDzI3ff9Yn7L7x1+rU\/\/MuN02c4LZGYeb38KrdvqhlzWBrA1CdwBO+UDoVXwK1jsWXmtBZWZxqmMocLGG7hLvEwt3kA4MNDdHqT+qZX9YsIsqw+iJZktILx\/gM\/dOeDv\/AT3\/r3T++cPSeTJuenAMDBEMMVLO1Z2r9vae\/KnkPXP\/GvnjrxnVPX3j730b\/\/2Ejy5\/7oOye\/8YrMths1L1uOsijy2c7Vzfn2NotpbYIMDIYcjmVpVZbX7vzkg7c\/ce83\/\/VvzDevlmneyGvnNdXzV9suXESK4nuJOoPz0HF3SRgleGaGXlCb9ERi+2OcVvsrfeQhW\/ax6pFaab4UUkBkzsqIISfzy28df+Y\/njt4xwc+9KmHHvzJh69duPaDb37v0rH3J9c25zs7nM9Lf1dggGyQjYajlZXxgdXDP3zHLY\/eVYyXzr14\/Nv\/5Y+vnDqd72xytlOVoI2akU0hqsjXkJJtfat8yaeeDYUFEuEpIQLXK6SLECZP2Y6rHtFOjERzKt+ATlpJMKcc7xntL1JbH1az56Uuv1Qj7lx99+zOZHrko3ef\/JPLHI6FeU3mF8IZSSnynXwy2Rjf8pGja9ftuemOGx944q5jX3vl1S986+rp85xscb5TpwhTKfiaedRciqL6NM0WMBwPl1fueOK+k3\/5ar5TQd9opvUl0gDZoSXquZUItYYLXCkVEGMmEu1UdWB5SO+ZQM+QEtpOpBSiRUA3rXKNekbcyC7CmaBKJZ9LwdoCuFQAzuazyYXvbVw+\/u7ew4duvOumGz90yx2ffoSjbL61IzuT+WTOghgNBuPR0p6V5fHSdGPn0lun3\/zicxePvbt1\/iKnO2Wgj8ynKOYsjJoxnHBVzVvoKMPWQdaI130JCk1VAqVfTzBCqREYJR+F0U7HCSdgSs7LAKC3KV+BGk9SKF\/dgMLExrXVQ2WpPJdiUmxvvvn0M3d+7uNnnn9r50zRTDNXNzefli398v6VO3\/sgfF4MNvY+sq\/+cqZ774x37jMMhymVS\/RXlYqdWYVtjeS4TJG49sfvzefzN955nssA31rKWI140qlUKu9PXTZhwYbF0TgSGdPgpjSh\/gIjwwbuYaZICPTWmIlKPZ6JGqb36j+TPa1Yc1UsPkgRQ3lF7lgznyazyfrW9fW3z6Br4\/GB\/ctH9yzfGB1Zd\/K0toKMhR5MdnamV7b2bm8tXVhfXJlUzhnGWTbhq6Ubn9UMZ2N0UN7RCBmddQIL10Re9vFV\/QgbEVJQ6HXpTp7ekw7c2GsDGI\/rrCEhl8ceTeXCe9b5+dR1zNQJChBNNb05ZjLbOfy90\/sPHn\/HZ\/9yOu\/+XXmpfdp3vZGzFHkRz76Q\/lg+Of\/9g\/ffub7s\/WLrDIqpmAuhZ5\/DyrwejhQRDJkTS+6vHLD\/qOffvi7v\/P16bWrpRYKRc5mcitSz0KX9xCvA+QCWIB5EqIRw5hGrHtCtWaBCDUKc1CgCys3\/RvQ7DlSbaFYSY2xNqqTDMuoejZsOwYqS2wo2QBVDLp+WstSJ0eRlxb3pRYc5X9TxVHULsAa\/HOoWO9USkx7STKvignNXwo+SVon9EJophSNPWkSNEZajWWJa4sRoJofqpvDUh5YxaENV2R5z97bbvnhX\/pbb33h+bPPvV6lUJQLTEjJMBjsuf2DUgw2zpxnPpWKmp+jmEtRGH18jZDWIWM6QnxpRcZ7Rvv2PfqPP7V9deOl3\/pyvnmlRIPKyKeqt1SQDBswPDAXpFG6q2kF9mXxuuMyzg800Wj0FGoIkRmExRR9BJaxNI1BpcRI7R8aLwBWG40ywgxFCUuzDMGrzP8GyDKWI7yN9Shqbr1y+CtqE8667CyKdqhPpfBCHYQI0LD0bkezxdnRZob9JGNpJhrBW\/TirbKGEUbNnhUo3cYo9sBkK0CMPVUCo6n2zCOUsL86RWpsvCnzCilykZkgk+lg49SZU19+7r7PPbp19tLVk\/PqBpdDTEIW843jJ6sJ3jIjuSha6Nt++\/pyNzaQ9UyMjNey1bXbHr9v783Xv\/Q7f5bvbMl8okT5KjS7floQpjWJNyzkFAWRo6ELoNFZjcFtG2B8pHtfrNBnt9BhpERrjMAMVQU4wD0kmtVS52H9EIaIT5ksXYAEi9JxuTZNKEvNGfKZFHOUrEOZlVcVn1otIQYChRmEICXlN+BCpokuOqwTxB8WQtRv63hkBvYu7opazG6kU5SIiIOkUf8Gj2Bjy1vdJ1aBd+0tbInN1nSewMaZK4Lsw59\/8tzr78+2Zw2WDhFUC2+OKgm0qJNegyZHubCijkwtE+BKOHQPVtZuf+y++z\/9yDP\/9f9ee\/e0TDcxrxDRata+pumdGw1fQdYMqwN9V9uXGVHvVeZuDDA+Eu\/PZhHC2QEknL9Wt4WmxIpzDZHQCMUBFghXuTT+R9WAH1leWbRnXQ7WbkIlYlZ6uig\/aakPWNR0PEjnBtjjh76OpXeQOQBv0AnAOJnkVeXlJuIlw8xdzZQvyUopli0z3HGMtjcJaj0jjFGvrQYoG6fXx2vje37miYvHL0w3JsISh6Ow0KNfsa69pOBRZYZnaGMPR6gJiWxl7faPP\/BDf\/PBl377qxfeeLtM3kY+lWJe170SnKtKhht2H7SyGLa0aB2vGQHjpJWnSezJZNdCcxJGz0fQGSJZ+USEYUjjh+ahSOir4CdAtXhSwEmzIakhbcZgCQOgjfIrmqwlkULxB0Sro2W8F3aZyCWfwgXOGwRDSABkV2s43Zb1w6qdhSt288OJisnmoovdHPTBThbFpXcuDlaXj372I5sXNrYvbQQyw8bpsFnfyFgFy2YotRyDOmZ8MKpI+aVVLO8d7tl772c\/dutDd373f3\/9zCuvc3JNZluoLPdzpUPUQEtrLWtNTBi2cDBtBP1W0Ldmc7VK1e8MMD6igxPRnvhJOqr7QIN4Yhp0LDl461M6WEpY9aO2DGSzOI3vLZTMmupOGNp60RVBV2pr\/j7a19onFrt\/SyNBdMVM7HpJxgvQjERAnP6z81PanOYIZEKsamCRF5ffPgvg6Gc+OtyzZ\/PclXwuko2q2d8yOLnhG1BHFGd15ZkNMViS4ZKMVmS0IuMVLK\/uv\/Xmj37+4\/uPHHzxt79y\/rU3Od2U6Rbq2bTIgLyupzpGyYypDLoRUcPmpKNinJ5w6YjToQHSE0iPSMAExFUtwv3SOUDgHNiIlN8S6LKbrQiBOq7+IxpER7R8jiraWoL\/WMQZx1FKLrCEVDQPvPMVMVPogqsUGwmWvk2maNV8A9IHL8VhBI2LqbuaY4zU9rf6FKn3RxYsiisnzl97\/\/KHfvzBmx85OtmcTzbmZFYvtkELg2fDWns4qqK\/h2OMlksUFMtrK4euv\/2J+x\/+2R+5durMd\/7nn15973SlyJ9PUcxaMYaaC4ETKa+HS2rzf1dtFFwseDdVH5vx1haP9u59MLlzq5FUlYWQrEhDftIcC\/CXMeA\/HWod1uhPcGBS\/Y+WlUTQBtPqp1tQNnJcjldatzyUIBwyoJs\/gGfu4apnqMy2tPNnmlQQj0IMoRbobZOLLMLkW3g4oSDWyrElq2p5cHOaDcYYLstodbR3\/x1PPnD3Zx55\/8TlU197+eqJ96YbG5LPWfkjKk+6rDoSkQ0kG2Tj8coNBw\/df9uHPvXAbGPz1d\/+2qVjJ\/PpThW+XczKLDQJrSvrWBGHgVBzeeZ\/wcpk4hBCJhVqAANGI5qxcBahSqyo9opKOYB4CcWFqA7NNntwsFMqvTeikdPovSJjR7abQjwO1EoP4D+GgYpHNVfwyUAX8+CuVqCEoLEmkZQuLNb4iuut0LcIU59HDf22YRax5L\/JZrSdAhPoDyzYAG0H2TY4bPu6AcuTbTCWwTJGqyvXH7jx\/tvv\/omHRytLZ157\/73vHNu6cHWysZlPp8zr1PQsywbD4eryyv7V\/XfddMdjH1o9uPfiD9478c1XLh5\/d75xldVQ6BStHiNXPl1txquVhkoQENY+QaT3WMWbUUwbKhaF9KwxlO8F9j3o+d4nsDV\/HcJ53hi1HGL9cksXepixDONMlphgZDrFm8FTU383iwAzObMitV9AssJbDLLpIe6hFiGNkKKnNGakQ\/ITnukDP0Y1QS6KPFlFMINyxngI6Wqs4a7Kbr5y2SqrzWGl0R8sYTAa799\/4LYjh47ecvi+2264+eDOLL+2ubOzMynmOTPJRkuj5fHa6hKmswtvnr7wg3cuHHtn48z5fGe7UqXldfww5zUhwcYBMTCzMEuC0X\/4tqKJioD0qflerUVlCLLvQV+d69xzPYiExGhvWX0gdLJyhy2kNnhGl3TZbrG6LlCniXM+m0K9zkX3VQ5IhlIxeUYujGHKwiQGFhPHpIGk5FKu40CcJQaSu1n5UX8J225YBjWUQ5U2PwBYRiY3jV82ksEI2VAwGK7u2XfowPjA3tG+1cHaEgYoCuY78+nWZL6+sX1xfeviVeG8XXvFvBEDl4p\/0PJSNqDKXWNqodJu1glxDHSqmrewnQvH8DDa91DcViZ83uIhHQRFDpIrQHSOPQPxUYL\/1PcYafZbL0LYwi+BVsAoIcyvk85Is2XpDIsYV8UMS3J0LjP0IbCdYHH0w9aXNAkiAfUQMK0cAbvgT6DuvuudWE+o6amrZv4QNQTKGIwRhLgEKo\/uJui7SZgp8tLMEnXyaWWDH\/d+seGq7p1JuuPwTsREYqowkOkad16GSdjV3wx74fdAjdO\/WauYvmCZ+DqTSJqB9ONlZs9hQothzzS6e76E6w361RqzdapdIvbjcoggIl7sSDQPkgoBQtT3xdR8ag0HLXBae99sDdBYD+NNExLHATrL0rQnjB7rwClT96NsvfVZlEygMEeRERnKP5YGSNWrBmr0eqqmxDwLFT7DykHTLDa7AlO3ot2QLLiRaDMYNx0wHTgN6U4T+VtrR6E9NugpNqIxOuo0xFDhwBi0IMwWkuKLnVXuOf2JtY6Go02hYVTjukKbYjMx7yeR6Q78yr21oPerRaZm7ROIrFuLdO+CiTG5qHaJJKKMQXggzvLqVM+YfUY37\/RtcNWTmIMgqnlQtjItOMVNE7pUBcuw8SKh8kqHRN1d\/HxGzrENa0V0l+eBuXna\/IIL9PS1gJv2DbSVZCskjqJ\/hQuJRTyuTTwHviZ8D8aTyDDUrgF7+MoM5u669ClcgBw3CuZ4o7GJDj4MEz36hs1FNDfaW1lHhXYwHOhcaUQyWY2KqhzejqvDIN4CXu0aCoQUl60dlUqBSBkxXoXQ0zmBwRiFVodb8yQ21nVRalWUcCj6AbcVpmnt9F2BY3yf9Kf0KcR2QLV6RodpPEFdgop2a6PzLBfZljpIEG9gzz4BD4YyJ7SZNghblxas84yYkqcbEk6PcI45ekcT00w+2o1VoPdLL0TNXPZgmAqdRx9d2E2fhWSX4CPC+MK5CR\/i7QSsaPp188FQZ78qbyRR4y\/xHgajSCnliNBzgGpxRnbmpjRFdMAHwal2D9QrkIE7zG41h7RFLEUgA4wPJ\/CQNFoNq31poBU0PwBzN6ULrGeHrLTj78U4vyRpM8RdCjrwq\/B3UhfDPyKg3wzpAT86Vj6ee14KuHbyJ7xaNPayIYIhcavUhiPqjr4LPYhu0acRqi01WlO9t1O5ubZWBo3WrFls0IedbkAsCcFAMOwCnuFAM+IBlyS\/xQSQEavnQdtfyEDGRzw3NaebkGBAJWIlTOEJCN1K1F3mQHLYtw+ad7gMdMdlSJOikOymujFJjzti2iPG3WT8l0\/Ir8NkPrE+dnAuE1oVcBD2BWP209JNKUi0vTfBsAR7ZKUITw7Yde9Ia2P1vBZOg+pcCurTWpFiXIztmjH+MV0tnIlWhXjimF0qJbyqtPynXISM+Adnc1XzKdrS0JuMAUB0Quvw71lipXlLFOlTSBLwXfq06SLuGAE\/TF5xILW2et7FjcPTXoZ6ZrgNr48vmZqqJp00dmiJr6OFQXdRgbjoQPdXpENdIYBgJVAlajAA3hVsNMMhics6n4Ex1aSuGtOMX7RLx8467GYSErVRh65ELUK4j38UpNRssvCsKVq6iCnGgfAeSziDhS44YT4mE0OyzkdbgGFjjCPBEwwx1UJDXAoBQD\/LVj+GSPw00iUK4NSjaBJpKSkBN\/TmhRY0YXoXM\/mLqeXnVP9GyV2fx4FCvJEIQwTd+yN0LA8Q80juZK37RzbD9VGd7++8uk\/vF214Yw32n3KekJ0sbAzTBzeBkjL1QzuUi9BsVoOcvQWn84kCZTNb8Zu2ycAujqKuy9\/\/i9GRDdspYcE5DSDeDkRciUJYS6oHJdCZMWgKEf+KREG7qYsRzkl5TSx7WsOIY1Have6Lbl1Snd48YALpsJxU3AtCpLPTK8TljUBLF1rmwFEYQcRFIoYBKSndB8uCJ3HoqwJGjFQUBUdX35ymExCGT9jWTMmyXUl0YgXCQTXa5GL3s3SexBDZ1dy9uIMSTZhmV7nnK7GcTDSg+4Awl4z1DEDfrt\/cCPQIgMIVaFBUpk5U2Lz42ISx9i3U2eaGVEfIX\/Q3hw26UTTlKBAF1NMV8cNdvhUlE77tMNxT43VAbWZnUdtWii+BMbO554s8f3ShbxcyRtrmrMm3gES8eW1K67r0uAB++BBHnRIQbrjwwEkm7kXS4jpxhrATAAgdRGmzYHV+L1LQoPrONOOISbyIf21fgESgir2T8SUIfcOCxz\/hSmgVTilSytdCxeVvmhg0miXHe9RtK7M+5qfNcdUHvSlWNfNiH8Xk06P9NKk8ydnoV0wQQMJ+XL9NG+jZbt8tpk3phscS15aphp6pOrPXH7b2cu\/5BJ1VjWj5SzclANvB0Ar8geT3p0vetZGotDRg4tYk1XT6NGMdMEZjOxJdeV340SxKBB9SdCQcrEu628DpqxRbfgUVHEObPKZQH4r7MAuFw2ApdcHkXtHmCR3V5UC65GYIDKR8kPxfh4mcroJUNTkSWbiYOtYf1KrHvyw8wnQjmJzn6p2Wjz5A36mSkjM4OEQPZGeUocoSrb\/w9DZTv1KnQTtgu6gg5cmvi1L\/nTDdMvADPJipbQ6le0dO79lMrZOQA2YS6wiboNptzWZ0BXCwSOwgAwsYoJtbE4ddjG8kNIgWsc+xnUmaeqiG7gkE\/g6w8IFnO4BuszH0EYNRTR+kHGkUBG7fmLJgY2Sd0KnZprllbfctEYCTWAD1LunD5+yGL3sHMWB75yZNwXDmuvVdrIDpWsmqvEVg9G9oRqRLEAuMMYCenD2Z8Y7Z2tAMnV0hfJjVr2nSLNJ9JG1\/vT8C6YsFRYVJlxmE22aoMW7xJCsWZoEL+zC24UwIlKN+AA5eQ92pMUbSe6cVGQ+RVPsJmewnYJlDjau3WjZLe2qQWw\/Ii+fX7KJWjFRmnYdpi+ka0WYoeSMXW3upM1MHqDA4R9ofYXpkKfxjXMHYLm0XE9rDmAaM+vlQYBx9RATWKIsh\/FR7H0D\/dGMoisYCL9iHbsQmdsazpxybcaaxYvDRSE\/KHYDO8coQ3aeLnCF9uPiUF+O9C105lnCffUbRI6EnT2Kah0HOArpJnz6yL2A4UjA7o6uvsnFSRQpjRsH6i3bbJaTHUmjLQURAku9Ra5oqKmAmiUY2BalD6JX8nB3AgdOc0D1iQQkUWFQFcJAFz46SwNvA\/AoxAbUGllmQNDRCDx5oVBuED0uEwqJg2oOqTeVCm2d89DEYCoy9YJTIwJpEKmMjlwrrXkYMqJzeO5J4wuvZI7q7LJWCtEFaoAqdYEbOqFJIC+S0xnspyCdA89LAWPWQo5qZYkps2t7kVEcGlALuI2FlFcUnge7EX9sdho1cm9iu3JngqmFcf5rYnCjuQmnrZdsyxWHAyeNBc2fs6jOT+1T0R8T1I6XzsAsbNYrtArTAGWbWQhIO3Ck9roIAetSAiM5XxMbSsfmBa6oQdGCIAUqXrfefXadni6XCNHohtodJcm+A9JQ\/irhkY4ZXlgt0jSxiYWfcsAHDaqaLZlY1bXAAH0ZC2BgS7VAoCKY5XHjMJwNJUdsvaIeqCNdBWJ+gk31h2O7HVmdmPKojnilZResHgtYTIAKQ4aoFxBm4MDtkBArG8B7dQwzODzjgtuXRApMQOBxF3CPQ7dPswtC9DNWEYzxdyLiIpXdIexoQhGUNwmVNBw2kukO0FrCW+apsdKJm2YeegcqBG7Edg7WR7h4DgKMXbdGLYEeOhKzwI6V1moEG0lBbtJnjFB7vA3huxdJpKpfeKNC59PpbcCRwNnuNdvu6qrZhH0ZNvzjw7GERdbYRTAsP\/Uff5aRRsFhvTKT5Vfg0aNpvvPNkQ7BgJMV3+CAMPF9g9tyiKMmzrGyGbrcZTonHlzz2vkMLVtD2eezpcpL8mUJI6G2zsfYFqR9JAdbUUQRmlRrOhtzFCmTKYybxvOzClM2eutEWiz50vuPhZtCOKSbPK3ijBypAUIgurjPhPwWmBEbJt7bSKPSFkTGJb3XntFqbskYq18+uMsjhtWfnUDzSO6K2vZ49haGrPTRyHbZMWTRExl4mAm30NsVldCxCEBodInH9k5wkA1i4ewXaqh6RZ1t82WgfTexqy2qlBXR7VDJ5jNOhzR3MshpNbB6jRKvC3kNLImFqoutLQQQdBw5Tb8EuOICS9vn3yY4IEKY44zYGhG1wIjp9C1FP1qfE0\/DH9HprI0+Oax7GOBYm9ujvSlSzz3r6I1VgeyTeSs42aBP+wIeeiXkl80xHjzskSnHpHPJAYrSkY6wRSaLAJ2XRF\/cLq3D1sIFEEsNCBLo78N1bg0bjEZFuK9EF0z5sQdQS03iBWnyAnlprEtJ6Nstw72hGfJqfGGDpcHoHCrvK\/r4lNL23NRI8rKRvyAepBzTsIzobtrC37G1awhEu6LkYwkMDo8cynoxViKQ7oUcJNotUUpDz5DFK9UA8DeoJJ3rvI+0UYLLUly5l3i4K4+QHriKc7WXtou8DNSwkHu2P9+\/Aqyb5AaEeqfSgWoTFUkd4tlMIoCBTfk1h6JE5ibGLgZyQfwrHowN4Ah1HaYjbxbcfTQqa1UK7OxPFoVkX6\/7RqrbSK9B+biCEhWifhFoTXxJ9yk8sumyURIazO3oobu0fFALsu4WR5IKSGApjULU4eE2sq+4mjRhovpvzCi5S0tmFkwu1UoGxHGPUjPbGsk7LZOveBgKxfjXgz5CuAeqTEH7H7JWB2M2xJV68bzhVicQrmSESJM0voj\/Sl5aiT8iI5HcM3bTRXwikiKj2IGcaQ+2xJ40XgHvtA7fXRfrMvobU+61FXheL3gN2Xz2v72SHmXLvGRwa3tGFeXSv3NG7gI5eAP3mFyLSKGbQ1SQxhJc7cFgmNExcCPf3NiDTwSB2s9MVANiDnHh+li2ynzwkiLjodS6WVwioHRLQJ6FzUieG2dxHkTHOZ\/wdnAtFJveufsg3PKPgyCwTTw7hXSDv6oVZEZRu8cpCc\/HJTZXiTENTXOtDKzVnVKXTlgGtlDtqIyLQZxg52YKpeVl2DjWqrckZA4WPBtTCRfrNtmNjhA7kPwwYX6BXNoa9iFmVpg6looU7CtokzgbYFSfRe6dO8t1AkEzcO7ZA2+KTStJD8CgL9ggEsMEdEnt+J69b10ekLPYI7frbIZb3W\/9CW5K3eriKp0bX4VdqWJyjK+u8yVGTltIbhjuz8TFJB03We48PBjL9Wz4WEndR4WbPaEwzMkYnnT6LbjQPF392GSc9mCIU\/vAZhLt7ltjR6OlPwt7Do\/dFFchIlHRr7LDiClGZ2ji44I4Wrlftq02fsPK4Rzh9IiTwEmzrILQtPYK3VtcTpFPJ9sFVlJKiiAMtKgcwSJepVuwNZnJGTcy1R3\/oPiwlI3Ud05g8KZCQbMezuvqLJMyXET9EcC5u\/KnUfCaJoB\/0k0C9brPpR3plPbsYn+lbdr5UeAFuo+vRjzph9wN3NtPRh0SvDMTBhxhiEm5fhOCJsSNxTDymbqOCLk69llkPvYvf5mr2TfI1LFpzMoeqpMi5PqhRQjaRrYIPauwIETcKicKVImc926Ex5W7Zc6pFjlLJx5WOh2LUGNAWcf5MU+BIgvg1F0b\/ta5XFsRRJIkGmRCgDlwlFl1wkQ\/M3Xw2plyvo09O46Pl0TX0LFoDZ5kaegEdXCdVArFr92tSwONKYPFczNYP2YOD0QaOeb003GaDUfHGCJdmOA3EFkM3biXBrgnbfDcMh\/a0gXhRkolnJRzUQFy8MT6pGDQTHarFYINWWxwZZc0ml58E3BfSfEBnSnBTdkEnWNHRZjNB7C9URrOfrkjb1CgOBaFJLGvcjc6vhCNdYifb0IzVtS78cCEys+1TmS+axW4WGtlEwCV6+pCOBP3DpoferJE0Eqofg9WVMw06VJFXoLpoLs4ZJz\/STcbR9B3cHZvON3QR0WCot+N\/WqoPKTiRDuRMr2wLa9tgC0gYtaB7XjIemIwpO3oBmi0y0wyqcgGvVUlAh9pZKoUP0+FrIikZ2hfVP886ypTwyiaa9a92V0q\/xX3QKjanqGc0UCvukXVBbozPJHqIjbh9mrI8CyY74Lr90SG5gJTrvfV8g0QqZKTB65BChQXfTclA9mDr6eYgeGEusKc3PEh8QLGrSjRzsaByGgshlOD1QlYgABrYhaSkTNCclI5F0xR9p28GAZNwpj2EZAAWtipp208h\/M7+R6S65U3zgERpQzVXnZTa1KAo49Oj3A5kgPGhJHCHdvg3+cgYdEJH7bhgMqosuirDM4myoAN2QNcygJfsDR9EwQKIBQUgesNPunqehQ8ExBgP\/Y6xuw0CPLsL7ArBYThxSyc9CbsvO5EWTKOrbRJJDEz3OM2YSIOIB0NSA7sQq2EY9u6h8DZBA6HjWtb3UDCMoQnvQTgGFAw1MF1xaKhwocqFgYcGooJBnx9BVkg4CM4FmSiLZDMuZrEbJeaCyw8BfNcHHuo6nG5dF8KtZgWy90Ojs4T4a35Htd78Cirp+wbbH9C5ifAbNtZ2QOjcR5O3Bb0bS7JbSV4IzZRlfmLuQiA4XUczuhU8DdJYG7zGlYuzm4BED0JkHJy6rjOTZZZqPMUJhPO3wuhLu+IrYgFkv2mS2e2a0xJi7DSBoXM12PGCfUAl6Zi7udcluLWscAFqF23XFrdjAtUpYhmp\/8nUU0sxy5YJAKgLMkr8aEfLwC5Ko\/muQzt8ic5GzdYV0Tdv\/fUQhaQ2nr2wIKnrKRhNvUXofqKsJKMkLlBinSG8naxDr8m+fYpdzpzssDpF4F6+oAoA7rOANAq1wPIPenr65q6syziEJg7WFZbOkRQwJ2ahcIFggMAjrydWw\/kzgRTbwy4H196IqI6DBIjuVuO7WP1VBn3k+vF6xmS6d\/go5LVUuUiJhArggjVOVxPkDAcEsIRRNiRukAanGfe+7k1PElOO71p4WgZMAxv3oFAwuXhfSQVTREi4aeyQrjf7QCAyxHl7YxuZ6NNiFa7lw9nxHdOsRjfuGvpEGCSPIr4ZlIQTcIn74tlV18WIX9o33znrW\/NmcWLR1cIoCaO9U7ApNoxXd0uKIaB0AtomWjMMX5SJbiG6+pG6goZpZA+pl8zJ6BB+kCqonRbbjj9Z0hmH7sbZOd4Vi7NM\/RgPf8KmZgZ3NUJ+0wcLabwAF9XQAd3YrPNO0J\/bnKf0ryaSOy0WsCBBZJjTU+tKKVuzo0qIijSyg5hw6hp4WjP4mU2g0rLEbhTpe4Pk5FSHHWzP3Wbci0NcT1obv0O4lmnQfxlZNdcIsZmBr1EEc8W6h2jDAk\/vUnBQFdb3iCEpJM4IEpy\/0BUxomklx7wOpjsLfyFUFCK5\/NyFGe5BOqA3iLFMOosppB+LJOD1FCPO7gMX\/q3pOmSddXRYpgbVKMIK0UAdsHMo0CYtRMj8NEhNoLReAENPmY2APVksCczUgzyJiEBjsG0GFz2MTacSktBK3O0VQ+TGaQaRnTKM7rBqwpaVjsaolXdIqxlq2gQgVmgqg1Qm7wo7ZO7ufEvg+8zEI+k2gQxCmKJiOwwrhPi1cLh44PE9Hm4uydZoV\/9ksdOWLwkAnEYWLsykpqZUkLan3xBGdaN03GO65Z\/TIVDnQdEF1rpelw4oHtrvpj1kFXesjW2iN0K9u8EEfkgCtmN6I2LAQtcQOAI0MkkZwRFz0PniiQ2QnfCdxUuJhFS69EdI+Supcp3+GyA+DZC6XmQHMIzIXTqJxJghNYSqf9hNNl2HZV1DNskTyffwjMZXYIWf7JZK68Q\/1F5+TEfZp8ts3XIgjX+j3lzgFF+SagxMyetK7+q4lgTQFYxLovYMSqPbdDadQBDCtvAE67kNqobTJxzELR1tu+xXikwTHWyvEpgkEGBvWXdf2CnWCh7e3pMorGZEJTInrIIXKUO9aqEXeASkTWUK8nqM3ocWfkU4JdB12ZAgOKjNq6yllEkLoqYn+qFiOj8XCzK9exkGH6WegjZ+I6oaYbwb\/SzheHK0I3dE6f7Brp3QIPxONhMMKIRYjuPEVaXqSTb9q25yo29KpOrKfnNU+shzFPlmHrLIGiVlz9v6btGmG\/tYg008DDFH9252dLPNhRpg+VCaLEr9LpR9W+\/beOpBGAUdEm12tDchzCiFg7sEoyZI5xgaY\/EmX0pBCG2WVpi7HQ86qutQXhNfUENjtRPsSzrkiJLKNqC+hhojEv+7UhD5HJBEmHAUKRZDM30b3cQorsAkdzmtUag6MzsRFzpu4qg8hLseUrF3jLR3lKRbYcS09S8QptpKd4EYcv7\/A5V66wHRWfq9AAAAAElFTkSuQmCC\" alt=\"SS\" data-no-lazy=\"1\"><\/button>\n                     <div class=\"ti-lang-wrap\"><span class=\"ti-lang-opt active\" data-lang=\"it\">IT<\/span><span class=\"ti-lang-opt\" data-lang=\"en\">EN<\/span><\/div>\n                <\/div>\n            <\/div>\n            <div class=\"ti-company-sub-row\"><div id=\"ti-company-sub\" style=\"display:none;\"><\/div><\/div>\n            <div class=\"ti-header-bottom\">\n                 <div class=\"ti-header-left-controls\">\n                     <div id=\"ti-sort-btn\" title=\"Ordina\" style=\"cursor:pointer; background:#2563eb; border-color:#1d4ed8; color:#fff;\">AZ<\/div>\n                     <button type=\"button\" id=\"ti-show-sospese-btn\" class=\"ti-btn\" title=\"Tutte: mostra tutte le ditte, incluse sospese e demo\" style=\"display:flex; align-items:center; justify-content:center; min-width:68px; background:#374151; color:#fff;\">Tutte<\/button>\n                     <textarea id=\"ti-filter-ditte\" rows=\"2\" placeholder=\"\ud83d\udd0d Cerca ditta, attivit\u00e0, esigenza\" autocomplete=\"off\" aria-label=\"Cerca ditta, attivit\u00e0, esigenza\"><\/textarea>\n                     <div class=\"ti-ditta-login-row-1770\">\n                         <div class=\"ti-ditta-picker\"><button type=\"button\" id=\"ti-ditta-trigger\" class=\"ti-ditta-trigger\">-- Scegli una ditta --<\/button><div id=\"ti-ditta-popup\" class=\"ti-ditta-popup\" style=\"display:none;\"><\/div><select id=\"ti-ditta\" style=\"display:none !important;\"><\/select><\/div>\n                         <button type=\"button\" id=\"ti-login-btn\" class=\"ti-btn\" style=\"\" onclick=\"if (window.openLoginModalSafe) window.openLoginModalSafe(); else if(window.openModal) window.openModal('ti-login-ov'); return false;\">Accedi<\/button>\n                     <\/div>\n                 <\/div>\n                 <div class=\"ti-header-right-controls\">\n                     <div id=\"ti-user-area\" class=\"ti-user-area\" onclick=\"window.openProfileModal()\">\n                          <img decoding=\"async\" id=\"ti-user-avatar\" class=\"ti-user-avatar\" src=\"\" style=\"display:none;\" onerror=\"this.style.display='none'\">\n                          <div class=\"ti-user-info\">\n                              <span id=\"ti-user-name\" class=\"ti-user-name\">Cliente\/Utente<\/span><span id=\"ti-user-role\" class=\"ti-user-role\"><\/span>\n                          <\/div>\n                      <\/div>\n                     <button type=\"button\" id=\"ti-logout-btn\" class=\"ti-btn ti-logout-btn\" data-ti-logout=\"1\" aria-label=\"Esci\" title=\"Esci\" style=\"display:none;\" onclick=\"if(window.doLogout){return window.doLogout(event);} return false;\">Esci<\/button>\n                 <\/div>\n            <\/div>\n        <\/div>\n                <div id=\"ti-mobile-direct-login\" class=\"\" aria-label=\"Login diretto Shop & Service fallback\">\n            <div class=\"ti-mobile-login-title\">Accesso diretto Shop & Service <span style=\"font-weight:600;color:#93c5fd;\">(fallback)<\/span><\/div>\n            <div style=\"font-size:12px;color:#cbd5e1;margin:-4px 0 8px 0;\">Usa questo accesso solo se il login principale non procede o restituisce errore.<\/div>\n            <div id=\"ti-direct-login-fallback-alert\" style=\"display:none;background:#78350f;color:#fff;border:1px solid #f59e0b;border-radius:8px;padding:7px;margin-bottom:8px;font-size:12px;line-height:1.35;\"><\/div>\n                        <form method=\"post\" action=\"\/en\/wp-json\/wp\/v2\/pages\/1165\" autocomplete=\"on\">\n                <input type=\"hidden\" name=\"ti_action\" value=\"ti_ai_login\">\n                <input type=\"hidden\" name=\"action\" value=\"ti_ai_login\">\n                <input type=\"hidden\" name=\"ti_mobile_login_redirect\" value=\"1\">\n                <input type=\"hidden\" name=\"redirect\" value=\"1\">\n                                <input id=\"ti-direct-login-user\" name=\"username\" placeholder=\"Username\" autocomplete=\"username\" data-ti-login-username=\"1\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\" inputmode=\"text\">\n                <input id=\"ti-direct-login-pass\" name=\"password\" type=\"password\" placeholder=\"Password\" autocomplete=\"current-password\" data-ti-login-password=\"1\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\">\n                <select id=\"ti-direct-login-db\" name=\"db_select\" aria-label=\"Ditta\">\n                    <option value=\"\">-- Scegli una ditta --<\/option>\n                                            <option value=\"bmw-terni.json\" >bmw-terni<\/option>\n                                            <option value=\"catering-terni.json\" >catering-terni<\/option>\n                                            <option value=\"Dev_sstest.json\" >Dev_sstest<\/option>\n                                            <option value=\"farmaciaterni.json\" >farmaciaterni<\/option>\n                                            <option value=\"ferramentaterni.json\" >ferramentaterni<\/option>\n                                            <option value=\"filatelico.json\" >filatelico<\/option>\n                                            <option value=\"fioraio.json\" >fioraio<\/option>\n                                            <option value=\"hairstyle.json\" >hairstyle<\/option>\n                                            <option value=\"hard&amp;soft.json\" >hard&amp;soft<\/option>\n                                            <option value=\"ristoranteterni.json\" >ristoranteterni<\/option>\n                                            <option value=\"termoidraulica-italiana.json\" >termoidraulica-italiana<\/option>\n                                    <\/select>\n                <button type=\"submit\" class=\"ti-mobile-login-submit\">Accedi<\/button>\n                <button type=\"button\" class=\"ti-mobile-login-submit ti-forgot-password-wide\" style=\"grid-column:1 \/ -1;margin-top:8px;background:#4b5563;font-size:12px;min-width:260px;min-height:44px;padding:10px 14px;white-space:normal;line-height:1.25;\" onclick=\"if(window.tiForgotPasswordFromLogin) window.tiForgotPasswordFromLogin('direct'); return false;\">Password dimenticata? Cambia tramite email<\/button>\n            <\/form>\n        <\/div>\n                <div class=\"ti-input-wrap\">\n            <div class=\"ti-input-main\">\n                <textarea id=\"ti-msg\" class=\"ti-msg\" rows=\"5\" placeholder=\"Scrivi qui...\"><\/textarea>\n                <div class=\"ti-send-wrap\">\n                    <button type=\"button\" id=\"ti-send\" class=\"ti-send\">INVIA<\/button>\n                    <button type=\"button\" id=\"ti-ok\" class=\"ti-btn ti-btn-ok\">OK \/ SI<\/button>\n                    <button type=\"button\" id=\"ti-x\" class=\"ti-btn ti-btn-x\">X \/ NO<\/button>\n                <\/div>\n            <\/div>\n            <div class=\"ti-actions-row\" style=\"flex-wrap:nowrap;\">\n                <button type=\"button\" id=\"ti-new\" class=\"ti-btn\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">Nuova<\/button>\n                <button type=\"button\" id=\"ti-copy\" class=\"ti-btn\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">Copia testo<\/button>\n                <button type=\"button\" id=\"ti-file\" class=\"ti-btn\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\" onclick=\"window.showUploadChoice('chat')\">File per AI<\/button>\n                <span id=\"ti-file-help-inline-1508\" class=\"ti-file-ai-help-dedicated-1508\" data-ti-dedicated-help=\"file-ai\" role=\"button\" tabindex=\"0\" title=\"Aiuto File per AI\" aria-label=\"Aiuto File per AI\" onclick=\"return window.tiOpenFileAiHelp1508 ? window.tiOpenFileAiHelp1508('main', event) : false;\">?<\/span>\n                <button type=\"button\" id=\"ti-products-btn\" class=\"ti-btn ti-btn-catalog ti-catalog-unavailable-1970\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">Prodotti<\/button>\n                <button type=\"button\" id=\"ti-services-btn\" class=\"ti-btn ti-btn-catalog ti-btn-services ti-catalog-unavailable-1970\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">Servizi<\/button>\n                <button type=\"button\" id=\"ti-activities-btn\" class=\"ti-btn ti-btn-catalog ti-btn-activities\" hidden aria-hidden=\"true\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px; display:none !important;\">Attivit\u00e0<\/button>\n                <button type=\"button\" id=\"ti-kbd-btn\" class=\"ti-btn\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">Tastiera<\/button>\n                <button type=\"button\" id=\"ti-mic\" class=\"ti-btn\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">Mic<\/button>\n                <button type=\"button\" id=\"ti-cam\" class=\"ti-btn\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">Cam<\/button>\n                <button type=\"button\" id=\"ti-mute-btn\" class=\"ti-btn\" style=\"flex:1 1 0; min-width:0; padding-left:4px; padding-right:4px;\">\ud83d\udd0a ON<\/button>\n                <button type=\"button\" id=\"ti-help-btn\" class=\"ti-help\" title=\"Aiuto\" aria-label=\"Aiuto\" style=\"flex:0 0 auto;\">?<\/button>\n            <\/div>\n            <style id=\"ti-actions-row-1153-css\">\n            .ti-actions-row .ti-btn { font-size:11px !important; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; box-sizing:border-box !important; }\n            @media (max-width:640px) { .ti-actions-row .ti-btn { font-size:9.5px !important; padding-left:2px !important; padding-right:2px !important; gap:2px !important; } }\n            @media (max-width:400px) { .ti-actions-row { gap:3px !important; } .ti-actions-row .ti-btn { font-size:8.5px !important; } }\n            <\/style>\n            <style id=\"ti-file-ai-help-style-1503\">\n            #ti-ai-outer .ti-file-ai-help-1503{display:inline-flex!important;align-items:center!important;justify-content:center!important;flex:0 0 34px!important;width:34px!important;min-width:34px!important;max-width:34px!important;height:30px!important;min-height:30px!important;margin:0 2px!important;padding:0!important;border:1px solid #4b5563!important;border-radius:7px!important;background:#374151!important;color:#fff!important;font-size:14px!important;font-weight:900!important;line-height:1!important;cursor:help!important;box-sizing:border-box!important;text-decoration:none!important;}\n            #ti-ai-outer .ti-file-ai-help-1503:hover,#ti-ai-outer .ti-file-ai-help-1503:focus{background:#4b5563!important;color:#fff!important;outline:2px solid rgba(147,197,253,.35)!important;}\n            #ti-conf-ov .ti-file-ai-help-1503{flex:0 0 34px!important;width:34px!important;min-width:34px!important;max-width:34px!important;height:30px!important;min-height:30px!important;font-size:14px!important;}\n            @media(max-width:640px){#ti-ai-outer .ti-file-ai-help-1503,#ti-conf-ov .ti-file-ai-help-1503{flex-basis:30px!important;width:30px!important;min-width:30px!important;max-width:30px!important;height:28px!important;min-height:28px!important;font-size:13px!important;}}\n            <\/style>\n            <div id=\"ti-admin-actions-row\" class=\"ti-admin-actions-row\" aria-label=\"Comandi amministrativi\"><\/div>\n        <\/div>\n        <div id=\"ti-chat-box\" class=\"ti-chat-box ti-scrollable-plugin ti-chat-after-ai-form-717\" data-ti-placement=\"after-ai-form\"><\/div>\n        <script>\n        \/\/ 30.9.1451: diagnostica mirata e temporanea sugli eventi touch nella chat principale - per capire\n        \/\/ esattamente cosa succede quando l'utente prova a scorrere verticalmente su smartphone (segnalato:\n        \/\/ lo scorrimento con le dita non funziona in questa sezione). Registra nell'array diagnostico gia'\n        \/\/ esistente (687), visibile e copiabile tramite il pulsante \"Log salvataggio\" gia' presente.\n        (function(){\n            var cb1451 = document.getElementById('ti-chat-box');\n            if (!cb1451) return;\n            function log1451(evName, ev){\n                try {\n                    window.__tiConfigSaveDiagLog687 = window.__tiConfigSaveDiagLog687 || [];\n                    var isMobileNow1451 = window.tiIsMobileLike ? window.tiIsMobileLike() : null;\n                    window.__tiConfigSaveDiagLog687.push({\n                        time: (Date.now?Date.now():(new Date()).getTime()),\n                        event: 'CHATSCROLL_1451_' + evName,\n                        detail: { scrollTop: cb1451.scrollTop, scrollHeight: cb1451.scrollHeight, clientHeight: cb1451.clientHeight, defaultPrevented: ev ? ev.defaultPrevented : null, isMobileLike: isMobileNow1451, touches: (ev && ev.touches) ? ev.touches.length : null },\n                        level: 'info'\n                    });\n                } catch(e) {}\n            }\n            cb1451.addEventListener('touchstart', function(ev){ log1451('touchstart', ev); }, {passive:true, capture:false});\n            cb1451.addEventListener('touchmove', function(ev){ log1451('touchmove', ev); }, {passive:true, capture:false});\n            cb1451.addEventListener('touchend', function(ev){ log1451('touchend', ev); }, {passive:true, capture:false});\n        })();\n        <\/script>\n        <div id=\"ti-order-confirm-host\" class=\"ti-order-confirm-host\"><\/div>\n        <div id=\"ti-ai-response-host\" class=\"ti-ai-response-host\"><\/div>\n        <div class=\"ti-shop-footer\">Target Informatica S.r.l. Via Filippo Turati, 16 05100 Terni \u2013 Italy Tel. +39 0744 288409\u201310<br>P.IVA 00664210556 CCIAA Terni 67219 \u2013 Trib.Terni n. 132\/94 \u00a9 Copyright 2025 Target Informatica S.r.l.<br><a href=\"https:\/\/www.targetinformatica.it\/\" target=\"_blank\" rel=\"noopener\">www.targetinformatica.it<\/a><div class=\"ti-shop-footer-contacts\" style=\"font-size:11px; text-align:center; margin-top:5px; line-height:1.55;\">\n            <div>Info: <a href=\"mailto:SSInfo@targetinformatica.it\">SSInfo@targetinformatica.it<\/a><\/div>\n            <div>Commerciale\/amministrazione: <a href=\"mailto:SSComm@targetinformatica.it\">SSComm@targetinformatica.it<\/a><\/div>\n            <div>Supporto tecnico: <a href=\"mailto:SSSupport@targetinformatica.it\">SSSupport@targetinformatica.it<\/a><\/div>\n        <\/div><\/div>\n\n        <div id=\"ti-conf-ov\" class=\"ti-ov ti-closable-ov\" style=\"z-index: 1000 !important;\">\n            <div class=\"ti-conf-window\">\n                <div class=\"ti-conf-header\">\n                    <h3 id=\"ti-conf-title\" style=\"color:#fff; margin:0; font-size:18px; font-weight:bold;\">Impostazioni Ditta<\/h3>\n                    <div class=\"ti-conf-header-right\">\n                        <span id=\"ti-conf-ref-datetime\" class=\"ti-company-ref-datetime ti-conf-ref-datetime\" title=\"Data e ora sistema ditta\"><\/span>\n                        <div id=\"ti-conf-global-btn\"><\/div>\n                    <\/div>\n                <\/div>\n                <div class=\"ti-conf-body\">\n                    <div id=\"ti-conf-cnt\" class=\"ti-scrollable-plugin\"><\/div>\n                <\/div>\n                <div class=\"ti-conf-footer\">\n                    <button type=\"button\" id=\"lbl-conf-save\" class=\"ti-btn\" style=\"flex:1; background:#374151 !important; color:#fff !important; cursor:pointer !important; font-size:16px !important; font-weight:800 !important; border:none !important;\" onpointerdown=\"try{window.tiShowConfigSaveDiag688&&window.tiShowConfigSaveDiag688('inline_pointerdown');}catch(e){}\" onmousedown=\"try{window.tiShowConfigSaveDiag688&&window.tiShowConfigSaveDiag688('inline_mousedown');}catch(e){}\" ontouchstart=\"try{window.tiShowConfigSaveDiag688&&window.tiShowConfigSaveDiag688('inline_touchstart');}catch(e){}\">Salva Modifiche<\/button>\n                                                            <button type=\"button\" id=\"ti-conf-file-ai-1479\" class=\"ti-btn\" style=\"flex:1; background:#1d4ed8 !important; color:#fff !important; cursor:pointer !important; font-size:12px !important; border:none !important;\" onclick=\"try{if(window.pickAiFile1088){return window.pickAiFile1088('config');} if(window.showUploadChoice){return window.showUploadChoice('config-bot-file');}}catch(e){} return false;\">File per AI<\/button>\n                    <button type=\"button\" id=\"ti-conf-email-sms-1591\" class=\"ti-btn\" style=\"flex:1; background:#0f766e !important; color:#fff !important; cursor:pointer !important; font-size:12px !important; border:none !important;\" onclick=\"return window.openConfigComm1591 ? window.openConfigComm1591(event) : false;\">Email\/SMS<\/button>\n                    <span id=\"ti-conf-file-ai-help-inline-1508\" class=\"ti-file-ai-help-dedicated-1508\" data-ti-dedicated-help=\"file-ai\" role=\"button\" tabindex=\"0\" title=\"Aiuto File per AI\" aria-label=\"Aiuto File per AI\" onclick=\"return window.tiOpenFileAiHelp1508 ? window.tiOpenFileAiHelp1508('config', event) : false;\">?<\/span>\n                    <button type=\"button\" class=\"ti-btn btn-close\" style=\"flex:1; background:#b91c1c !important; color:#fff !important; cursor:pointer !important; font-size:12px !important; border:none !important;\" onclick=\"try{if(window.log1088)window.log1088('DIAGNOSTICA 1259: click su Chiudi Configurazione registrato, avvio ricarica tra 400ms');}catch(e){} window.closeConfigModal(); setTimeout(function(){ try { location.reload(); } catch(e) { location.href = location.href; } }, 400);\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-config-comm-ov-1591\" class=\"ti-ov ti-closable-ov\" style=\"z-index:2147482500 !important;display:none;\">\n            <div class=\"ti-modal\" style=\"width:min(92vw,820px);max-height:92vh;overflow:auto;text-align:left;background:#0b1220;border:1px solid #334155;border-radius:12px;padding:0;\">\n                <div style=\"position:sticky;top:0;z-index:3;display:flex;align-items:center;justify-content:space-between;gap:10px;background:#111827;border-bottom:1px solid #334155;padding:12px 14px;\">\n                    <h3 id=\"ti-config-comm-title-1591\" style=\"color:#fff;margin:0;font-size:18px;\">Invio Email\/SMS<\/h3>\n                    <button type=\"button\" class=\"ti-btn\" style=\"background:#b91c1c;color:#fff;min-width:38px;font-size:18px;line-height:1;\" onclick=\"return window.closeConfigComm1591 ? window.closeConfigComm1591() : false;\" aria-label=\"Chiudi\">\u00d7<\/button>\n                <\/div>\n                <div style=\"padding:14px 16px;display:grid;gap:12px;\">\n                    <div id=\"ti-config-comm-status-1591\" style=\"display:none;padding:9px 11px;border-radius:8px;background:#172033;border:1px solid #334155;color:#bfdbfe;font-size:12px;\"><\/div>\n                    <div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px;\">\n                        <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Canale\n                            <select id=\"ti-config-comm-channel-1591\" class=\"ti-in\" style=\"width:100%;margin-top:5px;\" onchange=\"window.refreshConfigComm1591 && window.refreshConfigComm1591();\">\n                                <option value=\"email\" selected>Email<\/option><option value=\"sms\">SMS<\/option>\n                            <\/select>\n                        <\/label>\n                        <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Conferma invio al mittente\n                            <select id=\"ti-config-comm-confirm-1591\" class=\"ti-in\" style=\"width:100%;margin-top:5px;\">\n                                <option value=\"none\" selected>Nessuna<\/option><option value=\"email\">Email<\/option><option value=\"sms\">SMS<\/option>\n                            <\/select>\n                        <\/label>\n                    <\/div>\n                    <div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:10px;\">\n                        <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Mittente\n                            <input id=\"ti-config-comm-sender-1591\" class=\"ti-in\" type=\"text\" readonly style=\"width:100%;margin-top:5px;background:#111827;\" value=\"\">\n                            <span id=\"ti-config-comm-sender-note-1591\" style=\"display:block;color:#93c5fd;font-size:10px;font-weight:400;margin-top:4px;\"><\/span>\n                        <\/label>\n                        <label id=\"ti-config-comm-subject-wrap-1591\" style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Oggetto\n                            <input id=\"ti-config-comm-subject-1591\" class=\"ti-in\" type=\"text\" maxlength=\"180\" style=\"width:100%;margin-top:5px;\" value=\"Comunicazione Shop & Service\">\n                        <\/label>\n                    <\/div>\n                    <div id=\"ti-config-comm-filter-1602\" style=\"display:grid;grid-template-columns:minmax(170px,.7fr) minmax(260px,1.3fr);gap:10px;align-items:end;padding:10px;border:1px solid #334155;border-radius:9px;background:#0f172a;\">\n                        <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Seleziona contatti da\n                            <select id=\"ti-config-comm-scope-1602\" class=\"ti-in\" style=\"width:100%;margin-top:5px;\" onchange=\"return window.searchConfigCommContacts1602 ? window.searchConfigCommContacts1602() : false;\">\n                                <option value=\"all\" selected>Tutti<\/option><option value=\"utenti\">Utenti<\/option><option value=\"operatori\">Operatori<\/option>\n                            <\/select>\n                        <\/label>\n                        <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Ricerca contatti\n                            <span style=\"display:flex;gap:6px;align-items:center;margin-top:5px;\">\n                                <input id=\"ti-config-comm-search-1602\" class=\"ti-in\" type=\"text\" style=\"width:100%;min-width:0;\" placeholder=\"Nome, username, email o GSM\" onkeydown=\"if(event.key==='Enter'){event.preventDefault();return window.searchConfigCommContacts1602 ? window.searchConfigCommContacts1602() : false;}\">\n                                <button type=\"button\" id=\"ti-config-comm-search-btn-1602\" class=\"ti-btn\" title=\"Avvia ricerca\" aria-label=\"Avvia ricerca\" style=\"background:#2563eb;color:#fff;min-width:42px;padding:7px 10px;font-size:18px;line-height:1;\" onclick=\"return window.searchConfigCommContacts1602 ? window.searchConfigCommContacts1602() : false;\">\ud83d\udd0d<\/button>\n                            <\/span>\n                        <\/label>\n                        <div id=\"ti-config-comm-filter-note-1602\" style=\"grid-column:1\/-1;color:#93c5fd;font-size:10.5px;line-height:1.35;\">La ricerca rispetta la selezione Tutti\/Utenti\/Operatori. Destinatario e CC sono liste indipendenti: puoi selezionare contemporaneamente voci in entrambe.<\/div>\n                    <\/div>\n                    <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px;\" class=\"ti-config-comm-rec-grid-1591\">\n                        <div>\n                            <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Destinatario\/i<\/label>\n                            <div id=\"ti-config-comm-to-1591\" class=\"ti-in ti-config-comm-checklist-1609\" data-ti-recipient-role=\"to\" role=\"group\" aria-label=\"Destinatari\" style=\"width:100%;margin-top:5px;height:145px;overflow:auto;padding:6px;background:#020617;border:1px solid #475569;border-radius:6px;\"><\/div>\n                            <input id=\"ti-config-comm-manual-to-1591\" class=\"ti-in\" type=\"text\" style=\"width:100%;margin-top:6px;\" placeholder=\"Digita Email\/GSM manualmente; separa con ;\">\n                        <\/div>\n                        <div>\n                            <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">CC \/ altri destinatari<\/label>\n                            <div id=\"ti-config-comm-cc-1591\" class=\"ti-in ti-config-comm-checklist-1609\" data-ti-recipient-role=\"cc\" role=\"group\" aria-label=\"CC \/ altri destinatari\" style=\"width:100%;margin-top:5px;height:145px;overflow:auto;padding:6px;background:#020617;border:1px solid #475569;border-radius:6px;\"><\/div>\n                            <input id=\"ti-config-comm-manual-cc-1591\" class=\"ti-in\" type=\"text\" style=\"width:100%;margin-top:6px;\" placeholder=\"Digita Email\/GSM CC manualmente; separa con ;\">\n                        <\/div>\n                    <\/div>\n                    <div id=\"ti-config-comm-rec-note-1603\" style=\"margin-top:-4px;padding:7px 9px;border-radius:7px;background:#082f49;border:1px solid #0ea5e9;color:#e0f2fe;font-size:10.5px;line-height:1.35;\">Destinatario e CC sono indipendenti: puoi selezionare contemporaneamente uno o piu destinatari e uno o piu CC nello stesso invio.<\/div>\n                    <label style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Testo\n                        <textarea id=\"ti-config-comm-message-1591\" class=\"ti-in\" rows=\"8\" maxlength=\"12000\" style=\"width:100%;margin-top:5px;resize:vertical;min-height:150px;\" placeholder=\"Scrivi il testo del messaggio...\"><\/textarea>\n                    <\/label>\n                    <label id=\"ti-config-comm-files-wrap-1591\" style=\"color:#e5e7eb;font-size:12px;font-weight:700;\">Allegati Email\n                        <input id=\"ti-config-comm-files-1591\" type=\"file\" multiple style=\"display:block;width:100%;margin-top:6px;color:#e5e7eb;background:#111827;border:1px solid #334155;border-radius:8px;padding:8px;\">\n                        <span style=\"display:block;color:#94a3b8;font-size:10px;font-weight:400;margin-top:4px;\">Massimo 5 file, 10 MB ciascuno, 20 MB totali. Gli allegati non sono disponibili per SMS.<\/span>\n                    <\/label>\n                <\/div>\n                <div style=\"position:sticky;bottom:0;z-index:3;display:flex;justify-content:flex-end;gap:8px;flex-wrap:wrap;background:#111827;border-top:1px solid #334155;padding:11px 14px;\">\n                    <button type=\"button\" class=\"ti-btn\" style=\"background:#475569;color:#fff;\" onclick=\"return window.closeConfigComm1591 ? window.closeConfigComm1591() : false;\">Chiudi<\/button>\n                    <button type=\"button\" id=\"ti-config-comm-send-1591\" class=\"ti-btn\" style=\"background:#059669;color:#fff;font-weight:800;\" onclick=\"return window.sendConfigComm1591 ? window.sendConfigComm1591() : false;\">Invia<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <script>\n        \/\/ 30.9.1591 - form Email\/SMS Configurazione.\n        (function(){\n            'use strict';\n            window.__tiConfigCommMeta1591 = null;\n            window.__tiConfigCommBusy1591 = false;\n            window.__tiConfigCommNonce1591 = \"e6a1560060\";\n            window.__tiConfigCommSelected1602 = {to:new Set(), cc:new Set()};\n            window.__tiConfigCommSearch1602 = '';\n            window.__tiConfigCommLastChannel1602 = 'email';\n\n            function el(id){ return document.getElementById(id); }\n            function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#039;'}[c];}); }\n            function db1591(){ var s=el('ti-ditta'); return s ? String(s.value||'').trim() : ''; }\n            function status1591(msg, kind){ var h=el('ti-config-comm-status-1591'); if(!h)return; h.style.display=msg?'block':'none'; h.style.borderColor=kind==='err'?'#ef4444':(kind==='ok'?'#22c55e':'#334155'); h.style.color=kind==='err'?'#fecaca':(kind==='ok'?'#bbf7d0':'#bfdbfe'); h.innerHTML=msg||''; }\n            function lang1591(){ return String(window.currLang||'it').toLowerCase()==='en'?'en':'it'; }\n            function t1591(it,en){ return lang1591()==='en'?en:it; }\n            function jsonCall1591(fd){\n                var url=window.tiAjaxUrl||window.ajaxurl||window.tiUrl||window.location.href;\n                if(window.fetchJsonSafe) return window.fetchJsonSafe(url,{method:'POST',body:fd,credentials:'same-origin'});\n                return fetch(url,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();});\n            }\n            function payloadData1591(res){ return res && res.data ? res.data : res; }\n            function errorText1591(res){ var d=payloadData1591(res); if(typeof d==='string')return d; return (d&&d.message)||(d&&d.reply)||(res&&res.message)||t1591('Operazione non riuscita.','Operation failed.'); }\n            function normalizeSmsContact1611(v){\n                v=String(v==null?'':v).trim();if(!v)return '';\n                var m=v.match(\/(?:\\+|00)?[0-9][0-9\\s().-]{6,20}[0-9]\/);if(m&&m[0])v=String(m[0]);\n                v=v.replace(\/[\\s().-]+\/g,'');\n                if(v.indexOf('00')===0)v='+'+v.slice(2);\n                var plus=v.charAt(0)==='+';var d=v.replace(\/\\D+\/g,'');if(!d)return '';\n                if(!plus){if(d.indexOf('39')===0&&d.length>=10){}else if(d.length>=8&&d.length<=10)d='39'+d;}\n                if(d.length<8||d.length>15)return '';\n                return '+'+d;\n            }\n\n            \/\/ 30.9.1612 - ricostruisce i contatti direttamente dallo stato corrente della Configurazione.\n            \/\/ Ogni recapito appartiene esclusivamente alla riga che lo contiene; nessun valore viene\n            \/\/ ereditato\/coperto da un altra anagrafica. Se le tabelle locali sono disponibili, sono\n            \/\/ autorevoli anche per modifiche correnti non ancora salvate nel JSON fisico.\n            function fieldKindComm1612(k){\n                var n=norm1602(k).replace(\/[^a-z0-9]+\/g,'');\n                if(!n)return '';\n                if(\/email|emailaddress|mail|mailaddress|pec|postaelettronica\/.test(n))return 'email';\n                if(\/gsm|cellulare|mobile|telefono|tel|phone|whatsapp|cell\/.test(n))return 'phone';\n                return '';\n            }\n            function directRowVal1612(row,names){\n                if(!row||typeof row!=='object')return '';\n                var keys=Object.keys(row);\n                for(var i=0;i<names.length;i++){\n                    var wn=norm1602(names[i]).trim();\n                    for(var j=0;j<keys.length;j++){\n                        if(norm1602(keys[j]).trim()!==wn)continue;\n                        var v=row[keys[j]];return (v==null||typeof v==='object')?'':String(v).trim();\n                    }\n                }\n                return '';\n            }\n            function extractEmailsComm1612(v){\n                var m=String(v==null?'':v).match(\/[A-Z0-9._%+\\-]+@[A-Z0-9.\\-]+\\.[A-Z]{2,}\/ig)||[];\n                var seen=new Set(),out=[];m.forEach(function(x){x=String(x).trim();var k=x.toLowerCase();if(x&& !seen.has(k)){seen.add(k);out.push(x);}});return out;\n            }\n            function extractPhonesComm1612(v){\n                var parts=String(v==null?'':v).split(\/[;\\r\\n,|]+\/),seen=new Set(),out=[];\n                parts.forEach(function(p){var n=normalizeSmsContact1611(p);if(!n||seen.has(n))return;seen.add(n);out.push(n);});return out;\n            }\n            function currentConfigContacts1612(){\n                var db=window.currentDbData;\n                if(!db||!db.Tabelle||typeof db.Tabelle!=='object')return {available:false,contacts:[]};\n                var out=[],hasTable=false;\n                ['Utenti','Operatori'].forEach(function(logical){\n                    var real=Object.keys(db.Tabelle).find(function(k){return norm1602(k).trim()===norm1602(logical).trim();});\n                    if(!real||!Array.isArray(db.Tabelle[real]))return;hasTable=true;\n                    db.Tabelle[real].forEach(function(row,idx){\n                        if(!row||typeof row!=='object')return;\n                        var stato=directRowVal1612(row,['Stato','Status']);if(\/^cancellato$\/i.test(stato))return;\n                        var username=directRowVal1612(row,['Username','user','Login','Utente login']);\n                        var nome=directRowVal1612(row,['Utente','Operatore','Nome visualizzato','Display','Nominativo','Nome']);\n                        var cognome=directRowVal1612(row,['Cognome']);\n                        var label=(nome+' '+cognome).trim()||username||(logical+' riga '+(idx+1));\n                        Object.keys(row).forEach(function(field){\n                            var raw=row[field];if(raw==null||typeof raw==='object'||String(raw).trim()==='')return;\n                            var kind=fieldKindComm1612(field);\n                            if(kind==='email')extractEmailsComm1612(raw).forEach(function(mail){out.push({table:logical,row:idx,username:username,label:label,email:mail,phone:'',field:field,kind:'email'});});\n                            if(kind==='phone')extractPhonesComm1612(raw).forEach(function(phone){out.push({table:logical,row:idx,username:username,label:label,email:'',phone:phone,field:field,kind:'phone'});});\n                        });\n                    });\n                });\n                return {available:hasTable,contacts:out};\n            }\n            function applyCurrentConfigContacts1612(meta){\n                meta=meta||{};var local=currentConfigContacts1612();\n                if(local.available){meta.contacts=local.contacts;meta.contacts_source='config_current_1612';}\n                return meta;\n            }\n\n            function selectedValues1591(sel,channel){\n                if(!sel)return [];\n                var vals=[];\n                if(sel.tagName==='SELECT') vals=Array.from(sel.selectedOptions||[]).map(function(o){return String((o.dataset&&o.dataset.contact)||o.value||'').trim();});\n                else vals=Array.from(sel.querySelectorAll('input[type=\"checkbox\"][data-contact]:checked')).map(function(o){return String((o.dataset&&o.dataset.contact)||o.value||'').trim();});\n                vals=vals.filter(Boolean);\n                if(String(channel||'').toLowerCase()==='sms') vals=vals.map(normalizeSmsContact1611).filter(Boolean);\n                return Array.from(new Set(vals));\n            }\n            function syncActivity1591(activity){\n                try{\n                    if(!activity||!activity.table||!activity.row)return;\n                    [window.currentDbData,window.configOriginalDbData,window.currentDbViewData].forEach(function(db){\n                        if(!db||!db.Tabelle||!Array.isArray(db.Tabelle[activity.table]))return;\n                        var row=JSON.parse(JSON.stringify(activity.row));\n                        var idKey=Object.keys(row).find(function(k){return \/^id$\/i.test(String(k));});\n                        var id=idKey?String(row[idKey]||''):'';\n                        if(id && db.Tabelle[activity.table].some(function(r){return r&&idKey&&String(r[idKey]||'')===id;}))return;\n                        db.Tabelle[activity.table].push(row);\n                    });\n                }catch(e){}\n            }\n            function norm1602(v){ return String(v == null ? '' : v).toLowerCase().normalize ? String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'') : String(v == null ? '' : v).toLowerCase(); }\n            function selectionState1602(){\n                if(!window.__tiConfigCommSelected1602 || !window.__tiConfigCommSelected1602.to || !window.__tiConfigCommSelected1602.cc) window.__tiConfigCommSelected1602={to:new Set(),cc:new Set()};\n                return window.__tiConfigCommSelected1602;\n            }\n            function captureSelect1602(sel,set){\n                if(!sel||!set)return;\n                if(sel.tagName==='SELECT'){\n                    Array.from(sel.options||[]).forEach(function(o){\n                        var key=String((o.dataset&&o.dataset.selkey)||o.value||'').trim();\n                        if(!key)return;\n                        if(o.selected)set.add(key);else set.delete(key);\n                    });\n                    return;\n                }\n                Array.from(sel.querySelectorAll('input[type=\"checkbox\"][data-selkey]')).forEach(function(o){\n                    var key=String((o.dataset&&o.dataset.selkey)||'').trim();\n                    if(!key)return;\n                    if(o.checked)set.add(key);else set.delete(key);\n                });\n            }\n            window.captureConfigCommSelections1602=function(){\n                var st=selectionState1602(); \/* 1603: Destinatario e CC restano due insiemi indipendenti e possono coesistere. *\/ captureSelect1602(el('ti-config-comm-to-1591'),st.to);captureSelect1602(el('ti-config-comm-cc-1591'),st.cc);return st;\n            };\n            function contactScopeMatch1602(c,scope){\n                if(scope==='all'||!scope)return true;\n                var t=norm1602(c&&c.table||'');\n                if(scope==='utenti')return t.indexOf('utent')>=0;\n                if(scope==='operatori')return t.indexOf('operator')>=0;\n                return true;\n            }\n            function contactSearchMatch1602(c,val,q){\n                q=norm1602(q).trim();if(!q)return true;\n                var hay=norm1602([(c&&c.label)||'',(c&&c.username)||'',(c&&c.table)||'',(c&&c.email)||'',(c&&c.phone)||'',val||''].join(' '));\n                return q.split(\/\\s+\/).filter(Boolean).every(function(tok){return hay.indexOf(tok)>=0;});\n            }\n            function fillSelects1591(){\n                var meta=window.__tiConfigCommMeta1591||{};\n                var ch=(el('ti-config-comm-channel-1591')||{}).value||'email';\n                var to=el('ti-config-comm-to-1591'), cc=el('ti-config-comm-cc-1591');\n                if(!to||!cc)return;\n                var st=window.captureConfigCommSelections1602 ? window.captureConfigCommSelections1602() : selectionState1602();\n                if(window.__tiConfigCommLastChannel1602 && window.__tiConfigCommLastChannel1602!==ch){st.to.clear();st.cc.clear();}\n                window.__tiConfigCommLastChannel1602=ch;\n                var scope=String((el('ti-config-comm-scope-1602')||{}).value||'all').toLowerCase();\n                var q=String(window.__tiConfigCommSearch1602||'').trim();\n                to.innerHTML=''; cc.innerHTML='';\n                var matched=0;\n                function contactKey1608(c,val){\n                    return [String((c&&c.table)||''),String((c&&c.row)!=null?c.row:''),String((c&&c.kind)||ch),String((c&&c.field)||''),String(val||'')].join('|');\n                }\n                function addOpt(sel,set,c,val,label,match,role){\n                    if(!val)return;\n                    var key=contactKey1608(c,val);\n                    if(!match && !set.has(key))return; \/\/ le selezioni precedenti restano visibili\/incluse.\n                    var row=document.createElement('label');\n                    row.style.cssText='display:flex;align-items:flex-start;gap:7px;padding:5px 4px;border-bottom:1px solid #1f2937;color:#e5e7eb;font-size:11px;line-height:1.3;cursor:pointer;white-space:normal;';\n                    var o=document.createElement('input');\n                    o.type='checkbox';o.value=val;o.dataset.contact=val;o.dataset.selkey=key;o.dataset.recipientRole=role||'';o.checked=set.has(key);o.style.cssText='margin:1px 0 0 0;flex:0 0 auto;';\n                    var txt=document.createElement('span');txt.textContent=label+(match?'':' \u00b7 '+t1591('selezionato','selected'));txt.style.cssText='min-width:0;overflow-wrap:anywhere;';\n                    o.addEventListener('change',function(){if(o.checked)set.add(key);else set.delete(key);});\n                    row.appendChild(o);row.appendChild(txt);sel.appendChild(row);\n                }\n                (meta.contacts||[]).forEach(function(c){\n                    var val=ch==='email'?String(c.email||'').trim():String(c.phone||'').trim();\n                    if(!val)return;\n                    var match=contactScopeMatch1602(c,scope)&&contactSearchMatch1602(c,val,q);\n                    if(match)matched++;\n                    var label=(c.label||c.username||c.table||'Contatto')+' - '+val+' ['+(c.table||'')+(c.field?(' \u00b7 '+c.field):'')+']';\n                    \/\/ 30.9.1608: NON deduplicare per solo recapito. Due persone con la stessa Email\/GSM\n                    \/\/ devono restare due voci distinte e selezionabili nell elenco.\n                    addOpt(to,st.to,c,val,label,match,'to');addOpt(cc,st.cc,c,val,label,match,'cc');\n                });\n                var note=el('ti-config-comm-filter-note-1602');\n                if(note)note.textContent=t1591((ch==='email'?'Email disponibili nel filtro: ':'GSM\/Tel disponibili nel filtro: '),(ch==='email'?'Emails available in filter: ':'Mobile\/phone numbers available in filter: '))+matched+'. '+t1591('Sono mostrati solo Utenti\/Operatori che possiedono il recapito nella propria riga. Nessun recapito viene propagato ad altre anagrafiche.','Only Users\/Operators that have the contact in their own row are shown. No contact is propagated to other records.');\n            }\n            window.searchConfigCommContacts1602=function(){\n                try{window.captureConfigCommSelections1602&&window.captureConfigCommSelections1602();}catch(e){}\n                window.__tiConfigCommSearch1602=String((el('ti-config-comm-search-1602')||{}).value||'').trim();\n                fillSelects1591();\n                return false;\n            };\n            window.refreshConfigComm1591=function(){\n                var meta=window.__tiConfigCommMeta1591||{};\n                var ch=(el('ti-config-comm-channel-1591')||{}).value||'email';\n                var sender=meta.sender||{};\n                var senderVal=ch==='email'?String(sender.email||''):String(sender.phone||'');\n                var se=el('ti-config-comm-sender-1591'); if(se)se.value=senderVal;\n                var note=el('ti-config-comm-sender-note-1591');\n                if(note){\n                    if(ch==='sms') note.textContent=t1591('Mittente logico: GSM dell utente loggato. Il gateway usa il sender SMS autorizzato configurato.','Logical sender: logged-in user mobile number. The gateway uses the configured authorized SMS sender.');\n                    else note.textContent=t1591('Mittente: Email dell utente Shop & Service loggato.','Sender: email of the logged-in Shop & Service user.');\n                }\n                var sw=el('ti-config-comm-subject-wrap-1591'); if(sw)sw.style.display=ch==='email'?'block':'none';\n                var fw=el('ti-config-comm-files-wrap-1591'); if(fw)fw.style.display=ch==='email'?'block':'none';\n                var fi=el('ti-config-comm-files-1591'); if(fi)fi.disabled=ch!=='email';\n                var mt=el('ti-config-comm-manual-to-1591'), mc=el('ti-config-comm-manual-cc-1591');\n                if(mt)mt.placeholder=ch==='email'?t1591('Digita Email manualmente; separa con ;','Type email manually; separate with ;'):t1591('Digita GSM manualmente; separa con ;','Type mobile number manually; separate with ;');\n                if(mc)mc.placeholder=ch==='email'?t1591('Digita Email CC manualmente; separa con ;','Type CC email manually; separate with ;'):t1591('Digita GSM aggiuntivi manualmente; separa con ;','Type additional mobile numbers manually; separate with ;');\n                fillSelects1591();\n            };\n            window.closeConfigComm1591=function(){\n                var ov=el('ti-config-comm-ov-1591'); if(ov){ov.style.display='none';ov.style.visibility='hidden';ov.style.opacity='0';}\n                status1591('');\n                return false;\n            };\n            window.openConfigComm1591=function(ev){\n                try{if(ev){ev.preventDefault();ev.stopPropagation();}}catch(e){}\n                var db=db1591();\n                if(!db||db==='NEW_DB'||db==='Global'||db==='shopservicemain.json'){ if(window.tiAlert)window.tiAlert(t1591('Seleziona una ditta valida.','Select a valid company.')); return false; }\n                var ov=el('ti-config-comm-ov-1591'); if(!ov)return false;\n                ov.style.display='flex';ov.style.visibility='visible';ov.style.opacity='1';\n                var ch=el('ti-config-comm-channel-1591'); if(ch)ch.value='email';\n                window.__tiConfigCommSelected1602={to:new Set(),cc:new Set()};window.__tiConfigCommSearch1602='';window.__tiConfigCommLastChannel1602='email';\n                var sc1602=el('ti-config-comm-scope-1602');if(sc1602)sc1602.value='all';var sr1602=el('ti-config-comm-search-1602');if(sr1602)sr1602.value='';\n                var cf=el('ti-config-comm-confirm-1591'); if(cf)cf.value='none';\n                var subj=el('ti-config-comm-subject-1591'); if(subj)subj.value=t1591('Comunicazione Shop & Service','Shop & Service communication');\n                var msg=el('ti-config-comm-message-1591'); if(msg)msg.value='';\n                var mto=el('ti-config-comm-manual-to-1591'); if(mto)mto.value='';\n                var mcc=el('ti-config-comm-manual-cc-1591'); if(mcc)mcc.value='';\n                var files=el('ti-config-comm-files-1591'); if(files)files.value='';\n                status1591(t1591('Lettura mittente e contatti...','Loading sender and contacts...'));\n                var fd=new FormData();fd.append('action','ti_ai_config_email_sms_1591');fd.append('ti_action','ti_ai_config_email_sms_1591');fd.append('mode','meta');fd.append('db',db);fd.append('nonce',window.__tiConfigCommNonce1591||'');\n                jsonCall1591(fd).then(function(res){\n                    if(!res||res.success===false){status1591(esc(errorText1591(res)),'err');return;}\n                    var d=payloadData1591(res)||{};d=applyCurrentConfigContacts1612(d);window.__tiConfigCommMeta1591=d;\n                    window.refreshConfigComm1591();\n                    var s=d.sender||{};\n                    var missing=[];if(!s.email)missing.push('Email');if(!s.phone)missing.push('GSM');\n                    status1591((missing.length?t1591('Contatti mittente mancanti: ','Missing sender contacts: ')+esc(missing.join(', '))+'. ':'')+t1591('Seleziona il canale, i destinatari e scrivi il testo.','Select channel, recipients and type the message.'),missing.length?'warn':'ok');\n                    try{if(msg)msg.focus();}catch(e){}\n                }).catch(function(e){status1591(esc((e&&e.message)||e||t1591('Errore di rete.','Network error.')),'err');});\n                return false;\n            };\n            window.sendConfigComm1591=function(){\n                if(window.__tiConfigCommBusy1591)return false;\n                var meta=window.__tiConfigCommMeta1591||{};\n                var db=db1591();\n                var ch=(el('ti-config-comm-channel-1591')||{}).value||'email';\n                var sender=meta.sender||{};\n                try{window.captureConfigCommSelections1602&&window.captureConfigCommSelections1602();}catch(e){}\n                var to=selectedValues1591(el('ti-config-comm-to-1591'),ch);\n                var ccNow1611=selectedValues1591(el('ti-config-comm-cc-1591'),ch);\n                var manualTo=String((el('ti-config-comm-manual-to-1591')||{}).value||'').trim();\n                var message=String((el('ti-config-comm-message-1591')||{}).value||'').trim();\n                if(ch==='email'&&!sender.email){if(window.tiAlert)window.tiAlert(t1591('Email mittente non presente nell anagrafica dell utente loggato.','Sender email is missing from the logged-in user profile.'));return false;}\n                if(ch==='sms'&&!sender.phone){if(window.tiAlert)window.tiAlert(t1591('GSM mittente non presente nell anagrafica dell utente loggato.','Sender mobile number is missing from the logged-in user profile.'));return false;}\n                if(!to.length&&!manualTo){if(window.tiAlert)window.tiAlert(t1591('Seleziona o digita almeno un destinatario.','Select or type at least one recipient.'));return false;}\n                if(!message){if(window.tiAlert)window.tiAlert(t1591('Inserisci il testo del messaggio.','Enter the message text.'));return false;}\n                var files=el('ti-config-comm-files-1591');\n                if(ch==='sms'&&files&&files.files&&files.files.length){if(window.tiAlert)window.tiAlert(t1591('Gli allegati sono disponibili solo per Email.','Attachments are available only for Email.'));return false;}\n                if(files&&files.files&&files.files.length>5){if(window.tiAlert)window.tiAlert(t1591('Massimo 5 allegati per invio.','Maximum 5 attachments per send.'));return false;}\n                var total=0;if(files&&files.files)Array.from(files.files).forEach(function(f){total+=Number(f.size||0);});\n                if(total>20*1024*1024){if(window.tiAlert)window.tiAlert(t1591('Dimensione totale allegati superiore a 20 MB.','Total attachment size exceeds 20 MB.'));return false;}\n                window.__tiConfigCommBusy1591=true;\n                var send=el('ti-config-comm-send-1591');if(send){send.disabled=true;send.textContent=t1591('Invio...','Sending...');}\n                status1591(t1591('Invio in corso...','Sending...'));\n                var fd=new FormData();fd.append('action','ti_ai_config_email_sms_1591');fd.append('ti_action','ti_ai_config_email_sms_1591');fd.append('mode','send');fd.append('db',db);fd.append('nonce',window.__tiConfigCommNonce1591||'');fd.append('channel',ch);fd.append('confirm_channel',(el('ti-config-comm-confirm-1591')||{}).value||'none');fd.append('subject',String((el('ti-config-comm-subject-1591')||{}).value||''));fd.append('message',message);fd.append('to_selected',JSON.stringify(to));fd.append('cc_selected',JSON.stringify(ccNow1611));fd.append('manual_to',manualTo);fd.append('manual_cc',String((el('ti-config-comm-manual-cc-1591')||{}).value||''));\n                if(ch==='email'&&files&&files.files)Array.from(files.files).forEach(function(f){fd.append('attachments[]',f,f.name);});\n                jsonCall1591(fd).then(function(res){\n                    window.__tiConfigCommBusy1591=false;if(send){send.disabled=false;send.textContent=t1591('Invia','Send');}\n                    if(!res||res.success===false){var er=errorText1591(res);status1591(esc(er),'err');if(window.tiAlert)window.tiAlert(esc(er));return;}\n                    var d=payloadData1591(res)||{};syncActivity1591(d.activity||null);\n                    var reply=String(d.reply||t1591('Invio completato.','Sending completed.'));\n                    status1591(esc(reply),d.status==='partial'?'warn':'ok');\n                    window.closeConfigComm1591();\n                    if(window.tiAlert)window.tiAlert('<b>'+t1591('Invio completato','Sending completed')+'<\/b><br><br>'+esc(reply));\n                }).catch(function(e){\n                    window.__tiConfigCommBusy1591=false;if(send){send.disabled=false;send.textContent=t1591('Invia','Send');}\n                    var er=(e&&e.message)||String(e||t1591('Errore di rete.','Network error.'));status1591(esc(er),'err');if(window.tiAlert)window.tiAlert(esc(er));\n                });\n                return false;\n            };\n            document.addEventListener('keydown',function(ev){if(ev.key==='Escape'){var ov=el('ti-config-comm-ov-1591');if(ov&&ov.style.display!=='none'&&!window.__tiConfigCommBusy1591)window.closeConfigComm1591();}});\n        })();\n        <\/script>\n\n        <div id=\"ti-conf-import-preview-ov\" class=\"ti-ov\">\n            <div class=\"ti-modal\" style=\"width:90%;max-width:760px;text-align:left;\">\n                <h3 style=\"color:#fff;margin-top:0;border-bottom:1px solid #444;padding-bottom:10px;\">Anteprima modifiche import AI<\/h3>\n                <div style=\"font-size:12px;color:#9ca3af;margin-bottom:10px;\">Controlla l'anteprima delle modifiche. L'elenco non verr\u00e0 letto vocalmente. Nessun dato viene salvato finche non premi OK Conferma e salva oppure scrivi CONFERMA IMPORT.<\/div>\n                <div id=\"ti-conf-import-preview-last-update\" style=\"display:none;margin-top:10px;padding:8px 10px;border-radius:8px;border:1px solid #22c55e;background:#052e16;color:#bbf7d0;font-size:12px;font-weight:700;\"><\/div>\n                <div id=\"ti-conf-import-preview-body\" style=\"display:block;margin-top:10px;background:#000;padding:12px;border-radius:8px;border:1px solid #374151;color:#e5e7eb;white-space:normal;\"><\/div>\n                <div id=\"ti-conf-import-refine-box\" style=\"margin-top:12px;padding:10px;border-radius:8px;border:1px solid #1d4ed8;background:#0f172a;\">\n                    <label for=\"ti-conf-import-refine-prompt\" style=\"display:block;font-size:12px;color:#bfdbfe;font-weight:700;margin-bottom:6px;\">Raffina import con AI sulla base della prima anteprima<\/label>\n                    <textarea id=\"ti-conf-import-refine-prompt\" class=\"ti-in\" rows=\"3\" style=\"width:100%;min-height:70px;resize:vertical;\" placeholder=\"Es: usa il prezzo medio del range, sposta il principio attivo nella descrizione, elimina righe duplicate, normalizza categorie...\"><\/textarea>\n                    <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;align-items:center;\">\n                        <button type=\"button\" id=\"ti-conf-import-refine-btn\" class=\"ti-btn\" style=\"background:#2563eb;\" onclick=\"window.refineConfigImportPreview()\">Raffina anteprima con AI<\/button>\n                        <span id=\"ti-conf-import-refine-status\" style=\"font-size:12px;color:#93c5fd;\"><\/span>\n                    <\/div>\n                <\/div>\n                <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;\">\n                    <button type=\"button\" class=\"ti-btn ti-btn-ok\" onclick=\"window.confirmConfigImportPreview()\">OK Conferma e salva import<\/button>\n                    <button type=\"button\" class=\"ti-btn ti-btn-x\" onclick=\"window.cancelConfigImportPreview()\">X Annulla import<\/button>\n                    <button type=\"button\" class=\"ti-btn\" onclick=\"window.closeConfigImportPreview()\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-file-manager-ov\" class=\"ti-ov ti-closable-ov\" style=\"z-index: 1001 !important;\">\n            <div class=\"ti-modal\" style=\"width:90%; max-width:600px;\">\n                <h3 style=\"color:#fff;margin-top:0;border-bottom:1px solid #444;padding-bottom:10px;\">Gestione File Associati<\/h3>\n                <div id=\"fm-element-description\" style=\"display:none;margin:0 0 10px 0;padding:10px 12px;border-radius:10px;background:#0f172a;border:1px solid #2563eb;color:#dbeafe;font-size:13px;line-height:1.45;text-align:left;\"><\/div>\n                <div id=\"fm-storage-path\" style=\"display:none;margin:0 0 10px 0;padding:8px 10px;border-radius:8px;background:#020617;border:1px solid #334155;color:#bfdbfe;font-size:11px;word-break:break-all;\"><\/div>\n                <div id=\"fm-grid\" class=\"ti-file-grid\"><\/div>\n                <div id=\"ti-fm-native-wrap-617\" class=\"ti-native-upload-617\" style=\"margin-top:20px;\">\n                    <div class=\"ti-native-upload-row-617\">\n                        <input type=\"file\" id=\"ti-fm-native-file-617\" class=\"ti-native-file-617\" aria-label=\"Scegli file\" style=\"position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;\" tabindex=\"-1\" aria-hidden=\"true\" \/>\n                        <button type=\"button\" id=\"ti-fm-native-upload-btn-617\" class=\"ti-btn\" style=\"background:#2563eb;\" onclick=\"window.tiNativeUpload617 && window.tiNativeUpload617('manager'); return false;\">\ud83d\udcc1 Aggiungi file<\/button>\n                        <button type=\"button\" class=\"ti-btn\" style=\"background:#8b5cf6;\" onclick=\"window.chooseAIManager()\">\ud83e\udd16 Genera con AI<\/button>\n                    <\/div>\n                    <div id=\"ti-fm-native-status-617\" class=\"ti-native-status-617\"><\/div>\n                <\/div>\n                <div id=\"ti-fm-draft-status-1596\" style=\"display:block;margin-top:10px;padding:8px 10px;border-radius:8px;border:1px solid #334155;background:#020617;color:#cbd5e1;font-size:11px;line-height:1.4;text-align:left;\">Le associazioni vengono salvate solo premendo <b>Salva<\/b>. Chiudi non salva le modifiche.<\/div>\n                <div style=\"display:flex;gap:8px;align-items:center;margin-top:10px;\">\n                    <button type=\"button\" id=\"ti-fm-save-1596\" onclick=\"return window.saveFileManagerAssociations1596 ? window.saveFileManagerAssociations1596() : false;\" class=\"ti-btn\" style=\"flex:1;background:#059669;font-weight:800;\">Salva<\/button>\n                    <button type=\"button\" onclick=\"return window.closeFileManager1596 ? window.closeFileManager1596() : (window.closeModal('ti-file-manager-ov'), false);\" class=\"ti-btn btn-close\" style=\"flex:1;background:#4b5563;\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-login-ov\" class=\"ti-ov ti-closable-ov\">\n            <div class=\"ti-modal\">\n                <h3 id=\"lbl-login\" style=\"color:#fff;margin-top:0;\">Accedi<\/h3>\n                                <form id=\"ti-login-form\" autocomplete=\"on\" method=\"post\">\n                    <input type=\"hidden\" name=\"ti_action\" value=\"ti_ai_login\">\n                    <input type=\"hidden\" name=\"action\" value=\"ti_ai_login\">\n                    <input type=\"hidden\" name=\"ti_mobile_login_redirect\" value=\"1\">\n                    <input type=\"hidden\" id=\"l-db-hidden\" name=\"db\" value=\"\">\n                    <input id=\"l-user\" name=\"username\" class=\"ti-in\" placeholder=\"Username\" autocomplete=\"username\" data-ti-login-username=\"1\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\" inputmode=\"text\">\n                    <input id=\"l-pass\" name=\"password\" class=\"ti-in\" type=\"password\" placeholder=\"Password\" autocomplete=\"current-password\" data-ti-login-password=\"1\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\">\n                    <select id=\"l-db\" name=\"db_select\" class=\"ti-in\" aria-label=\"Ditta\" style=\"margin-top:8px; display:block;\">\n                        <option value=\"\">-- Scegli una ditta --<\/option>\n                                                    <option value=\"bmw-terni.json\" >bmw-terni<\/option>\n                                                    <option value=\"catering-terni.json\" >catering-terni<\/option>\n                                                    <option value=\"Dev_sstest.json\" >Dev_sstest<\/option>\n                                                    <option value=\"farmaciaterni.json\" >farmaciaterni<\/option>\n                                                    <option value=\"ferramentaterni.json\" >ferramentaterni<\/option>\n                                                    <option value=\"filatelico.json\" >filatelico<\/option>\n                                                    <option value=\"fioraio.json\" >fioraio<\/option>\n                                                    <option value=\"hairstyle.json\" >hairstyle<\/option>\n                                                    <option value=\"hard&amp;soft.json\" >hard&amp;soft<\/option>\n                                                    <option value=\"ristoranteterni.json\" >ristoranteterni<\/option>\n                                                    <option value=\"termoidraulica-italiana.json\" >termoidraulica-italiana<\/option>\n                                            <\/select>\n                    <button type=\"submit\" id=\"l-do\" class=\"ti-btn\" style=\"width:100%; min-height:44px; padding:10px 14px; background:#3b82f6; margin-top:10px;\">Accedi<\/button>\n                <\/form>\n                <button type=\"button\" id=\"ti-forgot-password-btn\" class=\"ti-btn ti-forgot-password-wide\" style=\"width:100%; min-width:260px; min-height:44px; padding:10px 14px; margin-top:8px; background:#4b5563; color:#fff; font-size:12px; line-height:1.25; white-space:normal;\" onclick=\"if(window.tiForgotPasswordFromLogin) window.tiForgotPasswordFromLogin('modal'); return false;\">Password dimenticata? Cambia tramite email<\/button>\n                <button type=\"button\" id=\"ti-show-direct-login-fallback\" class=\"ti-btn\" style=\"width:100%; margin-top:8px; background:#374151; color:#fff; font-size:12px;\" onclick=\"if(window.revealDirectLoginFallback) window.revealDirectLoginFallback('manuale'); return false;\">Se il login non procede, usa Accesso diretto<\/button>\n                <hr style=\"border-top:1px solid #444; margin:15px 0;\">\n                <button type=\"button\" class=\"ti-btn\" style=\"width:100%; background:#10b981;\" onclick=\"window.closeModal('ti-login-ov'); window.openProfileModal(true);\">Non hai un account? Registrati<\/button>\n                <button type=\"button\" onclick=\"window.closeModal('ti-login-ov')\" class=\"ti-btn btn-close\" style=\"width:100%; margin-top:10px;\">Chiudi<\/button>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-new-db-ov\" class=\"ti-ov ti-closable-ov\">\n            <div class=\"ti-modal\" style=\"width:90%;max-width:450px;text-align:left;\">\n                <h3 style=\"color:#fff;margin-top:0;text-align:center;border-bottom:1px solid #444;padding-bottom:10px;\">Crea Nuova Ditta<\/h3>\n                <div class=\"ti-new-db-info-top\" style=\"font-size:12px;color:#d1fae5;text-align:left;line-height:1.45;background:#052e25;border:1px solid #065f46;border-radius:10px;padding:10px;margin:0 0 12px 0;\">\n                    <p style=\"margin:0 0 8px 0;\">Alla fine del processo di creazione della ditta, verr\u00e0 generato l'archivio e farai l'accesso automatico a te riservato come configuratore.<\/p>\n                    <p style=\"margin:0 0 8px 0;\">Il servizio sar\u00e0 <b>GRATUITO di prova per 30 giorni senza impegno<\/b>, poi potrai eventualmente attivare la ditta alle condizioni commerciali previste per il servizio Shop &amp; Service disponibili direttamente durante la configurazione ed il periodo di prova.<\/p>\n                    <p style=\"margin:0;\">Trascorso il periodo di prova di 30 giorni, potrai comunque mantenere i dati in attesa del da farsi per ulteriori 30 giorni o cancellarli definitivamente.<\/p>\n                <\/div>\n                <form id=\"ti-new-db-form\" autocomplete=\"off\" onsubmit=\"return window.createDbSubmit ? window.createDbSubmit(event) : false;\">\n                    <label style=\"font-size:11px;color:#aaa;\">Nome della nuova Ditta*<\/label>\n                    <input id=\"nd-name\" class=\"ti-in\" style=\"margin-top:2px;\" placeholder=\"Es: Pizzeria Roma\" required>\n                    <h4 style=\"color:#38bdf8; margin:15px 0 5px 0; font-size:14px;\">Primo Utente (Configuratore)<\/h4>\n                    <label style=\"font-size:11px;color:#aaa;\">Username*<\/label>\n                    <input id=\"nd-user\" class=\"ti-in\" style=\"margin-top:2px;\" placeholder=\"Es: admin_roma\" required>\n                    <label style=\"font-size:11px;color:#aaa;\">Password*<\/label>\n                    <input id=\"nd-pass\" type=\"password\" class=\"ti-in\" style=\"margin-top:2px;\" placeholder=\"***\" required>\n                    <label style=\"font-size:11px;color:#aaa;\">Email (Opzionale)<\/label>\n                    <input id=\"nd-email\" type=\"email\" class=\"ti-in\" style=\"margin-top:2px;\" placeholder=\"info@pizzeriaroma.it\">\n                    <button type=\"submit\" id=\"ti-new-db-submit\" class=\"ti-btn\" style=\"width:100%; background:#10b981; margin-top:10px; font-weight:bold; font-size:15px; padding:10px;\">Crea e Accedi<\/button>\n                    <div id=\"ti-new-db-status\" role=\"status\" aria-live=\"polite\" style=\"display:none;margin-top:8px;padding:8px 10px;border-radius:8px;background:#0f172a;border:1px solid #334155;color:#dbeafe;font-size:12px;line-height:1.35;text-align:left;\"><\/div>\n                <\/form>\n                <a href=\"https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/Shop-Service%20Manual.pdf\" target=\"_blank\" rel=\"noopener\" class=\"ti-btn ti-new-db-manual-bottom\" style=\"width:100%;box-sizing:border-box;background:#059669;color:#fff;text-decoration:none;text-align:center;margin:8px 0 0 0;font-weight:bold;display:block;\">Manuale operativo Shop &amp; Service<\/a>\n                <button type=\"button\" onclick=\"window.closeModal('ti-new-db-ov')\" class=\"ti-btn btn-close\" style=\"width:100%; margin-top:5px;\">Annulla<\/button>\n            <\/div>\n        <\/div>\n        \n        <div id=\"ti-profile-ov\" class=\"ti-ov ti-closable-ov\">\n            <div class=\"ti-modal ti-scrollable-plugin\" style=\"width:90%;max-width:500px;text-align:left;\">\n                <h3 id=\"lbl-profile-title\" style=\"color:#fff;margin-top:0;text-align:center;border-bottom:1px solid #444;padding-bottom:10px;\">Profilo Utente<\/h3>\n                <div id=\"ti-profile-demo-temp-1752\" style=\"display:none;margin:0 0 12px 0;padding:10px 12px;border:1px solid #f59e0b;border-radius:10px;background:#422006;color:#fef3c7;font-size:12px;line-height:1.45;font-weight:700;\"><\/div>\n                <form id=\"ti-profile-form\" autocomplete=\"off\" onsubmit=\"event.preventDefault(); window.saveProfile();\">\n                    <div style=\"display:flex; gap:15px; align-items:center; margin-bottom:15px;\">\n                        <img decoding=\"async\" id=\"p-foto-preview\" src=\"\" style=\"width:60px;height:60px;border-radius:50%;background:#000;display:none;object-fit:cover;border:2px solid #38bdf8;\">\n                        <input type=\"hidden\" id=\"p-foto\" value=\"\">\n                        <button type=\"button\" class=\"ti-btn\" style=\"flex:1;\" onclick=\"window.showUploadChoice('p-foto')\">\ud83d\udcf7 Scegli Avatar<\/button>\n                    <\/div>\n                    \n                    <div class=\"ti-grid-2\">\n                        <div><label>Utente (Nome Cognome)*<\/label><input id=\"p-utente\" class=\"ti-in\" required autocomplete=\"off\" autocapitalize=\"words\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        <div><label>Username (Accesso)*<\/label><input id=\"p-user\" class=\"ti-in\" required autocomplete=\"username\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        \n                        <div><label id=\"lbl-p-pass\">Password*<\/label><input id=\"p-pass\" type=\"password\" class=\"ti-in\" placeholder=\"***\" autocomplete=\"current-password\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        <div><label>Email<\/label><input id=\"p-email\" type=\"email\" class=\"ti-in\" autocomplete=\"off\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        \n                        <div><label>Ragione Sociale<\/label><input id=\"p-ragione_sociale\" class=\"ti-in\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        <div><label>Indirizzo<\/label><input id=\"p-ind\" class=\"ti-in\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        \n                        <div><label>P.IVA \/ VAT<\/label><input id=\"p-piva_vat\" class=\"ti-in\" autocomplete=\"off\" autocapitalize=\"characters\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        <div><label>Codice Fiscale<\/label><input id=\"p-cod_fisc\" class=\"ti-in\" autocomplete=\"off\" autocapitalize=\"characters\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        \n                        <div><label>Codice ADE \/ SDI<\/label><input id=\"p-ade\" class=\"ti-in\" autocomplete=\"off\" autocapitalize=\"characters\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        <div><label>Telefono<\/label><input id=\"p-tel\" class=\"ti-in\" autocomplete=\"off\" autocapitalize=\"none\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        \n                        <div><label>Sesso<\/label><input id=\"p-sesso\" class=\"ti-in\" placeholder=\"M\/F\" autocomplete=\"off\" autocapitalize=\"characters\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        <div><label>Et\u00e0<\/label><input id=\"p-eta\" type=\"number\" class=\"ti-in\" value=\"0\" min=\"0\" autocomplete=\"off\"><\/div>\n\n                        <div><label>Dato 1<\/label><input id=\"p-dato_1\" class=\"ti-in\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        <div><label>Dato 2<\/label><input id=\"p-dato_2\" class=\"ti-in\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        \n                        <div style=\"grid-column: span 2;\"><label>Dato 3<\/label><input id=\"p-dato_3\" class=\"ti-in\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\"><\/div>\n                        \n                        <div style=\"grid-column: span 2;\">\n                            <label style=\"border-bottom:1px solid #444; padding-bottom:5px; margin-bottom:5px;\">Consensi<\/label>\n                            <div style=\"display:grid; grid-template-columns: 1fr 1fr; gap:5px;\">\n                                <label class=\"ti-cb-wrap\"><input type=\"checkbox\" id=\"p-com_mail\" checked> Com Mail<\/label>\n                                <label class=\"ti-cb-wrap\"><input type=\"checkbox\" id=\"p-com_email\" checked> Com Email<\/label>\n                                <label class=\"ti-cb-wrap\"><input type=\"checkbox\" id=\"p-com_sms\" checked> Com SMS<\/label>\n                                <label class=\"ti-cb-wrap\"><input type=\"checkbox\" id=\"p-com_tel\" checked> Com Tel<\/label>\n                            <\/div>\n                        <\/div>\n                        \n                        <div style=\"grid-column: span 2;\">\n                            <label>Note aggiuntive<\/label>\n                            <textarea id=\"p-nota\" class=\"ti-in\" rows=\"2\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\"><\/textarea>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"ti-profile-actions\" style=\"display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; margin-top:10px; align-items:stretch; justify-content:stretch;\">\n                        <button type=\"submit\" id=\"ti-profile-save-btn\" class=\"ti-btn ti-profile-btn-eq\" style=\"width:100%; background:#10b981 !important; color:#fff !important; font-weight:bold; font-size:15px; padding:0 12px !important; min-height:46px !important; height:46px !important; line-height:1 !important; display:flex !important; align-items:center !important; justify-content:center !important; box-sizing:border-box; white-space:nowrap;\">Salva<\/button>\n                        <button type=\"button\" onclick=\"window.closeModal('ti-profile-ov')\" class=\"ti-btn btn-close ti-profile-btn-eq\" style=\"width:100%; background:#374151 !important; color:#fff !important; font-size:15px; font-weight:bold; padding:0 12px !important; min-height:46px !important; height:46px !important; line-height:1 !important; display:flex !important; align-items:center !important; justify-content:center !important; box-sizing:border-box; white-space:nowrap;\">Chiudi<\/button>\n                        <button type=\"button\" id=\"ti-profile-cancel-btn\" onclick=\"window.cancelProfile()\" class=\"ti-btn ti-profile-btn-eq\" style=\"width:100%; background:#b91c1c !important; color:#fff !important; font-size:15px; font-weight:bold; padding:0 12px !important; min-height:46px !important; height:46px !important; line-height:1 !important; display:flex !important; align-items:center !important; justify-content:center !important; box-sizing:border-box; white-space:nowrap;\">Cancella<\/button>\n                    <\/div>\n                <\/form>\n            <\/div>\n        <\/div>\n\n\n        <div id=\"ti-report-ov\" class=\"ti-ov ti-closable-ov\" style=\"z-index:1002 !important;\">\n            <div class=\"ti-modal\" style=\"width:95%;max-width:1200px;text-align:left;\">\n                <h3 id=\"ti-report-title\" style=\"color:#fff;margin-top:0;border-bottom:1px solid #374151;padding-bottom:10px;\">\ud83d\udcca Report Attivit\u00e0<\/h3>\n                <div id=\"ti-report-cnt\"><\/div>\n                <div style=\"display:flex;gap:8px;margin-top:12px;\">\n                    <button type=\"button\" class=\"ti-btn btn-close\" data-ti-close-report=\"1\" style=\"flex:1;background:#4b5563;\" onclick=\"window.closeModal('ti-report-ov')\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-global-action-ov\" class=\"ti-ov ti-closable-ov\">\n            <div class=\"ti-modal\" style=\"width:90%;max-width:500px;position:relative;\">\n                <button type=\"button\" id=\"ti-global-action-help-btn-1563\" class=\"ti-header-help-btn\" title=\"Aiuto Modifica Globale Database\" aria-label=\"Aiuto Modifica Globale Database\" style=\"position:absolute;top:14px;right:50px;z-index:2147483646;\" onclick=\"if(window.openModal){window.openModal('ti-global-action-help-ov-1563');} return false;\">?<\/button>\n                <h3 style=\"color:#fff;margin-top:0;padding-right:88px;\">\ud83e\ude84 Modifica Globale Database<\/h3>\n                <p style=\"font-size:12px; color:#aaa; margin-bottom:10px;\">Puoi chiedere all'AI una <b>modifica globale<\/b> oppure un <b>consiglio operativo<\/b>. Le domande di consiglio non modificano alcun database.<\/p>\n                <div style=\"display:flex;gap:6px;align-items:stretch;margin-bottom:10px;\">\n                    <textarea id=\"global-action-prompt\" class=\"ti-in\" rows=\"3\" placeholder=\"Es: Come posso generare le foto mancanti di Prodotti e Servizi? oppure: Stato in Config = Demo\" style=\"flex:1;margin:0;min-width:0;\"><\/textarea>\n                    <button type=\"button\" id=\"global-action-template-btn\" class=\"ti-btn\" title=\"Scrivi comando: Adegua struttura database a template shopservicemain.json\" style=\"width:58px;min-width:58px;padding:6px 4px;background:#0f766e;color:#fff;font-size:10px;line-height:1.1;font-weight:800;white-space:normal;\" onclick=\"var el=document.getElementById('global-action-prompt'); if(el){el.value='Adegua struttura database a template shopservicemain.json'; el.focus(); try{el.dispatchEvent(new Event('input',{bubbles:true}));}catch(e){} try{el.dispatchEvent(new Event('change',{bubbles:true}));}catch(e){} } return false;\">Template<\/button>\n                <\/div>\n                <button type=\"button\" id=\"global-action-btn\" class=\"ti-btn\" style=\"width:100%;background:#8b5cf6;padding:10px;font-weight:bold;margin-bottom:10px;\" onclick=\"window.doGlobalAction()\">Esegui Modifica su Tutti i DB<\/button>\n                <div id=\"global-action-progress-wrap\" style=\"display:none; margin-bottom:10px;\">\n                    <div style=\"height:12px; background:#1f2937; border:1px solid #374151; border-radius:999px; overflow:hidden;\">\n                        <div id=\"global-action-progress-bar\" style=\"width:0%; height:100%; background:linear-gradient(90deg,#8b5cf6,#38bdf8);\"><\/div>\n                    <\/div>\n                    <div id=\"global-action-progress-text\" style=\"margin-top:6px; font-size:12px; color:#cbd5e1;\">0% - In attesa di avvio...<\/div>\n                <\/div>\n                <div id=\"global-action-res\" style=\"display:none; text-align:left; background:#222; padding:10px; border-radius:8px; border:1px solid #444; color:#10b981; font-size:12px; line-height:1.45; margin-bottom:10px; min-height:54px; max-height:180px; overflow-y:auto; white-space:pre-wrap;\"><\/div>\n                <button type=\"button\" id=\"ti-clean-orphans-global-btn\" class=\"ti-btn\" style=\"display:none;width:100%;background:#7c2d12;color:#fff;border:1px solid #9a3412;font-size:11px;margin-bottom:10px;padding:10px;font-weight:bold;\" onclick=\"if(window.runGlobalOrphanFileCleanup) window.runGlobalOrphanFileCleanup(); return false;\">\ud83e\uddf9 <b>Pulisci file non associati - Globale<\/b><\/button>\n                <button type=\"button\" id=\"ti-base-openai-key-btn-1638\" class=\"ti-btn\" style=\"width:100%;background:#1d4ed8;color:#fff;border:1px solid #2563eb;margin-bottom:6px;padding:10px;\" onclick=\"if(window.openBaseOpenAIKey1638) window.openBaseOpenAIKey1638(); return false;\">\ud83d\udd11 AI KEY base<\/button>\n                <button type=\"button\" id=\"ti-global-db-structure-pdf-btn-1641\" class=\"ti-btn\" style=\"width:100%;background:#334155;color:#fff;border:1px solid #475569;margin-bottom:6px;padding:10px;\" onclick=\"if(window.openModal){window.openModal('ti-global-db-structure-pdf-ov-1641');} return false;\">\ud83d\udcc4 Struttura standard database PDF<\/button>\n                <button type=\"button\" id=\"ti-avatar-settings-btn-1241\" class=\"ti-btn\" style=\"width:100%;background:#0f766e;color:#fff;border:1px solid #0d9488;margin-bottom:6px;padding:10px;\" onclick=\"if(window.openAvatarSettingsPanel1241) window.openAvatarSettingsPanel1241(); return false;\">\u2699\ufe0f Chiavi Avatar<\/button>\n                <button type=\"button\" id=\"ti-avatar-sandbox-btn-1232\" class=\"ti-btn\" style=\"width:100%;background:#7c3aed;color:#fff;border:1px solid #6d28d9;margin-bottom:10px;padding:10px;\" onclick=\"if(window.openAvatarSandboxPanel1232) window.openAvatarSandboxPanel1232(); return false;\">\ud83e\uddd1 Test Avatar (Sandbox)<\/button>\n                <button type=\"button\" class=\"ti-btn btn-close\" style=\"width:100%;background:#4b5563;\" onclick=\"window.closeModal('ti-global-action-ov')\">Chiudi<\/button>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-global-db-structure-pdf-ov-1641\" class=\"ti-ov ti-closable-ov\" style=\"z-index:2147483647 !important;\">\n            <div class=\"ti-modal\" style=\"width:96vw;max-width:1200px;height:92vh;max-height:92vh;display:flex;flex-direction:column;padding:12px;\">\n                <h3 style=\"color:#fff;margin:0 0 10px 0;\">\ud83d\udcc4 Shop &amp; Service - Struttura standard database<\/h3>\n                <iframe id=\"ti-global-db-structure-pdf-frame-1641\" src=\"https:\/\/www.tisoft.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/Shop-Service%20-%20Struttura%20standard%20database.pdf\" title=\"Shop-Service - Struttura standard database PDF\" style=\"width:100%;flex:1;min-height:0;background:#fff;border:1px solid #475569;border-radius:8px;\"><\/iframe>\n                <div style=\"display:flex;gap:8px;margin-top:10px;\">\n                    <a class=\"ti-btn\" href=\"https:\/\/www.tisoft.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/Shop-Service%20-%20Struttura%20standard%20database.pdf\" target=\"_blank\" rel=\"noopener\" style=\"flex:1;text-align:center;background:#2563eb;color:#fff;text-decoration:none;\">Apri PDF<\/a>\n                    <button type=\"button\" class=\"ti-btn btn-close\" style=\"flex:1;background:#4b5563;color:#fff;\" onclick=\"window.closeModal('ti-global-db-structure-pdf-ov-1641')\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-global-action-help-ov-1563\" class=\"ti-ov ti-closable-ov\" style=\"z-index:2147483646 !important;\">\n            <div class=\"ti-modal\" style=\"width:90%;max-width:560px;text-align:left;\">\n                <h3 style=\"color:#fff;border-bottom:1px solid #555;padding-bottom:10px;margin-top:0;\">Modifica Globale Database<\/h3>\n                <p style=\"color:#ccc;font-size:13px;margin:5px 0 12px 0;\"><b>Versione:<\/b> 30.9.2075<\/p>\n                <div style=\"font-size:12px;color:#d1d5db;line-height:1.5;background:#111827;border:1px solid #374151;border-radius:9px;padding:11px;margin-bottom:12px;\">\n                    <p style=\"margin:0 0 8px 0;\"><b>Funzione:<\/b> consente agli amministratori di richiedere modifiche coordinate sui database delle ditte disponibili.<\/p>\n                    <p style=\"margin:0 0 8px 0;\"><b>Sicurezza:<\/b> le operazioni che modificano dati devono presentare una preview reale prima del commit. Verifica sempre database coinvolti, tabelle, campi, righe da aggiungere\/eliminare e valori proposti prima di confermare.<\/p>\n                    <p style=\"margin:0 0 8px 0;\"><b>Utenti e Operatori:<\/b> per aggiungere o eliminare account usa richieste esplicite. Username e Password esistenti non devono essere svuotati da sostituzioni globali; le cancellazioni multiple richiedono criteri chiari.<\/p>\n                    <p style=\"margin:0;\"><b>Struttura:<\/b> il comando <i>Template<\/i> prepara la richiesta di adeguamento al modello <code>shopservicemain.json<\/code>. Non confermare modifiche strutturali non previste.<\/p>\n                <\/div>\n                <div style=\"font-size:12px;color:#cbd5e1;line-height:1.5;margin-bottom:12px;\">\n                    <b>Esempi:<\/b><br>\n                    \u2022 Aggiungi un operatore con Username, Password e dati indicati a tutti i database.<br>\n                    \u2022 Elimina tutti gli utenti con campo Username vuoto.<br>\n                    \u2022 Sostituisci un valore in uno specifico campo senza alterare gli altri dati.\n                <\/div>\n                <div style=\"display:flex;gap:8px;flex-wrap:wrap;\">\n                    <a href=\"https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/Shop-Service%20Manual.pdf\" target=\"_blank\" rel=\"noopener\" class=\"ti-btn\" style=\"flex:1;min-width:150px;text-align:center;background:#059669;color:#fff;text-decoration:none;line-height:24px;font-size:12px;\">\ud83d\udcc4 MANUALE PDF<\/a>\n                    <button type=\"button\" class=\"ti-btn\" style=\"flex:1;min-width:150px;background:#2563eb;color:#fff;font-size:12px;\" onclick=\"window.closeModal('ti-global-action-help-ov-1563'); if(window.openHelpModal){window.openHelpModal();} return false;\">? Aiuto generale<\/button>\n                    <button type=\"button\" class=\"ti-btn btn-close\" style=\"flex:1;min-width:120px;background:#4b5563;color:#fff;\" onclick=\"window.closeModal('ti-global-action-help-ov-1563');return false;\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-up-choice-ov\" class=\"ti-ov ti-closable-ov\">\n            <div class=\"ti-modal\" style=\"width:min(46vw,410px);max-width:min(46vw,410px);min-width:280px;\">\n                <h3 style=\"color:#fff;margin-top:0;\">Carica Immagine\/File<\/h3>\n                <div id=\"ti-main-native-wrap-617\" class=\"ti-native-upload-617\" style=\"margin-bottom:10px;\">\n                    <input type=\"file\" id=\"ti-main-native-file-617\" class=\"ti-native-file-617\" aria-label=\"Scegli file dal dispositivo\" style=\"position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;\" tabindex=\"-1\" aria-hidden=\"true\" \/>\n                    <button type=\"button\" id=\"ti-main-native-upload-btn-617\" class=\"ti-btn\" style=\"width:100%;margin-top:8px;background:#2563eb;padding:12px;font-size:14px;\" onclick=\"window.tiNativeUpload617 && window.tiNativeUpload617('main'); return false;\">\ud83d\udcf1 Carica da dispositivo\/supporto esterno<\/button>\n                    <div id=\"ti-main-native-status-617\" class=\"ti-native-status-617\"><\/div>\n                <\/div>\n                <button type=\"button\" class=\"ti-btn\" style=\"width:100%;margin-bottom:10px;background:#059669;padding:12px;font-size:14px;\" onclick=\"window.chooseAI()\">\ud83e\udd16 Cerca \/ Genera con AI<\/button>\n                <button type=\"button\" class=\"ti-btn btn-close\" style=\"width:100%;background:#4b5563;padding:10px;\" onclick=\"window.closeModal('ti-up-choice-ov')\">Annulla<\/button>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-ai-gen-ov\" class=\"ti-ov ti-closable-ov\" style=\"z-index: 1002 !important;\">\n            <div class=\"ti-modal\" style=\"width:90%;max-width:500px;\">\n                <h3 style=\"color:#fff;margin-top:0;\">\ud83e\udd16 AI Image Generator<\/h3>\n                <textarea id=\"ai-gen-prompt\" class=\"ti-in\" rows=\"3\" placeholder=\"Cosa ti serve? (es. Un logo per una pizzeria con forno a legna)...\"><\/textarea>\n                <div style=\"font-size:12px;color:#cbd5e1;margin:8px 0 6px 0;\">Istruzioni di dettaglio per la AI (opzionale). Esempio: <i>stile elegante, sfondo chiaro, inquadratura ravvicinata, foto realistica<\/i>.<\/div>\n                <textarea id=\"ai-gen-detail\" class=\"ti-in\" rows=\"3\" placeholder=\"Indica eventuali istruzioni di dettaglio per la generazione della foto\"><\/textarea>\n                <button type=\"button\" id=\"ai-gen-btn\" class=\"ti-btn\" style=\"width:100%;background:#8b5cf6;padding:10px;font-weight:bold;margin-bottom:10px;\" onclick=\"window.doAIGen()\">Genera Immagine<\/button>\n                <div id=\"ai-gen-res\" style=\"display:none; text-align:center;\">\n                    <img decoding=\"async\" id=\"ai-gen-img\" src=\"\" style=\"max-width:100%;border-radius:8px;margin-bottom:10px;max-height:300px;object-fit:contain;\">\n                    <button type=\"button\" class=\"ti-btn\" style=\"width:100%;background:#10b981;padding:10px;font-weight:bold;margin-bottom:5px;\" onclick=\"window.useAIGen()\">\u2705 Usa questa Immagine<\/button>\n                    <button type=\"button\" class=\"ti-btn\" style=\"width:100%;background:#2563eb;padding:8px;\" onclick=\"window.resetAIGen()\">\ud83d\udd04 Riprova<\/button>\n                <\/div>\n                <button type=\"button\" class=\"ti-btn btn-close\" style=\"width:100%;background:#4b5563;margin-top:10px;\" onclick=\"window.closeModal('ti-ai-gen-ov')\">Chiudi<\/button>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-col-help-ov\" class=\"ti-ov ti-closable-ov\">\n            <div class=\"ti-modal\" style=\"width:90%;max-width:500px;text-align:left;\">\n                <h3 id=\"col-help-title\" style=\"color:#fff;margin-top:0;border-bottom:1px solid #444;padding-bottom:8px;\">Aiuto Colonna<\/h3>\n                <div id=\"col-help-company\" style=\"display:none;text-align:center;color:#e5e7eb;font-size:12px;line-height:1.35;margin:-4px 0 10px 0;padding-bottom:10px;border-bottom:1px solid #374151;\"><\/div>\n                <div id=\"col-help-content\" style=\"background:#222; padding:15px; border-radius:8px; border:1px solid #444; color:#ccc; font-size:13px; min-height:80px; max-height:300px; overflow-y:auto; white-space:pre-wrap;\">\n                    \u23f3 Cerco nel manuale...\n                <\/div>\n                <div style=\"display:flex;gap:8px;margin-top:15px;flex-wrap:wrap;\">\n                    <button type=\"button\" id=\"ti-col-help-copy\" onclick=\"window.copyColumnHelpText357 && window.copyColumnHelpText357()\" class=\"ti-btn\" style=\"flex:1;min-width:120px;background:#2563eb;color:#fff;font-size:11px;padding:8px 10px;\">Copia testo<\/button>\n                    <button type=\"button\" onclick=\"window.closeModal('ti-col-help-ov')\" class=\"ti-btn btn-close\" style=\"flex:1;min-width:120px;background:#4b5563;\">Chiudi<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-cam-ov\" class=\"ti-ov ti-closable-ov\"><div class=\"ti-modal\" style=\"width:90%;max-width:500px\">\n            <h3 id=\"lbl-cam-title\" style=\"color:#fff\">Fotocamera<\/h3>\n            <div style=\"position:relative;\">\n                <video id=\"ti-video-feed\" style=\"width:100%;border-radius:8px;background:#000;min-height:200px;\" autoplay playsinline><\/video>\n                <div id=\"ti-cam-loading-msg-1291\" style=\"position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,0.75);border-radius:8px;padding:16px;box-sizing:border-box;text-align:center;\">\n                    <div style=\"font-size:36px;margin-bottom:10px;\">\u23f3<\/div>\n                    <div style=\"color:#fde68a;font-weight:700;font-size:14px;margin-bottom:6px;\">Telecamera in attivazione... attendere prego<\/div>\n                    <div style=\"color:#cbd5e1;font-size:12px;\">I tuoi dati verranno trattati nel rispetto della tua privacy<\/div>\n                <\/div>\n            <\/div>\n            <canvas id=\"ti-canvas-snap\" style=\"display:none\"><\/canvas>\n            <button type=\"button\" id=\"lbl-cam-snap\" class=\"ti-btn\" style=\"width:100%;margin-top:10px;background:#10b981;color:#fff;\" onclick=\"window.snapPhoto()\" disabled>Scatta Foto<\/button>\n            <style>#lbl-cam-snap:disabled { color: #6b7280 !important; }<\/style>\n            <button type=\"button\" onclick=\"window.closeCamModal()\" class=\"ti-btn btn-close\" style=\"width:100%;margin-top:5px;background:#b91c1c\">Chiudi<\/button>\n        <\/div><\/div>\n\n        <div id=\"ti-ateco-ov\" class=\"ti-ov ti-closable-ov\"><div class=\"ti-modal\" style=\"width:90%;max-width:500px;\">\n            <h3 style=\"color:#fff; margin-top:0;\">Ricerca Codice ATECO<\/h3>\n            <p style=\"font-size:12px; color:#aaa;\">Descrivi la tua attivit\u00e0 e l'IA trover\u00e0 i codici pi\u00f9 adatti.<\/p>\n            <div style=\"display:flex; gap:5px; margin-bottom:10px;\">\n                <input type=\"text\" id=\"ateco-in\" class=\"ti-in\" style=\"margin:0; padding:8px;\" placeholder=\"Es: Pizzeria da asporto\">\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;\" onclick=\"window.searchAteco()\">Cerca<\/button>\n            <\/div>\n            <input type=\"hidden\" id=\"ateco-target-id\" value=\"\">\n            <div id=\"ateco-res\" style=\"background:#222; padding:10px; border-radius:8px; border:1px solid #444; color:#ccc; font-size:12px; min-height:60px; max-height:200px; overflow-y:auto; text-align:left;\">\n                <i>Risultati della ricerca...<\/i>\n            <\/div>\n            <button type=\"button\" onclick=\"window.closeModal('ti-ateco-ov')\" class=\"ti-btn btn-close\" style=\"width:100%; margin-top:15px; background:#4b5563;\">Chiudi<\/button>\n        <\/div><\/div>\n\n        <div id=\"ti-kbd-ov\" class=\"ti-ov ti-closable-ov\"><div class=\"ti-modal ti-kbd-modal\" style=\"width:96vw; max-width:760px;\"><h3 id=\"lbl-kbd\" style=\"color:#fff;\">Tastiera<\/h3><input type=\"text\" id=\"ti-kbd-prev\" class=\"ti-in\" style=\"font-size:18px; margin-bottom:10px; background:#000;\" readonly><div id=\"ti-kbd-cnt\" class=\"ti-kbd\"><\/div><div style=\"display:flex; gap:5px; margin-top:10px;\"><button type=\"button\" id=\"ti-kbd-back\" class=\"ti-btn\" style=\"flex:1; background:#b91c1c;\">\u232b<\/button><button type=\"button\" id=\"ti-kbd-ok\" class=\"ti-btn\" style=\"flex:1; background:#059669;\">OK<\/button><button type=\"button\" onclick=\"window.closeModal('ti-kbd-ov')\" class=\"ti-btn btn-close\" style=\"flex:1;\">Chiudi<\/button><\/div><\/div><\/div>\n        \n        <div id=\"ti-help-ov\" class=\"ti-ov ti-closable-ov\"><div class=\"ti-modal\" style=\"text-align:left;\">\n            <h3 id=\"help-title\" style=\"color:#fff; border-bottom:1px solid #555; padding-bottom:10px; margin-top:0;\">Shop & Service<\/h3>\n            <div id=\"ti-help-company\" class=\"ti-help-company-main\" style=\"display:none;text-align:center;color:#e5e7eb;font-size:12px;line-height:1.38;margin:0 0 10px 0;padding:0 0 10px 0;border-bottom:1px solid #374151;\"><\/div>\n            <p style=\"color:#ccc; font-size:13px; margin:5px 0;\"><b>Versione:<\/b> <span id=\"help-ver\"><\/span><\/p>\n            <div id=\"help-email\" style=\"margin-bottom:15px;\"><\/div><div style=\"font-size:12px;color:#9ca3af;margin-bottom:10px;\">Nota manuale AI: tutti i campi Istruzioni nel database sono istruzioni operative dedicate alla AI e devono essere eseguite quando applicabili.<\/div><hr style=\"border:0; border-top:1px solid #444; margin:10px 0;\">\n            <p style=\"color:#38bdf8; font-size:12px; margin-bottom:5px;\"><b>Chiedi all'Assistente Shop & Service:<\/b><\/p>\n            <div style=\"display:flex; gap:5px; margin-bottom:10px;\">\n                <input type=\"text\" id=\"help-bot-in\" class=\"ti-in\" style=\"margin:0; padding:8px;\" placeholder=\"Es: Come prenoto?\">\n                <button type=\"button\" id=\"help-bot-send\" class=\"ti-btn\" style=\"background:#2563eb;\" onclick=\"window.sendHelpChat()\">\u279c<\/button>\n            <\/div>\n            <div id=\"help-bot-reply\" style=\"background:#222; padding:10px; border-radius:8px; border:1px solid #444; margin-bottom:12px; color:#ccc; font-size:12px; min-height:40px; max-height:150px; overflow-y:auto;\">\n                <i>Scrivi la tua domanda qui sopra per ricevere assistenza AI...<\/i>\n            <\/div>\n            <button type=\"button\" id=\"ti-help-support-toggle\" class=\"ti-btn\" style=\"width:100%; background:#0f766e; margin-bottom:10px;\">\ud83d\udee0\ufe0f Segnalazione assistenza tecnica<\/button>\n            <div id=\"ti-help-support-box\" style=\"display:none; margin-bottom:14px; background:#0b1220; border:1px solid #0f766e; border-radius:10px; padding:12px;\">\n                <div style=\"font-size:12px;color:#cbd5e1;margin-bottom:8px;\">Invia una segnalazione all\u2019assistenza tecnica. Se disponibile, verr\u00e0 allegata anche la copia dell\u2019ultima chat in corso.<\/div>\n                <label for=\"ti-support-email\" style=\"display:block;font-size:12px;color:#cbd5e1;margin-bottom:4px;\">Email mittente (opzionale)<\/label>\n                <input type=\"email\" id=\"ti-support-email\" class=\"ti-in\" style=\"margin:0 0 8px 0;\" placeholder=\"nome@dominio.it\">\n                <label for=\"ti-support-subject\" style=\"display:block;font-size:12px;color:#cbd5e1;margin-bottom:4px;\">Oggetto *<\/label>\n                <input type=\"text\" id=\"ti-support-subject\" class=\"ti-in\" style=\"margin:0 0 8px 0;\" placeholder=\"Oggetto della segnalazione\">\n                <label for=\"ti-support-message\" style=\"display:block;font-size:12px;color:#cbd5e1;margin-bottom:4px;\">Segnalazione *<\/label>\n                <textarea id=\"ti-support-message\" class=\"ti-in\" rows=\"5\" style=\"margin:0 0 8px 0;\" placeholder=\"Descrivi il problema o il suggerimento\"><\/textarea>\n                <div style=\"font-size:11px;color:#94a3b8;margin-bottom:10px;\">Destinatario: <b>Shop & Service<\/b>. In copia verr\u00e0 usata la tua e.mail se indicata o rilevata.<\/div>\n                <button type=\"button\" id=\"ti-support-send\" class=\"ti-btn\" style=\"width:100%; background:#2563eb;\">Invia segnalazione<\/button>\n            <\/div>\n            <div style=\"display:flex; gap:8px; flex-wrap:wrap; align-items:center;\">\n                <a href=\"https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/Shop-Service%20Manual.pdf\" target=\"_blank\" class=\"ti-btn\" style=\"flex:1 1 150px; text-align:center; background:#059669; color:#fff; text-decoration:none; line-height:24px; font-size:13px;\" id=\"btn-manual\">\ud83d\udcc4 MANUALE PDF<\/a>\n                <button type=\"button\" id=\"ti-help-reload-1713\" class=\"ti-btn ti-help-reload-1713\" title=\"Ricarica Shop & Service\" aria-label=\"Ricarica Shop & Service\" onclick=\"if(window.tiEmergencyResetLayout1676){return window.tiEmergencyResetLayout1676();} return false;\" style=\"flex:0 1 auto; background:#334155; color:#fff; font-size:9px; font-weight:800; line-height:1.05; padding:4px 7px; min-height:24px; white-space:nowrap;\">Ricarica Shop & Service<\/button>\n                <button type=\"button\" onclick=\"window.closeModal('ti-help-ov')\" class=\"ti-btn btn-close\" style=\"flex:1 1 100px; background:#4b5563;\">Chiudi<\/button>\n            <\/div>\n        <\/div><\/div>\n\n        <div id=\"ti-img-ov\" class=\"ti-ov ti-closable-ov\" onclick=\"window.closeModal('ti-img-ov')\" style=\"z-index: 2147483647 !important;\">\n            <div class=\"ti-modal\" style=\"background:transparent; border:none; box-shadow:none; padding:0; width:auto; max-height:100%;\">\n                <img decoding=\"async\" id=\"ti-full-img\" style=\"max-width:95vw; max-height:90vh; border-radius:8px; box-shadow:0 0 20px rgba(0,0,0,0.8);\" src=\"\" loading=\"lazy\">\n            <\/div>\n        <\/div>\n\n        <div id=\"ti-order-item-ov\" class=\"ti-ov ti-closable-ov\" style=\"z-index:2147483647 !important;\">\n            <div class=\"ti-modal\" style=\"width:92vw;max-width:820px;\">\n                <h3 id=\"ti-order-item-title\" style=\"color:#fff;margin-top:0;margin-bottom:14px;\">Dettaglio voce<\/h3>\n                <div class=\"ti-order-modal-grid\">\n                    <div><img decoding=\"async\" id=\"ti-order-item-img\" class=\"ti-order-modal-img\" src=\"\" loading=\"lazy\"><\/div>\n                    <div>\n                        <div id=\"ti-order-item-name\" style=\"font-size:18px;font-weight:800;color:#fff;margin-bottom:8px;\"><\/div>\n                        <div id=\"ti-order-item-caption\" class=\"ti-order-modal-caption\"><\/div>\n                        <div class=\"ti-order-modal-line\">Prezzo: <span id=\"ti-order-item-price\"><\/span><\/div>\n                        <div class=\"ti-order-modal-line\">Importo: <b id=\"ti-order-item-total\"><\/b><\/div>\n                        <div class=\"ti-order-modal-line\">Quantit\u00e0: <span class=\"ti-qty-stepper\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,-1)\">-<\/button><input type=\"text\" inputmode=\"decimal\" id=\"ti-order-item-qty\" class=\"ti-in\" style=\"max-width:140px;display:inline-block;margin-left:0;\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,1)\">+<\/button><\/span><\/div>\n                        <div id=\"ti-order-item-files\" class=\"ti-order-modal-files\" style=\"display:none;\"><\/div>\n                        <div class=\"ti-order-modal-actions\">\n                            <button type=\"button\" class=\"ti-btn ti-btn-ok\" style=\"flex:1;\" onclick=\"window.confirmOrderItemPopup()\">OK<\/button>\n                            <button type=\"button\" class=\"ti-btn btn-close\" style=\"flex:1;\" onclick=\"window.closeOrderItemPopup()\">Esci<\/button>\n                        <\/div>\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <input type=\"file\" id=\"ti-cam-in\" accept=\"image\/*\" capture=\"environment\" style=\"display:none;\" onchange=\"window.handleFileSelect(event)\">\n    <\/div>\n<script>\n\n\n    (function(){\n        try {\n            var t = window.localStorage;\n            if (t) { var k='__ti_ss_ls_test__'; t.setItem(k,'1'); t.removeItem(k); }\n        } catch(e) {\n            try {\n                var mem = {};\n                Object.defineProperty(window, 'localStorage', { configurable:true, value:{\n                    getItem:function(k){ return Object.prototype.hasOwnProperty.call(mem,k) ? mem[k] : null; },\n                    setItem:function(k,v){ mem[k] = String(v); },\n                    removeItem:function(k){ delete mem[k]; },\n                    clear:function(){ mem = {}; },\n                    key:function(i){ return Object.keys(mem)[i] || null; },\n                    get length(){ return Object.keys(mem).length; }\n                }});\n            } catch(ignore) {}\n        }\n    })();\n\n    \/\/ Protezione pagina Shop & Service da errori ripetuti di script esterni di navigazione.\n    \/\/ navigazione.js puo' usare .style su elementi non presenti nella pagina Shop & Service:\n    \/\/ il guard evita che l'errore sporchi la console o interrompa le funzioni del plugin.\n    (function installTiNavigationJsSafetyNet() {\n        if (window.__tiNavigationJsSafetyNetInstalled) return;\n        window.__tiNavigationJsSafetyNetInstalled = true;\n\n        function isNavigationStyleNullError(message, source) {\n            message = String(message || '');\n            source = String(source || '');\n            return \/(?:^|\\\/)navigazione\\.js(?:\\?|$)\/i.test(source)\n                && \/Cannot read properties of null\/i.test(message)\n                && \/\\bstyle\\b\/i.test(message);\n        }\n\n        const previousOnError = window.onerror;\n        window.onerror = function(message, source, lineno, colno, error) {\n            if (isNavigationStyleNullError(message, source)) return true;\n            if (typeof previousOnError === 'function') {\n                return previousOnError.apply(this, arguments);\n            }\n            return false;\n        };\n\n        window.addEventListener('error', function(evt) {\n            const message = evt && (evt.message || (evt.error && evt.error.message));\n            const source = evt && (evt.filename || (evt.error && evt.error.fileName));\n            if (isNavigationStyleNullError(message, source)) {\n                if (evt.preventDefault) evt.preventDefault();\n                if (evt.stopImmediatePropagation) evt.stopImmediatePropagation();\n                return true;\n            }\n        }, true);\n\n        function isSafeIgnoredScrollError(error) {\n            const message = error && error.message ? String(error.message) : String(error || '');\n            return \/Cannot read properties of null\/i.test(message) && \/\\bstyle\\b\/i.test(message);\n        }\n\n        function wrapWindowOnScroll() {\n            const handler = window.onscroll;\n            if (typeof handler !== 'function' || handler.__tiNavigationSafeWrapped) return;\n            const wrapped = function() {\n                try {\n                    return handler.apply(this, arguments);\n                } catch (error) {\n                    if (isSafeIgnoredScrollError(error)) return false;\n                    throw error;\n                }\n            };\n            wrapped.__tiNavigationSafeWrapped = true;\n            wrapped.__tiOriginalScrollHandler = handler;\n            window.onscroll = wrapped;\n        }\n\n        wrapWindowOnScroll();\n        document.addEventListener('DOMContentLoaded', wrapWindowOnScroll);\n        window.addEventListener('load', wrapWindowOnScroll);\n        let navGuardAttempts = 0;\n        const navGuardTimer = window.setInterval(function() {\n            wrapWindowOnScroll();\n            navGuardAttempts++;\n            if (navGuardAttempts >= 30) window.clearInterval(navGuardTimer);\n        }, 500);\n    })();\n\n    \/\/ Inizializzazione variabili globali sicura\n    window.gE = function(id) { return document.getElementById(id); };\n    const gE = window.gE;\n\n    window.tiIsMobileLike = function() {\n        try {\n            return !!(\n                (window.matchMedia && (window.matchMedia('(max-width: 900px)').matches || window.matchMedia('(pointer: coarse)').matches || window.matchMedia('(hover: none)').matches)) ||\n                ('ontouchstart' in window) ||\n                (navigator && navigator.maxTouchPoints && navigator.maxTouchPoints > 0)\n            );\n        } catch(e) {\n            return !!('ontouchstart' in window);\n        }\n    };\n\n    window.tiUrl = window.location.href.split('?')[0];\n    \/\/ 30.9.1471: misurazione diagnostica temporanea, richiesta esplicitamente dall'utente per confermare con\n    \/\/ certezza l'ipotesi che i (numerosi) MutationObserver del plugin, scattando tutti insieme quando\n    \/\/ Configurazione inserisce una tabella complessa nel DOM in un solo colpo, possano sovraccaricare il\n    \/\/ thread principale abbastanza da bloccare temporaneamente altre funzionalita' in corso (es. generazione\n    \/\/ foto, pulsante Log server). Intercetta in modo trasparente il costruttore globale, senza modificare\n    \/\/ nessuno dei singoli MutationObserver esistenti nel codice, misurando il tempo totale di esecuzione dei\n    \/\/ loro callback. Da rimuovere una volta confermata o esclusa questa ipotesi.\n    (function(){\n        try {\n            var origMO1471 = window.MutationObserver;\n            if (!origMO1471) return;\n            window.__tiMoStats1471 = { totalMs: 0, callCount: 0, slowestMs: 0, observerCount: 0 };\n            \/\/ 30.9.1474: tracciamento PER-OSSERVATORE aggiunto dopo la conferma (282.900 chiamate totali, una\n            \/\/ singola chiamata da 5,5 secondi) che il problema e' reale e di scala enorme - probabilmente un\n            \/\/ ciclo che si autoalimenta (un osservatore che, reagendo, modifica il DOM in un modo che fa\n            \/\/ scattare di nuovo se stesso o altri). Cattura un estratto del codice di ciascun callback (via\n            \/\/ toString) al momento della creazione, cosi' da poter identificare con certezza quale specifico\n            \/\/ osservatore, tra i 62 esistenti, sia il responsabile - senza dover ipotizzare o modificare alla\n            \/\/ cieca tutti gli altri.\n            window.__tiMoPerObserver1471 = [];\n            function WrappedMO1471(callback){\n                window.__tiMoStats1471.observerCount++;\n                var snippet = '(callback non leggibile)';\n                try { snippet = String(callback).replace(\/\\s+\/g,' ').slice(0, 90); } catch(e) {}\n                \/\/ 30.9.1477: aggiunta cattura dello stack di creazione - il solo estratto del codice non e'\n                \/\/ bastato a identificare l'osservatore esterno (non presente nel PHP del plugin) che continua a\n                \/\/ dominare il tempo misurato (fino al 67% in un test recente). Lo stack, a differenza del\n                \/\/ codice del callback, include tipicamente l'URL del file javascript di origine, permettendo\n                \/\/ di risalire con certezza al plugin\/tema responsabile.\n                var creationStack = '(stack non disponibile)';\n                try { creationStack = String((new Error('creato qui')).stack || '').split('\\n').slice(1, 6).join(' || '); } catch(e) {}\n                var entry = { snippet: snippet, totalMs: 0, callCount: 0, slowestMs: 0, creationStack: creationStack };\n                window.__tiMoPerObserver1471.push(entry);\n                var wrapped = function(mutations, observer){\n                    var start = performance.now();\n                    try { return callback.apply(this, arguments); }\n                    finally {\n                        var elapsed = performance.now() - start;\n                        window.__tiMoStats1471.totalMs += elapsed;\n                        window.__tiMoStats1471.callCount++;\n                        if (elapsed > window.__tiMoStats1471.slowestMs) window.__tiMoStats1471.slowestMs = elapsed;\n                        entry.totalMs += elapsed;\n                        entry.callCount++;\n                        if (elapsed > entry.slowestMs) entry.slowestMs = elapsed;\n                    }\n                };\n                return new origMO1471(wrapped);\n            }\n            WrappedMO1471.prototype = origMO1471.prototype;\n            window.MutationObserver = WrappedMO1471;\n            \/\/ 30.9.1472-fix: abbandonato il tentativo di integrazione con il pannello \"Log salvataggio\" - quel\n            \/\/ sistema rigenera completamente il proprio contenuto ad ogni evento (click, ecc.), cancellando\n            \/\/ qualsiasi scrittura diretta fatta dall'esterno, cosa che spiega perche' i tentativi precedenti non\n            \/\/ mostrassero mai i dati. Creato invece un pulsante e pannello dedicati e completamente separati,\n            \/\/ cosi' i dati di questa misurazione temporanea non rischiano di essere sovrascritti da nessun\n            \/\/ altro sistema esistente.\n            window.__tiMoHistory1471 = [];\n            var lastReported1471 = 0;\n            setInterval(function(){\n                var s = window.__tiMoStats1471;\n                if (s.totalMs === lastReported1471) return;\n                var delta = s.totalMs - lastReported1471;\n                lastReported1471 = s.totalMs;\n                if (delta < 30) return; \/\/ ignora variazioni trascurabili\n                window.__tiMoHistory1471.push({ ora: new Date().toLocaleTimeString(), tempo_aggiunto_ms: Math.round(delta), tempo_totale_ms: Math.round(s.totalMs), chiamate_totali: s.callCount, osservatori_attivi: s.observerCount, chiamata_piu_lenta_ms: Math.round(s.slowestMs) });\n                if (window.__tiMoHistory1471.length > 200) window.__tiMoHistory1471.shift();\n            }, 1000);\n            \/\/ 30.9.1480: la funzione di installazione del pulsante e' stata spostata in un hook wp_footer dedicato (vedi\n            \/\/ piu' avanti nel file, vicino agli altri pulsanti fluttuanti) - segnalato un disallineamento\n            \/\/ orizzontale rispetto agli altri pulsanti quando installata da questo blocco, eseguito molto prima\n            \/\/ nella sequenza di caricamento della pagina rispetto agli altri.\n        } catch(e) {}\n    })();\n    \/\/ 30.9.1456: diagnostica dedicata e persistente (sopravvive a un ricaricamento pagina, a differenza del\n    \/\/ log normale in memoria) per stabilire con certezza se la pagina si sta chiudendo\/ricaricando MENTRE il\n    \/\/ log normale in memoria) per stabilire con certezza se la pagina si sta chiudendo\/ricaricando MENTRE il\n    \/\/ processo di generazione foto AI in batch e' ancora attivo - un caso segnalato dall'utente in cui il\n    \/\/ processo sembrava interrompersi da solo, con conseguente scomparsa dei dati visualizzati.\n    (function(){\n        try {\n            var STORAGE_KEY_1456 = 'tiUnexpectedUnloadDuringBatch706_1456';\n            \/\/ All'avvio pagina: se un ricaricamento precedente ha lasciato un marcatore, registralo nel log\n            \/\/ diagnostico esistente (687), visibile e copiabile tramite \"Log salvataggio\" \/ \"Log server (diag)\".\n            var prevMarker1456 = sessionStorage.getItem(STORAGE_KEY_1456);\n            if (prevMarker1456) {\n                sessionStorage.removeItem(STORAGE_KEY_1456);\n                window.__tiConfigSaveDiagLog687 = window.__tiConfigSaveDiagLog687 || [];\n                window.__tiConfigSaveDiagLog687.push({\n                    time: (Date.now?Date.now():(new Date()).getTime()),\n                    event: 'PAGINA_RICARICATA_DURANTE_BATCH706_1456',\n                    detail: JSON.parse(prevMarker1456),\n                    level: 'warning'\n                });\n            }\n        } catch(e) {}\n        try {\n            window.addEventListener('pagehide', function(){\n                try {\n                    if (window.tiBatchAIGenState && window.tiBatchAIGenState.active && window.tiBatchAIGenState.source === '706') {\n                        sessionStorage.setItem('tiUnexpectedUnloadDuringBatch706_1456', JSON.stringify({\n                            total: window.tiBatchAIGenState.total,\n                            tableName: window.tiBatchAIGenState.tableName,\n                            db: window.tiBatchAIGenState.db,\n                            startedAt: window.tiBatchAIGenState.startedAt,\n                            unloadedAt: (Date.now?Date.now():(new Date()).getTime())\n                        }));\n                    }\n                } catch(e) {}\n            });\n        } catch(e) {}\n    })();\n    window.tiAjaxUrl = \"https:\/\/www.tisoft.it\/wp-admin\/admin-ajax.php\";\n    window.updateMobileViewportHeight = function() {\n        try {\n            const vh = (window.visualViewport && window.visualViewport.height ? window.visualViewport.height : window.innerHeight) * 0.01;\n            const root = document.getElementById('ti-ai-outer') || document.documentElement;\n            if (root && root.style) root.style.setProperty('--ti-vh', vh + 'px');\n            if (document.documentElement && document.documentElement.style) document.documentElement.style.setProperty('--ti-vh', vh + 'px');\n            if (document.body && document.body.style) document.body.style.setProperty('--ti-vh', vh + 'px');\n        } catch(e) {}\n    };\n    try { window.updateMobileViewportHeight(); window.addEventListener('resize', window.updateMobileViewportHeight, {passive:true}); if (window.visualViewport) window.visualViewport.addEventListener('resize', window.updateMobileViewportHeight, {passive:true}); } catch(e) {}\n    \/\/ 30.9.1967: i nomi database sono dati JavaScript, non testo HTML. wp_json_encode preserva '&' come carattere reale.\n    window.tiForced = \"\"; \n    window.tiForcedActivityQr = \"\"; \n    window.tiUser = \"\"; \n    window.tiRole = \"\"; \n    window.tiAccountTable = \"\";\n    window.tiProfileType = \"\";\n    window.tiStrictAdminLog1488 = false;\n    window.tiConfigSaveLogAllowed = window.tiStrictAdminLog1488 === true;\n    \/\/ 30.9.1665: 1 ora di inattivita per Amministratore\/Administrator\/SSGlobalAdmin;\n    \/\/ gli altri utenti autenticati mantengono 10 minuti. Un processo lungo realmente attivo sospende\n    \/\/ il conteggio idle fino a completamento\/interruzione e l'hotfix 1496 mantiene viva la sessione server.\n        window.tiIdleThresholdSec1463 = 0;\n    window.tiIsPrivilegedUploadUser = false;\n    window.tiDemoReadonly = false;\n    window.tiDemoReadonlyMessage = \"Accesso Demo in sola lettura: l utente ssdemo puo visualizzare la configurazione e usare la chat AI come utente base, ma non puo modificare, aggiungere, cancellare o salvare dati.\";\n    window.tiUserFoto = \"\"; window.tiUserFotoDb = \"\"; window.tiSessionDb = \"\"; \n    window.tiUserDisplay = \"\"; \n    window.tiVersion = \"30.9.2075\";\n    window.tiVersionDateTime = \"2026-10-14 11:26 CEST\";\n    window.tiProducerEmails = {\"info\":\"SSInfo@targetinformatica.it\",\"comm\":\"SSComm@targetinformatica.it\",\"support\":\"SSSupport@targetinformatica.it\"};\n    window.tiShopServiceActivationProductUrl = \"https:\\\/\\\/www.tisoft.it\\\/en\\\/prodotto\\\/shop-service-attivazione\\\/\";\n    window.tiShopServiceMonthlyProductUrl = \"https:\\\/\\\/www.tisoft.it\\\/en\\\/prodotto\\\/shop-service\\\/\";\n    window.tiShopServiceAiActsProductUrl = \"https:\\\/\\\/www.tisoft.it\\\/prodotto\\\/shop-service-ai-aggiuntiva\\\/\";\n    window.tiShopServiceActivationSku = \"SHOP-SERVICE-1\";\n    window.tiShopServiceMonthlySku = \"SHOP-SERVICE\";\n    window.tiShopServiceAiActsSku = \"SHOP-SERVICE-2\";\n    window.tiConfiguratorAccessMessage = \"\";\n    window.tiServerPrefs = [];\n    window.currLang = localStorage.getItem('ti_lang_' + window.tiUser) || 'it';\n    \/\/ 30.9.1970: per utenti comuni mostra Prodotti\/Servizi soltanto quando esiste almeno\n    \/\/ una voce realmente ordinabile secondo le stesse regole del catalogo: stato valido, nome e Prezzo > 0.\n    (function(){\n        'use strict';\n        var seq1970 = 0, lastDb1970 = '', timer1970 = null;\n        function txt1970(v){ return String(v == null ? '' : v).trim(); }\n        function privileged1970(){\n            var u = txt1970(window.tiUser).toLowerCase(), r = txt1970(window.tiRole).toLowerCase();\n            if (u === 'ssglobaladmin' || u === 'globaladmin') return true;\n            return \/amministratore|administrator|configuratore|configurator|responsabile|responsible|global\\s*admin|globaladmin|globale|sysadmin\/.test(r);\n        }\n        function btn1970(kind){ return document.getElementById(kind === 'products' ? 'ti-products-btn' : 'ti-services-btn'); }\n        function visible1970(kind, yes){\n            var b = btn1970(kind); if (!b) return;\n            b.classList.remove('ti-catalog-unavailable-1969');\n            if (yes) { b.classList.remove('ti-catalog-unavailable-1970'); b.removeAttribute('aria-hidden'); }\n            else { b.classList.add('ti-catalog-unavailable-1970'); b.setAttribute('aria-hidden','true'); }\n        }\n        function currentDb1970(){\n            var d = txt1970(window.tiForced || window.tiSessionDb || window.tiCurrentSelectedDb || '');\n            if (!d) { var s = document.getElementById('ti-ditta'); if (s) d = txt1970(s.value); }\n            return (d && d !== 'NEW_DB' && d !== 'Global') ? d : '';\n        }\n        function apply1970(force){\n            if (privileged1970()) { visible1970('products',true); visible1970('services',true); return; }\n            var db = currentDb1970();\n            if (!db) { visible1970('products',false); visible1970('services',false); lastDb1970=''; return; }\n            if (!force && db === lastDb1970) return;\n            lastDb1970 = db;\n            \/\/ Fail-closed: finche il server non conferma una voce ordinabile, il pulsante non compare.\n            visible1970('products',false); visible1970('services',false);\n            var mySeq1970 = ++seq1970;\n            var fd = new FormData();\n            fd.append('action','ti_ai_catalog_visibility_1970');\n            fd.append('ti_action','ti_ai_catalog_visibility_1970');\n            fd.append('db',db);\n            var direct = txt1970(window.tiUrl || '');\n            var admin = txt1970(window.tiAjaxUrl || window.ajaxurl || '\/wp-admin\/admin-ajax.php');\n            function parse1970(r){ if(!r.ok) throw new Error('HTTP '+r.status); return r.json(); }\n            function done1970(j){\n                if (mySeq1970 !== seq1970 || db !== currentDb1970()) return;\n                if (!(j && j.success && j.data)) throw new Error('Risposta non valida');\n                visible1970('products', j.data.products === true || j.data.products === 1 || j.data.products === '1');\n                visible1970('services', j.data.services === true || j.data.services === 1 || j.data.services === '1');\n            }\n            function failClosed1970(){\n                if (mySeq1970 !== seq1970 || db !== currentDb1970()) return;\n                visible1970('products',false); visible1970('services',false);\n                \/\/ Un solo retry leggero dopo un errore transitorio; nessuna esposizione di cataloghi non verificati.\n                clearTimeout(timer1970); timer1970=setTimeout(function(){ if(db===currentDb1970()) apply1970(true); },1800);\n            }\n            var opts={method:'POST',body:fd,credentials:'same-origin',cache:'no-store'};\n            if (direct) fetch(direct,opts).then(parse1970).then(done1970).catch(function(){\n                var fd2=new FormData();fd2.append('action','ti_ai_catalog_visibility_1970');fd2.append('ti_action','ti_ai_catalog_visibility_1970');fd2.append('db',db);\n                fetch(admin,{method:'POST',body:fd2,credentials:'same-origin',cache:'no-store'}).then(parse1970).then(done1970).catch(failClosed1970);\n            }); else fetch(admin,opts).then(parse1970).then(done1970).catch(failClosed1970);\n        }\n        window.tiRefreshPublicCatalogButtons1970 = function(force){ apply1970(force !== false); };\n        window.tiRefreshPublicCatalogButtons1969 = window.tiRefreshPublicCatalogButtons1970;\n        function schedule1970(force){ clearTimeout(timer1970); timer1970=setTimeout(function(){apply1970(!!force);},80); }\n        document.addEventListener('change',function(ev){ if(ev && ev.target && ev.target.id==='ti-ditta') schedule1970(true); },true);\n        document.addEventListener('click',function(ev){ var t=ev&&ev.target&&ev.target.closest?ev.target.closest('.ti-ditta-row,[data-db]'):null;if(t)setTimeout(function(){schedule1970(true);},120); },true);\n        if (document.readyState==='loading') document.addEventListener('DOMContentLoaded',function(){schedule1970(true);setTimeout(function(){schedule1970(true);},700);},{once:true});\n        else { schedule1970(true); setTimeout(function(){schedule1970(true);},700); }\n        window.addEventListener('pageshow',function(){schedule1970(true);});\n    })();\n    window.tiAudioPersistentAllowed716 = function() {\n        try {\n            const role = String(window.tiRole || window.tiUserRole || window.currentUserRole || '').toLowerCase();\n            const user = String(window.tiUser || window.tiUsername || '').trim().toLowerCase();\n            if (user === 'ssglobaladmin' || user === 'globaladmin') return true;\n            return \/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|globale\/.test(role);\n        } catch(e) { return false; }\n    };\n    window.tiAudioStorageKey716 = function() {\n        return 'ti_mute_state_' + location.host + '_' + (window.tiUser || 'guest');\n    };\n    window.tiAudioClearPersistentIfBase716 = function() {\n        try {\n            window.tiAudioKey = window.tiAudioStorageKey716 ? window.tiAudioStorageKey716() : ('ti_mute_state_' + location.host + '_' + (window.tiUser || 'guest'));\n            if (!window.tiAudioPersistentAllowed716 || !window.tiAudioPersistentAllowed716()) localStorage.removeItem(window.tiAudioKey);\n        } catch(e) {}\n    };\n    \n        window.tiUploadBase = \"https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\";\n    if (window.tiUploadBase.startsWith('\/')) window.tiUploadBase = window.location.origin + window.tiUploadBase; \n    window.tiUploadBase = window.tiUploadBase.replace(\/\\\/$\/, \"\");\n    window.tiSharedSetup = {\"shared_base_path\":\"\\\/home\\\/lqlo5s240ldu\\\/public_html\\\/wp-content\\\/uploads\\\/AI-data\\\/\",\"shared_base_url\":\"https:\\\/\\\/www.targetinformatica.it\\\/wp-content\\\/uploads\\\/AI-data\",\"effective_base_path\":\"\\\/home\\\/lqlo5s240ldu\\\/public_html\\\/wp-content\\\/uploads\\\/AI-data\\\/\",\"effective_base_url\":\"https:\\\/\\\/www.targetinformatica.it\\\/wp-content\\\/uploads\\\/AI-data\",\"docs_base_path\":\"\\\/home\\\/lqlo5s240ldu\\\/public_html\\\/wp-content\\\/uploads\\\/AI-data\\\/AI-docs\\\/Shop-service\\\/\",\"docs_base_url\":\"https:\\\/\\\/www.targetinformatica.it\\\/wp-content\\\/uploads\\\/AI-data\\\/AI-docs\\\/Shop-service\",\"manual_url\":\"https:\\\/\\\/www.targetinformatica.it\\\/wp-content\\\/uploads\\\/AI-data\\\/AI-docs\\\/Shop-service\\\/Shop-Service%20Manual.pdf\",\"default_base_path\":\"\\\/home\\\/lqlo5s240ldu\\\/public_html\\\/tisoft.it\\\/wp-content\\\/uploads\\\/AI-data\\\/\",\"default_base_url\":\"https:\\\/\\\/www.tisoft.it\\\/wp-content\\\/uploads\\\/AI-data\",\"target_url_example\":\"https:\\\/\\\/www.targetinformatica.it\\\/wp-content\\\/uploads\\\/AI-data\\\/AI-docs\\\/Shop-service\\\/\"};\n\n    window.currentDbData = null; window.configOriginalDbData = null; window.pendingEmail = false; window.lastUploadedFile = null; window.configBotFile = null; window.lastFileContext = null; window.currentDittaName = \"Ditta\"; window.isMuted = false; window.stream = null; window.sortMode = 'AZ'; window.ditteData = []; window.modifiedFields = new Set(); window.tiConfigDeletedRowsManifest = []; window.targetUploadContext = null; window.currentGenFilename = null; window.configWasSaved = false; window.tiQuickReplyText = ''; window.tiHiddenSendText = ''; window.tiHiddenSendLabel = '';\n    \/\/ 30.9.1657: token client per isolare tutte le risposte asincrone dalla ditta che le ha originate.\n    window.tiCompanyEpoch1657 = Number(window.tiCompanyEpoch1657 || 0);\n    window.tiNormalizeDb1657 = function(v){ return String(v || '').trim().replace(\/\\.json$\/i,'').toLowerCase(); };\n    window.tiDbPayloadMatches1657 = function(payload, expectedDb){\n        if (!payload || !expectedDb) return false;\n        const got = String(payload.__db_name || payload.__db || '').trim();\n        return !!got && window.tiNormalizeDb1657(got) === window.tiNormalizeDb1657(expectedDb);\n    };\n    window.tiResetCompanyScopedState1657 = function(nextDb){\n        const next = String(nextDb || '').trim();\n        const old = String(window.tiCurrentSelectedDb || ((document.getElementById('ti-ditta')||{}).value || '') || '').trim();\n        if (old && next && window.tiNormalizeDb1657(old) === window.tiNormalizeDb1657(next)) return false;\n        window.tiCompanyEpoch1657 = Number(window.tiCompanyEpoch1657 || 0) + 1;\n        try {\n            const a = window.tiMainChatActiveRequest1542;\n            if (a && !a.done) {\n                a.manualCancel = true;\n                a.companySwitch1657 = true;\n                if (a.controller) a.controller.abort();\n                if (a.bubble && a.bubble.parentNode) a.bubble.remove();\n            }\n        } catch(e) {}\n        try { window.currentDbData = null; window.currentDbViewData = null; window.configOriginalDbData = null; } catch(e) {}\n        try { if (window.clearLastFileContext) window.clearLastFileContext(); else window.lastFileContext = null; } catch(e) { window.lastFileContext = null; }\n        window.lastUploadedFile = null; window.configBotFile = null; window.targetUploadContext = null; window.currentGenFilename = null;\n        window.pendingEmail = false; window.tiQuickReplyText = ''; window.tiHiddenSendText = ''; window.tiHiddenSendLabel = '';\n        try { if (window.hideOrderConfirmPanel) window.hideOrderConfirmPanel(true); } catch(e) {}\n        return true;\n    };\n    window.tiCurrentSelectedDb = window.tiForced || ((String(window.tiUser || '').trim() && String(window.tiSessionDb || '').trim()) ? window.tiSessionDb : '') || localStorage.getItem('ti_saved_db') || window.tiSessionDb || '';\n    try { if (String(window.tiUser || '').trim() && String(window.tiSessionDb || '').trim() && !window.tiForced) localStorage.setItem('ti_saved_db', String(window.tiSessionDb).trim()); } catch(e1725boot) {}\n\n    window.getAlertPlainText = function() {\n        const el = gE('ti-alert-msg');\n        if (!el) return '';\n        return String(el.innerText || el.textContent || '').trim();\n    };\n    window.copyAlertText = function() {\n        const text = window.getAlertPlainText();\n        if (!text) return;\n        const done = function(ok) {\n            const btn = gE('ti-alert-copy');\n            if (!btn) return;\n            const old = btn.innerText || 'Copia testo';\n            btn.innerText = ok ? 'Copiato' : 'Errore copia';\n            setTimeout(function(){ btn.innerText = old; }, 1200);\n        };\n        if (navigator.clipboard && navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){ done(false); });\n            return;\n        }\n        try {\n            const ta = document.createElement('textarea');\n            ta.value = text;\n            ta.style.position = 'fixed';\n            ta.style.left = '-9999px';\n            document.body.appendChild(ta);\n            ta.focus(); ta.select();\n            const ok = document.execCommand('copy');\n            document.body.removeChild(ta);\n            done(ok);\n        } catch(e) { done(false); }\n    };\n    window.normalizeConfigStateValue = function(value) {\n        const raw = String(value == null ? '' : value).trim();\n        if (!raw) return '';\n        const v = raw.toLowerCase().normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').replace(\/\\s+\/g, ' ');\n        if (['operativo','operativa','a regime','regime','canone attivo','servizio attivo','abbonamento attivo'].includes(v)) return 'Operativo';\n        if (['attivo','attiva','attivato','abilitato','abilitata','enabled','si','s\u00ec','ok','richiesto','richiesta','registrato','registrata','completato','completata','completo','confermato','confermata'].includes(v)) return 'Attivo';\n        if (['demo','dimostrativa','dimostrativo','dimostrazione','ambiente demo'].includes(v)) return 'Demo';\n            if (['configurazione','config','in configurazione','bozza','draft','prova','test'].includes(v)) return 'Configurazione';\n        if (['sospesa','sospeso','sospendere','inattivo','inattiva','disabilitato','disabilitata','disabled','chiuso','chiusa','non disponibile','pausa','in pausa'].includes(v)) return 'Sospesa';\n        if (['cancellato','cancellata','eliminato','eliminata','rimosso','rimossa','annullato','annullata'].includes(v)) return 'Cancellato';\n        return raw;\n    };\n    window.isCompanyStateEnabled = function(state) {\n        state = window.normalizeConfigStateValue(state);\n        return state === 'Attivo' || state === 'Operativo';\n    };\n    window.getCurrentCompanyStateFromSelection = function() {\n        const d = gE('ti-ditta');\n        if (d && d.selectedIndex >= 0 && d.options[d.selectedIndex]) {\n            const opt = d.options[d.selectedIndex];\n            const raw = opt.dataset.companyState || opt.dataset.stato || opt.dataset.status || '';\n            if (raw) return window.normalizeConfigStateValue(raw);\n            const statusCode = String(opt.dataset.status || '').toLowerCase();\n            if (statusCode === 'sospesa') return 'Sospesa';\n            if (statusCode === 'demo') return 'Demo';\n            if (statusCode === 'configurazione') return 'Configurazione';\n        }\n        if (window.currentDbData && window.currentDbData.Tabelle) {\n            const cfgName = Object.keys(window.currentDbData.Tabelle).find(k => String(k).toLowerCase() === 'config') || 'Config';\n            const cfgRows = window.currentDbData.Tabelle[cfgName];\n            const cfg = Array.isArray(cfgRows) ? (cfgRows[0] || {}) : {};\n            const key = Object.keys(cfg).find(k => String(k).toLowerCase() === 'stato') || 'Stato';\n            return window.normalizeConfigStateValue(cfg[key] || '');\n        }\n        return '';\n    };\n    window.getCompanyLimitedNoticeHtml = function(state) {\n        state = window.normalizeConfigStateValue(state || window.getCurrentCompanyStateFromSelection());\n        if (window.isCompanyStateEnabled && window.isCompanyStateEnabled(state)) return '';\n        if (state !== 'Demo') {\n            var role1773=String(window.tiRole||'').toLowerCase(), user1773=String(window.tiUser||'').toLowerCase();\n            var admin1773=(user1773==='ssglobaladmin'||user1773==='globaladmin'||\/amministratore|administrator|(^|[^a-z])admin([^a-z]|$)\/i.test(role1773));\n            if(!admin1773) return '';\n        }\n        if (state === 'Demo') {\n            \/\/ 30.9.1749: il Demo e gestito unicamente dall avviso server completo.\n            return '';\n        }\n        if (state === 'Sospesa') {\n            return '<div class=\"ti-company-state-warning\" style=\"margin:8px 0 10px 0;padding:10px 12px;border-radius:10px;background:#78350f;border:1px solid #f59e0b;color:#fff;font-weight:700;font-size:13px;line-height:1.35;\">\u26a0\ufe0f Stato ditta: Sospesa<br>La ditta risulta sospesa. Ordini e prenotazioni possono essere provati, ma non avranno esito effettivo finch\u00e9 la ditta non torna Attiva o Operativa.<\/div>';\n        }\n        if (state === 'Configurazione') {\n            return '<div class=\"ti-company-state-warning\" style=\"margin:8px 0 10px 0;padding:10px 12px;border-radius:10px;background:#78350f;border:1px solid #f59e0b;color:#fff;font-weight:700;font-size:13px;line-height:1.35;\">\u26a0\ufe0f Stato ditta: Configurazione<br>La ditta risulta in configurazione. Ordini e prenotazioni possono essere provati, ma non avranno esito effettivo finch\u00e9 la configurazione non viene completata e la ditta non torna Attiva o Operativa.<\/div>';\n        }\n        return '';\n    };\n    window.applyCompanyLimitedNotice = function() {\n        const companySub = gE('ti-company-sub');\n        if (!companySub) return;\n        const html = window.getCompanyLimitedNoticeHtml();\n        if (html) {\n            companySub.innerHTML = html;\n            companySub.style.display = 'block';\n        } else {\n            companySub.innerHTML = '';\n            companySub.style.display = 'none';\n        }\n    };\n\n    window.updateCompanyReferenceDateTime = function() {\n        const targets = [gE('ti-company-ref-datetime'), gE('ti-conf-ref-datetime')].filter(Boolean);\n        if (!targets.length) return;\n        const d = gE('ti-ditta');\n        const opt = d && d.selectedIndex >= 0 ? d.options[d.selectedIndex] : null;\n        const txt = opt && opt.value && opt.value !== 'NEW_DB' ? String(opt.dataset.refDatetime || '') : '';\n        const tz = opt && opt.value && opt.value !== 'NEW_DB' ? String(opt.dataset.refTz || '') : '';\n        targets.forEach(function(el) {\n            if (!el) return;\n            if (txt) {\n                el.textContent = txt;\n                el.title = 'Data e ora sistema ditta' + (tz ? ' - ' + tz : '');\n                el.style.display = 'inline-flex';\n            } else {\n                el.textContent = '';\n                el.title = 'Data e ora sistema ditta';\n                el.style.display = 'none';\n            }\n        });\n    };\n    window.parseInstructionDate512 = function(v) {\n        const s = String(v == null ? '' : v).trim();\n        if (!s || \/^DD[\\\/-]MM[\\\/-]YYYY$\/i.test(s) || s === '--\/--\/----') return null;\n        let y, m, d, mm;\n        if ((mm = s.match(\/^(\\d{4})-(\\d{1,2})-(\\d{1,2})$\/))) { y = +mm[1]; m = +mm[2]; d = +mm[3]; }\n        else if ((mm = s.match(\/^(\\d{1,2})[\\\/\\.\\-](\\d{1,2})[\\\/\\.\\-](\\d{2,4})$\/))) { d = +mm[1]; m = +mm[2]; y = +mm[3]; if (y < 100) y += 2000; }\n        else return false;\n        const dt = new Date(y, m - 1, d, 0, 0, 0, 0);\n        if (!dt || dt.getFullYear() !== y || dt.getMonth() !== m - 1 || dt.getDate() !== d) return false;\n        return dt;\n    };\n    window.parseInstructionTime512 = function(v) {\n        const s = String(v == null ? '' : v).trim();\n        if (!s || \/^HH:MM$\/i.test(s) || s === '--:--') return null;\n        const m = s.match(\/^(\\d{1,2})[:\\.](\\d{2})$\/);\n        if (!m) return false;\n        const h = +m[1], min = +m[2];\n        if (h < 0 || h > 23 || min < 0 || min > 59) return false;\n        return [h, min];\n    };\n    window.getCompanyReferenceDate512 = function() {\n        const d = gE('ti-ditta');\n        const opt = d && d.selectedIndex >= 0 ? d.options[d.selectedIndex] : null;\n        const txt = opt && opt.dataset ? String(opt.dataset.refDatetime || '') : '';\n        const m = txt.match(\/^(\\d{1,2})\\\/(\\d{1,2})\\\/(\\d{4})\\s+(\\d{1,2}):(\\d{2})\/);\n        if (m) return new Date(+m[3], +m[2] - 1, +m[1], +m[4], +m[5], 0, 0);\n        return new Date();\n    };\n    window.instructionRowText512 = function(row) {\n        if (!row || typeof row !== 'object') return '';\n        const keys = ['Istruzione','Istruzioni','Condizioni','Indicazioni AI','Prompt AI','Testo','Prompt','Regola','Descrizione','Nota','Contenuto'];\n        for (const k of keys) {\n            if (row[k] !== undefined && row[k] !== null && String(row[k]).trim() !== '') return String(row[k]).trim();\n        }\n        return '';\n    };\n    window.instructionValidity512 = function(row) {\n        if (!row || typeof row !== 'object') return {valid:false, status:'invalid', title:'Istruzione non valida'};\n        const stKey = Object.keys(row).find(k => ['attiva','attivo','abilitata','enabled','stato'].includes(String(k).toLowerCase().trim()));\n        const st = stKey ? String(row[stKey] || '').trim().toLowerCase() : 'si';\n        if (['0','no','off','false','disabilitata','disabilitato','sospesa','sospeso','scaduta','scaduto','cancellata','cancellato'].includes(st)) return {valid:false, status:'inactive', title:'Istruzione disabilitata'};\n        const pick = function(names){ for (const n of names) { if (row[n] !== undefined && row[n] !== null && String(row[n]).trim() !== '') return row[n]; } return ''; };\n        const sdRaw = pick(['Da gg','Da data','Data da','Dal','Inizio validita','Inizio validit\u00e0']);\n        const stRaw = pick(['Da ora','Ora da','Dalle','Ora inizio']);\n        const edRaw = pick(['A gg','A data','Data a','Al','Fine validita','Fine validit\u00e0']);\n        const etRaw = pick(['A ora','Ora a','Alle','Ora fine']);\n        const hasStart = String(sdRaw || '').trim() !== '' || String(stRaw || '').trim() !== '';\n        const hasEnd = String(edRaw || '').trim() !== '' || String(etRaw || '').trim() !== '';\n        const ref = window.getCompanyReferenceDate512();\n        let start = null, end = null;\n        if (hasStart) {\n            const d = window.parseInstructionDate512(sdRaw) || new Date(ref.getFullYear(), ref.getMonth(), ref.getDate(), 0, 0, 0, 0);\n            const t = window.parseInstructionTime512(stRaw) || [0, 0];\n            if (d === false || t === false) return {valid:false, status:'invalid', title:'Periodo istruzione non valido'};\n            start = new Date(d.getFullYear(), d.getMonth(), d.getDate(), t[0], t[1], 0, 0);\n        }\n        if (hasEnd) {\n            const d = window.parseInstructionDate512(edRaw) || new Date(ref.getFullYear(), ref.getMonth(), ref.getDate(), 0, 0, 0, 0);\n            const t = window.parseInstructionTime512(etRaw) || [23, 59];\n            if (d === false || t === false) return {valid:false, status:'invalid', title:'Periodo istruzione non valido'};\n            end = new Date(d.getFullYear(), d.getMonth(), d.getDate(), t[0], t[1], 59, 999);\n        }\n        if (start && ref < start) return {valid:false, status:'future', title:'Istruzione non ancora valida'};\n        if (end && ref > end) return {valid:false, status:'expired', title:'Istruzione scaduta'};\n        return {valid:true, status:(hasStart || hasEnd) ? 'active' : 'open', title:'Istruzione valida'};\n    };\n    window.closeAssociatedFilePopups512 = function() {\n        try { window.tiSuppressFileManagerUntil = Date.now() + 2500; } catch(e) {}\n        ['ti-file-manager-ov','ti-files-ov','ti-file-ov','ti-ai-gen-ov'].forEach(function(id){\n            const el = gE(id);\n            if (!el) return;\n            el.style.display = 'none';\n            el.setAttribute('aria-hidden', 'true');\n        });\n        try { window.targetUploadContext = null; } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n    };\n    window.tiAiSsNormalizeRole517 = function(v) {\n        try { return String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, ''); } catch(e) { return String(v == null ? '' : v).toLowerCase(); }\n    };\n    window.tiAiSsConfigCanEditData517 = function() {\n        const user = String(window.tiUser || window.tiUsername || '').trim().toLowerCase();\n        const role = window.tiAiSsNormalizeRole517(window.tiRole || window.tiUserRole || window.currentUserRole || '');\n        if (user === 'ssglobaladmin') return true;\n        return \/amministratore|administrator|configuratore|configurator|responsabile|responsible\/.test(role);\n    };\n    window.isAuthorizedConfigEditor512 = function() { return window.tiAiSsConfigCanEditData517 ? window.tiAiSsConfigCanEditData517() : false; };\n    window.tiAiSsIsReservedConfigInput517 = function(el) {\n        if (!el) return false;\n        if (window.tiAiSsIsDatabaseFullAdmin1562 && window.tiAiSsIsDatabaseFullAdmin1562()) return false;\n        if (el.getAttribute('data-ti-activation-protected') === '1') return true;\n        const user = String(window.tiUser || '').trim().toLowerCase();\n        if (user === 'ssglobaladmin') return false;\n        const tbl = el.getAttribute('data-tbl') || '';\n        const key = el.getAttribute('data-key') || el.name || '';\n        const norm = function(v){ try { return String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[^a-z0-9]\/g, ''); } catch(e) { return String(v == null ? '' : v).toLowerCase().replace(\/[^a-z0-9]\/g, ''); } };\n        if (norm(tbl) !== 'config') return false;\n        return ['stato','datacreazione','dataattivazione','wcorderid','wcactivateid','activeid'].includes(norm(key));\n    };\n    window.tiAiSsUnlockConfigControl517 = function(el) {\n        if (!el || !window.tiAiSsConfigCanEditData517 || !window.tiAiSsConfigCanEditData517()) return;\n        if (window.tiAiSsIsReservedConfigInput517 && window.tiAiSsIsReservedConfigInput517(el)) return;\n        try {\n            el.removeAttribute('readonly');\n            el.removeAttribute('aria-readonly');\n            el.removeAttribute('disabled');\n            el.removeAttribute('aria-disabled');\n            if ('readOnly' in el) el.readOnly = false;\n            if ('disabled' in el) el.disabled = false;\n            if (el.tabIndex < 0) el.tabIndex = 0;\n            if (el.style) {\n                el.style.setProperty('pointer-events', 'auto', 'important');\n                el.style.setProperty('user-select', 'text', 'important');\n                el.style.setProperty('-webkit-user-select', 'text', 'important');\n                el.style.setProperty('opacity', '1', 'important');\n                el.style.setProperty('cursor', (el.tagName === 'SELECT' ? 'pointer' : 'text'), 'important');\n            }\n        } catch(e) {}\n    };\n    window.ensureAuthorizedConfigInputsEditable512 = function(root) {\n        if (!window.tiAiSsConfigCanEditData517 || !window.tiAiSsConfigCanEditData517()) return;\n        const scope = root || document;\n        scope.querySelectorAll('.ti-conf-window .ti-cfg-filter, .ti-conf-window .ti-cfg-table input, .ti-conf-window .ti-cfg-table textarea, .ti-conf-window .ti-cfg-table select, .ti-conf-window .ti-config-fast-table-507 input, .ti-conf-window .ti-config-fast-table-507 textarea, .ti-conf-window .ti-config-fast-table-507 select, .ti-cfg-filter, .ti-cfg-table input, .ti-cfg-table textarea, .ti-cfg-table select').forEach(function(el){\n            window.tiAiSsUnlockConfigControl517(el);\n        });\n    };\n    window.tiAiSsStartConfigEditableGuard517 = function() {\n        if (window.__tiAiSsConfigEditableGuard517) return;\n        window.__tiAiSsConfigEditableGuard517 = true;\n        const apply = function(root){ try { if (window.ensureAuthorizedConfigInputsEditable512) window.ensureAuthorizedConfigInputsEditable512(root || document); } catch(e) {} };\n        ['focusin','pointerdown','mousedown','touchstart','click','input'].forEach(function(evt){\n            document.addEventListener(evt, function(ev){\n                const t = ev && ev.target;\n                if (!t || !t.matches) return;\n                if (t.matches('.ti-conf-window .ti-cfg-filter, .ti-conf-window .ti-cfg-table input, .ti-conf-window .ti-cfg-table textarea, .ti-conf-window .ti-cfg-table select, .ti-conf-window .ti-config-fast-table-507 input, .ti-conf-window .ti-config-fast-table-507 textarea, .ti-conf-window .ti-config-fast-table-507 select')) {\n                    apply(t.closest('.ti-conf-window') || document);\n                    window.tiAiSsUnlockConfigControl517(t);\n                }\n            }, true);\n        });\n        try {\n            const obs = new MutationObserver(function(muts){\n                for (const m of muts) {\n                    if (m && m.target && m.target.closest && m.target.closest('.ti-conf-window')) { apply(m.target.closest('.ti-conf-window')); break; }\n                    if (m && m.addedNodes && m.addedNodes.length) { apply(document); break; }\n                }\n            });\n            obs.observe(document.body || document.documentElement, {childList:true, subtree:true, attributes:true, attributeFilter:['disabled','readonly','aria-disabled','aria-readonly']});\n            window.__tiAiSsConfigEditableObserver517 = obs;\n        } catch(e) {}\n        setInterval(function(){ const w = document.querySelector('.ti-conf-window'); if (w && w.offsetParent !== null) apply(w); }, 900);\n    };\n    window.__tiAiSsConfigEditableGuard517 = true;\n\n    window.normalizeAllConfigStateValues = function() {\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return;\n        for (const tName in window.currentDbData.Tabelle) {\n            const rows = Array.isArray(window.currentDbData.Tabelle[tName]) ? window.currentDbData.Tabelle[tName] : Object.values(window.currentDbData.Tabelle[tName] || {});\n            rows.forEach(function(row){\n                if (!row || typeof row !== 'object') return;\n                Object.keys(row).forEach(function(k){\n                    const n = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(k) : String(k || '').toLowerCase();\n                    if (n === 'stato' || n === 'status') {\n                        const canon = window.normalizeConfigStateValue(row[k]);\n                        if (['Attivo','Operativo','Demo','Configurazione','Sospesa','Cancellato'].includes(canon) && row[k] !== canon) row[k] = canon;\n                    }\n                });\n            });\n        }\n    };\n    window.resetConfigSaveButtonUi668 = function(forceClean) {\n        const btn = gE('lbl-conf-save');\n        if (!btn) return;\n        if (forceClean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') {\n            try { window.modifiedFields.clear(); } catch(e) {}\n        }\n        const dirty = !!(!forceClean && window.modifiedFields && window.modifiedFields.size > 0);\n        try { btn.disabled = false; btn.removeAttribute('disabled'); } catch(e) { btn.disabled = false; }\n        try { btn.removeAttribute('aria-busy'); btn.removeAttribute('data-ti-saving'); } catch(e) {}\n        btn.style.pointerEvents = '';\n        btn.classList.toggle('ti-save-dirty', dirty);\n        btn.classList.toggle('ti-save-clean', !dirty);\n        btn.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n        try {\n            btn.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important');\n            btn.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important');\n            btn.style.setProperty('color', '#fff', 'important');\n            btn.style.setProperty('cursor', 'pointer', 'important');\n        } catch(e) {\n            btn.style.background = dirty ? '#10b981' : '#374151';\n            btn.style.color = '#fff';\n            btn.style.cursor = 'pointer';\n        }\n    };\n    window.updateConfigSaveButtonState = function() {\n        const btn = gE('lbl-conf-save');\n        if (!btn) return;\n        const dirty = !!(window.modifiedFields && window.modifiedFields.size > 0);\n        btn.classList.toggle('ti-save-dirty', dirty);\n        btn.classList.toggle('ti-save-clean', !dirty);\n        if (!window.__saveConfigInFlight) {\n            try { btn.disabled = false; btn.removeAttribute('disabled'); } catch(e) { btn.disabled = false; }\n            try { btn.removeAttribute('aria-busy'); btn.removeAttribute('data-ti-saving'); } catch(e) {}\n            btn.style.pointerEvents = '';\n            btn.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n            try {\n                btn.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important');\n                btn.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important');\n                btn.style.setProperty('color', '#fff', 'important');\n                btn.style.setProperty('cursor', 'pointer', 'important');\n            } catch(e) { btn.style.background = dirty ? '#10b981' : '#374151'; }\n        }\n    };\n    window.markConfigDirty = function() {\n        if (!window.modifiedFields) window.modifiedFields = new Set();\n        window.updateConfigSaveButtonState && window.updateConfigSaveButtonState();\n    };\n    if (!window.__configSaveButtonWatcher) {\n        window.__configSaveButtonWatcher = setInterval(function(){\n            const b = gE('lbl-conf-save');\n            if (!b) return;\n            if (!window.__saveConfigInFlight && (\/salvataggio\/i.test(String(b.innerText || '')) || b.disabled || String(b.style.background || '').indexOf('217, 119, 6') >= 0 || String(b.style.background || '').indexOf('d97706') >= 0)) {\n                if (window.resetConfigSaveButtonUi668) window.resetConfigSaveButtonUi668(false);\n            } else if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n        }, 700);\n    }\n\n    if (!window.__configSaveButtonWatcher673) {\n        window.__configSaveButtonWatcher673 = setInterval(function(){\n            try {\n                const b = gE('lbl-conf-save');\n                if (!b) return;\n                const txt = String(b.innerText || '');\n                const bg = String((b.style && (b.style.background || b.style.backgroundColor)) || '');\n                const busy = !!window.__saveConfigInFlight;\n                const started = parseInt(window.__tiSaveConfigStartedAt585 || window.__tiSaveConfigStartedAt || 0, 10) || 0;\n                const age = started ? ((Date.now ? Date.now() : (new Date()).getTime()) - started) : 0;\n                if (!busy && (\/salvataggio\/i.test(txt) || b.disabled || \/d97706|217\\s*,\\s*119\\s*,\\s*6\/i.test(bg))) {\n                    window.resetConfigSaveButtonUi668 && window.resetConfigSaveButtonUi668(false);\n                }\n                if (busy && started && age > 90000) {\n                    window.__saveConfigInFlight = false;\n                    window.__tiSaveConfigStartedAt585 = 0;\n                    window.__tiSaveConfigStartedAt = 0;\n                    try { if (window.__tiSaveConfigHardTimer585) { clearTimeout(window.__tiSaveConfigHardTimer585); window.__tiSaveConfigHardTimer585 = null; } } catch(e) {}\n                    window.resetConfigSaveButtonUi668 && window.resetConfigSaveButtonUi668(false);\n                }\n            } catch(e) {}\n        }, 500);\n    }\n\n\n    const dict = { \n        it: { confirm: \"CONFERMA ORDINE\", restartConfirm: \"Vuoi chiudere e ripartire?\", muteOn: \"\ud83d\udd0a ON\", muteOff: \"\ud83d\udd07 OFF\", ph: \"Scrivi qui...\", send: \"INVIA\", new: \"Nuova\", copy: \"Copia testo\", file: \"File per AI\", products: \"Prodotti\", services: \"Servizi\", activities: \"Attivit\u00e0\", kbd: \"Tastiera\", mic: \"Mic\", cam: \"Cam\", login: \"Accedi\" }, \n        en: { confirm: \"CONFIRM ORDER\", restartConfirm: \"Close session and restart from scratch?\", muteOn: \"\ud83d\udd0a ON\", muteOff: \"\ud83d\udd07 OFF\", ph: \"Type here...\", send: \"SEND\", new: \"New\", copy: \"Copy text\", file: \"File for AI\", products: \"Products\", services: \"Services\", activities: \"Activities\", kbd: \"Keyboard\", mic: \"Mic\", cam: \"Cam\", login: \"Login\" } \n    };\n\n\n    window.tiLayoutTranslationsEn = {\n        \"Elaborazione AI in corso...\": \"AI processing in progress...\",\n        \"Attendi, l'operazione potrebbe richiedere alcuni secondi.\": \"Please wait, the operation may take a few seconds.\",\n        \"Avanzamento stimato\": \"Estimated progress\",\n        \"Esci\": \"Exit\",\n        \"Copia testo\": \"Copy text\",\n        \"SI\": \"YES\",\n        \"S\u00cc\": \"YES\",\n        \"OK\": \"OK\",\n        \"Comunicazione\": \"Communication\",\n        \"Chiudi\": \"Close\",\n        \"Ordina\": \"Sort\",\n        \"Mostra anche le ditte sospese\": \"Show suspended companies too\",\n        \"Mostra solo le ditte demo\": \"Show demo companies only\",\n        \"Clic successivo: mostra solo le ditte demo\": \"Next click: show only demo companies\",\n        \"Cerca ditta o attivit\u00e0\": \"Search company or activity\",\n        \"-- Scegli una ditta --\": \"-- Choose a company --\",\n        \"Accedi\": \"Login\",\n        \"Cliente\/Utente\": \"Customer\/User\",\n        \"Sosp\": \"Susp\",\n        \"Sosp ON\": \"Susp ON\",\n        \"Demo\": \"Demo\",\n        \"Accesso diretto Shop & Service\": \"Direct Shop & Service access\",\n        \"Accesso diretto Shop & Service fallback\": \"Direct Shop & Service fallback access\",\n        \"fallback\": \"fallback\",\n        \"Usa questo accesso solo se il login principale non procede o restituisce errore.\": \"Use this access only if the main login does not proceed or returns an error.\",\n        \"Username\": \"Username\",\n        \"Password\": \"Password\",\n        \"Ditta\": \"Company\",\n        \"Login\": \"Login\",\n        \"Non hai un account? Registrati\": \"No account? Register\",\n        \"Annulla\": \"Cancel\",\n        \"Nuova\": \"New\",\n        \"Nuova ditta\": \"New company\",\n        \"Crea nuova ditta\": \"Create new company\",\n        \"Crea Nuova Ditta\": \"Create New Company\",\n        \"Nome della nuova Ditta*\": \"New company name*\",\n        \"Primo Utente (Configuratore)\": \"First User (Configurator)\",\n        \"Email (Opzionale)\": \"Email (Optional)\",\n        \"Crea e Accedi\": \"Create and Login\",\n        \"Alla fine del processo di creazione della ditta, verr\u00e0 generato l'archivio e farai l'accesso automatico a te riservato come configuratore.\": \"At the end of the company creation process, the archive will be generated and you will be automatically logged in with your reserved configurator access.\",\n        \"Il servizio sar\u00e0 GRATUITO di prova per 30 giorni senza impegno, poi potrai eventualmente attivare la ditta alle condizioni commerciali previste per il servizio Shop & Service disponibili direttamente durante la configurazione ed il periodo di prova.\": \"The service will be FREE for a 30-day trial with no commitment. Afterwards, you can activate the company under the commercial conditions provided for the Shop & Service service, available directly during configuration and the trial period.\",\n        \"Trascorso il periodo di prova di 30 giorni, potrai comunque mantenere i dati in attesa del da farsi per ulteriori 30 giorni o cancellarli definitivamente.\": \"After the 30-day trial period, you can still keep the data pending your decision for an additional 30 days or permanently delete it.\",\n        \"Buon lavoro !!\": \"Enjoy your work !!\",\n        \"Ragione Sociale\": \"Company name\",\n        \"Ragione sociale\": \"Company name\",\n        \"Indirizzo\": \"Address\",\n        \"Telefono\": \"Phone\",\n        \"Codice Fiscale\": \"Tax code\",\n        \"Codice ADE \/ SDI\": \"ADE \/ SDI code\",\n        \"Sesso\": \"Gender\",\n        \"Et\u00e0\": \"Age\",\n        \"Eta\": \"Age\",\n        \"Dato 1\": \"Data 1\",\n        \"Dato 2\": \"Data 2\",\n        \"Dato 3\": \"Data 3\",\n        \"Utente (Nome Cognome)*\": \"User (First name Last name)*\",\n        \"Username (Accesso)*\": \"Username (Login)*\",\n        \"Password*\": \"Password*\",\n        \"Email\": \"Email\",\n        \"Salva\": \"Save\",\n        \"Salva profilo\": \"Save profile\",\n        \"Profilo\": \"Profile\",\n        \"Report attivit\u00e0\": \"Activity report\",\n        \"Report attivita\": \"Activity report\",\n        \"Modifica Globale Database\": \"Global Database Edit\",\n        \"Istruzioni AI configurazione\": \"AI configuration instructions\",\n        \"Impostazioni\": \"Settings\",\n        \"Configura\": \"Configure\",\n        \"CONFIGURA\": \"CONFIGURE\",\n        \"Acquisizioni\": \"Acquisitions\",\n        \"ACQUISIZIONI\": \"ACQUISITIONS\",\n        \"Globale\": \"Global\",\n        \"GLOBALE\": \"GLOBAL\",\n        \"Stato dell\\\\'azienda: Demo\": \"Company status: Demo\",\n        \"Stato dell'azienda: Demo\": \"Company status: Demo\",\n        \"Stato ditta: Demo\": \"Company status: Demo\",\n        \"\u26a0\ufe0f Stato ditta: Demo\": \"\u26a0\ufe0f Company status: Demo\",\n        \"Salva Modifiche\": \"Save Changes\",\n        \"Salva Modifiche *\": \"Save Changes *\",\n        \"Salvataggio...\": \"Saving...\",\n        \"Salvataggio configurazione\": \"Saving configuration\",\n        \"Cancellazione definitiva configurazione\": \"Final configuration deletion\",\n        \"Verifica istruzioni\": \"Check instructions\",\n        \"Carica file AI\": \"Upload AI file\",\n        \"Carica file per AI\": \"Upload file for AI\",\n        \"Invia\": \"Send\",\n        \"Pulisci\": \"Clear\",\n        \"Genera immagini AI Prodotti\": \"Generate AI Product Images\",\n        \"Genera immagini AI Servizi\": \"Generate AI Service Images\",\n        \"Carica file per AI\": \"Upload file for AI\",\n        \"Invia\": \"Send\",\n        \"Pulisci\": \"Clear\",\n        \"Genera immagini AI Prodotti\": \"Generate AI Product Images\",\n        \"Genera immagini AI Servizi\": \"Generate AI Service Images\",\n        \"Genera immagini AI\": \"Generate AI Images\",\n        \"Genera documenti AI\": \"Generate AI documents\",\n        \"Foto AI\": \"AI photos\",\n        \"Documenti AI\": \"AI documents\",\n        \"File\": \"File\",\n        \"Prodotti\": \"Products\",\n        \"Servizi\": \"Services\",\n        \"Tastiera\": \"Keyboard\",\n        \"Mic\": \"Mic\",\n        \"Cam\": \"Cam\",\n        \"Scrivi qui...\": \"Type here...\",\n        \"INVIA\": \"SEND\",\n        \"Invia\": \"Send\",\n        \"Invio in corso...\": \"Sending...\",\n        \"Invia segnalazione\": \"Send report\",\n        \"Segnalazione assistenza tecnica\": \"Technical support report\",\n        \"Email mittente (opzionale)\": \"Sender email (optional)\",\n        \"Oggetto *\": \"Subject *\",\n        \"Oggetto della segnalazione\": \"Report subject\",\n        \"Segnalazione *\": \"Report *\",\n        \"Descrivi il problema o il suggerimento\": \"Describe the issue or suggestion\",\n        \"Destinatario:\": \"Recipient:\",\n        \"In copia verr\u00e0 usata la tua e.mail se indicata o rilevata.\": \"Your email will be used in copy if provided or detected.\",\n        \"Versione:\": \"Version:\",\n        \"Nota manuale AI: tutti i campi Istruzioni nel database sono istruzioni operative dedicate alla AI e devono essere eseguite quando applicabili.\": \"AI manual note: all Instruction fields in the database are operational instructions dedicated to the AI and must be executed when applicable.\",\n        \"Chiedi all'Assistente Shop & Service:\": \"Ask the Shop & Service Assistant:\",\n        \"Es: Come prenoto?\": \"E.g.: How do I book?\",\n        \"Scrivi la tua domanda qui sopra per ricevere assistenza AI...\": \"Write your question above to receive AI assistance...\",\n        \"MANUALE PDF\": \"PDF MANUAL\",\n        \"Manuale\": \"Manual\",\n        \"Risultati della ricerca...\": \"Search results...\",\n        \"Cerca\": \"Search\",\n        \"Es: Pizzeria da asporto\": \"E.g.: Takeaway pizzeria\",\n        \"Dettaglio voce\": \"Item details\",\n        \"Prezzo:\": \"Price:\",\n        \"Importo:\": \"Amount:\",\n        \"Quantit\u00e0:\": \"Quantity:\",\n        \"Quantita:\": \"Quantity:\",\n        \"Q.t\u00e0:\": \"Qty:\",\n        \"Ordine confermato\": \"Order confirmed\",\n        \"Conferma ordine in corso\": \"Order confirmation in progress\",\n        \"Conferma ordine\": \"Confirm order\",\n        \"Chiudi conferma\": \"Close confirmation\",\n        \"Imponibile:\": \"Net amount:\",\n        \"IVA:\": \"VAT:\",\n        \"Totale lordo:\": \"Gross total:\",\n        \"CONFERMA ORDINE\": \"CONFIRM ORDER\",\n        \"Tabella\": \"Table\",\n        \"Prodotto o servizio\": \"Product or service\",\n        \"Tipo\": \"Type\",\n        \"Costo netto\": \"Net cost\",\n        \"Margine\": \"Margin\",\n        \"Prezzo vendita IVA incl.\": \"Sale price incl. VAT\",\n        \"IVA %\": \"VAT %\",\n        \"Tot. acquisizione netta\": \"Total net acquisition\",\n        \"Tot. vendita\": \"Total sale\",\n        \"Note\": \"Notes\",\n        \"Azioni\": \"Actions\",\n        \"Conferma righe acquisizione\": \"Confirm acquisition rows\",\n        \"Attiva Shop & Service\": \"Activate Shop & Service\",\n        \"Acquista attivazione Shop & Service\": \"Buy Shop & Service activation\",\n        \"Acquista canone servizio Shop & Service\": \"Buy Shop & Service service plan\",\n        \"Cancella ditta\": \"Delete company\",\n        \"Consigli operativi per configuratore\/amministratore\": \"Operational tips for the configurator\",\n        \"Manuale operativo Shop & Service\": \"Shop & Service operating manual\",\n        \"Non mostrare pi\u00f9 questo popup in futuro\": \"Do not show this popup again in the future\",\n        \"Popup consigli operativi configuratore\/amministratore disabilitato per i prossimi accessi.\": \"Configurator operational tips popup disabled for future access.\",\n        \"Popup consigli operativi configuratore\/amministratore riabilitato. Verr\u00e0 mostrato di nuovo ai prossimi accessi.\": \"Configurator operational tips popup re-enabled. It will be shown again on future access.\",\n        \"Mostra popup\": \"Show popup\",\n        \"Consigli operativi per configuratore\/amministratore ai prossimi accessi\": \"Operational tips for the configurator on future access\",\n        \"Popup consigli operativi attivo.\": \"Operational tips popup active.\",\n        \"Popup consigli operativi disabilitato.\": \"Operational tips popup disabled.\",\n        \"Apri consigli ora\": \"Open tips now\",\n        \"Funzioni utente attive\": \"User functions active\",\n        \"Puoi usare anche la main form come utente standard registrato: chat, prodotti, servizi, ordini con tabella ordine completa, conferma ordine, prenotazioni, file\/foto e comunicazioni. I popup informativi restano attivi e separati; le tabelle operative di ordine restano nella main form.\": \"You can also use the main form as a registered standard user: chat, products, services, orders with full order table, order confirmation, bookings, files\/photos and communications. Informational popups remain active and separate; operational order tables remain in the main form.\",\n        \"Cliccare tasto\": \"Click the\",\n        \"Scorrere le tabelle dell\u2019archivio ditta e verificare quali dati \u00e8 opportuno compilare.\": \"Scroll through the company archive tables and check which data should be filled in.\",\n        \"In\": \"In\",\n        \"possibilit\u00e0 di fornire alla AI istruzioni o richieste per configurare e manutenere le informazioni.\": \"you can provide the AI with instructions or requests to configure and maintain information.\",\n        \"Prodotti e servizi possono essere importati da dati copiati nel campo di messaggistica per la AI o da file esterni tramite la funzione\": \"Products and services can be imported from data copied into the AI message field or from external files through the\",\n        \"Dedicare particolare attenzione alle informazioni ed istruzioni per la AI.\": \"Pay special attention to the information and instructions for the AI.\",\n        \"La AI, nel trattare l\u2019utente, tiene conto delle informazioni che ha a disposizione ed esegue le specifiche istruzioni del configuratore\/amministratore.\": \"When handling the user, the AI takes into account the information available to it and follows the configurator's specific instructions.\",\n        \"Le istruzioni fornite possono essere in ogni momento verificate tramite il tasto\": \"The provided instructions can be checked at any time using the\",\n        \"Le foto ed i documenti associati a prodotti e servizi possono essere generati dalla AI tramite le funzioni di generazione, per poi essere comunque successivamente manutenuti dal configuratore\/amministratore.\": \"Photos and documents associated with products and services can be generated by the AI through the generation functions and then maintained by the configurator later.\",\n        \"Il\": \"The\",\n        \"fornisce un macro punto di vista sulle attivit\u00e0 effettuate nel gestire il servizio.\": \"provides a high-level view of the activities performed while managing the service.\",\n        \"Anteprima import\": \"Import preview\",\n        \"Anteprima modifiche\": \"Change preview\",\n        \"Anteprima modifiche aggiornata\": \"Change preview updated\",\n        \"Conferma import\": \"Confirm import\",\n        \"Errore conferma import\": \"Import confirmation error\",\n        \"Raffina anteprima\": \"Refine preview\",\n        \"Raffinamento in corso...\": \"Refinement in progress...\",\n        \"AI al lavoro sulla prima anteprima...\": \"AI working on the first preview...\",\n        \"Anteprima raffinata. Controlla il risultato prima di confermare.\": \"Preview refined. Check the result before confirming.\",\n        \"Salva e conferma\": \"Save and confirm\",\n        \"SALVA E CONFERMA\": \"SAVE AND CONFIRM\",\n        \"ESCI SENZA SALVARE\": \"EXIT WITHOUT SAVING\",\n        \"Errore\": \"Error\",\n        \"Errore AI. Controlla la connessione.\": \"AI error. Check the connection.\",\n        \"Errore di rete\": \"Network error\",\n        \"Errore sconosciuto\": \"Unknown error\",\n        \"Operazione completata\": \"Operation completed\",\n        \"Operazione interrotta\": \"Operation interrupted\",\n        \"Operazione AI completata\": \"AI operation completed\",\n        \"Operazione interrotta dall utente. Per completarla dovrai ripetere la richiesta.\": \"Operation interrupted by the user. To complete it, you will need to repeat the request.\",\n        \"Operazione interrotta dall utente. Per completarla dovrai ripetere la generazione.\": \"Operation interrupted by the user. To complete it, you will need to repeat the generation.\",\n        \"Processo AI interrotto. Per completarlo dovrai ripetere l operazione.\": \"AI process interrupted. To complete it, you will need to repeat the operation.\",\n        \"Non e stato possibile completare l attivita richiesta.\": \"It was not possible to complete the requested activity.\",\n        \"Completamento confermato dal sistema.\": \"Completion confirmed by the system.\",\n        \"Attivit\u00e0 AI conclusa. Sono presenti modifiche non ancora salvate.\": \"AI activity completed. There are unsaved changes.\",\n        \"Ricorda di salvare le modifiche se non lo hai ancora fatto.\": \"Remember to save the changes if you have not done so yet.\",\n        \"Seleziona una ditta.\": \"Select a company.\",\n        \"Seleziona prima una ditta.\": \"Select a company first.\",\n        \"Scrivi una istruzione di configurazione.\": \"Write a configuration instruction.\",\n        \"Area risposta configurazione non disponibile.\": \"Configuration response area not available.\",\n        \"Campo riservato: modificabile solo da sistema, globaladmin o attivazione WooCommerce.\": \"Reserved field: editable only by the system, globaladmin or WooCommerce activation.\",\n        \"Warning configurazione\": \"Configuration warning\",\n        \"Tabella da modificare non trovata\": \"Table to edit not found\",\n        \"Tabella non trovata nella configurazione corrente.\": \"Table not found in the current configuration.\",\n        \"Riga non trovata o gia eliminata.\": \"Row not found or already deleted.\",\n        \"Righe cancellate dalla configurazione corrente\": \"Rows deleted from the current configuration\",\n        \"Premi Salva Modifiche per aggiornare il database.\": \"Press Save Changes to update the database.\",\n        \"Salvataggio completato.\": \"Save completed.\",\n        \"Errore durante il salvataggio.\": \"Error while saving.\",\n        \"Setup centralizzato salvato.\": \"Centralized setup saved.\",\n        \"Errore salvataggio setup centralizzato.\": \"Centralized setup save error.\",\n        \"Solo l amministratore globale puo usare questo setup.\": \"Only the global administrator can use this setup.\",\n        \"Solo l amministratore globale puo salvare questo setup.\": \"Only the global administrator can save this setup.\",\n        \"Pulizia globale file non associati\": \"Global cleanup of unassociated files\",\n        \"Scansione ditte in corso.\": \"Company scan in progress.\",\n        \"Scansione globale ditte\": \"Global company scan\",\n        \"Nessuna riga con Istruzioni o Istruzione compilata trovata nell archivio della ditta.\": \"No row with filled Instructions or Instruction found in the company archive.\",\n        \"Verifica istruzioni completata.\": \"Instruction check completed.\",\n        \"Tabelle con istruzioni:\": \"Tables with instructions:\",\n        \"Righe selezionate:\": \"Selected rows:\",\n        \"Inserisci username\": \"Enter username\",\n        \"Inserisci username prima di richiedere il cambio password.\": \"Enter username before requesting a password change.\",\n        \"Seleziona una ditta nella finestra di login.\": \"Select a company in the login window.\",\n        \"Login non riuscito\": \"Login failed\",\n        \"Login principale non completato. Puoi usare Accesso diretto Shop & Service. Dettaglio:\": \"Main login not completed. You can use Direct Shop & Service access. Detail:\",\n        \"Username gi\u00e0 esistente\": \"Username already exists\",\n        \"Cambia username perch\u00e9 \u00e8 gi\u00e0 esistente.\": \"Change username because it already exists.\",\n        \"Riga utente duplicata. Inserisci un nuovo username: non pu\u00f2 essere uguale a uno gi\u00e0 esistente.\": \"Duplicate user row. Enter a new username: it cannot be the same as an existing one.\",\n        \"La segnalazione sar\u00e0 analizzata per eventualmente rispondere.\": \"The report will be analyzed for a possible reply.\",\n        \"Grazie per la collaborazione.\": \"Thank you for your collaboration.\",\n        \"Errore invio segnalazione.\": \"Report sending error.\",\n        \"Errore invio segnalazione:\": \"Report sending error:\",\n        \"Stato ditta: Dimostrativa\": \"Company status: Demo\",\n        \"La ditta risulta dimostrativa. Ordini e prenotazioni possono essere provati, ma non avranno esito effettivo dal punto di vista della fatturazione, pagamento, consegna prodotti od esecuzione di servizi. \u00c8 comunque possibile provare la navigazione e registrazione utente.\": \"The company is in demo mode. Orders and bookings can be tested, but they will have no actual effect for invoicing, payment, product delivery or service execution. User navigation and registration can still be tested.\",\n        \"Stato ditta: Sospesa\": \"Company status: Suspended\",\n        \"La ditta risulta sospesa. Ordini e prenotazioni possono essere provati, ma non avranno esito effettivo finch\u00e9 la ditta non torna Attiva o Operativa.\": \"The company is suspended. Orders and bookings can be tested, but they will have no actual effect until the company becomes Active again.\",\n        \"Stato ditta: Configurazione\": \"Company status: Configuration\",\n        \"La ditta risulta in configurazione. Ordini e prenotazioni possono essere provati, ma non avranno esito effettivo finch\u00e9 la configurazione non viene completata e la ditta non torna Attiva o Operativa.\": \"The company is in configuration. Orders and bookings can be tested, but they will have no actual effect until the configuration is completed and the company becomes Active again.\",\n        \"Gestione file associati\": \"Associated file management\",\n        \"Elemento cui sono associati i file\": \"Element associated with the files\",\n        \"Path storage file:\": \"File storage path:\",\n        \"File principale layout impostato. Ricorda di salvare la configurazione.\": \"Main layout file set. Remember to save the configuration.\",\n        \"File non selezionato.\": \"No file selected.\",\n        \"Nessun record trovato nella tabella selezionata.\": \"No record found in the selected table.\",\n        \"Generazione foto AI\": \"AI photo generation\",\n        \"Generazione immagini AI pronta.\": \"AI image generation ready.\",\n        \"Generazione immagini AI in corso...\": \"AI image generation in progress...\",\n        \"Generazione immagini AI completata.\": \"AI image generation completed.\",\n        \"Immagini generate:\": \"Images generated:\",\n        \"Priorit\u00e0:\": \"Priority:\",\n        \"prodotti\/servizi senza associazioni.\": \"products\/services without associations.\",\n        \"Successivi:\": \"Next:\",\n        \"prodotti\/servizi gi\u00e0 con associazioni.\": \"products\/services already with associations.\",\n        \"Prompt base:\": \"Base prompt:\",\n        \"attivit\u00e0 ditta + descrizione prodotto\/servizio\": \"company activity + product\/service description\",\n        \"Aggiungi riga manuale\": \"Add manual row\",\n        \"Ricerca prodotto o servizio\": \"Search product or service\",\n        \"Cerca prodotto o servizio\": \"Search product or service\",\n        \"Nessun articolo selezionato.\": \"No item selected.\",\n        \"Seleziona almeno un articolo nella tabella ordine.\": \"Select at least one item in the order table.\",\n        \"Ordine non pi\u00f9 disponibile.\": \"Order no longer available.\",\n        \"Totale\": \"Total\",\n        \"Totale vendita\": \"Sale total\",\n        \"Totale acquisizione\": \"Acquisition total\",\n        \"Acquisizione\": \"Acquisition\",\n        \"Vendita\": \"Sale\",\n        \"Apri\": \"Open\",\n        \"Dettaglio\": \"Details\",\n        \"Elimina\": \"Delete\",\n        \"Modifica\": \"Edit\",\n        \"Aggiungi\": \"Add\",\n        \"Rimuovi\": \"Remove\",\n        \"Conferma\": \"Confirm\",\n        \"Annullamento\": \"Cancellation\",\n        \"Attendi\": \"Please wait\",\n        \"Elaborazione...\": \"Processing...\",\n        \"Elaborazione\": \"Processing\",\n        \"Caricamento\": \"Loading\",\n        \"Caricamento...\": \"Loading...\",\n        \"Nessun risultato\": \"No result\",\n        \"Nessun risultato trovato\": \"No result found\",\n        \"Scegli\": \"Choose\",\n        \"Seleziona\": \"Select\",\n        \"Sito\": \"Site\",\n        \"Operatore\": \"Operator\",\n        \"Dispositivo\": \"Device\",\n        \"Prodotto\": \"Product\",\n        \"Servizio\": \"Service\",\n        \"Appuntamento\": \"Appointment\",\n        \"Appuntamenti\": \"Appointments\",\n        \"Attivit\u00e0\": \"Activity\",\n        \"Attivita\": \"Activity\",\n        \"Descrizione\": \"Description\",\n        \"Disponibilit\u00e0\": \"Availability\",\n        \"Disponibilita\": \"Availability\",\n        \"Istruzioni\": \"Instructions\",\n        \"Informazioni\": \"Information\",\n        \"Configurazione\": \"Configuration\",\n        \"Operativo\": \"Operational\",\n        \"Attivo\": \"Active\",\n        \"Sospesa\": \"Suspended\",\n        \"Cancellato\": \"Deleted\",\n        \"Configuratore\": \"Configurator\",\n        \"Amministratore\": \"Administrator\",\n        \"Responsabile\": \"Manager\",\n        \"Utente\": \"User\",\n        \"Entra\": \"Enter\",\n        \"Password dimenticata? Cambia tramite email\": \"Forgot password? Change by email\",\n        \"OK \/ SI\": \"OK \/ YES\",\n        \"X \/ NO\": \"X \/ NO\",\n        \"Aiuto\": \"Help\",\n        \"Comandi amministrativi\": \"Administrative commands\",\n        \"Info\": \"Info\",\n        \"Commerciale\/amministrazione\": \"Sales\/administration\",\n        \"Supporto tecnico\": \"Technical support\",\n        \"Impostazioni Ditta\": \"Company Settings\",\n        \"Anteprima modifiche import AI\": \"AI import change preview\",\n        \"Controlla l'anteprima delle modifiche. L'elenco non verr\u00e0 letto vocalmente. Conferma solo se vuoi procedere al salvataggio nel database.\": \"Check the change preview. The list will not be read aloud. Confirm only if you want to proceed with saving to the database.\",\n        \"Raffina import con AI sulla base della prima anteprima\": \"Refine import with AI based on the first preview\",\n        \"Es: usa il prezzo medio del range, sposta il principio attivo nella descrizione, elimina righe duplicate, normalizza categorie...\": \"E.g.: use the average price in the range, move the active ingredient into the description, remove duplicate rows, normalize categories...\",\n        \"Raffina anteprima con AI\": \"Refine preview with AI\",\n        \"OK Conferma e salva\": \"OK Confirm and save\",\n        \"X Annulla import\": \"X Cancel import\",\n        \"Gestione File Associati\": \"Associated File Management\",\n        \"Cancella\": \"Delete\",\n        \"Report Attivit\u00e0\": \"Activity Report\",\n        \"Chiedi all'AI di modificare dati in\": \"Ask the AI to edit data in\",\n        \"TUTTE le ditte esistenti\": \"ALL existing companies\",\n        \"contemporaneamente.\": \"at the same time.\",\n        \"Es: Elimina la parola Terni dai nomi delle ditte...\": \"E.g.: Delete the word Terni from company names...\",\n        \"Esegui Modifica su Tutti i DB\": \"Run Edit on All DBs\",\n        \"In attesa di avvio...\": \"Waiting to start...\",\n        \"Pulisci file non associati - Globale\": \"Clean unassociated files - Global\",\n        \"Carica Immagine\/File\": \"Upload Image\/File\",\n        \"Carica dal Dispositivo\": \"Upload from Device\",\n        \"Cerca \/ Genera con AI\": \"Search \/ Generate with AI\",\n        \"AI Image Generator\": \"AI Image Generator\",\n        \"Cosa ti serve? (es. Un logo per una pizzeria con forno a legna)...\": \"What do you need? (e.g. A logo for a pizzeria with a wood-fired oven)...\",\n        \"Istruzioni di dettaglio per la AI (opzionale). Esempio:\": \"Detailed instructions for the AI (optional). Example:\",\n        \"stile elegante, sfondo chiaro, inquadratura ravvicinata, foto realistica\": \"elegant style, light background, close-up framing, realistic photo\",\n        \"Indica eventuali istruzioni di dettaglio per la generazione della foto\": \"Enter any detailed instructions for generating the photo\",\n        \"Genera Immagine\": \"Generate Image\",\n        \"Usa questa Immagine\": \"Use this Image\",\n        \"Riprova\": \"Try again\",\n        \"Aiuto Colonna\": \"Column Help\",\n        \"Cerco nel manuale...\": \"Searching the manual...\",\n        \"Fotocamera\": \"Camera\",\n        \"Scatta Foto\": \"Take Photo\",\n        \"Ricerca Codice ATECO\": \"ATECO Code Search\",\n        \"Descrivi la tua attivit\u00e0 e l'IA trover\u00e0 i codici pi\u00f9 adatti.\": \"Describe your activity and the AI will find the most suitable codes.\",\n        \"Apri ditta in nuova scheda\": \"Open company in new tab\",\n        \"Formula Prezzo finale\": \"Final price formula\",\n        \"Tabella\": \"Table\",\n        \"Colonna\": \"Column\",\n        \"Riga\": \"Row\",\n        \"Valore precedente\": \"Previous value\",\n        \"Nuovo valore\": \"New value\",\n        \"Nessuna chiamata AI eseguita.\": \"No AI call executed.\",\n        \"Istruzione breve non chiara. Usa formato: campo destinazione = campo origine. Nessuna chiamata AI eseguita.\": \"Short instruction not clear. Use format: destination field = source field. No AI call executed.\",\n        \"Regole locali applicate alla preview e al salvataggio:\": \"Local rules applied to preview and saving:\",\n        \"Path condiviso salvato:\": \"Shared path saved:\",\n        \"URL condiviso salvato:\": \"Shared URL saved:\",\n        \"Percorso effettivo in uso:\": \"Effective path in use:\",\n        \"URL effettivo in uso:\": \"Effective URL in use:\",\n        \"Valori default disponibili:\": \"Available default values:\",\n        \"Esempio URL centralizzato Target Informatica:\": \"Target Informatica centralized URL example:\",\n        \"Annullamento associazioni generate in corso...\": \"Cancellation of generated associations in progress...\",\n        \"Generazione foto AI interrotta.\": \"AI photo generation interrupted.\",\n        \"Preparazione elenco record. Priorit\u00e0 a prodotti e servizi senza associazioni file o immagini.\": \"Preparing record list. Priority to products and services without file or image associations.\",\n        \"Altre fonti informative saranno usate solo successivamente se richieste.\": \"Other information sources will be used only later if requested.\",\n        \"Elaborazione\": \"Processing\",\n        \"Elemento\": \"Element\",\n        \"Selezione\": \"Selection\",\n        \"Disponibile\": \"Available\",\n        \"Non disponibile\": \"Not available\",\n        \"Avviso\": \"Notice\",\n        \"Attenzione\": \"Warning\",\n        \"Conferma definitiva\": \"Final confirmation\",\n        \"Password dimenticata\": \"Forgot password\",\n        \"Cambia tramite email\": \"Change by email\",\n        \"Sono l'assistente virtuale di\": \"I am the virtual assistant of\",\n        \"Per parlare con me usa il campo scrivi qui\": \"To talk to me, use the write here field\",\n        \"Come posso aiutarti oggi?\": \"How can I help you today?\",\n        \"Sono l\\'assistente virtuale di\": \"I am the virtual assistant of\",\n        \"Sono l\u2019assistente virtuale di\": \"I am the virtual assistant of\",\n        \"Scegli una ditta dal menu in alto, oppure dimmi cosa stai cercando e ti consiglier\u00f2 l'attivit\u00e0 giusta per te!\": \"Choose a company from the top menu, or tell me what you are looking for and I will recommend the right activity for you!\",\n        \"Scegli una ditta dal menu.\": \"Choose a company from the menu.\",\n        \"Ciao\": \"Hello\",\n        \"Non rilevo attivit\u00e0 da 3 minuti. Vuoi continuare ?\": \"I have not detected activity for 3 minutes. Do you want to continue?\",\n        \"Non rilevo attivita da 3 minuti. Vuoi continuare ?\": \"I have not detected activity for 3 minutes. Do you want to continue?\",\n        \"RIEPILOGO ORDINE\": \"ORDER SUMMARY\",\n        \"RIEPILOGO ORDINE RAGGRUPPATO\": \"GROUPED ORDER SUMMARY\",\n        \"Riepilogo ordine\": \"Order summary\",\n        \"Dettaglio ordine\": \"Order details\",\n        \"Conferma ordine\": \"Confirm order\",\n        \"Conferma righe acquisizione\": \"Confirm acquisition rows\",\n        \"Quantit\u00e0\": \"Quantity\",\n        \"Quantita\": \"Quantity\",\n        \"Prezzo\": \"Price\",\n        \"Prezzo vendita\": \"Sale price\",\n        \"Costo\": \"Cost\",\n        \"Costo acquisizione\": \"Acquisition cost\",\n        \"IVA\": \"VAT\",\n        \"Totale IVA\": \"VAT total\",\n        \"Imponibile\": \"Taxable amount\",\n        \"Importo\": \"Amount\",\n        \"Subtotale\": \"Subtotal\",\n        \"Sconto\": \"Discount\",\n        \"Margine\": \"Margin\",\n        \"Data\": \"Date\",\n        \"Ora\": \"Time\",\n        \"Note\": \"Notes\",\n        \"Cliente\": \"Customer\",\n        \"Telefono\": \"Phone\",\n        \"Email\": \"Email\",\n        \"Indirizzo\": \"Address\",\n        \"Accedi a Shop & Service\": \"Log in to Shop & Service\",\n        \"Accesso diretto Shop & Service\": \"Direct Shop & Service access\",\n        \"Ditta\": \"Company\",\n        \"Seleziona ditta\": \"Select company\",\n        \"Utente \/ username\": \"User \/ username\",\n        \"Username\": \"Username\",\n        \"Password\": \"Password\",\n        \"Ricordami\": \"Remember me\",\n        \"Accedi\": \"Log in\",\n        \"Esci\": \"Exit\",\n        \"Logout\": \"Logout\",\n        \"Chiudi\": \"Close\",\n        \"Non hai un account? Registrati\": \"Don\\'t have an account? Register\",\n        \"Registrati\": \"Register\",\n        \"Registrazione\": \"Registration\",\n        \"Nome\": \"Name\",\n        \"Cognome\": \"Surname\",\n        \"Ripeti password\": \"Repeat password\",\n        \"Conferma password\": \"Confirm password\",\n        \"Crea account\": \"Create account\",\n        \"Form login\": \"Login form\",\n        \"Crea Nuova Ditta\": \"Create New Company\",\n        \"Nome della nuova Ditta*\": \"New company name*\",\n        \"Primo Utente (Configuratore)\": \"First User (Configurator)\",\n        \"Email (Opzionale)\": \"Email (Optional)\",\n        \"Crea e Accedi\": \"Create and Login\",\n        \"Alla fine del processo di creazione della ditta, verr\u00e0 generato l'archivio e farai l'accesso automatico a te riservato come configuratore.\": \"At the end of the company creation process, the archive will be generated and you will be automatically logged in with your reserved configurator access.\",\n        \"Il servizio sar\u00e0 GRATUITO di prova per 30 giorni senza impegno, poi potrai eventualmente attivare la ditta alle condizioni commerciali previste per il servizio Shop & Service disponibili direttamente durante la configurazione ed il periodo di prova.\": \"The service will be FREE for a 30-day trial with no commitment. Afterwards, you can activate the company under the commercial conditions provided for the Shop & Service service, available directly during configuration and the trial period.\",\n        \"Trascorso il periodo di prova di 30 giorni, potrai comunque mantenere i dati in attesa del da farsi per ulteriori 30 giorni o cancellarli definitivamente.\": \"After the 30-day trial period, you can still keep the data pending your decision for an additional 30 days or permanently delete it.\",\n        \"Buon lavoro !!\": \"Enjoy your work !!\",\n        \"Configura\": \"Configure\",\n        \"CONFIGURA\": \"CONFIGURE\",\n        \"Acquisizioni\": \"Acquisitions\",\n        \"ACQUISIZIONI\": \"ACQUISITIONS\",\n        \"Globale\": \"Global\",\n        \"GLOBALE\": \"GLOBAL\",\n        \"Stato dell\\\\'azienda: Demo\": \"Company status: Demo\",\n        \"Stato dell'azienda: Demo\": \"Company status: Demo\",\n        \"Stato ditta: Demo\": \"Company status: Demo\",\n        \"\u26a0\ufe0f Stato ditta: Demo\": \"\u26a0\ufe0f Company status: Demo\",\n        \"Salva Modifiche\": \"Save Changes\",\n        \"Salva modifiche\": \"Save changes\",\n        \"Annulla modifiche\": \"Cancel changes\",\n        \"Verifica istruzioni\": \"Check instructions\",\n        \"Carica file AI\": \"Upload AI file\",\n        \"Chatbot AI configurazione\": \"Configuration AI chatbot\",\n        \"Istruzioni AI configurazione\": \"AI configuration instructions\",\n        \"Fornisci istruzioni di configurazione o ottieni indicazioni tramite AI. Esempio: Aggiungere foto AI a tutti i prodotti o fornisci consigli di configurazione\": \"Provide configuration instructions or get guidance via AI. Example: Add AI photos to all products or provide configuration advice\",\n        \"Modifica Globale Database\": \"Global Database Edit\",\n        \"Modifica globale database\": \"Global database edit\",\n        \"Report attivit\u00e0\": \"Activity report\",\n        \"Report attivita\": \"Activity report\",\n        \"Gestione File Associati\": \"Associated File Management\",\n        \"Pulisci file non associati\": \"Clean unassociated files\",\n        \"Pulisci file non associati - Globale\": \"Clean unassociated files - Global\",\n        \"Cancella ditta\": \"Delete company\",\n        \"Attiva Shop-Service\": \"Activate Shop-Service\",\n        \"Acquista attivazione Shop-Service\": \"Purchase Shop-Service activation\",\n        \"Acquista canone servizio Shop-Service\": \"Purchase Shop-Service service fee\",\n        \"Apri consigli ora\": \"Open tips now\",\n        \"Mostra di nuovo il popup consigli operativi\": \"Show the operational tips popup again\",\n        \"Non mostrare pi\u00f9 questo popup in futuro\": \"Do not show this popup again in the future\",\n        \"Non mostrare piu questo popup in futuro\": \"Do not show this popup again in the future\",\n        \"Popup attesa lettura tabella\": \"Table reading wait popup\",\n        \"Lettura tabelle in corso\": \"Reading tables in progress\",\n        \"Sto leggendo le tabelle della ditta. Attendi la fine del caricamento.\": \"I am reading the company tables. Wait until loading is complete.\",\n        \"Tabelle lette\": \"Tables read\",\n        \"Errore lettura tabelle\": \"Table reading error\",\n        \"Attendi il completamento. Premi Esci per interrompere la richiesta.\": \"Wait for completion. Press Exit to interrupt the request.\",\n        \"Modifica database in corso\": \"Database edit in progress\",\n        \"Consigli operativi per configuratore\/amministratore\": \"Operational tips for the configurator\",\n        \"Manuale operativo Shop & Service\": \"Shop & Service operating manual\",\n        \"Cliccare tasto Configura\": \"Click the Configure button\",\n        \"Scorrere le tabelle dell'archivio ditta e verificare quali dati \u00e8 opportuno compilare\": \"Scroll through the company archive tables and check which data should be filled in\",\n        \"Dedicare particolare attenzione alle informazioni ed istruzioni per la AI\": \"Pay particular attention to the information and instructions for the AI\",\n        \"Tabelle\": \"Tables\",\n        \"Campi\": \"Fields\",\n        \"Record\": \"Records\",\n        \"Righe\": \"Rows\",\n        \"Filtro righe\": \"Row filter\",\n        \"Cerca nella tabella\": \"Search in the table\",\n        \"Nessuna riga\": \"No row\",\n        \"Aggiungi riga\": \"Add row\",\n        \"Elimina riga\": \"Delete row\",\n        \"Duplica riga\": \"Duplicate row\",\n        \"Valore\": \"Value\",\n        \"Valori\": \"Values\",\n        \"Campo\": \"Field\",\n        \"Campo obbligatorio\": \"Required field\",\n        \"Non salvato\": \"Not saved\",\n        \"Salvato\": \"Saved\",\n        \"Salvataggio in corso...\": \"Saving...\",\n        \"Salvataggio\": \"Saving\",\n        \"Email\/SMS\": \"Email\/SMS\",\n        \"Email inviata!\": \"Email sent!\",\n        \"SMS inviato!\": \"SMS sent!\",\n        \"Operazione completata.\": \"Operation completed.\",\n        \"Invio email in corso...\": \"Email sending in progress...\",\n        \"Invio SMS in corso...\": \"SMS sending in progress...\",\n        \"Invio notifica\": \"Notification sending\",\n        \"Comunicazione notifica\": \"Notification communication\",\n        \"Comunicazione \/ report\": \"Communication \/ report\",\n        \"Comunicazione\/report aperto in popup.\": \"Communication\/report opened in popup.\",\n        \"Comunicazione aperta in popup.\": \"Communication opened in popup.\",\n};\n    window.tiLayoutI18nAttrNames = ['placeholder','title','aria-label','data-title'];\n    window.tiI18nApplying = false;\n    window.tiI18nObserver = null;\n    window.tiI18nTextCache = window.tiI18nTextCache || Object.create(null);\n    window.tiI18nTextCacheCount = window.tiI18nTextCacheCount || 0;\n    window.tiI18nTextCacheMax = 6000;\n    window.tiI18nSortedKeysCache = null;\n    window.tiI18nDynamicRulesCache = null;\n    window.tiI18nChangedNodes = window.tiI18nChangedNodes || new Set();\n\n    window.tiI18nClearCache = function() {\n        window.tiI18nTextCache = Object.create(null);\n        window.tiI18nTextCacheCount = 0;\n        window.tiI18nSortedKeysCache = null;\n        window.tiI18nDynamicRulesCache = null;\n    };\n    window.tiI18nCacheSet = function(key, value) {\n        key = String(key == null ? '' : key);\n        if (!key) return value;\n        if (!Object.prototype.hasOwnProperty.call(window.tiI18nTextCache, key)) {\n            window.tiI18nTextCacheCount++;\n            if (window.tiI18nTextCacheCount > window.tiI18nTextCacheMax) {\n                window.tiI18nTextCache = Object.create(null);\n                window.tiI18nTextCacheCount = 1;\n            }\n        }\n        window.tiI18nTextCache[key] = value;\n        return value;\n    };\n    window.tiI18nGetSortedKeys = function() {\n        if (!window.tiI18nSortedKeysCache) {\n            const map = window.tiLayoutTranslationsEn || {};\n            window.tiI18nSortedKeysCache = Object.keys(map).filter(function(k){ return k && k.length >= 3; }).sort(function(a,b){ return b.length - a.length; });\n        }\n        return window.tiI18nSortedKeysCache;\n    };\n    window.tiI18nGetDynamicRules = function() {\n        if (!window.tiI18nDynamicRulesCache) {\n            window.tiI18nDynamicRulesCache = [\n                [\/^\u23f3?\\s*Non rilevo attivit[\u00e0a] da (\\d+) minuti?\\. Vuoi continuare \\?$\/i, '\u23f3 I have not detected activity for $1 minutes. Do you want to continue?'],\n                [\/^Sono l\\\\?[\u2019']assistente virtuale di(?:\\s+(.+))?$\/i, function(m){ return 'I am the virtual assistant of' + (m[1] ? ' ' + m[1] : ''); }],\n                [\/^Sono l[\u2019']assistente virtuale di\\s*$\/i, 'I am the virtual assistant of '],\n                [\/^RIEPILOGO ORDINE(?:\\s+(.+))?$\/i, function(m){ return 'ORDER SUMMARY' + (m[1] ? ' ' + m[1] : ''); }],\n                [\/^Totale\\s+(.+):\\s*(.+)$\/i, 'Total $1: $2'],\n                [\/^(.+)\\s+in corso\\.\\.\\.$\/i, '$1 in progress...'],\n                [\/^Lettura tabella\\s+(.+)$\/i, 'Reading table $1'],\n                [\/^Lettura tabelle\\s+(.+)$\/i, 'Reading tables $1'],\n                [\/^Elemento in lavorazione:\\s*(.+)$\/i, 'Item being processed: $1'],\n                [\/^Impostazioni\\s+(.+)$\/i, 'Settings $1'],\n                [\/^Anteprima modifiche aggiornata alle\\s+(.+)$\/i, 'Change preview updated at $1'],\n                [\/^Errore:\\s*(.+)$\/i, 'Error: $1'],\n                [\/^Errore durante\\s+(.+)$\/i, 'Error during $1'],\n                [\/^Righe cancellate:\\s*(.+)$\/i, 'Deleted rows: $1'],\n                [\/^Tabelle con istruzioni:\\s*(.+)$\/i, 'Tables with instructions: $1'],\n                [\/^Righe selezionate:\\s*(.+)$\/i, 'Selected rows: $1'],\n                [\/^Elaborazione\\s+(.+)$\/i, 'Processing $1'],\n                [\/^Caricamento\\s+(.+)$\/i, 'Loading $1']\n            ];\n        }\n        return window.tiI18nDynamicRulesCache;\n    };\n\n    window.tiCleanVisibleEscapedChars = function(value) {\n        let s = String(value == null ? '' : value);\n        if (!s) return s;\n        let prev = null;\n        for (let i = 0; i < 4 && prev !== s; i++) {\n            prev = s;\n            s = s.replace(\/\\\\([\"'])\/g, '$1');\n            s = s.replace(\/^((?:\\s*[\"'\\\\]+)+)(?=\\s*(?:\u26a0\ufe0f|\u23f3|\u2705|\u274c|Company status|Stato ditta|Stato dell\\\\?'azienda|Sono l\\\\?'assistente|I am))\/u, '');\n            s = s.replace(\/^(\u26a0\ufe0f|\u23f3|\u2705|\u274c)(?:\\s*[\"'\\\\]+)+\\s*\/u, '$1 ');\n            s = s.replace(\/(Demo|Dimostrativa|Sospesa|Configurazione|Attivo|Operativo)(?:[\\s\"'\\\\]+)$\/u, '$1');\n        }\n        return s;\n    };\n    window.tiI18nNormalize = function(txt) {\n        const cleaned = window.tiCleanVisibleEscapedChars ? window.tiCleanVisibleEscapedChars(txt) : String(txt == null ? '' : txt);\n        return String(cleaned == null ? '' : cleaned).replace(\/\\u00a0\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n    };\n    window.tiI18nEscapeRegExp = function(txt) {\n        return String(txt).replace(\/[.*+?^${}()|[\\]\\\\]\/g, '\\\\$&');\n    };\n    window.tiI18nApplyCase = function(src, dst) {\n        src = String(src || ''); dst = String(dst || '');\n        if (!dst) return dst;\n        if (src === src.toUpperCase() && \/[A-Z\u00c0-\u00d6\u00d8-\u00de]\/i.test(src)) return dst.toUpperCase();\n        return dst;\n    };\n    window.tiTranslateLayoutStringToEn = function(value) {\n        const originalRaw = String(value == null ? '' : value);\n        const original = window.tiCleanVisibleEscapedChars ? window.tiCleanVisibleEscapedChars(originalRaw) : originalRaw;\n        if (!original.trim()) return original;\n        const cacheKey = 'en|' + original;\n        const cached = window.tiI18nTextCache && Object.prototype.hasOwnProperty.call(window.tiI18nTextCache, cacheKey) ? window.tiI18nTextCache[cacheKey] : null;\n        if (cached !== null) return cached;\n        const map = window.tiLayoutTranslationsEn || {};\n        const m = original.match(\/^(\\s*)([\\s\\S]*?)(\\s*)$\/);\n        const lead = m ? m[1] : '';\n        const body = m ? m[2] : original;\n        const tail = m ? m[3] : '';\n        const normalized = window.tiI18nNormalize(body);\n        if (!normalized) return window.tiI18nCacheSet(cacheKey, original);\n        if (Object.prototype.hasOwnProperty.call(map, normalized)) return window.tiI18nCacheSet(cacheKey, lead + map[normalized] + tail);\n        let out = body;\n        const dynamicRules = window.tiI18nGetDynamicRules ? window.tiI18nGetDynamicRules() : [];\n        for (const rule of dynamicRules) {\n            const mt = normalized.match(rule[0]);\n            if (mt) {\n                const repl = (typeof rule[1] === 'function') ? rule[1](mt) : normalized.replace(rule[0], rule[1]);\n                return window.tiI18nCacheSet(cacheKey, lead + repl + tail);\n            }\n        }\n        const keys = window.tiI18nGetSortedKeys ? window.tiI18nGetSortedKeys() : Object.keys(map);\n        for (const k of keys) {\n            if (out.indexOf(k) !== -1) out = out.split(k).join(window.tiI18nApplyCase(k, map[k]));\n        }\n        return window.tiI18nCacheSet(cacheKey, lead + out + tail);\n    };\n    window.tiTranslateLayoutString = function(value) {\n        const originalRaw = String(value == null ? '' : value);\n        const original = window.tiCleanVisibleEscapedChars ? window.tiCleanVisibleEscapedChars(originalRaw) : originalRaw;\n        if (window.currLang !== 'en' || !original.trim()) return original;\n        return window.tiTranslateLayoutStringToEn(original);\n    };\n    window.tiI18nShouldSkipNode = function(node) {\n        const el = node && node.nodeType === 1 ? node : (node && node.parentElement ? node.parentElement : null);\n        if (!el) return false;\n        const tag = String(el.tagName || '').toUpperCase();\n        if (['SCRIPT','STYLE','NOSCRIPT','SVG','CANVAS'].includes(tag)) return true;\n        if (el.closest && el.closest('[data-ti-no-i18n=\"1\"], .ti-no-i18n')) return true;\n        return false;\n    };\n    window.tiI18nTranslateTextNode = function(node) {\n        if (!node || node.nodeType !== 3 || window.tiI18nShouldSkipNode(node)) return;\n        const current = String(node.nodeValue || '');\n        if (typeof node.__tiI18nOrigin === 'undefined') {\n            node.__tiI18nOrigin = current;\n        } else {\n            const translatedOrigin = window.tiTranslateLayoutStringToEn ? window.tiTranslateLayoutStringToEn(node.__tiI18nOrigin) : window.tiTranslateLayoutString(node.__tiI18nOrigin);\n            if (current !== node.__tiI18nOrigin && current !== translatedOrigin) node.__tiI18nOrigin = current;\n        }\n        node.nodeValue = (window.currLang === 'en') ? window.tiTranslateLayoutString(node.__tiI18nOrigin) : node.__tiI18nOrigin;\n    };\n    window.tiI18nTranslateAttributes = function(el) {\n        if (!el || el.nodeType !== 1 || window.tiI18nShouldSkipNode(el)) return;\n        const attrs = window.tiLayoutI18nAttrNames || [];\n        if (!el.__tiI18nAttrOrigin) el.__tiI18nAttrOrigin = {};\n        attrs.forEach(function(attr){\n            if (!el.hasAttribute || !el.hasAttribute(attr)) return;\n            const current = el.getAttribute(attr);\n            if (typeof el.__tiI18nAttrOrigin[attr] === 'undefined') {\n                el.__tiI18nAttrOrigin[attr] = current;\n            } else {\n                const translatedOrigin = window.tiTranslateLayoutStringToEn ? window.tiTranslateLayoutStringToEn(el.__tiI18nAttrOrigin[attr]) : window.tiTranslateLayoutString(el.__tiI18nAttrOrigin[attr]);\n                if (current !== el.__tiI18nAttrOrigin[attr] && current !== translatedOrigin) el.__tiI18nAttrOrigin[attr] = current;\n            }\n            const base = el.__tiI18nAttrOrigin[attr];\n            el.setAttribute(attr, window.currLang === 'en' ? window.tiTranslateLayoutString(base) : base);\n        });\n        const tag = String(el.tagName || '').toUpperCase();\n        const type = String(el.getAttribute('type') || '').toLowerCase();\n        if (tag === 'INPUT' && ['button','submit','reset'].includes(type) && el.hasAttribute('value')) {\n            const currentVal = el.getAttribute('value');\n            if (typeof el.__tiI18nAttrOrigin.value === 'undefined') {\n                el.__tiI18nAttrOrigin.value = currentVal;\n            } else {\n                const translatedVal = window.tiTranslateLayoutStringToEn ? window.tiTranslateLayoutStringToEn(el.__tiI18nAttrOrigin.value) : window.tiTranslateLayoutString(el.__tiI18nAttrOrigin.value);\n                if (currentVal !== el.__tiI18nAttrOrigin.value && currentVal !== translatedVal) el.__tiI18nAttrOrigin.value = currentVal;\n            }\n            const baseVal = el.__tiI18nAttrOrigin.value;\n            el.setAttribute('value', window.currLang === 'en' ? window.tiTranslateLayoutString(baseVal) : baseVal);\n        }\n    };\n    window.tiI18nTranslateSubtree = function(root) {\n        if (!root) return;\n        if (root.nodeType === 3) {\n            window.tiI18nTranslateTextNode(root);\n            return;\n        }\n        if (root.nodeType !== 1 || window.tiI18nShouldSkipNode(root)) return;\n        window.tiI18nTranslateAttributes(root);\n        const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n            acceptNode: function(node) {\n                if (!node || !node.nodeValue || !node.nodeValue.trim()) return NodeFilter.FILTER_REJECT;\n                return window.tiI18nShouldSkipNode(node) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;\n            }\n        });\n        let node;\n        while ((node = walker.nextNode())) window.tiI18nTranslateTextNode(node);\n        if (root.querySelectorAll) root.querySelectorAll('*').forEach(function(el){ window.tiI18nTranslateAttributes(el); });\n    };\n    window.tiCleanEscapedUiInSubtree = function(root) {\n        if (!root || !window.tiCleanVisibleEscapedChars) return;\n        const cleanTextNode = function(node) {\n            if (!node || node.nodeType !== 3 || window.tiI18nShouldSkipNode(node)) return;\n            const cleaned = window.tiCleanVisibleEscapedChars(node.nodeValue || '');\n            if (cleaned !== node.nodeValue) {\n                node.nodeValue = cleaned;\n                node.__tiI18nOrigin = cleaned;\n            }\n        };\n        if (root.nodeType === 3) { cleanTextNode(root); return; }\n        if (root.nodeType !== 1 || window.tiI18nShouldSkipNode(root)) return;\n        const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n            acceptNode: function(node) {\n                if (!node || !node.nodeValue || !node.nodeValue.trim()) return NodeFilter.FILTER_REJECT;\n                return window.tiI18nShouldSkipNode(node) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;\n            }\n        });\n        let node;\n        while ((node = walker.nextNode())) cleanTextNode(node);\n        const attrs = window.tiLayoutI18nAttrNames || [];\n        const scanAttr = function(el) {\n            if (!el || !el.hasAttribute || window.tiI18nShouldSkipNode(el)) return;\n            attrs.forEach(function(attr){\n                if (!el.hasAttribute(attr)) return;\n                const val = el.getAttribute(attr);\n                const cleaned = window.tiCleanVisibleEscapedChars(val);\n                if (cleaned !== val) el.setAttribute(attr, cleaned);\n            });\n        };\n        scanAttr(root);\n        if (root.querySelectorAll) root.querySelectorAll('*').forEach(scanAttr);\n    };\n    window.applyLayoutLanguage = function(force) {\n        const root = document.body || document.getElementById('ti-ai-outer');\n        if (!root || window.tiI18nApplying) return;\n        window.tiI18nApplying = true;\n        try {\n            document.querySelectorAll('.ti-lang-opt').forEach(function(el){\n                el.classList.toggle('active', String(el.dataset.lang || '') === String(window.currLang || 'it'));\n            });\n            if (typeof dict !== 'undefined') {\n                const d = dict[window.currLang] || dict.it || {};\n                if (gE('ti-msg')) gE('ti-msg').placeholder = d.ph || (window.currLang === 'en' ? 'Type here...' : 'Scrivi qui...');\n                if (gE('ti-send')) gE('ti-send').innerText = d.send || (window.currLang === 'en' ? 'SEND' : 'INVIA');\n                if (gE('ti-new')) gE('ti-new').innerText = d.new || (window.currLang === 'en' ? 'New' : 'Nuova');\n                if (gE('ti-copy')) { gE('ti-copy').innerText = d.copy || (window.currLang === 'en' ? 'Copy text' : 'Copia testo'); }\n                if (gE('ti-file')) gE('ti-file').innerText = d.file || 'File per AI';\n                if (gE('ti-products-btn')) gE('ti-products-btn').innerText = d.products || (window.currLang === 'en' ? 'Products' : 'Prodotti');\n                if (gE('ti-services-btn')) gE('ti-services-btn').innerText = d.services || (window.currLang === 'en' ? 'Services' : 'Servizi');\n                if (gE('ti-activities-btn')) gE('ti-activities-btn').innerText = d.activities || (window.currLang === 'en' ? 'Activities' : 'Attivit\u00e0');\n                if (gE('ti-kbd-btn')) gE('ti-kbd-btn').innerText = d.kbd || (window.currLang === 'en' ? 'Keyboard' : 'Tastiera');\n                if (gE('ti-mic')) gE('ti-mic').innerText = d.mic || 'Mic';\n                if (gE('ti-cam')) gE('ti-cam').innerText = d.cam || 'Cam';\n                if (gE('ti-login-btn') && gE('ti-login-btn').style.display !== 'none') gE('ti-login-btn').innerText = d.login || (window.currLang === 'en' ? 'Login' : 'Accedi');\n            }\n            window.tiI18nTranslateSubtree(root);\n            if (window.updateActivitiesButtonVisibility) window.updateActivitiesButtonVisibility();\n            if (window.applyMuteState) window.applyMuteState();\n        } catch(e) {\n            try { console.warn('Shop & Service i18n layout error', e); } catch(ignore) {}\n        } finally {\n            window.tiI18nApplying = false;\n        }\n    };\n    window.tiOpenUserActivities = function() {\n        try {\n            const user = String(window.tiUser || '').trim();\n            if (!user) { if (window.tiAlert) window.tiAlert('Accedi prima di consultare le tue attivit\u00e0.'); return false; }\n            window.lastUploadedFile = null;\n            if (window.lastFileContext) {\n                window.lastFileContext.active = false;\n                window.lastFileContext.awaitingReuseChoice = false;\n                window.lastFileContext.pendingReusePrompt = '';\n            }\n            const label = (String(window.currLang || 'it').toLowerCase() === 'en') ? 'Activities' : 'Attivit\u00e0';\n            if (window.tiSendQuickReply) { window.tiSendQuickReply('__TI_USER_ACTIVITIES__', label); }\n            else {\n                window.tiHiddenSendText = '__TI_USER_ACTIVITIES__';\n                window.tiHiddenSendLabel = label;\n                const sendBtn = gE('ti-send');\n                if (sendBtn) sendBtn.click();\n            }\n            return false;\n        } catch(e) { try { console.warn('Shop & Service activities button error', e); } catch(ignore) {} return false; }\n    };\n    window.ensureActivitiesButton = function() {\n        try {\n            let b = gE('ti-activities-btn');\n            const services = gE('ti-services-btn');\n            if (!b) {\n                b = document.createElement('button');\n                b.type = 'button';\n                b.id = 'ti-activities-btn';\n                b.className = 'ti-btn ti-btn-catalog ti-btn-activities';\n                b.textContent = (String(window.currLang || 'it').toLowerCase() === 'en') ? 'Activities' : 'Attivit\u00e0';\n                if (services && services.parentNode) services.parentNode.insertBefore(b, services.nextSibling);\n                else {\n                    const row = document.querySelector('.ti-actions-row');\n                    if (row) row.appendChild(b);\n                }\n            } else if (services && services.parentNode && b.previousElementSibling !== services) {\n                services.parentNode.insertBefore(b, services.nextSibling);\n            }\n            b.onclick = window.tiOpenUserActivities;\n            b.style.alignItems = 'center';\n            b.style.justifyContent = 'center';\n            b.style.gap = '4px';\n            b.title = 'Attivit\u00e0 e appuntamenti dell utente loggato';\n            return b;\n        } catch(e) { return gE('ti-activities-btn'); }\n    };\n    window.updateActivitiesButtonVisibility = function() {\n        try {\n            const b = window.ensureActivitiesButton ? window.ensureActivitiesButton() : gE('ti-activities-btn');\n            if (!b) return;\n            const logged = !!String(window.tiUser || '').trim();\n            if (logged) {\n                b.removeAttribute('hidden');\n                b.disabled = false;\n                b.style.setProperty('display', 'inline-flex', 'important');\n                b.style.visibility = 'visible';\n                b.style.opacity = '1';\n            } else {\n                b.disabled = true;\n                b.style.setProperty('display', 'none', 'important');\n                b.style.visibility = 'hidden';\n                b.style.opacity = '0';\n            }\n        } catch(e) {}\n    };\n\n    window.installLayoutI18nObserver = function() {\n        \/\/ 30.9.1476: invertita la priorita' - document.body esiste sempre una volta caricata la pagina, quindi il\n        \/\/ fallback a #ti-ai-outer non veniva mai effettivamente usato, facendo osservare l'intera pagina anche\n        \/\/ quando il contenitore specifico del plugin sarebbe stato sufficiente.\n        const root = document.getElementById('ti-ai-outer') || document.body;\n        if (!root || window.tiI18nObserver) return;\n        let pending = null;\n        const changedNodes = window.tiI18nChangedNodes || new Set();\n        window.tiI18nChangedNodes = changedNodes;\n        const addChangedNode = function(node) {\n            if (!node) return;\n            if (node.nodeType === 3 || node.nodeType === 1) changedNodes.add(node);\n        };\n        window.tiI18nObserver = new MutationObserver(function(mutations){\n            \/\/ 30.9.1476: controllo lingua spostato in cima, PRIMA di esaminare le mutazioni - la versione\n            \/\/ precedente eseguiva forEach\/addChangedNode su ogni mutazione anche in italiano, scoprendo solo\n            \/\/ dopo 120ms (nel debounce) che la lingua non era inglese e quindi il lavoro non serviva. Confermato\n            \/\/ con 37.416 chiamate misurate durante un solo test. Non e' stata scelta la disconnessione completa\n            \/\/ dell'observer in italiano poiche' richiederebbe individuare e coordinarsi con un gestore di\n            \/\/ cambio lingua non ancora localizzato per la riattivazione - questo approccio piu' semplice ottiene\n            \/\/ comunque la parte piu' rilevante del beneficio senza quel rischio aggiuntivo.\n            if (window.currLang !== 'en') return;\n            if (window.tiI18nApplying) return;\n            mutations.forEach(function(m){\n                if (m.type === 'characterData') addChangedNode(m.target);\n                else if (m.type === 'attributes') addChangedNode(m.target);\n                else if (m.type === 'childList') (m.addedNodes || []).forEach(addChangedNode);\n            });\n            clearTimeout(pending);\n            pending = setTimeout(function(){\n                if (window.tiI18nApplying) return;\n                if (window.currLang !== 'en') { changedNodes.clear(); return; }\n                const fullScan = changedNodes.size > 120;\n                const nodes = fullScan ? [] : Array.from(changedNodes);\n                changedNodes.clear();\n                if (fullScan) { window.applyLayoutLanguage(false); return; }\n                window.tiI18nApplying = true;\n                try {\n                    nodes.forEach(function(node){ window.tiI18nTranslateSubtree(node); });\n                    if (window.applyMuteState) window.applyMuteState();\n                } catch(e) {\n                    try { console.warn('Shop & Service i18n incremental error', e); } catch(ignore) {}\n                } finally {\n                    window.tiI18nApplying = false;\n                }\n            }, 120);\n        });\n        window.tiI18nObserver.observe(root, {childList:true, subtree:true, characterData:true, attributes:true, attributeFilter:['placeholder','title','aria-label','data-title','value']});\n    };\n    window.tiApplyEnglishLayoutIfNeeded = function() {\n        try {\n            if (!['it','en'].includes(String(window.currLang || ''))) window.currLang = 'it';\n            window.installLayoutI18nObserver();\n            window.applyLayoutLanguage(true);\n        } catch(e) {}\n    };\n    document.addEventListener('DOMContentLoaded', window.tiApplyEnglishLayoutIfNeeded);\n    setTimeout(window.tiApplyEnglishLayoutIfNeeded, 0);\n\n    window.isConfiguratorUser = function() {\n        return \/amministratore|administrator|configuratore|configurator\/i.test(String(window.tiRole || '')) || String(window.tiUser || '') === 'SSGlobalAdmin';\n    };\n    window.isAdminConfiguratorUser = function() {\n        return \/amministratore|administrator|configuratore|configurator\/i.test(String(window.tiRole || '')) || String(window.tiUser || '') === 'SSGlobalAdmin';\n    };\n    window.isDbModificationWaitRole = function() {\n        return \/amministratore|administrator|configuratore|configurator|responsabile|responsible\/i.test(String(window.tiRole || '')) || String(window.tiUser || '') === 'SSGlobalAdmin';\n    };\n    window.getStoragePathForTable = function(dbName, tblName) {\n        const dbRaw = String(dbName || '').replace(\/\\.json$\/i, '');\n        const tbl = String(tblName || '').trim();\n        if (!dbRaw || !tbl) return '';\n        let p = '\/wp-content\/uploads\/AI-data\/' + dbRaw + '\/Tabelle\/' + tbl;\n        if (!\/(prodott|serviz)\/i.test(tbl)) p += '\/Docs';\n        return p;\n    };\n    window.showDbOperationWait = function(operationLabel, detail) {\n        if (!window.isDbModificationWaitRole || !window.isDbModificationWaitRole()) return false;\n        if (typeof window.showProgressPopup === 'function') {\n            window.showProgressPopup(operationLabel || 'Modifica database in corso', detail || 'Attendi il completamento. Premi Esci per interrompere la richiesta.', {cancellable:true, targetPercent:85, stepMs:450, startPercent:5});\n            return true;\n        }\n        return false;\n    };\n    window.hideDbOperationWait = function(success, finalText, opts) {\n        if (typeof window.hideProgressPopup === 'function') {\n            window.hideProgressPopup(success !== false, finalText || (success === false ? 'Operazione interrotta' : 'Operazione completata'), Object.assign({notifyUser:false}, opts || {}));\n        }\n    };\n\n    window.showTableReadWait = function(title, detail, currentItem) {\n        try {\n            window.__tiTableReadWaitSuppressed343 = true;\n            if (typeof window.tiDismissCompletedTableReadLoader343 === 'function') {\n                window.tiDismissCompletedTableReadLoader343('showTableReadWait-suppressed');\n            }\n        } catch(e) {}\n        return false;\n    };\n    window.hideTableReadWait = function(success, finalText) {\n        try {\n            if (typeof window.tiDismissCompletedTableReadLoader343 === 'function') {\n                window.tiDismissCompletedTableReadLoader343('hideTableReadWait');\n            }\n            \/\/ Non richiamare hideProgressPopup per la lettura tabelle: il popup e' stato soppresso.\n        } catch(e) {}\n    };\n    window.getShopServiceManualUrl = function() {\n        try {\n            const setup = window.tiSharedSetup || {};\n            let u = String(setup.manual_url || '').trim();\n            if (!u) {\n                const base = String(setup.docs_base_url || 'https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service').replace(\/\\\/+$\/, '');\n                u = base + '\/Shop-Service%20Manual.pdf';\n            }\n            return u;\n        } catch(e) {\n            return 'https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/Shop-Service%20Manual.pdf';\n        }\n    };\n\n    window.escapeAttrValue = window.escapeAttrValue || function(v) {\n        return String(v == null ? '' : v).replace(\/&\/g, '&amp;').replace(\/\"\/g, '&quot;').replace(\/<\/g, '&lt;').replace(\/>\/g, '&gt;');\n    };\n\n    window.getConfiguratorOperationalTipsUserKey = function() {\n        const d = gE('ti-ditta');\n        const dbKey = d && d.value ? String(d.value) : 'no-db';\n        const userKey = String(window.tiUser || window.tiUserDisplay || 'configuratore');\n        return encodeURIComponent(dbKey) + '_' + encodeURIComponent(userKey);\n    };\n\n    window.getConfiguratorOperationalTipsShownKey = function() {\n        return 'ti_cfg_operational_tips_shown_' + window.getConfiguratorOperationalTipsUserKey();\n    };\n\n    window.getConfiguratorOperationalTipsDisabledKey = function() {\n        return 'ti_cfg_operational_tips_disabled_' + window.getConfiguratorOperationalTipsUserKey();\n    };\n\n    window.isConfiguratorOperationalTipsDisabled = function() {\n        try {\n            return !!(window.localStorage && localStorage.getItem(window.getConfiguratorOperationalTipsDisabledKey()) === '1');\n        } catch(e) { return false; }\n    };\n\n    window.setConfiguratorOperationalTipsDisabled = function(disabled, silent) {\n        disabled = !!disabled;\n        try {\n            if (window.localStorage) {\n                if (disabled) localStorage.setItem(window.getConfiguratorOperationalTipsDisabledKey(), '1');\n                else localStorage.removeItem(window.getConfiguratorOperationalTipsDisabledKey());\n            }\n            if (!disabled && window.sessionStorage) sessionStorage.removeItem(window.getConfiguratorOperationalTipsShownKey());\n        } catch(e) {}\n        if (window.syncConfiguratorOperationalTipsFlagUI) window.syncConfiguratorOperationalTipsFlagUI();\n        if (!silent && window.tiAlert) {\n            window.tiAlert(disabled ? 'Popup consigli operativi configuratore\/amministratore disabilitato per i prossimi accessi.' : 'Popup consigli operativi configuratore\/amministratore riabilitato. Verr\u00e0 mostrato di nuovo ai prossimi accessi.');\n        }\n    };\n\n    window.syncConfiguratorOperationalTipsFlagUI = function() {\n        const enabled = !(window.isConfiguratorOperationalTipsDisabled && window.isConfiguratorOperationalTipsDisabled());\n        const cb = gE('ti-cfg-tips-enabled');\n        const status = gE('ti-cfg-tips-status');\n        if (cb) cb.checked = enabled;\n        if (status) status.textContent = enabled ? 'Popup consigli operativi attivo.' : 'Popup consigli operativi disabilitato.';\n    };\n\n    window.handleConfiguratorTipsFlagChange = function(cb) {\n        const enabled = !!(cb && cb.checked);\n        window.setConfiguratorOperationalTipsDisabled(!enabled, false);\n    };\n\n    window.getConfiguratorWelcomeHtml = function() {\n        if (!window.isConfiguratorUser()) return '';\n        let html = String(window.tiConfiguratorAccessMessage || '');\n        const roleNow = String(window.tiRole || '').toLowerCase();\n        const privileged = (!!window.tiUser && window.tiUser === 'SSGlobalAdmin') || \/amministratore|configuratore|responsabile|globale\/.test(roleNow);\n        if (privileged) {\n            const note = [\n                '<div style=\"margin-top:8px;padding:8px 10px;border-radius:10px;background:#0f172a;border:1px solid #334155;color:#bfdbfe;font-size:12px;line-height:1.35;\">',\n                '<b>Funzioni utente attive<\/b><br>',\n                \"Puoi usare anche la main form come utente standard registrato: chat, prodotti, servizi, ordini con tabella ordine completa, conferma ordine, prenotazioni, file\\\/foto e comunicazioni. I popup informativi restano attivi e separati; le tabelle operative di ordine restano nella main form.\",\n                '<\/div>'\n            ].join('');\n            html = html ? (html + note) : note;\n        }\n        return html;\n    };\n\n    window.getConfiguratorOperationalTipsHtml = function() {\n        const manualUrl = window.getShopServiceManualUrl ? window.getShopServiceManualUrl() : 'https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/Shop-Service%20Manual.pdf';\n        const disabled = window.isConfiguratorOperationalTipsDisabled && window.isConfiguratorOperationalTipsDisabled();\n        const safeManualUrl = window.escapeAttrValue ? window.escapeAttrValue(manualUrl) : manualUrl;\n        return `\n            <div style=\"text-align:left;line-height:1.45;font-size:13px;color:#e5e7eb;\">\n                <div style=\"font-size:17px;font-weight:800;color:#ffffff;margin-bottom:10px;\">Consigli operativi per configuratore\/amministratore<\/div>\n                <ol style=\"margin:0;padding-left:20px;\">\n                    <li>Cliccare tasto <b>Configura<\/b>.<\/li>\n                    <li>Scorrere le tabelle dell\u2019archivio ditta e verificare quali dati \u00e8 opportuno compilare.<\/li>\n                    <li>In <b>Istruzioni AI configurazione<\/b>, possibilit\u00e0 di fornire alla AI istruzioni o richieste per configurare e manutenere le informazioni.<\/li>\n                    <li>Prodotti e servizi possono essere importati da dati copiati nel campo di messaggistica per la AI o da file esterni tramite la funzione <b>Carica file AI<\/b>.<\/li>\n                    <li>Dedicare particolare attenzione alle informazioni ed istruzioni per la AI.<\/li>\n                    <li>La AI, nel trattare l\u2019utente, tiene conto delle informazioni che ha a disposizione ed esegue le specifiche istruzioni del configuratore\/amministratore.<\/li>\n                    <li>Le istruzioni fornite possono essere in ogni momento verificate tramite il tasto <b>Verifica istruzioni<\/b>.<\/li>\n                    <li>Le foto ed i documenti associati a prodotti e servizi possono essere generati dalla AI tramite le funzioni di generazione, per poi essere comunque successivamente manutenuti dal configuratore\/amministratore.<\/li>\n                    <li>Il <b>Report attivit\u00e0<\/b> fornisce un macro punto di vista sulle attivit\u00e0 effettuate nel gestire il servizio.<\/li>\n                <\/ol>\n                <div style=\"margin-top:14px;padding-top:12px;border-top:1px solid #374151;display:flex;gap:10px;align-items:center;justify-content:space-between;flex-wrap:wrap;\">\n                    <a href=\"${safeManualUrl}\" target=\"_blank\" rel=\"noopener\" class=\"ti-btn\" style=\"background:#059669;color:#fff;text-decoration:none;font-size:12px;padding:8px 10px;border-radius:8px;display:inline-flex;align-items:center;gap:6px;\">\ud83d\udcc4 Manuale operativo Shop & Service<\/a>\n                    <label style=\"display:flex;align-items:center;gap:7px;color:#cbd5e1;font-size:12px;cursor:pointer;\">\n                        <input type=\"checkbox\" id=\"ti-cfg-tips-disable-from-popup\" ${disabled ? 'checked' : ''} onchange=\"if(window.setConfiguratorOperationalTipsDisabled) window.setConfiguratorOperationalTipsDisabled(this.checked, true);\">\n                        Non mostrare pi\u00f9 questo popup in futuro\n                    <\/label>\n                <\/div>\n            <\/div>`;\n    };\n\n    window.showConfiguratorOperationalTipsPopup = function(force) {\n        if (!window.isConfiguratorUser || !window.isConfiguratorUser()) return false;\n        if (!force && window.isConfiguratorOperationalTipsDisabled && window.isConfiguratorOperationalTipsDisabled()) return false;\n        const key = window.getConfiguratorOperationalTipsShownKey ? window.getConfiguratorOperationalTipsShownKey() : 'ti_cfg_operational_tips_shown_config_admin';\n        try {\n            if (!force && window.sessionStorage && sessionStorage.getItem(key) === '1') return false;\n            if (window.sessionStorage) sessionStorage.setItem(key, '1');\n        } catch(e) {}\n        const html = window.getConfiguratorOperationalTipsHtml ? window.getConfiguratorOperationalTipsHtml() : '';\n        if (!html) return false;\n        let shown = false;\n        if (window.showPrivilegedCommunicationPopup) {\n            shown = window.showPrivilegedCommunicationPopup(html, 'Consigli operativi per configuratore\/amministratore', {text: window.tiPlainTextFromHtml ? window.tiPlainTextFromHtml(html) : html});\n        } else if (window.tiAlert) {\n            window.tiAlert(html);\n            shown = true;\n        }\n        if (shown && window.syncConfiguratorOperationalTipsFlagUI) setTimeout(window.syncConfiguratorOperationalTipsFlagUI, 0);\n        return shown;\n    };\n\n    function utoa(str) { return window.btoa(unescape(encodeURIComponent(str))); }\n    \n    window.getRecordLabelForUpload = function(tblName, rowObj, fallback) {\n        const tbl = String(tblName || '').toLowerCase();\n        const row = rowObj || {};\n        const picks = ['Descrizione','Prodotto','Servizio','Username','Utente','Nome','Titolo','Ragione sociale'];\n        for (const k of picks) {\n            if (row && row[k] && String(row[k]).trim()) return String(row[k]).trim();\n            const hit = Object.keys(row || {}).find(x => String(x).toLowerCase() === String(k).toLowerCase());\n            if (hit && String(row[hit] || '').trim()) return String(row[hit]).trim();\n        }\n        if (fallback) return String(fallback).trim();\n        return tbl === 'utenti' ? 'utente' : (tblName || 'record');\n    };\n\n    window.isLegacyUserImagePath = function(val) {\n        return \/^wp-content\\\/uploads\\\/ai-data\\\/.+\\\/utenti\\\/\/i.test(String(val || '').trim());\n    };\n    window.getFullImgUrl = function(val, dbName, tName, recordLabel) {\n        if (!val) return '';\n        val = String(val).trim().replace(\/&amp;\/gi,'&').replace(\/&#38;\/g,'&');\n        if (val.indexOf(',') !== -1) val = String(val.split(',')[0] || '').trim();\n        let dbRaw = dbName ? String(dbName).replace(\/\\.json$\/i, '') : '';\n        const tableName = String(tName || '').trim();\n        if (!val) return '';\n        if (window.isLegacyUserImagePath(val) && \/^utenti$\/i.test(tableName)) return '';\n        const buildCurrent1657 = function(fileName, tblOverride, recOverride){\n            const f = String(fileName || '').split(\/[\\\/]\/).pop();\n            if (!f) return '';\n            const tb = String(tblOverride || tableName || '').trim();\n            const rr = String(recOverride || recordLabel || '').trim();\n            return window.tiUrl + '?ti_action=ti_ai_get_image&db=' + encodeURIComponent(dbRaw) + '&tbl=' + encodeURIComponent(tb) + '&file=' + encodeURIComponent(f) + (rr ? '&record=' + encodeURIComponent(rr) : '');\n        };\n        if (val.indexOf('ti_action=ti_ai_get_image') !== -1) {\n            try {\n                const u = new URL(val, window.location.origin);\n                const f = u.searchParams.get('file') || '';\n                const tb = tableName || u.searchParams.get('tbl') || '';\n                const rr = recordLabel || u.searchParams.get('record') || '';\n                if (dbRaw) return buildCurrent1657(f, tb, rr);\n            } catch(e) {}\n            return val;\n        }\n        const decoded1657 = (()=>{ try{return decodeURIComponent(val);}catch(e){return val;} })();\n        const aiData1657 = String(decoded1657).match(\/\\\/AI-data\\\/([^\\\/?#]+)\\\/\/i);\n        if (aiData1657) {\n            const seg = String(aiData1657[1] || '');\n            if (\/^AI-docs$\/i.test(seg)) {\n                if (\/^https?:\\\/\\\/\/i.test(val)) return val;\n                return window.location.origin + '\/' + val.replace(\/^\\\/+\/, '');\n            }\n            return buildCurrent1657(String(decoded1657).split(\/[\\\/?#]\/).filter(Boolean).pop() || '');\n        }\n        if (\/^https?:\\\/\\\/\/i.test(val)) return val;\n        if (\/^\\\/\/.test(val)) return window.location.origin + val;\n        if (\/^wp-content\\\/uploads\\\/\/i.test(val) || \/^uploads\\\/\/i.test(val)) {\n            return buildCurrent1657(String(val).split('\/').pop());\n        }\n        if (val.indexOf('\/') !== -1) val = val.split('\/').pop();\n        return buildCurrent1657(val);\n    };\n    window.getCompanyFallbackMediaUrl = function(dbName) {\n        const dbVal = dbName || (gE('ti-ditta') ? gE('ti-ditta').value : '');\n        let logo = '';\n        const currentPayloadMatches1657 = !!(window.currentDbData && window.currentDbData.Tabelle\n            && window.tiDbPayloadMatches1657 && window.tiDbPayloadMatches1657(window.currentDbData, dbVal));\n        if (currentPayloadMatches1657 && Array.isArray(window.currentDbData.Tabelle.Config) && window.currentDbData.Tabelle.Config[0]) {\n            const cfg = window.currentDbData.Tabelle.Config[0];\n            logo = cfg.Logo || cfg.logo || cfg.Immagine || cfg.immagine || '';\n        }\n        if (!logo && Array.isArray(window.ditteData)) {\n            const hit = window.ditteData.find(d => (d.db || '') === dbVal || (d.db || '') === String(dbVal).replace('.json','') + '.json');\n            if (hit) {\n                logo = hit.logo || '';\n                if (!logo && hit.qr) return hit.qr;\n            }\n        }\n        if (logo) return window.getFullImgUrl(logo, dbVal, 'Config');\n        if (Array.isArray(window.ditteData)) {\n            const hit = window.ditteData.find(d => (d.db || '') === dbVal || (d.db || '') === String(dbVal).replace('.json','') + '.json');\n            if (hit && hit.qr) return hit.qr;\n        }\n        return '';\n    };\n\n    \/\/ 30.9.1968 - Fallback immagini della tabella ordine: esclusivamente Logo ditta, mai QR.\n    window.getCompanyOrderLogoUrl1968 = function(dbName) {\n        const dbVal = String(dbName || (gE('ti-ditta') ? gE('ti-ditta').value : '') || '').trim();\n        if (!dbVal) return '';\n        const normDb1968 = function(v){ return String(v || '').trim().replace(\/\\.json$\/i,'').toLowerCase(); };\n        let logo = '';\n        const tryPayload1968 = function(payload){\n            try {\n                if (!payload || !payload.Tabelle || !Array.isArray(payload.Tabelle.Config) || !payload.Tabelle.Config[0]) return '';\n                if (window.tiDbPayloadMatches1657 && !window.tiDbPayloadMatches1657(payload, dbVal)) return '';\n                const cfg = payload.Tabelle.Config[0] || {};\n                return String(cfg.Logo || cfg.logo || cfg.Immagine || cfg.immagine || '').trim();\n            } catch(e) { return ''; }\n        };\n        logo = tryPayload1968(window.currentDbData) || tryPayload1968(window.currentDbViewData);\n        if (!logo && Array.isArray(window.ditteData)) {\n            const wanted = normDb1968(dbVal);\n            const hit = window.ditteData.find(function(d){ return d && normDb1968(d.db || d.database || '') === wanted; });\n            if (hit) logo = String(hit.logo || hit.Logo || '').trim();\n        }\n        if (!logo) return '';\n        try { return window.getFullImgUrl ? String(window.getFullImgUrl(logo, dbVal, 'Config', 'Config') || '') : ''; } catch(e) { return ''; }\n    };\n\n    window.getSafePreviewUrl = function(val, dbName, tName, keyName, recordLabel) {\n        const fb = window.getCompanyFallbackMediaUrl(dbName || (gE('ti-ditta') ? gE('ti-ditta').value : '')) || '';\n        const raw = String(val || '').trim();\n        const tbl = String(tName || '').toLowerCase();\n        const key = String(keyName || '').toLowerCase();\n        const url = window.getFullImgUrl(raw, dbName, tName, recordLabel);\n        if (!raw) return fb || url;\n        if ((tbl === 'utenti' || key === 'immagine' || key === 'foto' || key === 'logo') && window.isLegacyUserImagePath(raw)) {\n            return fb || url;\n        }\n        return url || fb;\n    };\n    window.applyFallbackImage = function(imgEl) {\n        if (!imgEl) return;\n        const fb = imgEl.getAttribute('data-fallback') || window.getCompanyFallbackMediaUrl(gE('ti-ditta') ? gE('ti-ditta').value : '');\n        if (fb && imgEl.src !== fb) {\n            imgEl.onerror = null;\n            imgEl.src = fb;\n            return;\n        }\n        imgEl.style.display = 'none';\n    };\n\n    window.fmtNum = function(num) {\n        let n = parseFloat(num) || 0;\n        let parts = n.toFixed(2).split('.');\n        parts[0] = parts[0].replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, \".\");\n        return parts.join(',');\n    };\n\n    window.parseIvaRate = function(val, defVal = 22) {\n        if (val == null) return defVal;\n        let raw = String(val).trim();\n        if (!raw) return defVal;\n        raw = raw.replace(\/%\/g, '').replace(',', '.');\n        let n = parseFloat(raw);\n        return isNaN(n) ? defVal : n;\n    };\n\n    window.calcVatAmountFromGross = function(gross, ivaRate) {\n        let g = parseFloat(gross) || 0;\n        let r = window.parseIvaRate(ivaRate, 22);\n        if (r <= 0) return 0;\n        return g - (g \/ (1 + (r \/ 100)));\n    };\n\n    window.calcVatNetFromGross = function(gross, ivaRate) {\n        let g = parseFloat(gross) || 0;\n        let vat = window.calcVatAmountFromGross(g, ivaRate);\n        return g - vat;\n    };\n\n\n    window.fetchJsonSafe = function(url, options) {\n        const opts = Object.assign({}, options || {});\n        let tableReadWait = false;\n        let tableReadWaitShown = false;\n        let tableReadOk = false;\n        let tableReadTitle = '\u23f3 Lettura tabelle in corso';\n        let tableReadDetail = 'Sto leggendo le tabelle della ditta. Attendi la fine del caricamento.';\n        let tableReadItem = '';\n        try {\n            tableReadWait = !!opts.tiShowTableReadWait;\n            if (opts.tiTableReadTitle) tableReadTitle = String(opts.tiTableReadTitle);\n            if (opts.tiTableReadDetail) tableReadDetail = String(opts.tiTableReadDetail);\n            if (opts.tiTableReadItem) tableReadItem = String(opts.tiTableReadItem);\n            delete opts.tiShowTableReadWait;\n            delete opts.tiTableReadTitle;\n            delete opts.tiTableReadDetail;\n            delete opts.tiTableReadItem;\n        } catch(e) {}\n        \/\/ 30.9.1379: timeout opzionale (assente per default, per non alterare il comportamento delle\n        \/\/ moltissime chiamate esistenti a questa funzione condivisa) - un chiamante puo' richiederlo passando\n        \/\/ {tiTimeoutMs: N}. Stesso problema di \"nessun limite di tempo\" gia' trovato e corretto piu' volte in\n        \/\/ altre funzioni di questa sessione.\n        let timeoutTimer1379 = null;\n        try {\n            if (opts.tiTimeoutMs && Number(opts.tiTimeoutMs) > 0) {\n                const timeoutMs1379 = Number(opts.tiTimeoutMs);\n                delete opts.tiTimeoutMs;\n                if (!opts.signal && typeof AbortController !== 'undefined') {\n                    const ctl1379 = new AbortController();\n                    opts.signal = ctl1379.signal;\n                    timeoutTimer1379 = setTimeout(function(){ try { ctl1379.abort(); } catch(e){} }, timeoutMs1379);\n                }\n            } else {\n                delete opts.tiTimeoutMs;\n            }\n        } catch(e) {}\n        try {\n            if (opts.body instanceof FormData && opts.body.has('ti_action') && !opts.body.has('action')) {\n                opts.body.append('action', opts.body.get('ti_action'));\n            }\n            if (opts.body instanceof FormData && window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(opts.body);\n        } catch(e) {}\n        const tiNoLongProcessSignal = !!opts.tiNoLongProcessSignal;\n        if (Object.prototype.hasOwnProperty.call(opts, 'tiNoLongProcessSignal')) delete opts.tiNoLongProcessSignal;\n        if (!tiNoLongProcessSignal && !opts.signal && window.tiLongProcessState && window.tiLongProcessState.controller) {\n            opts.signal = window.tiLongProcessState.controller.signal;\n        }\n        if (tableReadWait && typeof window.showTableReadWait === 'function') {\n            tableReadWaitShown = window.showTableReadWait(tableReadTitle, tableReadDetail, tableReadItem);\n        }\n        const requestPromise = fetch(url, opts).then(async (response) => {\n            const raw = await response.text();\n            if (!response.ok) {\n                const httpErr = new Error(`HTTP ${response.status}: ${raw.slice(0, 180) || 'Risposta server vuota'}`);\n                httpErr.httpStatus = response.status;\n                throw httpErr;\n            }\n            try {\n                return JSON.parse(raw);\n            } catch (err) {\n                throw new Error(`Risposta server non valida: ${raw.slice(0, 180) || 'vuota'}`);\n            }\n        }).then((data) => {\n            try {\n                if (data && data.success === false && data.data && data.data.maintenance && data.data.maintenance.active) {\n                    var maint = data.data.maintenance || {};\n                    if (typeof window.tiSsEnterMaintenance496 === 'function') {\n                        window.tiSsEnterMaintenance496(maint.message || (data.data && data.data.message) || 'Shop & Service temporaneamente in manutenzione.', maint.detail || '');\n                    }\n                    var mErr = new Error((data.data && data.data.message) || 'Shop & Service temporaneamente in manutenzione.');\n                    mErr.maintenance = maint;\n                    throw mErr;\n                }\n            } catch(checkErr) {\n                throw checkErr;\n            }\n            tableReadOk = true;\n            return data;\n        }).catch((err) => {\n            if (err && err.name === 'AbortError') {\n                const abortErr = new Error(timeoutTimer1379 === null ? 'Processo interrotto dall utente.' : 'Il server non ha risposto entro il tempo previsto.');\n                abortErr.userCancelled = (timeoutTimer1379 === null);\n                throw abortErr;\n            }\n            throw err;\n        }).finally(() => { try { if (timeoutTimer1379) clearTimeout(timeoutTimer1379); } catch(e){} });\n        if (!tableReadWaitShown || typeof requestPromise.finally !== 'function') return requestPromise;\n        return requestPromise.finally(function(){\n            if (typeof window.hideTableReadWait === 'function') window.hideTableReadWait(tableReadOk, tableReadOk ? 'Tabelle lette' : 'Errore lettura tabelle');\n        });\n    };\n\n\n    window.tiAppendCurrentLanguageToFormData = function(fd) {\n        try {\n            if (!(fd instanceof FormData)) return fd;\n            const lang = (String(window.currLang || 'it').toLowerCase().indexOf('en') === 0) ? 'en' : 'it';\n            if (!fd.has('ti_lang')) fd.append('ti_lang', lang);\n            if (!fd.has('ti_ui_lang')) fd.append('ti_ui_lang', lang);\n        } catch(e) {}\n        return fd;\n    };\n    window.buildAjaxFormData = function(actionName, extra) {\n        const fd = new FormData();\n        fd.append('action', actionName);\n        fd.append('ti_action', actionName);\n        if (extra && typeof extra === 'object') {\n            Object.keys(extra).forEach((key) => {\n                if (typeof extra[key] !== 'undefined' && extra[key] !== null) fd.append(key, extra[key]);\n            });\n        }\n        return window.tiAppendCurrentLanguageToFormData(fd);\n    };\n    window.ensureAjaxActionField = function(fd) {\n        if (!(fd instanceof FormData)) return fd;\n        if (!fd.has('action') && fd.has('ti_action')) fd.append('action', fd.get('ti_action'));\n        return window.tiAppendCurrentLanguageToFormData(fd);\n    };\n\n    window.postFormDataJsonSafe = function(url, fd, options) {\n        const formData = window.ensureAjaxActionField(fd);\n        let targetUrl = url || window.tiAjaxUrl || window.tiUrl;\n        \/\/ Le azioni di configurazione usano l'autenticazione interna del plugin.\n        \/\/ Se l'utente non e loggato in WordPress, admin-ajax.php puo rispondere HTTP 400: 0.\n        \/\/ Per queste richieste usiamo quindi l'endpoint pagina\/interceptor, che e lo stesso flusso del chatbot configurazione.\n        try {\n            const act = (formData instanceof FormData) ? String(formData.get('ti_action') || formData.get('action') || '') : '';\n            if (act === 'ti_ai_config_action' && window.tiUrl && !(options && options.tiForceAjaxUrl)) targetUrl = window.tiUrl;\n        } catch(e) {}\n        const opts = Object.assign({method:'POST', body:formData, credentials:'same-origin', tiNoLongProcessSignal:true}, options || {});\n        return window.fetchJsonSafe(targetUrl, opts).catch(function(fetchErr){\n            if (!window.jQuery || !(formData instanceof FormData)) throw fetchErr;\n            return new Promise(function(resolve, reject){\n                window.jQuery.ajax({\n                    url: targetUrl,\n                    method: 'POST',\n                    data: formData,\n                    processData: false,\n                    contentType: false,\n                    cache: false,\n                    dataType: 'json',\n                    timeout: 180000,\n                    success: function(data){ resolve(data); },\n                    error: function(xhr, textStatus, errorThrown){\n                        let msg = errorThrown || textStatus || 'errore rete';\n                        try {\n                            const txt = xhr && xhr.responseText ? String(xhr.responseText).trim() : '';\n                            if (txt) msg = txt.slice(0, 220);\n                        } catch(e) {}\n                        const err = new Error('XHR fallback fallito: ' + msg);\n                        err.originalFetchError = fetchErr;\n                        reject(err);\n                    }\n                });\n            });\n        });\n    };\n\n    if (!window.__tiFetchLanguageWrapped && window.fetch) {\n        window.__tiFetchLanguageWrapped = true;\n        window.__tiOriginalFetchForLang = window.fetch.bind(window);\n        window.fetch = function(input, init) {\n            try {\n                if (init && init.body instanceof FormData && window.tiAppendCurrentLanguageToFormData) {\n                    if (init.body.has('ti_action') && !init.body.has('action')) init.body.append('action', init.body.get('ti_action'));\n                    window.tiAppendCurrentLanguageToFormData(init.body);\n                }\n            } catch(e) {}\n            return window.__tiOriginalFetchForLang(input, init);\n        };\n    }\n\n    window.tiLongProcessState = { controller: null, cancellable: false, cancelled: false, label: '' };\n    window.beginLongAIProcess = function(label, cancellable = true) {\n        if (window.tiLongProcessState.controller && !window.tiLongProcessState.cancelled) {\n            try { window.tiLongProcessState.controller.abort(); } catch(e) {}\n        }\n        window.tiLongProcessState = {\n            controller: new AbortController(),\n            cancellable: !!cancellable,\n            cancelled: false,\n            label: label || 'Processo AI'\n        };\n        return window.tiLongProcessState.controller;\n    };\n    window.clearLongAIProcess = function() {\n        window.tiLongProcessState = { controller: null, cancellable: false, cancelled: false, label: '' };\n    };\n    window.isLongAIProcessCancelled = function() {\n        return !!(window.tiLongProcessState && window.tiLongProcessState.cancelled);\n    };\n    window.cancelLongAIProcess = function() {\n        if (typeof window.confirmCancelBatchAIGen === 'function' && window.confirmCancelBatchAIGen()) return;\n        const state = window.tiLongProcessState || {};\n        let handledConfigCancel434 = false;\n        try {\n            if (typeof window.cancelActiveConfigAiRequest434 === 'function') handledConfigCancel434 = !!window.cancelActiveConfigAiRequest434('user_exit');\n        } catch(e) {}\n        if (!state.controller || !state.cancellable) {\n            window.closeModal('ti-ai-loader-ov');\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            if (!handledConfigCancel434) window.tiAlert('Processo AI interrotto. Per completarlo dovrai ripetere l operazione.');\n            return;\n        }\n        state.cancelled = true;\n        try { state.controller.abort(); } catch(e) {}\n        window.closeModal('ti-ai-loader-ov');\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        if (!handledConfigCancel434) window.tiAlert('Processo AI interrotto. Per completarlo dovrai ripetere l operazione.');\n    };\n\n    window.tiModalBaseZ = 2147482000;\n    window.tiModalMaxZ = 2147483647;\n    window.tiModalCommunicationZ = {\n        'ti-alert-ov': 2147483647,\n        'ti-ai-loader-ov': 2147483646\n    };\n    window.tiModalStack = 0;\n    window.setPluginModalZIndex = function(el, z) {\n        if (!el) return;\n        const zi = Math.max(1, Math.min(window.tiModalMaxZ || 2147483647, parseInt(z, 10) || window.tiModalBaseZ || 2147482000));\n        try { el.style.setProperty('z-index', String(zi), 'important'); }\n        catch(e) { el.style.zIndex = String(zi); }\n    };\n    window.getPluginModalBaseZ = function(el) {\n        if (el && el.id && window.tiModalCommunicationZ && window.tiModalCommunicationZ[el.id]) return window.tiModalCommunicationZ[el.id];\n        return window.tiModalBaseZ || 2147482000;\n    };\n    window.ensurePluginModalRoot = function() {\n        let root = document.getElementById('ti-plugin-modal-root');\n        if (!root) {\n            root = document.createElement('div');\n            root.id = 'ti-plugin-modal-root';\n            root.style.setProperty('z-index', '2147483000', 'important');\n            document.body.appendChild(root);\n        }\n        try { root.style.setProperty('z-index', '2147483000', 'important'); } catch(e) {}\n        return root;\n    };\n    window.getPluginModalClosePanel = function(ov) {\n        if (!ov || !ov.children) return null;\n        const direct = Array.from(ov.children || []).find(function(ch){ return ch && ch.classList && (ch.classList.contains('ti-conf-window') || ch.classList.contains('ti-modal')); });\n        if (direct) return direct;\n        return ov.querySelector ? ov.querySelector('.ti-conf-window, .ti-modal') : null;\n    };\n    window.closePluginFormModal = function(id) {\n        if (id === 'ti-conf-ov' && typeof window.closeConfigModal === 'function') return window.closeConfigModal();\n        if (id === 'ti-cam-ov' && typeof window.closeCamModal === 'function') return window.closeCamModal();\n        if (id === 'ti-order-item-ov' && typeof window.closeOrderItemPopup === 'function') return window.closeOrderItemPopup();\n        return window.closeModal(id);\n    };\n    window.ensureClosableModalControls = function(root) {\n        const scope = root && root.querySelectorAll ? root : document;\n        const overlays = scope.matches && scope.matches('.ti-ov') ? [scope] : Array.from(scope.querySelectorAll ? scope.querySelectorAll('.ti-ov') : []);\n        overlays.forEach(function(ov){\n            if (!ov || !ov.id || ov.id === 'ti-img-ov' || ov.id === 'ti-alert-ov' || ov.id === 'ti-ai-loader-ov') return;\n            const panel = window.getPluginModalClosePanel(ov);\n            if (!panel) return;\n            if (!panel.style.position || panel.style.position === 'static') panel.style.position = 'relative';\n            if (!panel.querySelector('.ti-modal-x-red')) {\n                const x = document.createElement('button');\n                x.type = 'button';\n                x.className = 'ti-modal-x-red';\n                x.setAttribute('aria-label', 'Chiudi');\n                x.title = 'Chiudi';\n                x.textContent = '\u00d7';\n                x.addEventListener('click', function(ev){\n                    ev.preventDefault(); ev.stopPropagation();\n                    var wasConfigOv = (ov.id === 'ti-conf-ov');\n                    if (wasConfigOv) {\n                        try { if (window.log1088) window.log1088('DIAGNOSTICA 1261: click su X rossa Configurazione registrato, avvio ricarica tra 400ms'); } catch(e) {}\n                    }\n                    window.closePluginFormModal(ov.id);\n                    if (wasConfigOv) {\n                        setTimeout(function(){ try { location.reload(); } catch(e) { location.href = location.href; } }, 400);\n                    }\n                });\n                panel.appendChild(x);\n            }\n            const hasCloseBtn = !!panel.querySelector('.ti-modal-bottom-close-row, [data-ti-bottom-close=\"1\"]') || Array.from(panel.querySelectorAll ? panel.querySelectorAll('button, a') : []).some(function(b){ return \/\\bchiudi\\b\/i.test(String(b.textContent || '')); });\n            if (!hasCloseBtn) {\n                const row = document.createElement('div');\n                row.className = 'ti-modal-bottom-close-row';\n                row.setAttribute('data-ti-bottom-close', '1');\n                const btn = document.createElement('button');\n                btn.type = 'button';\n                btn.className = 'ti-btn btn-close';\n                btn.textContent = 'Chiudi';\n                btn.addEventListener('click', function(ev){ ev.preventDefault(); ev.stopPropagation(); window.closePluginFormModal(ov.id); });\n                row.appendChild(btn);\n                panel.appendChild(row);\n            }\n        });\n    };\n    window.portalizePluginModals = function() {\n        const root = window.ensurePluginModalRoot();\n        document.querySelectorAll('.ti-ov').forEach(function(el){\n            if (el.parentNode !== root) root.appendChild(el);\n            el.style.position = 'fixed';\n            el.style.inset = '0';\n            window.setPluginModalZIndex(el, window.getPluginModalBaseZ(el));\n        });\n        if (window.ensureClosableModalControls) window.ensureClosableModalControls(root);\n        if (window.updateCompanyReferenceDateTime) window.updateCompanyReferenceDateTime();\n    };\n    window.bringPluginModalToFront = function(el) {\n        if (!el) return;\n        if (el.id && window.tiModalCommunicationZ && window.tiModalCommunicationZ[el.id]) {\n            window.setPluginModalZIndex(el, window.tiModalCommunicationZ[el.id]);\n            return;\n        }\n        window.tiModalStack = (window.tiModalStack || 0) + 1;\n        if (window.tiModalStack > 1200) window.tiModalStack = 1;\n        window.setPluginModalZIndex(el, (window.tiModalBaseZ || 2147482000) + window.tiModalStack);\n    };\n    window.keepUserCommunicationPopupsInFront = function() {\n        ['ti-ai-loader-ov', 'ti-admin-comm-ov', 'ti-alert-ov'].forEach(function(id){\n            const el = gE(id);\n            if (!el) return;\n            const disp = String(el.style.display || '').replace(\/\\s+\/g, '').toLowerCase();\n            if (disp === 'flex' || disp === 'block') {\n                window.bringPluginModalToFront(el);\n                if (id === 'ti-alert-ov') {\n                    const btn = gE('ti-alert-no') || gE('ti-alert-yes');\n                    if (btn && typeof btn.focus === 'function') {\n                        setTimeout(function(){ try { btn.focus({preventScroll:true}); } catch(e) { try { btn.focus(); } catch(e2) {} } }, 0);\n                    }\n                }\n            }\n        });\n    };\n    window.preparePluginModal = function(id) {\n        const el = typeof id === 'string' ? gE(id) : id;\n        if (!el) return null;\n        window.portalizePluginModals();\n        const root = window.ensurePluginModalRoot();\n        if (el.parentNode !== root) root.appendChild(el);\n        el.style.position = 'fixed';\n        el.style.inset = '0';\n        window.setPluginModalZIndex(el, window.getPluginModalBaseZ(el));\n        return el;\n    };\n    window.showPluginModal = function(id) {\n        const el = window.preparePluginModal(id);\n        if (!el) return null;\n        if (window.ensureClosableModalControls) window.ensureClosableModalControls(el);\n        window.bringPluginModalToFront(el);\n        el.style.display = 'flex';\n        try { if (window.applyLayoutLanguage) window.applyLayoutLanguage(true); } catch(e) {}\n        window.keepUserCommunicationPopupsInFront();\n        window.updatePluginScrollLock();\n        return el;\n    };\n    window.updatePluginScrollLock = function() {\n        const hasOpen = !!document.querySelector('.ti-ov[style*=\"display: flex\"], .ti-ov[style*=\"display:flex\"], #ti-ai-loader-ov[style*=\"display: flex\"], #ti-ai-loader-ov[style*=\"display:flex\"]');\n        const isMobile = window.tiIsMobileLike ? window.tiIsMobileLike() : !!(window.matchMedia && window.matchMedia('(max-width: 900px)').matches);\n        \/\/ Su smartphone e dispositivi touch non bloccare mai lo scroll del body:\n        \/\/ alcuni browser mobili restano non scorrevoli dopo login\/modal.\n        if (isMobile) {\n            document.documentElement.classList.remove('ti-no-scroll');\n            document.body.classList.remove('ti-no-scroll');\n            document.documentElement.style.overflowY = 'auto';\n            document.body.style.overflowY = 'auto';\n            document.documentElement.style.overflowX = 'hidden';\n            document.body.style.overflowX = 'hidden';\n            document.documentElement.style.height = 'auto';\n            document.body.style.height = 'auto';\n            document.documentElement.style.position = 'static';\n            document.body.style.position = 'static';\n            document.documentElement.style.touchAction = 'pan-y';\n            document.body.style.touchAction = 'pan-y';\n            return;\n        }\n        document.documentElement.classList.toggle('ti-no-scroll', hasOpen);\n        document.body.classList.toggle('ti-no-scroll', hasOpen);\n    };\n    window.keepPluginModalInFront = function(id) {\n        const el = typeof id === 'string' ? gE(id) : id;\n        if (!el) return null;\n        if (el.style.display === 'flex' || el.style.display === 'block') {\n            window.preparePluginModal(el);\n            window.bringPluginModalToFront(el);\n            window.keepUserCommunicationPopupsInFront();\n        }\n        return el;\n    };\n    window.openModal = function(id) {\n        try {\n            if (window.updateMobileViewportHeight) window.updateMobileViewportHeight();\n            window.showPluginModal(id);\n            if (id === 'ti-login-ov') {\n                setTimeout(function(){\n                    if (window.tiMobileUnlockScroll) window.tiMobileUnlockScroll();\n                    if (!(window.tiIsMobileLike && window.tiIsMobileLike())) {\n                        const u = gE('l-user');\n                        if (u && typeof u.focus === 'function') { try { u.focus({preventScroll:true}); } catch(e) {} }\n                    }\n                    if (window.bindMobileLoginButton) window.bindMobileLoginButton();\n                }, 120);\n            }\n        } catch(e) {}\n    };\n    window.closeModal = function(id) {\n        try {\n            const el = typeof id === 'string' ? gE(id) : id;\n            if (el) {\n                el.style.display = 'none';\n                window.updatePluginScrollLock();\n                window.keepUserCommunicationPopupsInFront();\n            }\n        } catch(e) {}\n    };\n    if (!window.__tiCloseButtonsFallback664) {\n        window.__tiCloseButtonsFallback664 = true;\n        document.addEventListener('click', function(ev){\n            try {\n                var btn = ev.target && ev.target.closest ? ev.target.closest('button, a, [role=\"button\"]') : null;\n                if (!btn) return;\n                if (btn.id === 'ti-logout-btn') return;\n                var label = String(btn.textContent || btn.getAttribute('aria-label') || btn.title || '').trim().toLowerCase();\n                var isClose = label === '\u00d7' || label === 'x' || label === 'chiudi' || label === 'esci' || label === 'annulla';\n                if (!isClose && !(btn.classList && (btn.classList.contains('btn-close') || btn.classList.contains('ti-modal-x-red')))) return;\n                var ov = btn.closest('.ti-ov, #ti-direct-upload-ov-621, #ti-ai-loader-ov, #ti-alert-ov, #ti-admin-comm-ov');\n                if (!ov || !ov.id) return;\n                if (ov.id === 'ti-report-ov') {\n                    var inlineClose = String(btn.getAttribute('onclick') || '');\n                    var explicitReportClose = \/closeModal\\(['\"]ti-report-ov['\"]\\)\/.test(inlineClose) || btn.getAttribute('data-ti-close-report') === '1';\n                    if (!explicitReportClose) return;\n                }\n                if (ov.id === 'ti-direct-upload-ov-621') return; \/\/ gestito da exitUpload per rispettare annullamento upload.\n                if (ov.id === 'ti-ai-loader-ov' && typeof window.tiIsActiveProcess1546 === 'function' && window.tiIsActiveProcess1546() && typeof window.tiConfirmAndAbortActiveProcess1546 === 'function' && !window.__tiCancel1546Force) {\n                    try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e1546) {}\n                    window.tiConfirmAndAbortActiveProcess1546('Processo in corso');\n                    return;\n                }\n                setTimeout(function(){\n                    try {\n                        var visible = ov && (ov.style.display === 'flex' || ov.style.display === 'block' || getComputedStyle(ov).display !== 'none');\n                        if (visible && window.closePluginFormModal) window.closePluginFormModal(ov.id);\n                    } catch(e2) {}\n                }, 60);\n            } catch(e) {}\n        }, true);\n    }\n    try { window.portalizePluginModals(); if (window.ensureClosableModalControls) window.ensureClosableModalControls(); } catch(e) {}\n    if (typeof window.initPluginDateInputs !== 'function') {\n        window.initPluginDateInputs = function(root) {\n            const scope = root || document;\n            scope.querySelectorAll('input[type=\"date\"], input[type=\"time\"]').forEach(function(inp){\n                const v = String(inp.value || '').trim();\n                if (inp.type === 'date' && !\/^\\d{4}-\\d{2}-\\d{2}$\/.test(v)) inp.value = '';\n                if (inp.type === 'time' && !\/^\\d{2}:\\d{2}$\/.test(v)) inp.value = '';\n                if (inp.type === 'date') { inp.placeholder = 'gg\/mm\/aaaa'; inp.title = inp.title || 'Seleziona una data'; }\n                if (inp.type === 'time') { inp.placeholder = 'hh:mm'; inp.title = inp.title || 'Seleziona un orario'; }\n            });\n        };\n    }\n\n    window.closeConfigModal = function() {\n        if (window.hasPendingImportAssociations && window.hasPendingImportAssociations()) {\n            const importOv = gE('ti-conf-import-preview-ov');\n            const previewOpen = importOv && String(importOv.style.display || '').indexOf('flex') !== -1;\n            if (previewOpen) {\n                window.closeConfigImportPreview(false);\n                return;\n            }\n        }\n        const hadSaved = !!window.configWasSaved;\n        window.closeModal('ti-conf-ov');\n        if (!hadSaved) {\n            window.currentDbData = null;\n            window.configOriginalDbData = null;\n            if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear();\n            if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            return;\n        }\n        window.configWasSaved = false;\n        const fd = window.buildAjaxFormData('ti_ai_reset_flow');\n        fetch(window.tiUrl, {method:'POST', body:window.ensureAjaxActionField(fd)}).then(() => location.reload());\n    };\n\n    window.tiLoaderState = { timer: null, percent: 0, target: 90, startedAt: 0, active: false };\n    window.showProgressPopup = function(title, subtitle, opts = {}) {\n        const ov = gE('ti-ai-loader-ov'); if(!ov) return;\n        const titleEl = gE('ti-loader-title'); const subEl = gE('ti-loader-sub'); const itemEl = gE('ti-loader-current-item');\n        const wrap = gE('ti-loader-progress-wrap'); const pct = gE('ti-loader-percent'); const bar = gE('ti-loader-bar');\n        const actions = gE('ti-loader-actions');\n        const cancellable = opts.cancellable !== false;\n        window.beginLongAIProcess(title || 'Elaborazione AI in corso...', cancellable);\n        if (titleEl) titleEl.innerText = title || 'Elaborazione AI in corso...';\n        if (subEl) subEl.innerText = subtitle || \"Attendi, l'operazione potrebbe richiedere alcuni secondi.\";\n        if (itemEl) {\n            const currentItem = String(opts.currentItem || opts.itemName || '').trim();\n            itemEl.style.display = currentItem ? 'block' : 'none';\n            itemEl.innerText = currentItem ? ('Elemento in lavorazione: ' + currentItem) : '';\n        }\n        if (wrap) wrap.style.display = 'block';\n        if (actions) actions.style.display = cancellable ? 'block' : 'none';\n        window.tiLoaderState.active = true;\n        window.tiLoaderState.percent = Math.max(0, Math.min(100, parseInt(opts.startPercent || 0, 10) || 0));\n        window.tiLoaderState.target = Math.max(window.tiLoaderState.percent, Math.min(99, parseInt(opts.targetPercent || 90, 10) || 90));\n        window.tiLoaderState.startedAt = Date.now();\n        if (pct) pct.innerText = window.tiLoaderState.percent + '%';\n        if (bar) bar.style.width = window.tiLoaderState.percent + '%';\n        window.showPluginModal('ti-ai-loader-ov');\n        clearInterval(window.tiLoaderState.timer);\n        const stepMs = Math.max(150, parseInt(opts.stepMs || 500, 10) || 500);\n        window.tiLoaderState.timer = setInterval(() => {\n            if (!window.tiLoaderState.active) return;\n            let inc = 1;\n            if (window.tiLoaderState.percent < 20) inc = 4;\n            else if (window.tiLoaderState.percent < 45) inc = 3;\n            else if (window.tiLoaderState.percent < 70) inc = 2;\n            else inc = 1;\n            window.tiLoaderState.percent = Math.min(window.tiLoaderState.target, window.tiLoaderState.percent + inc);\n            if (pct) pct.innerText = window.tiLoaderState.percent + '%';\n            if (bar) bar.style.width = window.tiLoaderState.percent + '%';\n            if (window.tiLoaderState.percent >= window.tiLoaderState.target) clearInterval(window.tiLoaderState.timer);\n        }, stepMs);\n    };\n    window.updateProgressPopup = function(percent, title, subtitle, currentItem) {\n        const ov = gE('ti-ai-loader-ov'); if(!ov) return;\n        const titleEl = gE('ti-loader-title'); const subEl = gE('ti-loader-sub'); const itemEl = gE('ti-loader-current-item');\n        const wrap = gE('ti-loader-progress-wrap'); const pct = gE('ti-loader-percent'); const bar = gE('ti-loader-bar');\n        window.tiLoaderState.active = true;\n        clearInterval(window.tiLoaderState.timer);\n        if (titleEl && title) titleEl.innerText = title;\n        if (subEl && subtitle) subEl.innerText = subtitle;\n        if (itemEl) {\n            const itemName = String(currentItem || '').trim();\n            itemEl.style.display = itemName ? 'block' : 'none';\n            itemEl.innerText = itemName ? ('Elemento in lavorazione: ' + itemName) : '';\n        }\n        if (wrap) wrap.style.display = 'block';\n        window.tiLoaderState.percent = Math.max(0, Math.min(100, parseInt(percent, 10) || 0));\n        if (pct) pct.innerText = window.tiLoaderState.percent + '%';\n        if (bar) bar.style.width = window.tiLoaderState.percent + '%';\n        window.showPluginModal('ti-ai-loader-ov');\n    };\n    window.hideProgressPopup = function(success = true, finalText = '', opts = {}) {\n        const ov = gE('ti-ai-loader-ov'); if(!ov) return;\n        const titleEl = gE('ti-loader-title'); const subEl = gE('ti-loader-sub'); const itemEl = gE('ti-loader-current-item'); const pct = gE('ti-loader-percent'); const bar = gE('ti-loader-bar');\n        const actions = gE('ti-loader-actions');\n        try { const tipEl1458 = gE('ti-loader-tip-keep-active-1458'); if (tipEl1458) tipEl1458.style.display = 'none'; } catch(e) {}\n        const wasCancelled = window.isLongAIProcessCancelled();\n        window.tiLoaderState.active = false;\n        clearInterval(window.tiLoaderState.timer);\n        if (actions) actions.style.display = 'none';\n        if (itemEl) { itemEl.style.display = 'none'; itemEl.innerText = ''; }\n        const remindSave = !!opts.remindSave && window.modifiedFields && window.modifiedFields.size > 0;\n        const successMsg = (opts.successMessage || finalText || 'Operazione AI completata') + (remindSave ? '\\n\\nRicorda di salvare le modifiche se non lo hai ancora fatto.' : '');\n        const errorMsg = opts.errorMessage || finalText || 'Operazione interrotta';\n        if (success) {\n            if (titleEl) titleEl.innerText = finalText || 'Operazione completata';\n            if (subEl) subEl.innerText = remindSave ? 'Attivit\u00e0 AI conclusa. Sono presenti modifiche non ancora salvate.' : 'Completamento confermato dal sistema.';\n            if (pct) pct.innerText = '100%';\n            if (bar) bar.style.width = '100%';\n            \/\/ 30.9.1454: la chiusura del popup e il conseguente avviso di completamento dipendevano da un\n            \/\/ singolo setTimeout(450ms), lo stesso tipo di meccanismo gia' confermato inaffidabile in questa\n            \/\/ sessione - se non scattava, l'utente restava senza alcun avviso chiaro di completamento, pur\n            \/\/ avendo il processo effettivamente terminato con successo. Ora quattro meccanismi indipendenti\n            \/\/ (setTimeout, controllo periodico, requestAnimationFrame, cambio scheda\/focus) garantiscono che\n            \/\/ l'avviso venga mostrato in ogni caso.\n            (function(){\n                var fired1454 = false;\n                function fire1454(){\n                    if (fired1454) return; fired1454 = true;\n                    window.closeModal('ti-ai-loader-ov');\n                    window.clearLongAIProcess();\n                    if (opts.notifyUser !== false) { window.tiAlert(successMsg); }\n                }\n                try { setTimeout(fire1454, 450); } catch(e) {}\n                try {\n                    var start1454 = Date.now ? Date.now() : (new Date()).getTime();\n                    var iv1454 = setInterval(function(){ if (fired1454) { clearInterval(iv1454); return; } if ((Date.now?Date.now():(new Date()).getTime()) - start1454 >= 450) fire1454(); }, 200);\n                } catch(e) {}\n                try { if (typeof requestAnimationFrame === 'function') requestAnimationFrame(function(){ setTimeout(fire1454, 0); }); } catch(e) {}\n                try {\n                    var catchup1454 = function(){ if (!fired1454) fire1454(); };\n                    document.addEventListener('visibilitychange', catchup1454, {once:true});\n                    window.addEventListener('focus', catchup1454, {once:true});\n                } catch(e) {}\n            })();\n        } else {\n            if (titleEl) titleEl.innerText = finalText || 'Operazione interrotta';\n            if (subEl) subEl.innerText = 'Non e stato possibile completare l attivita richiesta.';\n            (function(){\n                var fired1454b = false;\n                function fire1454b(){\n                    if (fired1454b) return; fired1454b = true;\n                    window.closeModal('ti-ai-loader-ov');\n                    if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess();\n                    if (opts.notifyUser !== false) { window.tiAlert(errorMsg); }\n                }\n                try { setTimeout(fire1454b, 250); } catch(e) {}\n                try {\n                    var start1454b = Date.now ? Date.now() : (new Date()).getTime();\n                    var iv1454b = setInterval(function(){ if (fired1454b) { clearInterval(iv1454b); return; } if ((Date.now?Date.now():(new Date()).getTime()) - start1454b >= 250) fire1454b(); }, 150);\n                } catch(e) {}\n                try { if (typeof requestAnimationFrame === 'function') requestAnimationFrame(function(){ setTimeout(fire1454b, 0); }); } catch(e) {}\n                try {\n                    var catchup1454b = function(){ if (!fired1454b) fire1454b(); };\n                    document.addEventListener('visibilitychange', catchup1454b, {once:true});\n                    window.addEventListener('focus', catchup1454b, {once:true});\n                } catch(e) {}\n            })();\n        }\n    };\n\n    (function installTiRobustLongProgress327(){\n        if (window.__tiRobustLongProgress327Installed) return;\n        window.__tiRobustLongProgress327Installed = true;\n        function clampPct(v) {\n            v = parseInt(v, 10);\n            if (!isFinite(v) || isNaN(v)) v = 0;\n            return Math.max(0, Math.min(100, v));\n        }\n        function completionText(txt) {\n            txt = String(txt || '').toLowerCase();\n            if (\/chiarimento richiesto|indicami|specifiche|specifica|quali record|criterio piu preciso|criterio pi\u00f9 preciso|record aggiornati:\\s*0\/.test(txt)) return false;\n            return \/completamento confermato|operazione completata|completata|completato|conclusa|concluso|tabelle lette|anteprima import pronta\/.test(txt);\n        }\n        function setLoaderPercent327(percent, title, subtitle, currentItem) {\n            const state = window.tiLoaderState || (window.tiLoaderState = {});\n            const pct = clampPct(percent);\n            const pctEl = gE('ti-loader-percent');\n            const barEl = gE('ti-loader-bar');\n            const titleEl = gE('ti-loader-title');\n            const subEl = gE('ti-loader-sub');\n            const itemEl = gE('ti-loader-current-item');\n            state.percent = pct;\n            if (pctEl) pctEl.innerText = pct + '%';\n            if (barEl) barEl.style.width = pct + '%';\n            if (titleEl && title) titleEl.innerText = String(title);\n            if (subEl && subtitle) subEl.innerText = String(subtitle);\n            if (itemEl && currentItem !== undefined) {\n                const itemName = String(currentItem || '').trim();\n                itemEl.style.display = itemName ? 'block' : 'none';\n                itemEl.innerText = itemName ? ('Elemento in lavorazione: ' + itemName) : '';\n            }\n        }\n        function stopWatch327() {\n            const state = window.tiLoaderState || {};\n            if (state.watchdog327) clearInterval(state.watchdog327);\n            state.watchdog327 = null;\n        }\n        function startWatch327(opts) {\n            opts = opts || {};\n            const state = window.tiLoaderState || (window.tiLoaderState = {});\n            stopWatch327();\n            state.watchStart327 = Date.now();\n            state.watchStartPercent327 = clampPct(state.percent || opts.startPercent || 0);\n            state.watchTarget327 = Math.max(state.watchStartPercent327, Math.min(98, clampPct(opts.targetPercent || state.target || 94)));\n            \/\/ Tempo atteso realistico: se i timer sono sospesi, al tick successivo la percentuale salta in avanti in base al tempo trascorso.\n            state.watchExpectedMs327 = Math.max(30000, Math.min(120000, parseInt(opts.expectedMs || 55000, 10) || 55000));\n            state.watchdog327 = setInterval(function(){\n                try {\n                    if (!state.active) { stopWatch327(); return; }\n                    const elapsed = Math.max(0, Date.now() - (state.watchStart327 || Date.now()));\n                    const start = clampPct(state.watchStartPercent327 || 0);\n                    const target = Math.max(start, Math.min(98, clampPct(state.watchTarget327 || state.target || 94)));\n                    let estimated = start + ((target - start) * Math.min(1, elapsed \/ (state.watchExpectedMs327 || 55000)));\n                    if (elapsed > (state.watchExpectedMs327 || 55000)) {\n                        const extra = Math.min(1, (elapsed - (state.watchExpectedMs327 || 55000)) \/ 90000);\n                        estimated = target + ((99 - target) * extra);\n                    }\n                    if (elapsed > 180000) estimated = 99;\n                    let current = clampPct(state.percent || 0);\n                    if (Math.floor(estimated) > current) {\n                        let sub = '';\n                        if (elapsed > 90000) sub = 'Elaborazione ancora in corso lato server. Attendo la risposta conclusiva e verifico il completamento.';\n                        setLoaderPercent327(Math.floor(estimated), '', sub, undefined);\n                    }\n                    const titleTxt = gE('ti-loader-title') ? gE('ti-loader-title').innerText : '';\n                    const subTxt = gE('ti-loader-sub') ? gE('ti-loader-sub').innerText : '';\n                    if (completionText(titleTxt + ' ' + subTxt)) {\n                        setLoaderPercent327(100, '', 'Completamento confermato dal sistema.', undefined);\n                        stopWatch327();\n                    }\n                } catch(e) {}\n            }, 1000);\n        }\n        if (typeof window.showProgressPopup === 'function' && !window.showProgressPopup.__tiRobustProgress327) {\n            const prevShow = window.showProgressPopup;\n            window.showProgressPopup = function(title, subtitle, opts) {\n                const ret = prevShow.apply(this, arguments);\n                startWatch327(opts || {});\n                return ret;\n            };\n            window.showProgressPopup.__tiRobustProgress327 = true;\n        }\n        if (typeof window.updateProgressPopup === 'function' && !window.updateProgressPopup.__tiRobustProgress327) {\n            const prevUpdate = window.updateProgressPopup;\n            window.updateProgressPopup = function(percent, title, subtitle, currentItem) {\n                const state = window.tiLoaderState || {};\n                let pct = clampPct(percent);\n                const cur = clampPct(state.percent || 0);\n                \/\/ La percentuale non deve regredire per aggiornamenti parziali\/fallback.\n                if (pct < 100 && cur > pct) pct = cur;\n                const ret = prevUpdate.call(this, pct, title, subtitle, currentItem);\n                if (pct >= 100 || completionText(String(title || '') + ' ' + String(subtitle || ''))) {\n                    setLoaderPercent327(100, title || '', subtitle || 'Completamento confermato dal sistema.', currentItem);\n                    stopWatch327();\n                }\n                return ret;\n            };\n            window.updateProgressPopup.__tiRobustProgress327 = true;\n        }\n        if (typeof window.hideProgressPopup === 'function' && !window.hideProgressPopup.__tiRobustProgress327) {\n            const prevHide = window.hideProgressPopup;\n            window.hideProgressPopup = function(success, finalText, opts) {\n                if (success !== false) {\n                    setLoaderPercent327(100, finalText || 'Operazione completata', 'Completamento confermato dal sistema.', undefined);\n                    stopWatch327();\n                }\n                return prevHide.apply(this, arguments);\n            };\n            window.hideProgressPopup.__tiRobustProgress327 = true;\n        }\n        window.tiForceLoaderComplete327 = function(title, subtitle) {\n            setLoaderPercent327(100, title || 'Operazione completata', subtitle || 'Completamento confermato dal sistema.', undefined);\n            stopWatch327();\n        };\n    })();\n\n\n    (function installTiProgressStallGuard338(){\n        if (window.__tiProgressStallGuard338Installed) return;\n        window.__tiProgressStallGuard338Installed = true;\n        function txt(id) { const el = gE(id); return el ? String(el.innerText || el.textContent || '') : ''; }\n        function pctVal() { const raw = txt('ti-loader-percent').replace(\/[^0-9]\/g, ''); const n = parseInt(raw || '0', 10); return isNaN(n) ? 0 : n; }\n        function loaderEl() { return gE('ti-ai-loader-ov'); }\n        function isVisible(el) { return !!el && (el.style.display === 'flex' || el.style.display === 'block'); }\n        function isCompletionText(v) {\n            v = String(v || '').toLowerCase();\n            if (\/chiarimento richiesto|indicami|specifiche|specifica|quali record|criterio piu preciso|criterio pi\u00f9 preciso|record aggiornati:\\s*0|errore|fallito|interrotto\/.test(v)) return false;\n            return \/completamento confermato|operazione completata|completata|completato|conclusa|concluso|tabelle lette|anteprima import pronta\/.test(v);\n        }\n        function shouldAutoClose() {\n            const ov = loaderEl();\n            if (!isVisible(ov)) return false;\n            const combined = txt('ti-loader-title') + ' ' + txt('ti-loader-sub');\n            return pctVal() >= 100 && isCompletionText(combined);\n        }\n        function forceClose(reason) {\n            try {\n                const state = window.tiLoaderState || {};\n                state.active = false;\n                if (state.timer) clearInterval(state.timer);\n                if (state.watchdog327) clearInterval(state.watchdog327);\n                if (state.stallGuard338) clearInterval(state.stallGuard338);\n                state.timer = null;\n                state.watchdog327 = null;\n                const ov = loaderEl();\n                if (ov) ov.style.display = 'none';\n                if (typeof window.updatePluginScrollLock === 'function') window.updatePluginScrollLock();\n                if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess();\n                if (typeof window.keepUserCommunicationPopupsInFront === 'function') window.keepUserCommunicationPopupsInFront();\n                if (window.console && console.info) console.info('[TI Shop Service] loader auto-closed 30.9.664:', reason || 'completed');\n            } catch(e) {}\n        }\n        function scheduleClose(reason, delay) {\n            try {\n                const state = window.tiLoaderState || (window.tiLoaderState = {});\n                if (state.closeTimer338) clearTimeout(state.closeTimer338);\n                state.closeTimer338 = setTimeout(function(){ if (shouldAutoClose()) forceClose(reason); }, Math.max(250, delay || 900));\n            } catch(e) {}\n        }\n        window.tiForceCloseCompletedLoader338 = function(reason) {\n            if (shouldAutoClose()) forceClose(reason || 'manual-check');\n        };\n        if (typeof window.updateProgressPopup === 'function' && !window.updateProgressPopup.__tiProgressStallGuard338) {\n            const prevUpdate338 = window.updateProgressPopup;\n            window.updateProgressPopup = function(percent, title, subtitle, currentItem) {\n                const ret = prevUpdate338.apply(this, arguments);\n                const combined = String(title || '') + ' ' + String(subtitle || '') + ' ' + txt('ti-loader-title') + ' ' + txt('ti-loader-sub');\n                if ((parseInt(percent, 10) || 0) >= 100 || isCompletionText(combined)) scheduleClose('updateProgressPopup', 900);\n                return ret;\n            };\n            window.updateProgressPopup.__tiProgressStallGuard338 = true;\n        }\n        if (typeof window.hideProgressPopup === 'function' && !window.hideProgressPopup.__tiProgressStallGuard338) {\n            const prevHide338 = window.hideProgressPopup;\n            window.hideProgressPopup = function(success, finalText, opts) {\n                const ret = prevHide338.apply(this, arguments);\n                if (success !== false) scheduleClose('hideProgressPopup', 1400);\n                return ret;\n            };\n            window.hideProgressPopup.__tiProgressStallGuard338 = true;\n        }\n        if (typeof window.hideTableReadWait === 'function' && !window.hideTableReadWait.__tiProgressStallGuard338) {\n            const prevHideTable338 = window.hideTableReadWait;\n            window.hideTableReadWait = function(success, finalText) {\n                const ret = prevHideTable338.apply(this, arguments);\n                if (success !== false) scheduleClose('hideTableReadWait', 750);\n                return ret;\n            };\n            window.hideTableReadWait.__tiProgressStallGuard338 = true;\n        }\n        const state = window.tiLoaderState || (window.tiLoaderState = {});\n        if (state.stallGuard338) clearInterval(state.stallGuard338);\n        state.stallGuard338 = setInterval(function(){\n            try {\n                if (!shouldAutoClose()) return;\n                if (!state.completedVisibleSince338) state.completedVisibleSince338 = Date.now();\n                if ((Date.now() - state.completedVisibleSince338) > 2500) forceClose('periodic-stall-guard');\n            } catch(e) {}\n        }, 1000);\n        document.addEventListener('visibilitychange', function(){\n            if (!document.hidden) scheduleClose('visibility-return', 650);\n        });\n        window.addEventListener('focus', function(){ scheduleClose('window-focus', 650); });\n    })();\n\n\n    (function installTiCompletedLoaderDomReaper339(){\n        if (window.__tiCompletedLoaderDomReaper339Installed) return;\n        window.__tiCompletedLoaderDomReaper339Installed = true;\n        function byId(id){ return document.getElementById(id); }\n        function textOf(el){ return el ? String(el.innerText || el.textContent || '') : ''; }\n        function norm(s){ return String(s || '').toLowerCase().replace(\/\\s+\/g, ' ').trim(); }\n        function isBadCompletionText(s){\n            s = norm(s);\n            if (!s) return false;\n            if (\/errore|fallito|interrotto|annulla|chiarimento|specifiche|indicami|record aggiornati\\s*0\/.test(s)) return false;\n            return \/tabelle lette\/.test(s) && \/completamento confermato\/.test(s) && \/avanzamento stimato\/.test(s) && \/100\\s*%\/.test(s);\n        }\n        function isVisible(el){\n            if (!el) return false;\n            try {\n                var cs = window.getComputedStyle(el);\n                if (!cs || cs.display === 'none' || cs.visibility === 'hidden' || parseFloat(cs.opacity || '1') === 0) return false;\n                var r = el.getBoundingClientRect();\n                return r.width > 0 && r.height > 0;\n            } catch(e) {\n                return !!(el && el.offsetParent !== null);\n            }\n        }\n        function hardHide(el, reason){\n            if (!el) return false;\n            try {\n                if (window.console && console.info) console.info('[TI Shop Service] completed loader removed 30.9.664:', reason || '', el.id || el.className || el.tagName);\n            } catch(e) {}\n            try { el.classList.add('ti-loader-force-hidden-339'); } catch(e) {}\n            try {\n                el.style.setProperty('display', 'none', 'important');\n                el.style.setProperty('visibility', 'hidden', 'important');\n                el.style.setProperty('pointer-events', 'none', 'important');\n                el.style.setProperty('opacity', '0', 'important');\n                el.setAttribute('aria-hidden', 'true');\n            } catch(e) {}\n            try {\n                var st = window.tiLoaderState || (window.tiLoaderState = {});\n                st.active = false;\n                if (st.timer) clearInterval(st.timer);\n                if (st.watchdog327) clearInterval(st.watchdog327);\n                if (st.stallGuard338) clearInterval(st.stallGuard338);\n                if (st.closeTimer338) clearTimeout(st.closeTimer338);\n                st.timer = null; st.watchdog327 = null; st.closeTimer338 = null;\n            } catch(e) {}\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            try { if (typeof window.updatePluginScrollLock === 'function') window.updatePluginScrollLock(); } catch(e) {}\n            return true;\n        }\n        function findSmallestCompletedNode(){\n            var nodes = [];\n            try {\n                nodes = Array.from(document.querySelectorAll('#ti-ai-loader-ov, .ti-loader-box, #ti-plugin-modal-root > *, .ti-ov, [id*=\"loader\"], [class*=\"loader\"], [id*=\"progress\"], [class*=\"progress\"], [id*=\"wait\"], [class*=\"wait\"]'));\n            } catch(e) { nodes = []; }\n            var best = null, bestArea = Infinity;\n            nodes.forEach(function(el){\n                if (!el || el.id === 'ti-conf-ov') return;\n                if (!isVisible(el)) return;\n                var tx = textOf(el);\n                if (!isBadCompletionText(tx)) return;\n                var closeTarget = el.closest && el.closest('#ti-ai-loader-ov') ? el.closest('#ti-ai-loader-ov') : el;\n                if (closeTarget && closeTarget.id === 'ti-conf-ov') closeTarget = el;\n                var r = closeTarget.getBoundingClientRect ? closeTarget.getBoundingClientRect() : {width:9999,height:9999};\n                var area = Math.max(1, (r.width || 1) * (r.height || 1));\n                if (area < bestArea) { bestArea = area; best = closeTarget; }\n            });\n            return best;\n        }\n        function reap(reason){\n            var changed = false;\n            try {\n                var ov = byId('ti-ai-loader-ov');\n                if (ov && isBadCompletionText(textOf(ov))) changed = hardHide(ov, reason || 'loader-overlay') || changed;\n            } catch(e) {}\n            try {\n                var box = findSmallestCompletedNode();\n                if (box) changed = hardHide(box, reason || 'completed-node') || changed;\n            } catch(e) {}\n            return changed;\n        }\n        window.tiReapCompletedLoader339 = reap;\n        function schedule(reason, delay){ setTimeout(function(){ reap(reason); }, delay || 120); }\n        if (typeof window.updateProgressPopup === 'function' && !window.updateProgressPopup.__tiCompletedLoaderDomReaper339) {\n            var prevUpdate339 = window.updateProgressPopup;\n            window.updateProgressPopup = function(){\n                var ret = prevUpdate339.apply(this, arguments);\n                schedule('updateProgressPopup', 180);\n                schedule('updateProgressPopup-late', 900);\n                return ret;\n            };\n            window.updateProgressPopup.__tiCompletedLoaderDomReaper339 = true;\n        }\n        if (typeof window.hideProgressPopup === 'function' && !window.hideProgressPopup.__tiCompletedLoaderDomReaper339) {\n            var prevHide339 = window.hideProgressPopup;\n            window.hideProgressPopup = function(){\n                var ret = prevHide339.apply(this, arguments);\n                schedule('hideProgressPopup', 260);\n                schedule('hideProgressPopup-late', 1100);\n                return ret;\n            };\n            window.hideProgressPopup.__tiCompletedLoaderDomReaper339 = true;\n        }\n        if (typeof window.hideTableReadWait === 'function' && !window.hideTableReadWait.__tiCompletedLoaderDomReaper339) {\n            var prevHideTable339 = window.hideTableReadWait;\n            window.hideTableReadWait = function(){\n                var ret = prevHideTable339.apply(this, arguments);\n                schedule('hideTableReadWait', 180);\n                schedule('hideTableReadWait-late', 900);\n                return ret;\n            };\n            window.hideTableReadWait.__tiCompletedLoaderDomReaper339 = true;\n        }\n        \/\/ Controllo continuo leggero: serve quando il loader e' gia' rimasto nel DOM prima dell'installazione del fix.\n        var ticks = 0;\n        var timer = setInterval(function(){\n            ticks++;\n            reap('periodic-' + ticks);\n            if (ticks > 1800) clearInterval(timer); \/\/ 30 minuti, poi basta\n        }, 1000);\n        document.addEventListener('visibilitychange', function(){ if (!document.hidden) schedule('visibilitychange', 100); });\n        window.addEventListener('focus', function(){ schedule('focus', 100); });\n        document.addEventListener('click', function(){ schedule('click', 50); }, true);\n        schedule('install', 250);\n        schedule('install-late', 1500);\n    })();\n\n    (function installTiTableReadNoBlock343(){\n        if (window.__tiTableReadNoBlock343Installed) return;\n        window.__tiTableReadNoBlock343Installed = true;\n        function txt(el){ return el ? String(el.innerText || el.textContent || '') : ''; }\n        function norm(s){ return String(s || '').toLowerCase().replace(\/\\s+\/g, ' ').trim(); }\n        function isCompletedTableReadText(s){\n            s = norm(s);\n            if (!s) return false;\n            if (\/errore|fallito|interrotto|annulla|chiarimento|specifiche|record aggiornati\\s*0\/.test(s)) return false;\n            return (\/tabelle lette|lettura tabelle\/.test(s)) && (\/completamento confermato|100\\s*%|avanzamento stimato\/.test(s));\n        }\n        function hardHide(el){\n            if (!el) return false;\n            try {\n                el.style.setProperty('display', 'none', 'important');\n                el.style.setProperty('visibility', 'hidden', 'important');\n                el.style.setProperty('opacity', '0', 'important');\n                el.style.setProperty('pointer-events', 'none', 'important');\n                el.setAttribute('aria-hidden', 'true');\n            } catch(e) {}\n            return true;\n        }\n        window.tiDismissCompletedTableReadLoader343 = function(reason){\n            var changed = false;\n            try {\n                var ov = document.getElementById('ti-ai-loader-ov');\n                if (ov && isCompletedTableReadText(txt(ov))) changed = hardHide(ov) || changed;\n            } catch(e) {}\n            try {\n                Array.prototype.forEach.call(document.querySelectorAll('.ti-loader-box, #ti-ai-loader-ov'), function(el){\n                    if (el && isCompletedTableReadText(txt(el))) {\n                        var target = (el.closest && el.closest('#ti-ai-loader-ov')) || el;\n                        changed = hardHide(target) || changed;\n                    }\n                });\n            } catch(e) {}\n            try {\n                var st = window.tiLoaderState || (window.tiLoaderState = {});\n                st.active = false;\n                if (st.timer) clearInterval(st.timer);\n                if (st.watchdog327) clearInterval(st.watchdog327);\n                if (st.stallGuard338) clearInterval(st.stallGuard338);\n                if (st.closeTimer338) clearTimeout(st.closeTimer338);\n                st.timer = null; st.watchdog327 = null; st.closeTimer338 = null;\n            } catch(e) {}\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            try { if (typeof window.updatePluginScrollLock === 'function') window.updatePluginScrollLock(); } catch(e) {}\n            try { if (changed && window.console && console.info) console.info('[TI Shop Service] table-read loader dismissed 30.9.664:', reason || ''); } catch(e) {}\n            return changed;\n        };\n        if (typeof window.showProgressPopup === 'function' && !window.showProgressPopup.__tiNoTableReadLoader343) {\n            var prevShow343 = window.showProgressPopup;\n            window.showProgressPopup = function(title, subtitle, opts){\n                var combined = norm(String(title || '') + ' ' + String(subtitle || ''));\n                if (\/lettura tabelle|sto leggendo.*tabelle\/.test(combined)) {\n                    window.__tiTableReadWaitSuppressed343 = true;\n                    window.tiDismissCompletedTableReadLoader343('showProgressPopup-suppressed');\n                    return null;\n                }\n                return prevShow343.apply(this, arguments);\n            };\n            window.showProgressPopup.__tiNoTableReadLoader343 = true;\n        }\n        if (typeof window.updateProgressPopup === 'function' && !window.updateProgressPopup.__tiNoTableReadLoader343) {\n            var prevUpdate343 = window.updateProgressPopup;\n            window.updateProgressPopup = function(percent, title, subtitle, currentItem){\n                var combined = norm(String(title || '') + ' ' + String(subtitle || '') + ' ' + txt(document.getElementById('ti-loader-title')) + ' ' + txt(document.getElementById('ti-loader-sub')));\n                if ((parseInt(percent, 10) || 0) >= 100 && \/tabelle lette|lettura tabelle\/.test(combined)) {\n                    window.tiDismissCompletedTableReadLoader343('updateProgressPopup');\n                    return null;\n                }\n                return prevUpdate343.apply(this, arguments);\n            };\n            window.updateProgressPopup.__tiNoTableReadLoader343 = true;\n        }\n        [120, 700, 1500, 3000].forEach(function(ms){ setTimeout(function(){ window.tiDismissCompletedTableReadLoader343('install-' + ms); }, ms); });\n        var ticks = 0;\n        var timer = setInterval(function(){\n            ticks++;\n            window.tiDismissCompletedTableReadLoader343('periodic-' + ticks);\n            if (ticks > 240) clearInterval(timer);\n        }, 500);\n        document.addEventListener('visibilitychange', function(){ if (!document.hidden) setTimeout(function(){ window.tiDismissCompletedTableReadLoader343('visibility'); }, 80); });\n        window.addEventListener('focus', function(){ setTimeout(function(){ window.tiDismissCompletedTableReadLoader343('focus'); }, 80); });\n        document.addEventListener('click', function(){ setTimeout(function(){ window.tiDismissCompletedTableReadLoader343('click'); }, 20); }, true);\n    })();\n\n    window.clearLastFileContext = function() {\n        window.lastUploadedFile = null;\n        window.lastFileContext = null;\n    };\n\n    window.rememberLastFileContext = function(url, promptText, isImportFlow) {\n        if (!url) return;\n        window.lastFileContext = {\n            url: url,\n            lastActionPrompt: promptText || '',\n            pendingReusePrompt: '',\n            active: !!isImportFlow,\n            awaitingReuseChoice: false,\n            createdAt: Date.now()\n        };\n    };\n\n    window.extractPromptFromRow = function(row) {\n        if (!row || typeof row !== 'object') return '';\n        let descKey = Object.keys(row).find(k => ['descrizione','dettaglio','note'].includes(k.toLowerCase()));\n        let nameKey = Object.keys(row).find(k => ['nome','prodotto','servizio','articolo','titolo'].includes(k.toLowerCase()));\n        let promptText = (nameKey && row[nameKey] ? row[nameKey] + '. ' : '') + (descKey && row[descKey] ? row[descKey] : '');\n        return promptText.trim();\n    };\n\n    window.populateAIGenPrompt = function(row) {\n        let promptText = '';\n        if (row && typeof row === 'object') {\n            promptText = window.extractPromptFromRow(row);\n        } else if (gE('ti-msg') && gE('ti-msg').value.trim()) {\n            promptText = gE('ti-msg').value.trim();\n        }\n        if (gE('ai-gen-prompt')) gE('ai-gen-prompt').value = promptText;\n        if (gE('ti-msg') && promptText) gE('ti-msg').value = promptText;\n        return promptText;\n    };\n\n    window.isImportFollowupText = function(txt) {\n        if (!txt) return false;\n        return \/^(1|2|3|ok|si|s\u00ec|yes|no|x|annulla)$\/i.test(txt.trim()) || \/(import|reimport|file caricat|ultimo file|riutilizz|ripeti l'ultima azione|ultima azione)\/i.test(txt);\n    };\n\n    window.askReuseLastFile = function(requestText) {\n        if (!window.lastFileContext || !window.lastFileContext.url) return false;\n        window.lastFileContext.awaitingReuseChoice = true;\n        window.lastFileContext.pendingReusePrompt = requestText || window.lastFileContext.lastActionPrompt || 'Importa di nuovo i dati dal file caricato.';\n        window.addMsg('ai', \"Ho ancora disponibile l'ultimo file caricato. Vuoi riutilizzarlo e ripetere l'ultima azione? (SI\/NO)\");\n        return true;\n    };\n\n    window.getOrderViewStorageKey = function() {\n        const dbVal = (gE('ti-ditta') && gE('ti-ditta').value) ? gE('ti-ditta').value : (window.tiForced || 'global');\n        const userKey = window.tiUser || 'guest';\n        return 'ti_order_view_mode::' + userKey + '::' + dbVal;\n    };\n\n    window.isNonEmptyConfigFlag = function(v) { return String(v == null ? '' : v).trim() !== ''; };\n    window.getOrderConfigRow = function() {\n        try {\n            const pickRowFromDb = function(dbObj) {\n                if (!dbObj || !dbObj.Tabelle) return null;\n                const tables = dbObj.Tabelle || {};\n                const keys = Object.keys(tables || {});\n                let cfgKey = keys.find(function(k){ return String(k || '').toLowerCase() === 'config'; });\n                if (!cfgKey) cfgKey = keys.find(function(k){ return String(k || '').toLowerCase().indexOf('config') !== -1; });\n                if (!cfgKey || !Array.isArray(tables[cfgKey])) return null;\n                const firstRow = tables[cfgKey].find(function(r){ return r && typeof r === 'object' && !Array.isArray(r); });\n                return firstRow || null;\n            };\n            let row = pickRowFromDb(window.currentDbViewData || null) || pickRowFromDb(window.currentDbData || null);\n            if (row) return row;\n            const sel = gE('ti-ditta');\n            const opt = sel && sel.options ? sel.options[sel.selectedIndex] : null;\n            if (!opt) return null;\n            return { Tab_tab: opt.getAttribute('data-tab-tab') || '', Tab_sma: opt.getAttribute('data-tab-sma') || '', Tab_med: opt.getAttribute('data-tab-med') || '', Tab_lar: opt.getAttribute('data-tab-lar') || '' };\n        } catch(e) { return null; }\n    };\n    window.getOrderConfigFieldValue = function(fieldName) {\n        const row = window.getOrderConfigRow();\n        if (!row) return '';\n        const norm = function(v){ return String(v == null ? '' : v).toLowerCase().replace(\/[^a-z0-9]+\/g, ''); };\n        const wanted = norm(fieldName);\n        const realKey = Object.keys(row).find(function(k){ return norm(k) === wanted; });\n        return realKey ? row[realKey] : '';\n    };\n    window.getOrderViewAllowedModes = function() {\n        const map = [{ field:'Tab_tab', mode:'table' },{ field:'Tab_sma', mode:'small' },{ field:'Tab_med', mode:'medium' },{ field:'Tab_lar', mode:'large' }];\n        const allowed = map.filter(function(one){ return window.isNonEmptyConfigFlag(window.getOrderConfigFieldValue(one.field)); }).map(function(one){ return one.mode; });\n        return allowed.length ? allowed : ['table'];\n    };\n    window.getOrderViewPreference = function() {\n        const allowed = window.getOrderViewAllowedModes();\n        const storageKey = window.getOrderViewStorageKey();\n        const stored = localStorage.getItem(storageKey);\n        if (stored && allowed.includes(stored)) return stored;\n        const dbVal = (gE('ti-ditta') && gE('ti-ditta').value) ? gE('ti-ditta').value : (window.tiForced || '');\n        if (dbVal && window.tiServerPrefs && window.tiServerPrefs[dbVal] && allowed.includes(window.tiServerPrefs[dbVal].order_view_mode)) return window.tiServerPrefs[dbVal].order_view_mode;\n        return allowed[0] || 'table';\n    };\n\n    window.escapeHtml = function(str) {\n        return String(str || '').replace(\/[&<>\"']\/g, function(ch) {\n            return ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'})[ch] || ch;\n        });\n    };\n\n    window.setOrderView = function(btn, mode) {\n        const wrap = btn.closest('.ti-order-wrap');\n        const allowed = window.getOrderViewAllowedModes ? window.getOrderViewAllowedModes() : ['table','small','medium','large'];\n        if (!wrap || !allowed.includes(mode)) return;\n        wrap.className = wrap.className.replace(\/\\bti-view-(table|small|medium|large)\\b\/g, '').replace(\/\\s{2,}\/g, ' ').trim();\n        wrap.classList.add('ti-view-' + mode);\n        wrap.querySelectorAll('.ti-order-view-btn').forEach(function(b){ b.classList.toggle('active', b.dataset.view === mode); });\n        const storageKey = window.getOrderViewStorageKey();\n        localStorage.setItem(storageKey, mode);\n        const dbVal = (gE('ti-ditta') && gE('ti-ditta').value) ? gE('ti-ditta').value : (window.tiForced || '');\n        if (dbVal) {\n            if (!window.tiServerPrefs || typeof window.tiServerPrefs !== 'object') window.tiServerPrefs = {};\n            if (!window.tiServerPrefs[dbVal] || typeof window.tiServerPrefs[dbVal] !== 'object') window.tiServerPrefs[dbVal] = {};\n            window.tiServerPrefs[dbVal].order_view_mode = mode;\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_save_ui_pref');\n            fd.append('pref_key', 'order_view_mode');\n            fd.append('pref_value', mode);\n            fd.append('db', dbVal);\n            fetch(window.tiUrl, {method:'POST', body:fd}).catch(function(){});\n        }\n        if (window.initConfigTopScrollbars) setTimeout(function(){ window.initConfigTopScrollbars(wrap); }, 20);\n        window.calcOrderWrapTotals(wrap);\n    };\n\n    window.parseQtyInput = function(val) {\n        let raw = String(val == null ? '' : val).trim();\n        if (raw === '') return 0;\n        raw = raw.replace(\/\\s+\/g, '');\n        if (raw.indexOf(',') !== -1 && raw.indexOf('.') !== -1) raw = raw.replace(\/\\.\/g, '').replace(',', '.');\n        else if (raw.indexOf(',') !== -1) raw = raw.replace(',', '.');\n        let n = parseFloat(raw);\n        return isNaN(n) ? 0 : Math.max(0, n);\n    };\n    window.formatQtyInput = function(val) {\n        const n = window.parseQtyInput(val);\n        return window.fmtNum(n);\n    };\n    window.stepQtyInput = function(btn, delta) {\n        const wrap = btn ? btn.closest('.ti-qty-stepper') : null;\n        const inp = wrap ? wrap.querySelector('input') : null;\n        if (!inp) return;\n        const nextVal = Math.max(0, window.parseQtyInput(inp.value) + (parseFloat(delta) || 0));\n        inp.value = window.formatQtyInput(nextVal);\n        if (typeof window.syncOrderQty === 'function') window.syncOrderQty(inp);\n        else if (typeof inp.oninput === 'function') inp.oninput();\n    };\n\n    window.calcOrderWrapTotals = function(wrap) {\n        if (!wrap) return;\n        let totalQty = 0, totalVal = 0;\n        wrap.querySelectorAll('.ti-prod-table tbody tr').forEach(tr => {\n            if (tr.style.display === 'none') return;\n            const qtyInput = tr.querySelector('.ti-q');\n            if (!qtyInput) return;\n            const qty = window.parseQtyInput(qtyInput.value || '0');\n            const price = parseFloat(tr.getAttribute('data-price') || '0') || 0;\n            totalQty += qty;\n            totalVal += qty * price;\n        });\n        wrap.querySelectorAll('.ti-order-total-qty').forEach(el => el.innerText = window.fmtNum(totalQty));\n        wrap.querySelectorAll('.ti-order-total-value').forEach(el => el.innerText = '\u20ac ' + window.fmtNum(totalVal));\n    };\n\n    window.syncOrderQty = function(inp) {\n        const wrap = inp.closest('.ti-order-wrap');\n        if (!wrap) return;\n        const orderId = inp.getAttribute('data-order-id');\n        const qty = window.parseQtyInput(inp.value);\n        const formatted = window.fmtNum(qty);\n        wrap.querySelectorAll('.ti-q[data-order-id=\"' + orderId + '\"]').forEach(el => {\n            if (el !== inp) el.value = formatted;\n            else if (document.activeElement !== el) el.value = formatted;\n        });\n        wrap.querySelectorAll('.p-tot[data-order-id=\"' + orderId + '\"]').forEach(el => {\n            const price = parseFloat(el.getAttribute('data-price') || '0') || 0;\n            el.innerText = window.fmtNum(price * qty);\n        });\n        window.calcOrderWrapTotals(wrap);\n        \/\/ 30.9.1627: se l'utente aveva chiuso il riepilogo prima della conferma,\n        \/\/ una modifica quantita rende nuovamente necessaria la conferma e lo riapre.\n        try {\n            const token1627 = window.ensureOrderWrapToken ? window.ensureOrderWrapToken(wrap) : '';\n            if (token1627 && !(window.confirmedOrderTokens && window.confirmedOrderTokens[token1627])) {\n                if (window.dismissedOrderConfirmTokens1606) delete window.dismissedOrderConfirmTokens1606[token1627];\n                window.pendingOrderState = { token: token1627 };\n            }\n        } catch(e1627) {}\n        window.refreshOrderConfirmPanel();\n    };\n\n    window.sortTI = function(th, colIdx) {\n        const table = th.closest('table');\n        if (!table) return;\n        const tbody = table.querySelector('tbody');\n        const rows = Array.from(tbody.querySelectorAll('tr'));\n        const asc = th.dataset.sortDir !== 'asc';\n        table.querySelectorAll('th').forEach(h => delete h.dataset.sortDir);\n        th.dataset.sortDir = asc ? 'asc' : 'desc';\n        rows.sort((a, b) => {\n            const av = window.getComparableCellValue(a.children[colIdx]);\n            const bv = window.getComparableCellValue(b.children[colIdx]);\n            let cmp = 0;\n            if (av.type === 'num' && bv.type === 'num') cmp = av.value - bv.value;\n            else cmp = String(av.value).localeCompare(String(bv.value), 'it');\n            return asc ? cmp : -cmp;\n        });\n        rows.forEach(r => tbody.appendChild(r));\n        const wrap = table.closest('.ti-order-wrap');\n        if (wrap) window.calcOrderWrapTotals(wrap);\n    };\n\n    window.filterTI = function(inp, colIdx) {\n        const table = inp.closest('table');\n        if (!table) return;\n        const val = inp.value.trim().toLowerCase();\n        table.querySelectorAll('tbody tr').forEach(tr => {\n            const cellTxt = (tr.children[colIdx]?.innerText || '').trim().toLowerCase();\n            tr.style.display = !val || cellTxt.includes(val) ? '' : 'none';\n        });\n        const wrap = table.closest('.ti-order-wrap');\n        if (wrap) window.calcOrderWrapTotals(wrap);\n    };\n\n    window.orderToolbarState = window.orderToolbarState || {};\n    window.getOrderWrapState = function(wrap) {\n        if (!wrap) return {filters:{name:'', desc:'', price:''}, sort:'name_asc'};\n        if (!wrap.dataset.orderWrapId) wrap.dataset.orderWrapId = 'ow-' + Math.random().toString(36).slice(2, 10);\n        const id = wrap.dataset.orderWrapId;\n        if (!window.orderToolbarState[id]) window.orderToolbarState[id] = {filters:{name:'', desc:'', price:''}, sort:'name_asc'};\n        return window.orderToolbarState[id];\n    };\n    window.filterOrderWrap = function(inp, key) {\n        const wrap = inp.closest('.ti-order-wrap');\n        if (!wrap) return;\n        const st = window.getOrderWrapState(wrap);\n        st.filters[key] = inp.value || '';\n        window.applyOrderWrapFilters(wrap);\n    };\n    window.sortOrderWrap = function(sel) {\n        const wrap = sel.closest('.ti-order-wrap');\n        if (!wrap) return;\n        const st = window.getOrderWrapState(wrap);\n        st.sort = sel.value || 'name_asc';\n        window.applyOrderWrapFilters(wrap);\n    };\n    window.applyOrderWrapFilters = function(wrap) {\n        if (!wrap) return;\n        const st = window.getOrderWrapState(wrap);\n        const rows = Array.from(wrap.querySelectorAll('.ti-prod-table tbody tr'));\n        const cards = Array.from(wrap.querySelectorAll('.ti-order-card'));\n        const allIds = new Set();\n        rows.forEach(tr => allIds.add(tr.getAttribute('data-order-id') || ''));\n        cards.forEach(card => allIds.add(card.getAttribute('data-order-id') || ''));\n        const visibility = {};\n        allIds.forEach(id => {\n            const src = wrap.querySelector('.ti-prod-table tbody tr[data-order-id=\"' + id + '\"]') || wrap.querySelector('.ti-order-card[data-order-id=\"' + id + '\"]');\n            if (!src) return;\n            const name = src.getAttribute('data-name') || '';\n            const desc = src.getAttribute('data-desc') || '';\n            const price = src.getAttribute('data-price') || '';\n            const okName = window.configFilterMatches(name, st.filters.name || '');\n            const okDesc = window.configFilterMatches(desc, st.filters.desc || '');\n            const okPrice = window.configFilterMatches(price, st.filters.price || '');\n            visibility[id] = !!(okName && okDesc && okPrice);\n        });\n        rows.forEach(tr => { tr.style.display = visibility[tr.getAttribute('data-order-id') || ''] ? '' : 'none'; });\n        cards.forEach(card => { card.style.display = visibility[card.getAttribute('data-order-id') || ''] ? '' : 'none'; });\n        const [sortKey, sortDir] = String(st.sort || 'name_asc').split('_');\n        const sorter = (a, b) => {\n            const getVal = (el) => {\n                const raw = (sortKey === 'price') ? (el.getAttribute('data-price') || '0') : (el.getAttribute('data-' + sortKey) || '');\n                return window.getComparableCellValue({innerText: raw});\n            };\n            const av = getVal(a), bv = getVal(b);\n            let cmp = 0;\n            if (av.type === 'num' && bv.type === 'num') cmp = av.value - bv.value;\n            else cmp = String(av.value).localeCompare(String(bv.value), 'it');\n            return sortDir === 'desc' ? -cmp : cmp;\n        };\n        const tbody = wrap.querySelector('.ti-prod-table tbody');\n        rows.sort(sorter).forEach(tr => tbody.appendChild(tr));\n        const grid = wrap.querySelector('.ti-order-grid-view');\n        cards.sort(sorter).forEach(card => grid.appendChild(card));\n        window.calcOrderWrapTotals(wrap);\n    };\n\n    window.getTemplateRowForTable = function(tName) {\n        if (window.currentDbData && window.currentDbData.__templateTabelle && window.currentDbData.__templateTabelle[tName] && window.currentDbData.__templateTabelle[tName][0] && typeof window.currentDbData.__templateTabelle[tName][0] === 'object') {\n            return window.currentDbData.__templateTabelle[tName][0];\n        }\n        return null;\n    };\n\n    window.getTemplateSchemaKeys = function(tName) {\n        let keys = [];\n        const templateRow = window.getTemplateRowForTable(tName);\n        if (templateRow && typeof templateRow === 'object' && !Array.isArray(templateRow)) {\n            keys = Object.keys(templateRow);\n        }\n        const actualRows1577 = (window.currentDbData && window.currentDbData.Tabelle && Array.isArray(window.currentDbData.Tabelle[tName])) ? window.currentDbData.Tabelle[tName] : [];\n        if (!keys.length) {\n            actualRows1577.forEach(function(row){\n                if (!row || typeof row !== 'object' || Array.isArray(row)) return;\n                Object.keys(row).forEach(function(k){ if (!\/^__ti_\/i.test(String(k)) && !keys.includes(k)) keys.push(k); });\n            });\n        } else if (window.tiAiSsIsDatabaseFullAdmin1562 && window.tiAiSsIsDatabaseFullAdmin1562()) {\n            \/\/ 30.9.1577: un amministratore deve vedere tutti i campi realmente presenti nel database,\n            \/\/ anche se il template storico non li contiene (es. Config.Stato\/ActiveID\/TotAIActs\/AIActs\/SS-Key).\n            actualRows1577.forEach(function(row){\n                if (!row || typeof row !== 'object' || Array.isArray(row)) return;\n                Object.keys(row).forEach(function(k){ if (!\/^__ti_\/i.test(String(k)) && !keys.includes(k)) keys.push(k); });\n            });\n        }\n        const low = String(tName || '').toLowerCase();\n        if (low === 'config' && window.tiAiSsIsDatabaseFullAdmin1562 && window.tiAiSsIsDatabaseFullAdmin1562()) {\n            const desired1577 = ['ID','Ditta','Attivita','Attivit\u00e0','Stato','Ragione sociale','Data creazione','Data attivazione','ActiveID','TotAIActs','AIActs','SS-Key'];\n            keys = desired1577.filter(function(k){ return keys.includes(k); }).concat(keys.filter(function(k){ return !desired1577.includes(k); }));\n        } else if (low === 'informazioni') {\n            const desired = ['ID','Tipo','Descrizione','Istruzioni','Data','Ora','Nota','Stato','Immagine','Iva'];\n            keys = desired.filter(k => keys.includes(k)).concat(keys.filter(k => !desired.includes(k)));\n        } else if (low === 'istruzioni') {\n            const desired = ['ID','Istruzione','Da gg','A gg','Da ora','A ora','Nota','Stato','Immagine','Iva','Data','Ora'];\n            keys = desired.filter(k => keys.includes(k)).concat(keys.filter(k => !desired.includes(k)));\n        }\n        if (!keys.includes('ID')) keys.unshift('ID');\n        return keys;\n    };\n\n    window.buildTemplateDefaultValue = function(tplVal) {\n        if (tplVal === undefined || tplVal === null) return '';\n        const str = String(tplVal).trim();\n        if (str === 'DD\/MM\/YYYY' || str === 'HH:MM') return '';\n        return tplVal;\n    };\n\n    window.getTemplateEmptyRow = function(tName, nextId) {\n        const templateRow = window.getTemplateRowForTable(tName);\n        const keys = window.getTemplateSchemaKeys(tName);\n        const row = {};\n        keys.forEach(function(k){\n            if (String(k).toLowerCase() === 'id') {\n                row[k] = nextId;\n                return;\n            }\n            if (templateRow && Object.prototype.hasOwnProperty.call(templateRow, k)) {\n                row[k] = window.buildTemplateDefaultValue(templateRow[k]);\n            } else {\n                row[k] = '';\n            }\n        });\n        if (!('ID' in row)) row.ID = nextId;\n        return row;\n    };\n\n    window.normalizeTableRowsToTemplate = function(tName) {\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tName]) return;\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        const keys = window.getTemplateSchemaKeys(tName);\n        const templateRow = window.getTemplateRowForTable(tName);\n        const vm1698 = window.currentDbData.__ti_virtual_tables_1698 && window.currentDbData.__ti_virtual_tables_1698[tName];\n        if (vm1698 && !vm1698.hydrated) {\n            const out1698 = rows.slice();\n            for (let idx1698=0; idx1698<rows.length; idx1698++) {\n                if (!rows[idx1698] || typeof rows[idx1698] !== 'object') continue;\n                const safeRow = rows[idx1698], clean = {};\n                keys.forEach(function(k){\n                    if (Object.prototype.hasOwnProperty.call(safeRow,k)) clean[k]=safeRow[k];\n                    else if (String(k).toLowerCase()==='id') clean[k]=(safeRow.ID || (idx1698+1));\n                    else if (templateRow && Object.prototype.hasOwnProperty.call(templateRow,k)) clean[k]=window.buildTemplateDefaultValue(templateRow[k]);\n                    else clean[k]='';\n                });\n                Object.keys(safeRow).forEach(function(k){ if(!Object.prototype.hasOwnProperty.call(clean,k)) clean[k]=safeRow[k]; });\n                if(!('ID' in clean)) clean.ID=idx1698+1;\n                out1698[idx1698]=clean;\n            }\n            window.currentDbData.Tabelle[tName]=out1698;\n            return;\n        }\n        window.currentDbData.Tabelle[tName] = rows.map(function(srcRow, idx){\n            const safeRow = (srcRow && typeof srcRow === 'object' && !Array.isArray(srcRow)) ? srcRow : {};\n            const clean = {};\n            keys.forEach(function(k){\n                if (Object.prototype.hasOwnProperty.call(safeRow, k)) {\n                    clean[k] = safeRow[k];\n                } else if (window.getConfigFieldAliasCandidates) {\n                    const aliasKey = window.getConfigFieldAliasCandidates(k).find(function(a){ return Object.prototype.hasOwnProperty.call(safeRow, a); });\n                    if (aliasKey) clean[k] = safeRow[aliasKey];\n                    else if (String(k).toLowerCase() === 'id') clean[k] = (safeRow.ID || (idx + 1));\n                    else if (templateRow && Object.prototype.hasOwnProperty.call(templateRow, k)) clean[k] = window.buildTemplateDefaultValue(templateRow[k]);\n                    else clean[k] = '';\n                } else if (String(k).toLowerCase() === 'id') {\n                    clean[k] = (safeRow.ID || (idx + 1));\n                } else if (templateRow && Object.prototype.hasOwnProperty.call(templateRow, k)) {\n                    clean[k] = window.buildTemplateDefaultValue(templateRow[k]);\n                } else {\n                    clean[k] = '';\n                }\n            });\n            Object.keys(safeRow).forEach(function(k){ if (!Object.prototype.hasOwnProperty.call(clean, k)) clean[k] = safeRow[k]; });\n            if (!('ID' in clean)) clean.ID = idx + 1;\n            return clean;\n        });\n    };\n\n    window.isAccountTableName = function(tName) {\n        const low = String(tName || '').toLowerCase();\n        return low.indexOf('utent') !== -1 || low.indexOf('operator') !== -1;\n    };\n\n    window.isUsernameFieldName = function(key) {\n        const low = String(key || '').trim().toLowerCase();\n        return low === 'username' || low === 'user';\n    };\n\n    window.getConfigUsernameValue = function(row) {\n        if (!row || typeof row !== 'object') return '';\n        const key = Object.keys(row).find(function(k){ return window.isUsernameFieldName(k); });\n        return key ? String(row[key] == null ? '' : row[key]).trim() : '';\n    };\n\n    window.normalizeUsernameForCheck = function(v) {\n        return String(v == null ? '' : v).trim().toLowerCase();\n    };\n\n    window.getConfigRowIdValue = function(row) {\n        if (!row || typeof row !== 'object') return '';\n        for (const k of ['ID','Id','id']) {\n            if (Object.prototype.hasOwnProperty.call(row, k)) {\n                const v = String(row[k] == null ? '' : row[k]).trim();\n                if (v) return v;\n            }\n        }\n        return '';\n    };\n\n    window.getOriginalConfigRowsForTable = function(tName) {\n        const tables = window.configOriginalDbData && window.configOriginalDbData.Tabelle ? window.configOriginalDbData.Tabelle : null;\n        if (!tables) return null;\n        if (Array.isArray(tables[tName])) return tables[tName];\n        const wanted = String(tName || '').toLowerCase();\n        for (const oldName in tables) {\n            if (String(oldName).toLowerCase() === wanted && Array.isArray(tables[oldName])) return tables[oldName];\n        }\n        return null;\n    };\n\n    window.getOriginalConfigRow = function(tName, idx, row) {\n        const rows = window.getOriginalConfigRowsForTable(tName);\n        if (!rows) return null;\n        const newId = window.getConfigRowIdValue(row);\n        const indexRow = rows[parseInt(idx, 10)];\n        if (indexRow && typeof indexRow === 'object') {\n            const oldId = window.getConfigRowIdValue(indexRow);\n            if (!newId || !oldId || newId === oldId) return indexRow;\n        }\n        if (newId) {\n            for (const oldRow of rows) {\n                if (oldRow && typeof oldRow === 'object' && window.getConfigRowIdValue(oldRow) === newId) return oldRow;\n            }\n        }\n        return null;\n    };\n\n    window.isConfigUsernameNewOrChanged = function(tName, idx, row) {\n        if (!row || typeof row !== 'object') return false;\n        const username = window.getConfigUsernameValue(row);\n        const key = window.normalizeUsernameForCheck(username);\n        if (!key) return false;\n        const origRow = window.getOriginalConfigRow(tName, idx, row);\n        if (origRow && typeof origRow === 'object') {\n            return window.normalizeUsernameForCheck(window.getConfigUsernameValue(origRow)) !== key;\n        }\n        if (window.configOriginalDbData && window.configOriginalDbData.Tabelle) return true;\n        const uKey = Object.keys(row).find(function(k){ return window.isUsernameFieldName(k); }) || '';\n        return !!(window.modifiedFields && window.modifiedFields.has(`${tName}-${idx}-${uKey}`));\n    };\n\n    window.findDuplicateUsernameInConfig = function(username, excludeTbl, excludeIdx) {\n        const wanted = window.normalizeUsernameForCheck(username);\n        if (!wanted || !window.currentDbData || !window.currentDbData.Tabelle) return null;\n        const tables = window.currentDbData.Tabelle;\n        for (const tName in tables) {\n            if (!window.isAccountTableName(tName)) continue;\n            let rows = tables[tName];\n            if (!Array.isArray(rows)) rows = tables[tName] = Object.values(rows || {});\n            for (let i = 0; i < rows.length; i++) {\n                const row = rows[i] || {};\n                const sameRow = String(tName).toLowerCase() === String(excludeTbl || '').toLowerCase() && parseInt(excludeIdx, 10) === i;\n                if (sameRow) continue;\n                const state = String(row.Stato || row.state || row.status || '').trim().toLowerCase();\n                if (state === 'cancellato' || state.indexOf('cancellat') !== -1) continue;\n                const rowUsername = window.getConfigUsernameValue(row);\n                const cand = window.normalizeUsernameForCheck(rowUsername);\n                if (cand && cand === wanted) return {table:tName, idx:i, username:(rowUsername || username)};\n            }\n        }\n        return null;\n    };\n\n    window.focusConfigUsernameCell = function(tbl, idx) {\n        try {\n            const nodes = document.querySelectorAll('.ti-cfg-table input, .ti-cfg-table textarea, .ti-cfg-table select');\n            for (const el of nodes) {\n                if (!el.dataset) continue;\n                if (String(el.dataset.tbl || '').toLowerCase() !== String(tbl || '').toLowerCase()) continue;\n                if (String(el.dataset.idx || '') !== String(idx)) continue;\n                if (!window.isUsernameFieldName(el.dataset.key || '')) continue;\n                if (el.scrollIntoView) el.scrollIntoView({behavior:'smooth', block:'center', inline:'center'});\n                el.style.setProperty('border-color', '#ef4444', 'important');\n                el.style.setProperty('box-shadow', '0 0 0 2px rgba(239,68,68,.55)', 'important');\n                window.forceWhiteEditStyle && window.forceWhiteEditStyle(el);\n                setTimeout(function(){ try { el.focus(); if (el.select) el.select(); } catch(e) {} }, 120);\n                return true;\n            }\n        } catch(e) {}\n        return false;\n    };\n\n    window.showDuplicateUsernamePopup = function(username, dup) {\n        const u = String(username || '').trim();\n        const where = dup && dup.table ? ('<br><small>Presente in tabella <b>' + window.escapeHtml(dup.table) + '<\/b>, riga ' + (parseInt(dup.idx, 10) + 1) + '.<\/small>') : '';\n        window.tiAlert('Username gi\u00e0 esistente' + (u ? ': <b>' + window.escapeHtml(u) + '<\/b>' : '') + '.<br>Cambia username perch\u00e9 \u00e8 gi\u00e0 esistente.' + where);\n    };\n\n    window.checkConfigUsernameDuplicateInput = function(tbl, idx, key, el) {\n        if (!window.isAccountTableName(tbl) || !window.isUsernameFieldName(key)) return false;\n        const username = el ? String(el.value || '').trim() : '';\n        if (!username) return false;\n        const row = (window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl]) ? window.currentDbData.Tabelle[tbl][idx] : null;\n        if (row && window.isConfigUsernameNewOrChanged && !window.isConfigUsernameNewOrChanged(tbl, idx, row)) return false;\n        const dup = window.findDuplicateUsernameInConfig(username, tbl, idx);\n        if (!dup) return false;\n        if (el) {\n            el.style.setProperty('border-color', '#ef4444', 'important');\n            el.style.setProperty('box-shadow', '0 0 0 2px rgba(239,68,68,.55)', 'important');\n            window.forceWhiteEditStyle && window.forceWhiteEditStyle(el);\n            setTimeout(function(){ try { el.focus(); if (el.select) el.select(); } catch(e) {} }, 80);\n        }\n        window.showDuplicateUsernamePopup(username, dup);\n        return true;\n    };\n\n    window.validateConfigUniqueUsernames = function() {\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return true;\n        const tables = window.currentDbData.Tabelle;\n        for (const tName in tables) {\n            if (!window.isAccountTableName(tName)) continue;\n            let rows = tables[tName];\n            if (!Array.isArray(rows)) rows = tables[tName] = Object.values(rows || {});\n            for (let i = 0; i < rows.length; i++) {\n                const row = rows[i] || {};\n                const state = String(row.Stato || row.state || row.status || '').trim().toLowerCase();\n                if (state === 'cancellato' || state.indexOf('cancellat') !== -1) continue;\n                const username = window.getConfigUsernameValue(row);\n                if (!window.normalizeUsernameForCheck(username)) continue;\n                if (window.isConfigUsernameNewOrChanged && !window.isConfigUsernameNewOrChanged(tName, i, row)) continue;\n                const dup = window.findDuplicateUsernameInConfig(username, tName, i);\n                if (dup) {\n                    window.showDuplicateUsernamePopup(username, dup);\n                    window.focusConfigUsernameCell(tName, i);\n                    return false;\n                }\n            }\n        }\n        return true;\n    };\n\n    window.isConfigSingleRowTable379 = function(tName) {\n        try {\n            return String(tName || '').trim().toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[^a-z0-9]\/g, '') === 'config';\n        } catch(e) {\n            return String(tName || '').trim().toLowerCase() === 'config';\n        }\n    };\n\n    window.addTableRow = function(tName) {\n        if (window.isConfigSingleRowTable379 && window.isConfigSingleRowTable379(tName)) {\n            if (window.tiAlert) window.tiAlert('La tabella Config \u00e8 a riga unica: non \u00e8 possibile aggiungere righe.');\n            return false;\n        }\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tName]) return;\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        window.normalizeTableRowsToTemplate(tName);\n        rows = window.currentDbData.Tabelle[tName];\n        const vm1910 = window.currentDbData.__ti_virtual_tables_1698 && window.currentDbData.__ti_virtual_tables_1698[tName] ? window.currentDbData.__ti_virtual_tables_1698[tName] : null;\n        if (vm1910 && !vm1910.hydrated && typeof window.tiConfigAddVirtualRow1910 === 'function') return window.tiConfigAddVirtualRow1910(tName);\n        const nextId = rows.reduce(function(maxId, row){ const n = parseInt((row && row.ID != null) ? row.ID : 0, 10); return isNaN(n) ? maxId : Math.max(maxId, n); }, 0) + 1;\n        const newIndex1910 = rows.length;\n        rows.push(window.getTemplateEmptyRow(tName, nextId));\n        try {\n            if(!window.tiConfigPendingNewRows1910) window.tiConfigPendingNewRows1910 = {};\n            if(!Array.isArray(window.tiConfigPendingNewRows1910[tName])) window.tiConfigPendingNewRows1910[tName] = [];\n            window.tiConfigPendingNewRows1910[tName].push({index:newIndex1910});\n            if(!window.tiConfigStructuralChangedTables1907) window.tiConfigStructuralChangedTables1907 = new Set();\n            window.tiConfigStructuralChangedTables1907.add(tName);\n        } catch(e1910) {}\n        if (!window.modifiedFields) window.modifiedFields = new Set(); window.modifiedFields.add(`${tName}-__row_added`); window.modifiedFields.add(`${tName}-${newIndex1910}-__structural_1910`); if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n        try { var st1910=window.ensureConfigTableState?window.ensureConfigTableState(tName):null; if(st1910) st1910.page=Math.max(1,Math.ceil(rows.length\/100)); } catch(e1910p) {}\n        window.configForceTop = false;\n        try {\n            var fastHolder1910=document.getElementById('ti-config-fast-table-body-'+String(tName||'').toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/[^a-z0-9]+\/g,''));\n            if(fastHolder1910 && typeof window.tiConfigFastRenderTable507==='function') window.tiConfigFastRenderTable507(tName); else window.renderConfig();\n        } catch(e1910r) { window.renderConfig(); }\n    };\n\n    window.duplicateTableRow = function(tName, idx) {\n        if (window.isConfigSingleRowTable379 && window.isConfigSingleRowTable379(tName)) {\n            if (window.tiAlert) window.tiAlert('La tabella Config \u00e8 a riga unica: non \u00e8 possibile duplicare righe.');\n            return false;\n        }\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tName] || !window.currentDbData.Tabelle[tName][idx]) return;\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows);\n        const clone = JSON.parse(JSON.stringify(rows[idx]));\n        clone.ID = rows.length + 1;\n        if (window.isAccountTableName(tName)) {\n            Object.keys(clone || {}).forEach(function(k){ if (window.isUsernameFieldName(k)) clone[k] = ''; });\n        }\n        rows.splice(idx + 1, 0, clone);\n        try { if(!window.tiConfigStructuralChangedTables1907) window.tiConfigStructuralChangedTables1907 = new Set(); window.tiConfigStructuralChangedTables1907.add(tName); } catch(e1909) {}\n        if (!window.modifiedFields) window.modifiedFields = new Set(); window.modifiedFields.add(`${tName}-__row_duplicated`); window.modifiedFields.add(`${tName}-0-__structural_1909`); if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n        window.renderConfig();\n        if (window.isAccountTableName(tName)) window.tiAlert('Riga utente duplicata. Inserisci un nuovo username: non pu\u00f2 essere uguale a uno gi\u00e0 esistente.');\n    };\n\n    window.canPhysicallyDeleteUserRows = function() {\n        const r = String(window.tiRole || '').toLowerCase();\n        return r.includes('amministratore') || r.includes('configuratore') || String(window.tiUser || '').toLowerCase() === 'ssglobaladmin';\n    };\n\n    window.reindexTableRows = function(tName) {\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tName]) return [];\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        rows.forEach(function(rowObj, rowIdx) {\n            if (!rowObj || typeof rowObj !== 'object') return;\n            if (Object.prototype.hasOwnProperty.call(rowObj, 'ID')) rowObj.ID = rowIdx + 1;\n            else if (Object.prototype.hasOwnProperty.call(rowObj, 'Id')) rowObj.Id = rowIdx + 1;\n            else if (Object.prototype.hasOwnProperty.call(rowObj, 'id')) rowObj.id = rowIdx + 1;\n        });\n        window.currentDbData.Tabelle[tName] = rows;\n        return rows;\n    };\n\n    window.markTableRowsModified = function(tName) {\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tName]) return;\n        if (!window.modifiedFields) window.modifiedFields = new Set();\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        rows.forEach(function(rowObj, rowIdx) {\n            Object.keys(rowObj || {}).forEach(function(k) {\n                window.modifiedFields.add(`${tName}-${rowIdx}-${k}`); if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            });\n        });\n    };\n\n    window.mustKeepAtLeastOneConfigRow = function(tName) {\n        const low = String(tName || '').trim().toLowerCase();\n        return low === 'config' || low === 'utenti';\n    };\n\n    window.clearSingleRemainingRow = function(tName, rowIndex) {\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !Object.prototype.hasOwnProperty.call(window.currentDbData.Tabelle, tName)) return false;\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        const idx = parseInt(rowIndex, 10);\n        if (isNaN(idx) || idx < 0 || idx >= rows.length) return false;\n        const oldRow = (rows[idx] && typeof rows[idx] === 'object' && !Array.isArray(rows[idx])) ? rows[idx] : {};\n        const keys = (window.getTemplateSchemaKeys ? window.getTemplateSchemaKeys(tName) : Object.keys(oldRow || {}));\n        const clean = {};\n        keys.forEach(function(k) {\n            if (String(k).toLowerCase() === 'id') clean[k] = 1;\n            else clean[k] = '';\n        });\n        Object.keys(oldRow || {}).forEach(function(k) {\n            if (!Object.prototype.hasOwnProperty.call(clean, k)) clean[k] = (String(k).toLowerCase() === 'id') ? 1 : '';\n        });\n        rows[idx] = clean;\n        window.currentDbData.Tabelle[tName] = rows;\n        if (!window.modifiedFields) window.modifiedFields = new Set();\n        Object.keys(clean || {}).forEach(function(k) { window.modifiedFields.add(`${tName}-${idx}-${k}`); });\n        window.modifiedFields.add(`${tName}-${idx}-__row_cleared`); if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n        return true;\n    };\n\n    window.resolveConfigTableName = function(tName) {\n        const wanted = String(tName || '').trim();\n        const tables = (window.currentDbData && window.currentDbData.Tabelle) ? window.currentDbData.Tabelle : null;\n        if (!tables) return wanted;\n        if (Object.prototype.hasOwnProperty.call(tables, wanted)) return wanted;\n        const norm = function(v) {\n            try { v = String(v || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, ''); } catch(e) { v = String(v || ''); }\n            return v.toLowerCase().replace(\/[^a-z0-9]\/g, '');\n        };\n        const nw = norm(wanted);\n        for (const k in tables) {\n            if (String(k) === wanted || norm(k) === nw) return k;\n        }\n        return wanted;\n    };\n\n    window.getConfigRowIdCI = function(row) {\n        if (!row || typeof row !== 'object') return '';\n        const keys = Object.keys(row);\n        for (let i = 0; i < keys.length; i++) {\n            if (String(keys[i]).trim().toLowerCase() === 'id') return String(row[keys[i]] == null ? '' : row[keys[i]]).trim();\n        }\n        return '';\n    };\n\n    window.recordConfigDeletedRowsManifest = function(tName, rows, indexes) {\n        if (!window.tiConfigDeletedRowsManifest) window.tiConfigDeletedRowsManifest = [];\n        rows = Array.isArray(rows) ? rows : [];\n        (indexes || []).forEach(function(i){\n            i = parseInt(i, 10);\n            if (isNaN(i) || i < 0 || i >= rows.length) return;\n            const rowCopy = JSON.parse(JSON.stringify(rows[i] || {}));\n            window.tiConfigDeletedRowsManifest.push({\n                table: String(tName || ''),\n                idx: i,\n                id: window.getConfigRowIdCI ? window.getConfigRowIdCI(rowCopy) : '',\n                row: rowCopy,\n                row_count_before: rows.length,\n                row_count_after: Math.max(0, rows.length - 1),\n                deleted_at: new Date().toISOString()\n            });\n        });\n    };\n\n    window.rememberConfigDeletedTableSnapshot = function(tName) {\n        tName = window.resolveConfigTableName ? window.resolveConfigTableName(tName) : tName;\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !Object.prototype.hasOwnProperty.call(window.currentDbData.Tabelle, tName)) return;\n        if (!window.tiConfigDeletedTableSnapshots) window.tiConfigDeletedTableSnapshots = {};\n        if (!window.tiConfigDeletedTableSnapshotBeforeCounts) window.tiConfigDeletedTableSnapshotBeforeCounts = {};\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        const beforeCount = parseInt(window.tiConfigDeletedTableSnapshotBeforeCounts[tName] || rows.length, 10) || rows.length;\n        window.tiConfigDeletedTableSnapshots[tName] = {\n            table: String(tName || ''),\n            row_count_before: Math.max(beforeCount, rows.length),\n            row_count_after: rows.length,\n            rows: JSON.parse(JSON.stringify(rows || [])),\n            saved_at: new Date().toISOString()\n        };\n    };\n\n    window.refreshConfigDeletedTableSnapshotsFromCurrentData = function() {\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.tiConfigDeletedTableSnapshots) return;\n        if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory();\n        Object.keys(window.tiConfigDeletedTableSnapshots || {}).forEach(function(tName){\n            const realTbl = window.resolveConfigTableName ? window.resolveConfigTableName(tName) : tName;\n            if (!window.currentDbData.Tabelle || !Object.prototype.hasOwnProperty.call(window.currentDbData.Tabelle, realTbl)) return;\n            let rows = window.currentDbData.Tabelle[realTbl];\n            if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[realTbl] = Object.values(rows || {});\n            const snap = window.tiConfigDeletedTableSnapshots[tName] || {};\n            const beforeCount = Math.max(parseInt(snap.row_count_before || 0, 10) || 0, parseInt((window.tiConfigDeletedTableSnapshotBeforeCounts || {})[realTbl] || 0, 10) || 0, rows.length);\n            window.tiConfigDeletedTableSnapshots[tName] = {\n                table: String(realTbl || tName || ''),\n                row_count_before: beforeCount,\n                row_count_after: rows.length,\n                rows: JSON.parse(JSON.stringify(rows || [])),\n                saved_at: new Date().toISOString()\n            };\n        });\n    };\n\n    window.applyConfigDeletedTableSnapshotsToCurrentData = function() {\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.tiConfigDeletedTableSnapshots) return;\n        Object.keys(window.tiConfigDeletedTableSnapshots || {}).forEach(function(tName){\n            const snap = window.tiConfigDeletedTableSnapshots[tName] || {};\n            const rows = Array.isArray(snap.rows) ? snap.rows : null;\n            if (!rows) return;\n            const realTbl = window.resolveConfigTableName ? window.resolveConfigTableName(tName) : tName;\n            if (!window.currentDbData.Tabelle[realTbl] || !Array.isArray(window.currentDbData.Tabelle[realTbl])) return;\n            \/\/ Se una vecchia ricostruzione ha rimesso righe cancellate, forza la tabella nello stato post-cancellazione.\n            if (window.currentDbData.Tabelle[realTbl].length > rows.length) {\n                window.currentDbData.Tabelle[realTbl] = JSON.parse(JSON.stringify(rows));\n            }\n        });\n    };\n\n    \/\/ 30.9.1630: distingue modifiche realmente effettuate dall utente dalle differenze create dal rendering.\n    \/\/ In particolare DD\/MM\/YYYY e HH:MM sono valori sentinella del DB ma vengono mostrati volutamente vuoti:\n    \/\/ il semplice rendering\/focus\/salvataggio non deve convertirli in stringa vuota ne marcarli come modificati.\n    window.tiConfigUserEditedFields1630 = window.tiConfigUserEditedFields1630 || new Set();\n    window.tiConfigEnsureUserEditSnapshot1630 = function() {\n        try {\n            if (window.__tiConfigUserEditSnapshotRef1630 !== window.configOriginalDbData) {\n                if (window.tiConfigUserEditedFields1630 && typeof window.tiConfigUserEditedFields1630.clear === 'function') window.tiConfigUserEditedFields1630.clear();\n                window.__tiConfigUserEditSnapshotRef1630 = window.configOriginalDbData || null;\n            }\n        } catch(e) {}\n    };\n    window.tiConfigFieldSig1630 = function(tbl, idx, key) {\n        const realTbl = window.resolveConfigTableName ? (window.resolveConfigTableName(tbl) || tbl) : tbl;\n        return String(realTbl || '') + '-' + String(parseInt(idx, 10)) + '-' + String(key || '');\n    };\n    window.tiConfigPlaceholderEquivalent1630 = function(stored, visible) {\n        const a = String(stored == null ? '' : stored).trim().toUpperCase();\n        const b = String(visible == null ? '' : visible).trim().toUpperCase();\n        if (a === b) return true;\n        if (b === '' && (a === 'DD\/MM\/YYYY' || a === 'HH:MM' || a === '--\/--\/----' || a === '--:--')) return true;\n        return false;\n    };\n    window.tiConfigWasUserEdited1630 = function(tbl, idx, key) {\n        try { if (window.tiConfigEnsureUserEditSnapshot1630) window.tiConfigEnsureUserEditSnapshot1630(); } catch(e) {}\n        try { return !!(window.tiConfigUserEditedFields1630 && window.tiConfigUserEditedFields1630.has(window.tiConfigFieldSig1630(tbl, idx, key))); }\n        catch(e) { return false; }\n    };\n    if (!window.__tiConfigUserEditedTracker1630) {\n        const mark1630 = function(ev) {\n            try { if (window.tiConfigEnsureUserEditSnapshot1630) window.tiConfigEnsureUserEditSnapshot1630(); } catch(e) {}\n            const el = ev && ev.target;\n            if (!el || !el.matches || !el.matches('#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]')) return;\n            const tbl = el.getAttribute('data-tbl') || '', key = el.getAttribute('data-key') || '', idx = parseInt(el.getAttribute('data-idx') || '', 10);\n            if (!tbl || !key || isNaN(idx)) return;\n            if (!window.tiConfigUserEditedFields1630) window.tiConfigUserEditedFields1630 = new Set();\n            window.tiConfigUserEditedFields1630.add(window.tiConfigFieldSig1630(tbl, idx, key));\n        };\n        ['beforeinput','input','change','paste','cut'].forEach(function(evName){ document.addEventListener(evName, mark1630, true); });\n        window.__tiConfigUserEditedTracker1630 = true;\n    }\n\n    window.syncVisibleConfigInputsToMemory = function() {\n        try { if (window.tiConfigEnsureUserEditSnapshot1630) window.tiConfigEnsureUserEditSnapshot1630(); } catch(e) {}\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return;\n        const root = gE('ti-conf-cnt') || document;\n        root.querySelectorAll('input[data-tbl][data-idx][data-key], textarea[data-tbl][data-idx][data-key], select[data-tbl][data-idx][data-key]').forEach(function(el){\n            const tbl = el.getAttribute('data-tbl') || '';\n            const key = el.getAttribute('data-key') || '';\n            const idx = parseInt(el.getAttribute('data-idx') || '', 10);\n            if (!tbl || !key || isNaN(idx)) return;\n            const realTbl = window.resolveConfigTableName ? (window.resolveConfigTableName(tbl) || tbl) : tbl;\n            if (!window.currentDbData.Tabelle[realTbl] || !window.currentDbData.Tabelle[realTbl][idx]) return;\n            let val = '';\n            if (el.tagName === 'SELECT' && el.multiple) val = Array.from(el.selectedOptions || []).map(function(o){ return String(o.value || '').trim(); }).filter(Boolean).join(', ');\n            else if (el.type === 'checkbox') val = el.checked ? (el.value || '1') : '';\n            else val = el.value;\n            if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val);\n\n            const sig = window.tiConfigFieldSig1630(realTbl, idx, key);\n            const originalRows = window.configOriginalDbData && window.configOriginalDbData.Tabelle ? window.configOriginalDbData.Tabelle[realTbl] : null;\n            const originalVal = Array.isArray(originalRows) && originalRows[idx] && typeof originalRows[idx] === 'object' ? originalRows[idx][key] : undefined;\n            const explicitlyEdited = window.tiConfigWasUserEdited1630(realTbl, idx, key);\n\n            \/\/ Ripara anche un eventuale falso delta gia creato dal vecchio listener click\/focus 666.\n            if (!explicitlyEdited && originalVal !== undefined && window.tiConfigPlaceholderEquivalent1630(originalVal, val)) {\n                window.currentDbData.Tabelle[realTbl][idx][key] = originalVal;\n                try { if (window.modifiedFields) window.modifiedFields.delete(sig); } catch(e) {}\n                try { if (el && el.dataset) delete el.dataset.dirty; } catch(e) {}\n                return;\n            }\n\n            const oldVal = window.currentDbData.Tabelle[realTbl][idx][key];\n            if (String(oldVal == null ? '' : oldVal) !== String(val == null ? '' : val)) {\n                window.currentDbData.Tabelle[realTbl][idx][key] = val;\n                if (!window.modifiedFields) window.modifiedFields = new Set();\n                window.modifiedFields.add(sig);\n                try { if (el && el.dataset) el.dataset.dirty = '1'; } catch(e) {}\n                try { if (el && el.style) el.style.borderColor = '#60a5fa'; } catch(e) {}\n                try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n            }\n        });\n    };\n\n    window.syncConfigTableAfterRowMutation = function(tName) {\n        tName = window.resolveConfigTableName ? window.resolveConfigTableName(tName) : tName;\n        try {\n            if (window.currentDbViewData && window.currentDbViewData !== window.currentDbData && window.currentDbViewData.Tabelle && window.currentDbData && window.currentDbData.Tabelle && Object.prototype.hasOwnProperty.call(window.currentDbData.Tabelle, tName)) {\n                window.currentDbViewData.Tabelle[tName] = JSON.parse(JSON.stringify(window.currentDbData.Tabelle[tName] || []));\n            }\n        } catch(e) {}\n        try { window.__configRelationSupportCache = null; } catch(e) {}\n        try { window.__tiLastConfigRowMutation = Date.now(); } catch(e) {}\n    };\n\n    window.deleteConfigRowsByIndexes = function(tName, indexes, opts) {\n        opts = opts || {};\n        tName = window.resolveConfigTableName ? window.resolveConfigTableName(tName) : tName;\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !Object.prototype.hasOwnProperty.call(window.currentDbData.Tabelle, tName)) return false;\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        const ixs = Array.from(new Set((indexes || []).map(function(v){ return parseInt(v, 10); }).filter(function(n){ return !isNaN(n) && n >= 0 && n < rows.length; }))).sort(function(a,b){ return b-a; });\n        if (!ixs.length) { window.tiLastConfigDeleteCount = 0; return false; }\n        const keepOne = window.mustKeepAtLeastOneConfigRow && window.mustKeepAtLeastOneConfigRow(tName);\n        if (keepOne && ixs.length >= rows.length) {\n            window.tiLastConfigDeleteCount = 0;\n            window.tiAlert('La tabella ' + String(tName || '') + ' deve mantenere almeno una riga. Righe cancellate: 0.');\n            return false;\n        }\n        if (!window.tiConfigDeletedTableSnapshotBeforeCounts) window.tiConfigDeletedTableSnapshotBeforeCounts = {};\n        if (!window.tiConfigDeletedTableSnapshotBeforeCounts[tName]) window.tiConfigDeletedTableSnapshotBeforeCounts[tName] = rows.length;\n        if (window.recordConfigDeletedRowsManifest) window.recordConfigDeletedRowsManifest(tName, rows, ixs);\n        const beforeDeleteLen = rows.length;\n        if (!keepOne && rows.length === 1 && ixs.length === 1) {\n            rows.splice(ixs[0], 1);\n        } else {\n            ixs.forEach(function(i){ rows.splice(i, 1); });\n        }\n        window.tiLastConfigDeleteCount = Math.max(0, beforeDeleteLen - rows.length);\n        window.tiConfigDeletedRowsCountTotal = Math.max(0, parseInt(window.tiConfigDeletedRowsCountTotal || 0, 10) || 0) + window.tiLastConfigDeleteCount;\n        window.currentDbData.Tabelle[tName] = rows;\n        window.reindexTableRows(tName);\n        if (window.rememberConfigDeletedTableSnapshot) window.rememberConfigDeletedTableSnapshot(tName);\n        window.markTableRowsModified(tName);\n        if (!window.modifiedFields) window.modifiedFields = new Set();\n        window.modifiedFields.add(`${tName}-__rows_deleted`);\n        window.modifiedFields.add(`${tName}-__table_rewritten`);\n        window.modifiedFields.add(`${tName}-0-__structural_1909`);\n        try { if(!window.tiConfigStructuralChangedTables1907) window.tiConfigStructuralChangedTables1907 = new Set(); window.tiConfigStructuralChangedTables1907.add(tName); } catch(e1909) {}\n        if (window.syncConfigTableAfterRowMutation) window.syncConfigTableAfterRowMutation(tName);\n        if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n        if (opts.render !== false) {\n            window.configForceTop = true;\n            window.renderConfig();\n        }\n        return true;\n    };\n\n    window.delTableRow = function(tName, idx, sourceEl, opts) {\n        opts = opts || {};\n        tName = window.resolveConfigTableName ? window.resolveConfigTableName(tName) : tName;\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !Object.prototype.hasOwnProperty.call(window.currentDbData.Tabelle, tName)) {\n            window.tiAlert && window.tiAlert('Tabella non trovata nella configurazione corrente.');\n            return false;\n        }\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows || {});\n        const rowIndex = parseInt(idx, 10);\n        if (isNaN(rowIndex) || rowIndex < 0 || rowIndex >= rows.length) {\n            window.tiAlert && window.tiAlert('Riga non trovata o gia eliminata.');\n            return false;\n        }\n        const doDelete = function(){\n            if (window.deleteConfigRowsByIndexes) {\n                const ok = window.deleteConfigRowsByIndexes(tName, [rowIndex], {render:true});\n                if (ok) window.tiAlert('Righe cancellate dalla configurazione corrente: ' + (window.tiLastConfigDeleteCount || 1) + '. Premi Salva Modifiche per aggiornare il database.');\n                return !!ok;\n            }\n            rows.splice(rowIndex, 1);\n            window.currentDbData.Tabelle[tName] = rows;\n            window.reindexTableRows(tName);\n            window.markTableRowsModified(tName);\n            if (window.syncConfigTableAfterRowMutation) window.syncConfigTableAfterRowMutation(tName);\n            window.configForceTop = true;\n            window.renderConfig();\n            window.tiAlert && window.tiAlert('Righe cancellate dalla configurazione corrente: 1. Premi Salva Modifiche per aggiornare il database.');\n            return true;\n        };\n        if (opts && opts.noConfirm) return doDelete();\n        const deleteRowForConfirm1589 = (rows && rows[rowIndex] && typeof rows[rowIndex] === 'object') ? rows[rowIndex] : {};\n        const findDeleteValue1589 = function(names){\n            const keys = Object.keys(deleteRowForConfirm1589 || {});\n            for (let n = 0; n < names.length; n++) {\n                const wanted = String(names[n] || '').toLowerCase();\n                const realKey = keys.find(function(k){ return String(k || '').trim().toLowerCase() === wanted; });\n                if (realKey != null) {\n                    const value = String(deleteRowForConfirm1589[realKey] == null ? '' : deleteRowForConfirm1589[realKey]).trim();\n                    if (value !== '') return value;\n                }\n            }\n            return '';\n        };\n        const escapeDeleteHtml1589 = function(value){\n            return String(value == null ? '' : value).replace(\/[&<>\"']\/g, function(c){\n                return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];\n            });\n        };\n        const deleteDescription1589 = findDeleteValue1589(['Descrizione','Description','Descrizione voce','Voce','Nome','Prodotto','Servizio','Titolo']);\n        const deleteDescriptionHtml1589 = deleteDescription1589\n            ? '<b>Descrizione voce:<\/b> ' + escapeDeleteHtml1589(deleteDescription1589) + '<br><br>'\n            : '';\n        const msg = 'Eliminare questa riga dalla tabella ' + escapeDeleteHtml1589(String(tName || '')) + '?<br><br>'\n            + deleteDescriptionHtml1589\n            + 'La riga verra rimossa dalla configurazione corrente. Per aggiornare il database dovrai premere Salva Modifiche.';\n        if (typeof window.tiConfirmYesNoAction === 'function') window.tiConfirmYesNoAction(msg, doDelete, null, 'ELIMINA', 'ANNULLA');\n        else if (typeof window.tiConfirm === 'function') window.tiConfirm(msg, doDelete);\n        else doDelete();\n        return true;\n    };\n\n    window.addTableCol = function(tName) {\n        const colName = prompt('Nome nuova colonna:');\n        if (!colName || !window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tName]) return;\n        let rows = window.currentDbData.Tabelle[tName];\n        if (!Array.isArray(rows)) rows = window.currentDbData.Tabelle[tName] = Object.values(rows);\n        rows.forEach(r => { if (!(colName in r)) r[colName] = ''; });\n        window.renderConfig();\n    };\n\n    window.getPluginScrollable = function(target) {\n        if (!target) return null;\n        const pluginRoot = target.closest('#ti-ai-outer');\n        if (!pluginRoot) return null;\n        let node = target.nodeType === 1 ? target : target.parentElement;\n        while (node && node !== pluginRoot) {\n            const canScroll = node.classList && (\n                node.classList.contains('ti-scrollable-plugin') ||\n                node.classList.contains('ti-modal') ||\n                node.classList.contains('ti-chat-box') ||\n                node.classList.contains('ti-cfg-table-container') ||\n                node.classList.contains('ti-conf-body') ||\n                node.classList.contains('ti-table-wrap')\n            );\n            if (canScroll) {\n                const style = window.getComputedStyle(node);\n                const overflowY = style.overflowY || '';\n                const reallyScrollable = (overflowY === 'auto' || overflowY === 'scroll' || node.scrollHeight > node.clientHeight + 4);\n                if (reallyScrollable) return node;\n            }\n            node = node.parentElement;\n        }\n        const doc = document.scrollingElement || document.documentElement || document.body;\n        return (doc && doc.scrollHeight > doc.clientHeight + 4) ? doc : pluginRoot;\n    };\n\n    document.addEventListener('wheel', function(e) {\n        const pluginRoot = e.target.closest && e.target.closest('#ti-ai-outer');\n        if (!pluginRoot) return;\n        const scrollable = window.getPluginScrollable(e.target);\n        if (!scrollable || scrollable === pluginRoot) return;\n        const before = scrollable.scrollTop;\n        scrollable.scrollTop += e.deltaY;\n        if (scrollable.scrollTop !== before || e.deltaY !== 0) {\n            e.preventDefault();\n            e.stopPropagation();\n        }\n    }, { passive: false, capture: true });\n\n    document.addEventListener('touchmove', function(e) { \n        const isMobile = window.tiIsMobileLike ? window.tiIsMobileLike() : !!(window.matchMedia && window.matchMedia('(max-width: 900px)').matches);\n        if (isMobile) return; \/\/ su smartphone\/touch lascia sempre libero lo scorrimento verticale a un dito\n        const isModalOpen = document.querySelector('.ti-ov[style*=\"display: flex\"], .ti-ov[style*=\"display:flex\"], #ti-ai-loader-ov[style*=\"display: flex\"], #ti-ai-loader-ov[style*=\"display:flex\"]'); \n        if (isModalOpen) { \n            const t = e.target;\n            const scrollable = t && t.closest ? (t.closest('.ti-conf-body') || t.closest('.ti-table-wrap') || t.closest('.ti-chat-box') || t.closest('.ti-modal') || t.closest('.ti-cfg-table-container') || t.closest('.ti-scrollable-plugin') || t.closest('#help-bot-reply') || t.closest('#col-help-content') || t.closest('#ateco-res') || t.closest('#global-action-res') || t.closest('#fm-grid')) : null; \n            if (!scrollable) e.preventDefault(); \n        } \n    }, { passive: false });\n\n\n    window.tiIsPrivilegedCurrentUser = function() {\n        const roleNow = String(window.tiRole || '').toLowerCase();\n        const userNow = String(window.tiUser || '');\n        return (!!userNow && userNow === 'SSGlobalAdmin') || \/amministratore|configuratore|responsabile|globale\/.test(roleNow);\n    };\n\n    window.tiInformativePopupsEnabled = true;\n    window.tiHasStandardMainFormAccess = function() {\n        return !!String(window.tiUser || '').trim();\n    };\n    window.ensureStandardMainFormForCurrentUser = function() {\n        if (!window.tiHasStandardMainFormAccess || !window.tiHasStandardMainFormAccess()) return;\n        const ids = ['ti-msg','ti-send','ti-new','ti-copy','ti-file','ti-products-btn','ti-services-btn','ti-kbd-btn','ti-mic','ti-cam'];\n        ids.forEach(function(id){\n            const el = gE(id);\n            if (!el) return;\n            el.disabled = false;\n            el.removeAttribute('disabled');\n            el.removeAttribute('aria-hidden');\n            if (el.style && el.style.display === 'none') el.style.display = '';\n            if (el.id === 'ti-msg') { el.readOnly = false; el.removeAttribute('readonly'); }\n        });\n        const wrap = document.querySelector('#ti-ai-outer .ti-input-wrap');\n        if (wrap) { wrap.style.display = ''; wrap.removeAttribute('aria-hidden'); }\n        const actions = document.querySelector('#ti-ai-outer .ti-actions-row');\n        if (actions) { actions.style.display = ''; actions.removeAttribute('aria-hidden'); }\n        document.querySelectorAll('#ti-ai-outer .ti-order-wrap,#ti-ai-outer .ti-order-table-shell,#ti-ai-outer .ti-order-grid-view,#ti-ai-outer .ti-order-confirm-host,#ti-ai-outer table.ti-prod-table').forEach(function(el){\n            el.style.display = '';\n            el.removeAttribute('aria-hidden');\n        });\n        document.querySelectorAll('#ti-ai-outer .ti-order-wrap button,#ti-ai-outer .ti-order-table-shell button,#ti-ai-outer .ti-order-grid-view button,#ti-ai-outer .ti-order-confirm-host button,#ti-ai-outer table.ti-prod-table button').forEach(function(btn){\n            btn.disabled = false;\n            btn.removeAttribute('disabled');\n            btn.removeAttribute('aria-hidden');\n        });\n    };\n\n    window.tiPlainTextFromHtml = function(html) {\n        try {\n            const tmp = document.createElement('div');\n            tmp.innerHTML = String(html == null ? '' : html)\n                .replace(\/<br\\s*\\\/?>\/gi, '\\n')\n                .replace(\/<\\\/p>\/gi, '\\n')\n                .replace(\/<\\\/div>\/gi, '\\n')\n                .replace(\/<\\\/li>\/gi, '\\n');\n            return (tmp.innerText || tmp.textContent || '').replace(\/\\n{3,}\/g, '\\n\\n').trim();\n        } catch(e) {\n            return String(html == null ? '' : html).replace(\/<[^>]+>\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n        }\n    };\n\n    window.tiCopyTextToClipboard = function(text, btn) {\n        text = String(text == null ? '' : text);\n        const done = function(ok){\n            if (!btn) return;\n            const old = btn.textContent;\n            btn.textContent = ok ? 'Copiato' : 'Errore copia';\n            setTimeout(function(){ btn.textContent = old || 'Copia testo'; }, 1200);\n        };\n        if (navigator.clipboard && navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){\n                try { const ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.left='-9999px'; document.body.appendChild(ta); ta.focus(); ta.select(); const ok=document.execCommand('copy'); document.body.removeChild(ta); done(ok); } catch(e){ done(false); }\n            });\n            return;\n        }\n        try { const ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.left='-9999px'; document.body.appendChild(ta); ta.focus(); ta.select(); const ok=document.execCommand('copy'); document.body.removeChild(ta); done(ok); } catch(e){ done(false); }\n    };\n\n    window.tiSanitizePrivilegedPopupHtml = function(content) {\n        let html = String(content == null ? '' : content);\n        try {\n            if (\/\\[TABLE\\]|ti-order-wrap|ti-prod-table|ti-order-table-shell|ti-order-grid-view\/i.test(html)) {\n                let post = '';\n                if (\/\\[TABLE\\]\/i.test(html)) {\n                    const lastClose = html.lastIndexOf('[\/P]');\n                    if (lastClose >= 0) post = html.slice(lastClose + 4).trim();\n                    html = html.split('[TABLE]')[0] + (post ? '<br><br>' + post : '');\n                }\n                const tmp = document.createElement('div');\n                tmp.innerHTML = html;\n                tmp.querySelectorAll('.ti-order-wrap,.ti-order-table-shell,.ti-order-grid-view,.ti-order-toolbar,.ti-order-filterbar,.ti-order-confirm-host,table.ti-prod-table').forEach(function(el){ el.remove(); });\n                tmp.querySelectorAll('table').forEach(function(tbl){\n                    if (tbl.closest && tbl.closest('#ti-report-cnt')) return;\n                    const txt = (tbl.innerText || tbl.textContent || '').trim();\n                    if (\/voce|quantit|prezzo|totale|descrizione\/i.test(txt)) tbl.remove();\n                });\n                html = tmp.innerHTML;\n            }\n        } catch(e) {}\n        return html;\n    };\n\n    window.tiPopupPlaceholderMessage = function(title) {\n        const t = String(title || 'Comunicazione').replace(\/<[^>]+>\/g, '').trim();\n        return '\ud83d\udccc ' + (t || 'Comunicazione\/report') + ' aperto in popup separato. Usa il pulsante <b>Copia testo<\/b> nel popup per copiare il contenuto.';\n    };\n\n    window.showPrivilegedCommunicationPopup = function(content, title, opts) {\n        if (!window.tiIsPrivilegedCurrentUser || !window.tiIsPrivilegedCurrentUser()) return false;\n        const ov = gE('ti-admin-comm-ov');\n        const box = gE('ti-admin-comm-msg');\n        const titleEl = gE('ti-admin-comm-title');\n        const copyBtn = gE('ti-admin-comm-copy');\n        const closeBtn = gE('ti-admin-comm-close');\n        if (!ov || !box || !titleEl) return false;\n        const html = (window.tiSanitizePrivilegedPopupHtml ? window.tiSanitizePrivilegedPopupHtml(content) : String(content == null ? '' : content)).trim();\n        if (!html) return false;\n        titleEl.textContent = title || 'Comunicazione';\n        box.innerHTML = html;\n        const plain = window.tiPlainTextFromHtml ? window.tiPlainTextFromHtml(html) : String(html).replace(\/<[^>]+>\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n        box.setAttribute('data-copy-text', plain);\n        \/\/ 30.9.1643: copia dinamicamente il popup corrente, non lo snapshot creato all'apertura.\n        \/\/ Include il titolo e tutto il testo visibile, anche se tradotto o aggiornato dopo il rendering.\n        if (copyBtn) copyBtn.onclick = function(){\n            let current = '';\n            try {\n                const titleNow = String((titleEl && (titleEl.innerText || titleEl.textContent)) || title || 'Comunicazione').trim();\n                const bodyNow = String((box && (box.innerText || box.textContent)) || '').trim();\n                const extraValues = [];\n                if (box) box.querySelectorAll('input,textarea,select').forEach(function(el){\n                    if (!el || el.type === 'button' || el.type === 'submit' || el.type === 'hidden') return;\n                    let v = '';\n                    if (el.tagName === 'SELECT') {\n                        try { v = Array.from(el.selectedOptions || []).map(function(o){ return o.textContent || o.value || ''; }).join(', '); } catch(e) { v = el.value || ''; }\n                    } else if ((el.type === 'checkbox' || el.type === 'radio')) {\n                        v = el.checked ? (el.value || 'SI') : '';\n                    } else v = el.value || '';\n                    v = String(v || '').trim();\n                    if (v) extraValues.push(v);\n                });\n                current = (titleNow ? titleNow + '\\n\\n' : '') + bodyNow + (extraValues.length ? '\\n\\n' + extraValues.join('\\n') : '');\n            } catch(e) {}\n            if (!String(current || '').trim()) current = (String(title || 'Comunicazione').trim() + '\\n\\n' + plain).trim();\n            box.setAttribute('data-copy-text', current);\n            window.tiCopyTextToClipboard(current, copyBtn);\n        };\n        if (closeBtn) closeBtn.onclick = function(){ window.closeModal('ti-admin-comm-ov'); };\n        window.showPluginModal('ti-admin-comm-ov');\n        try { if (window.applyLayoutLanguage) window.applyLayoutLanguage(true); } catch(e) {}\n        window.keepUserCommunicationPopupsInFront();\n        setTimeout(window.keepUserCommunicationPopupsInFront, 0);\n        setTimeout(window.keepUserCommunicationPopupsInFront, 80);\n        return true;\n    };\n\n    window.tiIsFunctionalOrderContent = function(content) {\n        const s = String(content == null ? '' : content);\n        if (!s.trim()) return false;\n        return \/\\[TABLE\\]|\\[P\\]|ti-order-wrap|ti-prod-table|ti-order-table-shell|ti-order-grid-view|ti-order-confirm-host|confirmPendingOrder|Conferma ordine|CONFERMA ORDINE|tabella ordine\/i.test(s);\n    };\n\n    window.shouldShowPrivilegedCommunicationPopup = function(text, force) {\n        if (window.tiIsFunctionalOrderContent && window.tiIsFunctionalOrderContent(text)) return false;\n        if (force) return true;\n        if (!window.tiIsPrivilegedCurrentUser || !window.tiIsPrivilegedCurrentUser()) return false;\n        const plain = String(text == null ? '' : text).replace(\/<[^>]+>\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n        if (!plain) return false;\n        if (plain.length >= 260) return true;\n        return \/(report|riepilogo|comunicaz|avviso|warning|errore|database|configurazione|salvataggio|righe cancellate|modifica globale|anteprima|import|istruzioni|prenotaz|appuntament|ordine concluso|notifica|email)\/i.test(plain);\n    };\n\n    window.maybeShowPrivilegedCommunicationPopup = function(content, title, force) {\n        if (window.tiIsFunctionalOrderContent && window.tiIsFunctionalOrderContent(content)) return false;\n        const plain = window.tiPlainTextFromHtml ? window.tiPlainTextFromHtml(content) : String(content || '');\n        if (!window.shouldShowPrivilegedCommunicationPopup(plain, !!force)) return false;\n        return window.showPrivilegedCommunicationPopup(content, title || 'Comunicazione', {text: plain});\n    };\n\n    window.tiSanitizeUserVisibleUploadMessage636 = window.tiSanitizeUserVisibleUploadMessage636 || function(msg) {\n        var out = String(msg == null ? '' : msg);\n        var neutralUpload = \"Upload file non disponibile con il profilo corrente. Usa la procedura guidata prevista oppure richiedi l'abilitazione della sorgente file.\";\n        var neutralAttach = \"Upload e associazione file non disponibili con il profilo corrente. Usa la procedura guidata prevista oppure richiedi l'abilitazione della sorgente file.\";\n        out = out.replace(\/Errore\\s+aggiunta\\s+file\\s+da\\s+PC\\s*:\\s*Upload\\s+file\\s+disponibile\\s+solo\\s+per[^\\r\\n.<]*\/gi, 'Errore upload file: ' + neutralUpload);\n        out = out.replace(\/Upload\\s+file\\s+disponibile\\s+solo\\s+per[^\\r\\n.<]*\/gi, neutralUpload);\n        out = out.replace(\/Upload\\s+e\\s+associazione\\s+file\\s+disponibili\\s+solo\\s+per[^\\r\\n.<]*\/gi, neutralAttach);\n        out = out.replace(\/Associazione\\s+file\\s+disponibile\\s+solo\\s+per[^\\r\\n.<]*\/gi, 'Associazione file non disponibile con il profilo corrente.');\n        if (\/upload|file|associazione\/i.test(out)) {\n            out = out.replace(\/\\bSSGlobalAdmin\\b|\\bglobal\\s*admin\\b|\\bglobaladmin\\b\/gi, 'profilo abilitato');\n            out = out.replace(\/\\bamministratore\\b|\\bamministratori\\b|\\badministrator\\b\/gi, 'profilo abilitato');\n            out = out.replace(\/profilo abilitato\\s*,\\s*profilo abilitato(?:\\s*,\\s*profilo abilitato)*(?:\\s*o\\s*profilo abilitato)?\/gi, 'profilo abilitato');\n        }\n        return out;\n    };\n\n\n    window.tiResetAlertModalStyle668 = function() {\n        try {\n            const modal = gE('ti-alert-modal') || (gE('ti-alert-ov') ? gE('ti-alert-ov').querySelector('.ti-modal') : null);\n            const msgBox = gE('ti-alert-msg');\n            if (modal) {\n                modal.classList.remove('ti-config-warning-modal-668');\n                modal.style.width = '300px';\n                modal.style.maxWidth = '';\n                modal.style.minWidth = '';\n                modal.style.padding = '20px';\n                modal.style.textAlign = 'center';\n                modal.style.maxHeight = '90vh';\n                modal.style.overflowY = 'auto';\n            }\n            if (msgBox) {\n                msgBox.classList.remove('ti-config-warning-msg-668');\n                msgBox.style.fontSize = '15px';\n                msgBox.style.lineHeight = '1.4';\n                msgBox.style.marginBottom = '20px';\n                msgBox.style.maxHeight = '';\n                msgBox.style.overflowY = '';\n                msgBox.style.textAlign = '';\n                msgBox.style.fontWeight = 'normal';\n                msgBox.style.wordBreak = '';\n            }\n        } catch(e) {}\n    };\n    window.tiApplyConfigWarningAlertStyle668 = function() {\n        try {\n            const modal = gE('ti-alert-modal') || (gE('ti-alert-ov') ? gE('ti-alert-ov').querySelector('.ti-modal') : null);\n            const msgBox = gE('ti-alert-msg');\n            if (modal) {\n                modal.classList.add('ti-config-warning-modal-668');\n                modal.style.width = 'min(96vw, 780px)';\n                modal.style.maxWidth = '780px';\n                modal.style.minWidth = 'min(96vw, 360px)';\n                modal.style.padding = '14px 16px';\n                modal.style.textAlign = 'left';\n                modal.style.maxHeight = '88vh';\n                modal.style.overflowY = 'auto';\n            }\n            if (msgBox) {\n                msgBox.classList.add('ti-config-warning-msg-668');\n                msgBox.style.fontSize = '12px';\n                msgBox.style.lineHeight = '1.25';\n                msgBox.style.marginBottom = '12px';\n                msgBox.style.maxHeight = '72vh';\n                msgBox.style.overflowY = 'auto';\n                msgBox.style.textAlign = 'left';\n                msgBox.style.fontWeight = '600';\n                msgBox.style.wordBreak = 'normal';\n                const ul = msgBox.querySelector('ul');\n                if (ul) { ul.style.marginTop = '7px'; ul.style.paddingLeft = '16px'; }\n                msgBox.querySelectorAll('li').forEach(function(li){ li.style.marginBottom = '8px'; li.style.paddingLeft = '2px'; });\n            }\n        } catch(e) {}\n    };\n\n    window.tiAlert = function(msg) {\n        try { if (window.tiResetAlertModalStyle668) window.tiResetAlertModalStyle668(); } catch(e) {}\n        if (window.tiSanitizeUserVisibleUploadMessage636) msg = window.tiSanitizeUserVisibleUploadMessage636(msg);\n        if (window.tiCleanVisibleEscapedChars) msg = window.tiCleanVisibleEscapedChars(msg);\n        gE('ti-alert-msg').innerHTML = msg;\n        try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(gE('ti-alert-msg')); } catch(e) {}\n        if (gE('ti-alert-copy')) { gE('ti-alert-copy').style.display = 'block'; gE('ti-alert-copy').onclick = window.copyAlertText; }\n        gE('ti-alert-yes').style.display = 'none';\n        gE('ti-alert-no').innerText = 'OK';\n        gE('ti-alert-no').onclick = () => { window.closeModal('ti-alert-ov'); };\n        window.showPluginModal('ti-alert-ov');\n        try { if (window.applyLayoutLanguage) window.applyLayoutLanguage(true); } catch(e) {}\n        window.keepUserCommunicationPopupsInFront();\n        setTimeout(window.keepUserCommunicationPopupsInFront, 0);\n        setTimeout(window.keepUserCommunicationPopupsInFront, 80);\n    };\n\n    window.tiConfirm = function(msg, callback) {\n        try { if (window.tiResetAlertModalStyle668) window.tiResetAlertModalStyle668(); } catch(e) {}\n        if (window.tiSanitizeUserVisibleUploadMessage636) msg = window.tiSanitizeUserVisibleUploadMessage636(msg);\n        if (window.tiCleanVisibleEscapedChars) msg = window.tiCleanVisibleEscapedChars(msg);\n        gE('ti-alert-msg').innerHTML = msg;\n        try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(gE('ti-alert-msg')); } catch(e) {}\n        if (gE('ti-alert-copy')) { gE('ti-alert-copy').style.display = 'block'; gE('ti-alert-copy').onclick = window.copyAlertText; }\n        gE('ti-alert-yes').style.display = 'block';\n        gE('ti-alert-no').innerText = 'ANNULLA';\n        gE('ti-alert-yes').onclick = () => {\n            window.closeModal('ti-alert-ov');\n            if (typeof callback === 'function') callback();\n        };\n        gE('ti-alert-no').onclick = () => { window.closeModal('ti-alert-ov'); };\n        window.showPluginModal('ti-alert-ov');\n        try { if (window.applyLayoutLanguage) window.applyLayoutLanguage(true); } catch(e) {}\n        window.keepUserCommunicationPopupsInFront();\n        setTimeout(window.keepUserCommunicationPopupsInFront, 0);\n        setTimeout(window.keepUserCommunicationPopupsInFront, 80);\n    };\n\n\n    window.tiConfirmYesNoAction = function(msg, yesCb, noCb, yesLabel = 'OK', noLabel = 'ANNULLA') {\n        try { if (window.tiResetAlertModalStyle668) window.tiResetAlertModalStyle668(); } catch(e) {}\n        gE('ti-alert-msg').innerHTML = msg;\n        if (gE('ti-alert-copy')) { gE('ti-alert-copy').style.display = 'block'; gE('ti-alert-copy').onclick = window.copyAlertText; }\n        gE('ti-alert-yes').style.display = 'block';\n        gE('ti-alert-yes').innerText = yesLabel;\n        gE('ti-alert-no').innerText = noLabel;\n        try {\n            const yesBtn1647 = gE('ti-alert-yes');\n            if (yesBtn1647) {\n                if (\/modifica\/i.test(String(yesLabel || ''))) {\n                    \/\/ 30.9.1648: label Globale lunga sempre contenuta nel pulsante, anche con temi CSS aggressivi.\n                    yesBtn1647.style.setProperty('font-size', '8.5px', 'important');\n                    yesBtn1647.style.setProperty('line-height', '1.05', 'important');\n                    yesBtn1647.style.setProperty('white-space', 'normal', 'important');\n                    yesBtn1647.style.setProperty('overflow-wrap', 'anywhere', 'important');\n                    yesBtn1647.style.setProperty('word-break', 'normal', 'important');\n                    yesBtn1647.style.setProperty('padding', '6px 4px', 'important');\n                    yesBtn1647.style.setProperty('min-width', '118px', 'important');\n                    yesBtn1647.style.setProperty('min-height', '34px', 'important');\n                    yesBtn1647.style.setProperty('height', 'auto', 'important');\n                    yesBtn1647.style.setProperty('text-align', 'center', 'important');\n                } else {\n                    yesBtn1647.style.removeProperty('font-size');\n                    yesBtn1647.style.removeProperty('line-height');\n                    yesBtn1647.style.removeProperty('white-space');\n                    yesBtn1647.style.removeProperty('overflow-wrap');\n                    yesBtn1647.style.removeProperty('word-break');\n                    yesBtn1647.style.removeProperty('padding');\n                    yesBtn1647.style.removeProperty('min-width');\n                    yesBtn1647.style.removeProperty('min-height');\n                    yesBtn1647.style.removeProperty('height');\n                    yesBtn1647.style.removeProperty('text-align');\n                }\n            }\n        } catch(e1647) {}\n        gE('ti-alert-yes').onclick = () => {\n            window.closeModal('ti-alert-ov');\n            if (typeof yesCb === 'function') yesCb();\n        };\n        gE('ti-alert-no').onclick = () => {\n            window.closeModal('ti-alert-ov');\n            if (typeof noCb === 'function') noCb();\n        };\n        window.showPluginModal('ti-alert-ov');\n        try { if (window.applyLayoutLanguage) window.applyLayoutLanguage(true); } catch(e) {}\n        window.keepUserCommunicationPopupsInFront();\n        setTimeout(window.keepUserCommunicationPopupsInFront, 0);\n        setTimeout(window.keepUserCommunicationPopupsInFront, 80);\n    };\n\n    window.tiBatchAIGenState = { active: false, pendingConfirm: false, generated: [] };\n\n    window.refreshCurrentConfigDb = function(dbValue) {\n        const dbSel = gE('ti-ditta');\n        const db = dbValue || (dbSel ? dbSel.value : '');\n        if (!db || db === 'NEW_DB') return Promise.resolve(false);\n        const fdDb = window.buildAjaxFormData('ti_ai_get_db_data', {db: db});\n        return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fdDb, tiNoLongProcessSignal:true, tiShowTableReadWait:true, tiTableReadTitle:'\u23f3 Lettura tabelle configurazione', tiTableReadDetail:'Sto aggiornando le tabelle della ditta selezionata.', tiTableReadItem: db}).then(function(dbRes) {\n            if (dbRes && dbRes.success && dbRes.data) {\n                window.currentDbData = dbRes.data;\n                if (window.renderConfig) window.renderConfig();\n                try { if (window.showActivityFromQrIfRequested) window.showActivityFromQrIfRequested(); } catch(e) {}\n                return true;\n            }\n            return false;\n        }).catch(function(){ return false; });\n    };\n\n    window.confirmCancelBatchAIGen = function() {\n        const st = window.tiBatchAIGenState || {};\n        if (!st.active || st.pendingConfirm) return false;\n        const generated = Array.isArray(st.generated) ? st.generated : [];\n        const generatedCount = generated.length;\n        st.pendingConfirm = true;\n        const lp = window.tiLongProcessState || {};\n        lp.cancelled = true;\n        try { if (lp.controller) lp.controller.abort(); } catch(e) {}\n        window.closeModal('ti-ai-loader-ov');\n\n        const finishKeep = function() {\n            st.active = false;\n            st.pendingConfirm = false;\n            if (window.clearLongAIProcess) window.clearLongAIProcess();\n            const msg = generatedCount > 0\n                ? 'Generazione interrotta. Le associazioni gi\u00e0 generate sono state mantenute. Associazioni mantenute: ' + generatedCount + '.'\n                : 'Generazione interrotta. Nessuna associazione era stata ancora generata.';\n            const rb = gE('ti-conf-ai-reply');\n            if (rb) { rb.style.display = 'block'; rb.innerHTML = window.escapeHtml(msg); }\n            window.refreshCurrentConfigDb(st.db).then(function(){ window.tiAlert(msg); });\n        };\n\n        const finishRevert = function() {\n            if (!generatedCount) { finishKeep(); return; }\n            const fd = window.buildAjaxFormData('ti_ai_config_action', {\n                db: st.db || (gE('ti-ditta') ? gE('ti-ditta').value : ''),\n                mode: 'batch_ai_images_revert',\n                items_json: JSON.stringify(generated)\n            });\n            const rb = gE('ti-conf-ai-reply');\n            if (rb) { rb.style.display = 'block'; rb.innerHTML = 'Annullamento associazioni generate in corso...'; }\n            window.postFormDataJsonSafe((window.tiAjaxUrl || window.tiUrl), fd, {tiNoLongProcessSignal:true}).then(function(res){\n                st.active = false;\n                st.pendingConfirm = false;\n                if (window.clearLongAIProcess) window.clearLongAIProcess();\n                const removed = res && res.data && typeof res.data.removed !== 'undefined' ? parseInt(res.data.removed, 10) || 0 : 0;\n                const msg = 'Generazione interrotta. Associazioni generate annullate: ' + removed + '.';\n                if (rb) rb.innerHTML = window.escapeHtml(msg);\n                window.refreshCurrentConfigDb(st.db).then(function(){ window.tiAlert(msg); });\n            }).catch(function(err){\n                st.active = false;\n                st.pendingConfirm = false;\n                if (window.clearLongAIProcess) window.clearLongAIProcess();\n                const msg = 'Generazione interrotta. Non sono riuscito ad annullare automaticamente le associazioni gi\u00e0 generate. Verifica la configurazione. Dettaglio: ' + ((err && err.message) ? err.message : 'errore sconosciuto');\n                if (rb) rb.innerHTML = window.escapeHtml(msg);\n                window.tiAlert(msg);\n            });\n        };\n\n        const question = generatedCount > 0\n            ? 'Sono gi\u00e0 state generate ' + generatedCount + ' associazioni immagine.<br><br>Vuoi mantenerle oppure annullarle?'\n            : 'Vuoi uscire dalla generazione foto AI?<br><br>Nessuna associazione risulta ancora generata.';\n        if (generatedCount > 0 && typeof window.tiConfirmYesNoAction === 'function') {\n            window.tiConfirmYesNoAction(question, finishKeep, finishRevert, 'MANTIENI ASSOCIAZIONI', 'ANNULLA ASSOCIAZIONI');\n        } else if (typeof window.tiConfirmYesNoAction === 'function') {\n            window.tiConfirmYesNoAction(question, finishKeep, function(){\n                st.active = false;\n                st.pendingConfirm = false;\n                if (window.clearLongAIProcess) window.clearLongAIProcess();\n                const rb = gE('ti-conf-ai-reply');\n                if (rb) { rb.style.display = 'block'; rb.innerHTML = 'Generazione foto AI interrotta.'; }\n            }, 'ESCI', 'CONTINUA');\n        } else {\n            finishKeep();\n        }\n        return true;\n    };\n\n\n    window.openFileManager = function(tbl, idx, key) {\n        if (Date.now && Date.now() < (window.tiSuppressFileManagerUntil || 0)) return false;\n        if (!window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tbl] || !window.currentDbData.Tabelle[tbl][idx]) return false;\n        let val = window.currentDbData.Tabelle[tbl][idx][key] || '';\n        window.targetUploadContext = { tbl, idx, key, val };\n        const fmRowObj = (window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl]) ? window.currentDbData.Tabelle[tbl][idx] : null;\n        const fmDescBox = gE('fm-element-description');\n        if (fmDescBox) {\n            try {\n                const recordLabel = window.getRecordLabelForUpload ? window.getRecordLabelForUpload(tbl, fmRowObj, tbl) : (tbl || 'record');\n                let fullDesc = window.extractPromptFromRow ? window.extractPromptFromRow(fmRowObj) : '';\n                fullDesc = String(fullDesc || '').trim();\n                const shownDesc = fullDesc || recordLabel || 'Elemento senza descrizione disponibile';\n                const safeTbl = window.escapeHtml(tbl || '');\n                const safeKey = window.escapeHtml(key || '');\n                const safeDesc = window.escapeHtml(shownDesc);\n                const safeLabel = window.escapeHtml(recordLabel || shownDesc || '');\n                const rowNum = (parseInt(idx, 10) || 0) + 1;\n                fmDescBox.style.display = 'block';\n                fmDescBox.innerHTML = '<div style=\"font-weight:800;color:#93c5fd;margin-bottom:4px;\">Elemento cui sono associati i file<\/div>'\n                    + '<div><b>Descrizione:<\/b> ' + safeDesc + '<\/div>'\n                    + (safeLabel && safeLabel !== safeDesc ? '<div style=\"font-size:12px;color:#bfdbfe;margin-top:2px;\"><b>Voce:<\/b> ' + safeLabel + '<\/div>' : '')\n                    + '<div style=\"font-size:11px;color:#94a3b8;margin-top:4px;\">Tabella: ' + safeTbl + ' \u00b7 Riga rif.: ' + rowNum + ' \u00b7 Campo: ' + safeKey + '<\/div>';\n            } catch(e) {\n                fmDescBox.style.display = 'none';\n                fmDescBox.innerHTML = '';\n            }\n        }\n        let files = window.tiTokenizeFileRefs666 ? window.tiTokenizeFileRefs666(val) : String(val || '').split(\/[,;\\r\\n]+\/).map(f => f.trim()).filter(f=>f);\n        let html = '';\n        files.forEach((f, i) => {\n            let rowObj = (window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl]) ? window.currentDbData.Tabelle[tbl][idx] : null;\n            let dbForMeta676 = gE('ti-ditta') ? (gE('ti-ditta').value || '') : '';\n            let recordLabelForMeta676 = window.getRecordLabelForUpload(tbl, rowObj, tbl);\n            let url = window.getSafePreviewUrl(f, dbForMeta676, tbl, window.targetUploadContext && window.targetUploadContext.key ? window.targetUploadContext.key : '', recordLabelForMeta676);\n            let meta = window.tiFileMetaFromRef666 ? window.tiFileMetaFromRef666(f, url) : {name:f, ext:(String(f).match(\/\\.[a-z0-9]{1,8}$\/i)||[''])[0] || 'n\/d', isImg:\/\\.(jpg|jpeg|png|webp|gif)$\/i.test(f), isPdf:\/\\.pdf$\/i.test(f)};\n            let safeUrl = window.escapeHtml ? window.escapeHtml(url || '') : String(url || '');\n            let safeRef = window.escapeHtml ? window.escapeHtml(f || '') : String(f || '');\n            let safeName = window.escapeHtml ? window.escapeHtml(meta.name || f || 'file') : String(meta.name || f || 'file');\n            let safeExt = window.escapeHtml ? window.escapeHtml(meta.ext || 'n\/d') : String(meta.ext || 'n\/d');\n            let openArg = encodeURIComponent(url || '');\n            let preview = '';\n            if (meta.isImg) {\n                preview = `<div class=\"ti-file-preview-666\"><img decoding=\"async\" src=\"${safeUrl}\" alt=\"Preview ${safeName}\" onclick=\"window.open(decodeURIComponent('${openArg}'), '_blank')\"><\/div>`;\n            } else if (meta.isPdf) {\n                preview = `<div class=\"ti-file-preview-666 ti-file-preview-pdf-666\"><iframe src=\"${safeUrl}#toolbar=0&navpanes=0\" title=\"Preview ${safeName}\" loading=\"lazy\"><\/iframe><\/div>`;\n            } else {\n                preview = `<div class=\"ti-file-preview-666 file-icon\" onclick=\"window.open(decodeURIComponent('${openArg}'), '_blank')\">\ud83d\udcc4<\/div>`;\n            }\n            const primaryBadge = (i === 0) ? `<div style=\"margin-top:4px;padding:3px 5px;border-radius:999px;background:#22c55e;color:#052e16;font-size:10px;font-weight:800;\">Principale layout<\/div>` : `<button type=\"button\" onclick=\"window.setPrimaryFileInManager(${i})\" style=\"margin-top:4px;font-size:9px;padding:2px 5px;border-radius:999px;background:#334155;color:#e5e7eb;border:1px solid #64748b;\">Rendi principale<\/button>`;\n            html += `<div class=\"ti-file-item\" style=\"position:relative;${i === 0 ? 'border-color:#22c55e;box-shadow:0 0 0 1px rgba(34,197,94,.45);' : ''}\">\n                        ${preview}\n                        ${primaryBadge}\n                        <div class=\"ti-file-name\" title=\"${safeRef}\" onclick=\"window.open(decodeURIComponent('${openArg}'), '_blank')\" style=\"cursor:pointer;\">${safeName}<\/div>\n                        <div class=\"ti-file-meta-666\"><b>Tipo:<\/b> ${safeExt}<\/div>\n                        <div class=\"ti-file-meta-666\"><b>Dimensione:<\/b> <span data-ti-file-size-url=\"${safeUrl}\" data-ti-file-ref=\"${safeRef}\" data-ti-file-db=\"${window.escapeHtml ? window.escapeHtml(dbForMeta676 || '') : String(dbForMeta676 || '')}\" data-ti-file-tbl=\"${window.escapeHtml ? window.escapeHtml(tbl || '') : String(tbl || '')}\" data-ti-file-record=\"${window.escapeHtml ? window.escapeHtml(recordLabelForMeta676 || '') : String(recordLabelForMeta676 || '')}\">calcolo...<\/span><\/div>\n                        <button type=\"button\" class=\"ti-file-del\" onclick=\"window.removeFileFromManager(${i})\">X<\/button>\n                        <button type=\"button\" onclick=\"window.open(decodeURIComponent('${openArg}'), '_blank')\" style=\"margin-top:2px; font-size:9px; padding:2px; border-radius:3px;\">Apri<\/button>\n                     <\/div>`;\n        });\n        if(files.length === 0) html = '<p style=\"color:#aaa; font-size:12px; grid-column: 1 \/ -1;\">Nessun file presente.<\/p>';\n        const pathBox = gE('fm-storage-path');\n        if (pathBox) {\n            const showPath = window.isAdminConfiguratorUser && window.isAdminConfiguratorUser();\n            const storagePath = window.getStoragePathForTable(gE('ti-ditta') ? gE('ti-ditta').value : '', tbl);\n            pathBox.style.display = showPath && storagePath ? 'block' : 'none';\n            if (showPath && storagePath) pathBox.innerHTML = '<b>Path storage file:<\/b><br>' + window.escapeHtml(storagePath);\n        }\n        gE('fm-grid').innerHTML = html;\n        try { if (window.tiRefreshFileManagerMeta666) setTimeout(window.tiRefreshFileManagerMeta666, 30); } catch(e) {}\n        try {\n            const fmOv = gE('ti-file-manager-ov');\n            if (fmOv) {\n                fmOv.dataset.tbl = tbl || '';\n                fmOv.dataset.idx = String(idx);\n                fmOv.dataset.key = key || '';\n                fmOv.setAttribute('data-ti-config-child-modal', '1');\n            }\n        } catch(e) {}\n        window.openModal('ti-file-manager-ov');\n        try {\n            const fmOv = gE('ti-file-manager-ov');\n            if (fmOv) {\n                if (window.preparePluginModal) window.preparePluginModal(fmOv);\n                fmOv.style.setProperty('display', 'flex', 'important');\n                fmOv.style.setProperty('z-index', '2147483500', 'important');\n                fmOv.removeAttribute('aria-hidden');\n                fmOv.setAttribute('data-ti-force-front', '1');\n                if (window.updatePluginScrollLock) window.updatePluginScrollLock();\n            }\n        } catch(e) {}\n    };\n\n    window.setPrimaryFileInManager = function(fileIndex) {\n        let ctx = window.targetUploadContext;\n        if (!ctx) return;\n        let val = window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] || '';\n        let files = window.tiTokenizeFileRefs666 ? window.tiTokenizeFileRefs666(val) : String(val || '').split(\/[,;\\r\\n]+\/).map(f => f.trim()).filter(f=>f);\n        if (fileIndex <= 0 || fileIndex >= files.length) return;\n        const picked = files.splice(fileIndex, 1)[0];\n        files.unshift(picked);\n        window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] = files.join(', ');\n        if(!window.modifiedFields) window.modifiedFields = new Set();\n        window.modifiedFields.add(`${ctx.tbl}-${ctx.idx}-${ctx.key}`); if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n        window.renderConfig();\n        window.openFileManager(ctx.tbl, ctx.idx, ctx.key);\n        if (window.tiAlert) window.tiAlert('File principale layout impostato. Ricorda di salvare la configurazione.');\n    };\n\n    window.removeFileFromManager = function(fileIndex) {\n        let ctx = window.targetUploadContext;\n        if (!ctx || !window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[ctx.tbl] || !window.currentDbData.Tabelle[ctx.tbl][ctx.idx]) return;\n        const ctxSnapshot = { tbl: ctx.tbl, idx: ctx.idx, key: ctx.key };\n        let val = window.currentDbData.Tabelle[ctxSnapshot.tbl][ctxSnapshot.idx][ctxSnapshot.key] || '';\n        let filesBeforeDelete = window.tiTokenizeFileRefs666 ? window.tiTokenizeFileRefs666(val) : String(val || '').split(\/[,;\\r\\n]+\/).map(f => f.trim()).filter(f=>f);\n        const fileName = filesBeforeDelete[fileIndex] || '';\n        if (!fileName) { window.tiAlert('File non selezionato.'); return; }\n        let filesAfterDelete = filesBeforeDelete.slice();\n        filesAfterDelete.splice(fileIndex, 1);\n        const newVal = filesAfterDelete.join(', ');\n        const rowObj = (window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[ctxSnapshot.tbl]) ? window.currentDbData.Tabelle[ctxSnapshot.tbl][ctxSnapshot.idx] : null;\n        const applyLocalFileRemoval = function(ctx, msg, markUnsaved) {\n            if (!window.currentDbData.Tabelle) window.currentDbData.Tabelle = {};\n            if (!window.currentDbData.Tabelle[ctx.tbl]) window.currentDbData.Tabelle[ctx.tbl] = [];\n            if (!window.currentDbData.Tabelle[ctx.tbl][ctx.idx]) window.currentDbData.Tabelle[ctx.tbl][ctx.idx] = {};\n            window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] = newVal;\n            try { window.currentDbViewData = null; } catch(e) {}\n            try { if (window.syncConfigTableAfterRowMutation) window.syncConfigTableAfterRowMutation(ctx.tbl); } catch(e) {}\n            try {\n                var cssEsc = window.CSS && CSS.escape ? CSS.escape : function(v){ return String(v).replace(\/([\\\"'\\[\\]#.:>+~*^$|=!])\/g, '\\\\$1'); };\n                document.querySelectorAll('#ti-conf-ov [data-tbl=\"' + cssEsc(ctx.tbl) + '\"][data-idx=\"' + cssEsc(ctx.idx) + '\"][data-key=\"' + cssEsc(ctx.key) + '\"]').forEach(function(inp){ if (inp) { inp.value = newVal; inp.setAttribute('data-ti-last-file-removal-676', String(Date.now ? Date.now() : new Date().getTime())); } });\n            } catch(e) {}\n            if (markUnsaved) {\n                if(!window.modifiedFields) window.modifiedFields = new Set();\n                window.modifiedFields.add(`${ctx.tbl}-${ctx.idx}-${ctx.key}`);\n                if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            }\n            window.renderConfig();\n            window.openFileManager(ctx.tbl, ctx.idx, ctx.key);\n            if (window.tiAlert && msg) window.tiAlert(msg);\n        };\n        window.tiConfirm(\"Rimuovere questa associazione file dal record?\\n\\nIl riferimento verr\u00e0 tolto dalla configurazione corrente. Premi Salva Modifiche per confermare.\", function() {\n            let ctx = ctxSnapshot;\n            try {\n                window.pendingLinkedFileRemovals = window.pendingLinkedFileRemovals || [];\n                window.pendingLinkedFileRemovals.push({\n                    db: (gE('ti-ditta') ? (gE('ti-ditta').value || '') : ''),\n                    tbl: ctx.tbl,\n                    idx: ctx.idx,\n                    key: ctx.key,\n                    file: fileName,\n                    removed_at: new Date().toISOString()\n                });\n            } catch(e) {}\n            applyLocalFileRemoval(ctx, 'Associazione file rimossa dalla configurazione corrente. Premi Salva Modifiche per confermare la modifica. Il file fisico nello storage non viene cancellato automaticamente da questa X rossa.', true);\n        });\n    };\n\n    window.tiCloseFileManagerForAction = function(actionName) {\n        try {\n            window.__tiFileManagerExplicitClose337 = Date.now ? Date.now() : new Date().getTime();\n            window.__tiFileManagerOpening337 = 0;\n            window.__tiFileManagerAction340 = actionName || 'action';\n        } catch(e) {}\n        try { if (window.closeModal) window.closeModal('ti-file-manager-ov'); } catch(e) {}\n        try {\n            const ov = gE('ti-file-manager-ov');\n            if (ov) {\n                ov.style.setProperty('display', 'none', 'important');\n                ov.setAttribute('aria-hidden', 'true');\n                ov.classList.remove('ti-modal-active','ti-ov-active','is-active','active','show');\n            }\n        } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n    };\n\n    window.chooseLocalManager = function() {\n        if (window.tiOpenDirectUpload616) return window.tiOpenDirectUpload616(window.targetUploadContext || 'manager');\n        return false;\n    };\n\n    window.getCompanyActivity = function() {\n        try {\n            if (!window.currentDbData || !window.currentDbData.Tabelle) return '';\n            const cfgRows = window.currentDbData.Tabelle.Config || window.currentDbData.Tabelle.config || [];\n            const row = Array.isArray(cfgRows) && cfgRows.length ? cfgRows[0] : null;\n            if (!row) return '';\n            return row['Attivita'] || row['Attivit\u00e0'] || row['Attivita\\u0300'] || '';\n        } catch(e) { return ''; }\n    };\n\n    window.getInfoLinksForAIGen = function() {\n        try {\n            if (!window.currentDbData || !window.currentDbData.Tabelle) return [];\n            const tables = window.currentDbData.Tabelle;\n            const infoRows = tables.Informazioni || tables.informazioni || [];\n            const links = [];\n            (Array.isArray(infoRows) ? infoRows : []).forEach(row => {\n                if (!row || typeof row !== 'object') return;\n                Object.values(row).forEach(val => {\n                    if (typeof val !== 'string') return;\n                    const matches = val.match(\/https?:\\\/\\\/[^\\s<>'\"]+\/gi);\n                    if (matches) matches.forEach(u => { if (!links.includes(u)) links.push(u); });\n                });\n            });\n            return links.slice(0, 5);\n        } catch(e) { return []; }\n    };\n\n    window.buildAIGenPrompt = function(descriptionText) {\n        const parts = [];\n        const activity = (window.getCompanyActivity() || '').trim();\n        const desc = (descriptionText || '').trim();\n        const infoLinks = window.getInfoLinksForAIGen();\n        if (activity) parts.push('Attivit\u00e0 ditta: ' + activity);\n        if (infoLinks.length) parts.push('Verifica anzitutto questi link informazioni del database: ' + infoLinks.join(' | '));\n        if (desc) parts.push('Descrizione da associare: ' + desc);\n        return parts.join('\\n');\n    };\n\n    window.chooseAIManager = function() {\n        const ctx = window.targetUploadContext;\n        if (!ctx || !ctx.tbl || ctx.idx === undefined || !ctx.key) {\n            if (window.tiAlert) window.tiAlert('Gestione file associati: record\/campo non disponibile. Riapri la form dalla tabella.');\n            return false;\n        }\n        let row = null;\n        try {\n            if (window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[ctx.tbl]) {\n                row = window.currentDbData.Tabelle[ctx.tbl][ctx.idx] || null;\n            }\n        } catch(e) {}\n        if (typeof window.populateAIGenPrompt === 'function') window.populateAIGenPrompt(row);\n        else if (gE('ai-gen-prompt')) gE('ai-gen-prompt').value = window.buildAIGenPrompt ? window.buildAIGenPrompt(row ? (row.Descrizione || row.Prodotto || row.Servizio || row.Nome || '') : '') : '';\n        if (gE('ai-gen-detail')) gE('ai-gen-detail').value = '';\n        if (gE('ai-gen-res')) gE('ai-gen-res').style.display = 'none';\n        if (gE('ai-gen-img')) gE('ai-gen-img').src = '';\n        if (gE('ai-gen-btn')) {\n            gE('ai-gen-btn').disabled = false;\n            gE('ai-gen-btn').innerText = 'Genera Immagine';\n            gE('ai-gen-btn').style.display = 'block';\n        }\n        window.currentGenFilename = null;\n        try { window.openModal('ti-ai-gen-ov'); } catch(e) {}\n        try {\n            const fmOv = gE('ti-file-manager-ov');\n            if (fmOv) {\n                fmOv.style.setProperty('display', 'flex', 'important');\n                fmOv.style.setProperty('z-index', '2147483645', 'important');\n                fmOv.removeAttribute('aria-hidden');\n            }\n            const aiOv = gE('ti-ai-gen-ov');\n            if (aiOv) {\n                aiOv.setAttribute('data-ti-config-child-modal', '1');\n                aiOv.style.setProperty('display', 'flex', 'important');\n                aiOv.style.setProperty('z-index', '2147483646', 'important');\n                aiOv.removeAttribute('aria-hidden');\n                if (window.preparePluginModal) window.preparePluginModal(aiOv);\n            }\n            if (window.updatePluginScrollLock) window.updatePluginScrollLock();\n            setTimeout(function(){ try { if (gE('ai-gen-prompt')) gE('ai-gen-prompt').focus({preventScroll:true}); } catch(e) {} }, 60);\n        } catch(e) {}\n        return false;\n    };\n\n    window.syncLoginDbSelect = function() {\n        try {\n            const loginDb = gE('l-db');\n            const mainDb = gE('ti-ditta');\n            const hiddenDb = gE('l-db-hidden');\n            if (!loginDb) return;\n            if (mainDb && mainDb.options && mainDb.options.length) {\n                loginDb.innerHTML = '';\n                const first = document.createElement('option');\n                first.value = '';\n                first.textContent = '-- Scegli una ditta --';\n                loginDb.appendChild(first);\n                Array.from(mainDb.options || []).forEach(function(opt){\n                if (!opt || opt.disabled) return;\n                const v = String(opt.value || '');\n                if (v === 'NEW_DB') return;\n                const o = document.createElement('option');\n                o.value = v;\n                o.textContent = opt.textContent || v || '-- Scegli una ditta --';\n                Array.from(opt.attributes || []).forEach(function(a){\n                    if (a && a.name && a.name.indexOf('data-') === 0) o.setAttribute(a.name, a.value);\n                });\n                loginDb.appendChild(o);\n                });\n            }\n            let target = (mainDb && mainDb.value && mainDb.value !== 'NEW_DB') ? mainDb.value : '';\n            if (!target) target = window.tiForced || '';\n            if (!target) {\n                try { target = localStorage.getItem('ti_saved_db') || ''; } catch(e) {}\n            }\n            if (target && !Array.from(loginDb.options).some(function(o){ return o.value === target; })) {\n                \/\/ 30.9.2039: accesso diretto\/repository remoto. Il DB forzato puo essere valido anche se\n                \/\/ non compare nella lista HTML generata dal filesystem locale.\n                const forcedOpt2039=document.createElement('option');forcedOpt2039.value=target;forcedOpt2039.textContent=String(target).replace(\/\\.json$\/i,'');forcedOpt2039.setAttribute('data-ti-forced-2039','1');loginDb.appendChild(forcedOpt2039);\n            }\n            if (target && Array.from(loginDb.options).some(function(o){ return o.value === target; })) loginDb.value = target;\n            else if (loginDb.options.length === 2 && !loginDb.options[0].value) loginDb.selectedIndex = 1;\n\n            \/\/ 30.9.1775: anche l Accesso diretto usa sempre la lista ditte appena riletta dalla Main.\n            \/\/ Non lasciare nel fallback il SELECT generato dall HTML iniziale, che puo essere obsoleto dopo Crea ditta.\n            const directDb1775 = gE('ti-direct-login-db');\n            if (directDb1775) {\n                const directPrev1775 = String(directDb1775.value || '').trim();\n                directDb1775.innerHTML = loginDb.innerHTML;\n                const directTarget1775 = target || directPrev1775;\n                if (directTarget1775 && Array.from(directDb1775.options).some(function(o){ return o.value === directTarget1775; })) directDb1775.value = directTarget1775;\n                else if (directDb1775.options.length === 2 && !directDb1775.options[0].value) directDb1775.selectedIndex = 1;\n                if (window.tiForced) directDb1775.style.setProperty('display','none','important');\n            }\n\n            const hasRealOptions = Array.from(loginDb.options).some(function(o){ return o.value; });\n            const shouldShow = !window.tiForced && hasRealOptions;\n            loginDb.style.display = shouldShow ? 'block' : 'none';\n            if (hiddenDb) hiddenDb.value = (loginDb && loginDb.value) ? loginDb.value : (target || hiddenDb.value || '');\n            if (!loginDb.dataset.tiHiddenSyncBound) {\n                loginDb.dataset.tiHiddenSyncBound = '1';\n                loginDb.addEventListener('change', function(){ const h = gE('l-db-hidden'); if (h) h.value = loginDb.value || ''; }, false);\n            }\n        } catch(e) {}\n    };\n\n    window.getLoginDbValue = function() {\n        const modalDb = gE('l-db');\n        const hiddenDb = gE('l-db-hidden');\n        const mainDb = gE('ti-ditta');\n        let v = '';\n        if (modalDb && modalDb.value && modalDb.value !== 'NEW_DB') v = modalDb.value;\n        if (!v && hiddenDb && hiddenDb.value && hiddenDb.value !== 'NEW_DB') v = hiddenDb.value;\n        if (!v && mainDb && mainDb.value && mainDb.value !== 'NEW_DB') v = mainDb.value;\n        if (!v && window.tiForced) v = window.tiForced;\n        if (!v) {\n            try { v = localStorage.getItem('ti_saved_db') || ''; } catch(e) {}\n        }\n        return v;\n    };\n\n    window.tiCloseDirectLoginFallback = function() {\n        try {\n            const dl = gE('ti-mobile-direct-login');\n            if (!dl) return;\n            dl.classList.remove('ti-direct-login-visible');\n            dl.classList.remove('ti-direct-login-manual-open');\n            dl.style.display = 'none';\n            dl.setAttribute('aria-hidden', 'true');\n        } catch(e) {}\n    };\n\n    \/\/ 30.9.1995: un errore SSGlobalAdmin e solo un errore credenziali, non uno stato di layout.\n    \/\/ Chiude ogni UI di fallback\/login rimasta, conserva lo Username per il retry e rilascia la Main.\n    window.tiCleanupFailedGlobalLogin1995 = function(username) {\n        try {\n            const who = String(username || '').trim();\n            if (!\/^SSGlobalAdmin$\/i.test(who)) return false;\n            try {\n                sessionStorage.removeItem('ti_login_failed_clear');\n                sessionStorage.setItem('ti_failed_global_login_1997', String(Date.now()));\n            } catch(e) {}\n            try { localStorage.setItem('ti_failed_global_login_2011', String(Date.now())); localStorage.removeItem('ti_last_login_user'); } catch(e) {}\n            ['l-user','ti-direct-login-user'].forEach(function(id){ var el=gE(id); if(el) el.value='SSGlobalAdmin'; });\n            ['l-pass','ti-direct-login-pass'].forEach(function(id){ var el=gE(id); if(el) el.value=''; });\n            try { if (window.tiCloseDirectLoginFallback) window.tiCloseDirectLoginFallback(); } catch(e) {}\n            try { if (window.closeModal) window.closeModal('ti-login-ov'); else { var ov=gE('ti-login-ov'); if(ov){ ov.style.setProperty('display','none','important'); ov.setAttribute('aria-hidden','true'); } } } catch(e) {}\n            try {\n                window.tiLoginInProgress=false;\n                window.__tiLoginSubmitting186=false;\n                window.__tiLogoutInProgress=false;\n            } catch(e) {}\n            try {\n                [document.documentElement,document.body].forEach(function(el){ if(!el)return; ['ti-no-scroll','ti-busy','ti-loading','ti-modal-blocked','ti-no-click'].forEach(function(c){el.classList.remove(c);}); el.style.removeProperty('pointer-events'); });\n            } catch(e) {}\n            try {\n                window.dispatchEvent(new CustomEvent('ti:ss-global-login-failed', {detail:{username:'SSGlobalAdmin',ts:Date.now()}}));\n            } catch(e) { try { window.dispatchEvent(new Event('ti:ss-global-login-failed')); } catch(ignore) {} }\n            [40,160,420,900,1800].forEach(function(ms){ setTimeout(function(){ try { if(window.tiSSReleaseMain1983) window.tiSSReleaseMain1983('global-login-failed-1997'); if(window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {} },ms); });\n            return true;\n        } catch(e) { return false; }\n    };\n\n    window.revealDirectLoginFallback = function(reason, detail) {\n        try {\n            const dl = gE('ti-mobile-direct-login');\n            if (!dl) return;\n            dl.classList.add('ti-direct-login-visible');\n            dl.classList.add('ti-direct-login-manual-open');\n            dl.style.display = '';\n            dl.removeAttribute('aria-hidden');\n            const modalUser = gE('l-user');\n            const modalPass = gE('l-pass');\n            const directUser = gE('ti-direct-login-user');\n            const directPass = gE('ti-direct-login-pass');\n            const directDb = gE('ti-direct-login-db');\n            const directBtn = dl.querySelector('button[type=\"submit\"], .ti-mobile-login-submit');\n            if (directUser && modalUser && modalUser.value) directUser.value = modalUser.value;\n            if (directPass && modalPass && modalPass.value) directPass.value = modalPass.value;\n            const dbVal = window.getLoginDbValue ? window.getLoginDbValue() : '';\n            if (directDb && dbVal) directDb.value = dbVal;\n            const box = gE('ti-direct-login-fallback-alert');\n            if (box) {\n                const baseMsg = 'Accesso tramite tasto Accedi non riuscito. Utilizza Accesso diretto Shop & Service per completare il login.';\n                box.textContent = detail ? (baseMsg + ' Dettaglio: ' + detail) : baseMsg;\n                box.style.display = 'block';\n            }\n            if (window.closeModal) window.closeModal('ti-login-ov');\n            try { window.tiScrollIntoViewSafe ? window.tiScrollIntoViewSafe(dl) : dl.scrollIntoView({behavior:'smooth', block:'center'}); } catch(e) { try { dl.scrollIntoView({behavior:'smooth', block:'center'}); } catch(ignore) {} }\n            setTimeout(function(){\n                try {\n                    if (directPass && !directPass.value) directPass.focus();\n                    else if (directBtn) directBtn.focus();\n                    else if (directUser) directUser.focus();\n                } catch(e) {}\n            }, 220);\n        } catch(e) {}\n    };\n\n\n    window.tiPrepareChatLoginAs = function(username) {\n        try {\n            if (window.syncLoginDbSelect) window.syncLoginDbSelect();\n            const u = gE('l-user');\n            const p = gE('l-pass');\n            if (u) u.value = username || '';\n            if (window.openLoginModalSafe) window.openLoginModalSafe(); else if (window.openModal) window.openModal('ti-login-ov');\n            setTimeout(function(){ try { if (p) { p.value = ''; p.focus(); } } catch(e) {} }, 120);\n        } catch(e) {\n            if (window.openLoginModalSafe) window.openLoginModalSafe();\n        }\n    };\n\n    window.openLoginModalSafe = function() {\n        try { if (window.syncLoginDbSelect) window.syncLoginDbSelect(); } catch(e) {}\n        if (window.openModal) window.openModal('ti-login-ov');\n        setTimeout(function(){\n            try {\n                if (window.syncLoginDbSelect) window.syncLoginDbSelect();\n                if (!(window.tiIsMobileLike && window.tiIsMobileLike())) {\n                    const u = gE('l-user'); if (u) u.focus();\n                }\n            } catch(e) {}\n        }, 80);\n    };\n\n    window.mobileLoginXhr = function(url, fd) {\n        return new Promise(function(resolve, reject){\n            try {\n                const xhr = new XMLHttpRequest();\n                xhr.open('POST', url, true);\n                xhr.withCredentials = true;\n                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n                xhr.onreadystatechange = function(){\n                    if (xhr.readyState !== 4) return;\n                    const raw = xhr.responseText || '';\n                    if (xhr.status < 200 || xhr.status >= 300) {\n                        reject(new Error('HTTP ' + xhr.status + ': ' + raw.slice(0, 180)));\n                        return;\n                    }\n                    try { resolve(JSON.parse(raw)); }\n                    catch(e) { reject(new Error('Risposta server non valida: ' + raw.slice(0, 180))); }\n                };\n                xhr.onerror = function(){ reject(new Error('Errore rete XHR')); };\n                xhr.ontimeout = function(){ reject(new Error('Timeout login')); };\n                xhr.timeout = 240000;\n                xhr.send(fd);\n            } catch(e) { reject(e); }\n        });\n    };\n\n    window.doLogin = function() {\n        const userEl = gE('l-user');\n        const passEl = gE('l-pass');\n        const loginBtn = gE('l-do');\n        try { if (window.syncLoginDbSelect) window.syncLoginDbSelect(); } catch(e) {}\n        const u = userEl ? userEl.value.trim() : '';\n        const dbVal = (window.getLoginDbValue ? window.getLoginDbValue() : '');\n        const hardCodedAdmin1978 = \/^SSGlobalAdmin$\/i.test(u);\n        if (hardCodedAdmin1978 && typeof window.tiGlobalLogin2046 === 'function') { return window.tiGlobalLogin2046('modal'); }\n        if (!u) { window.tiAlert('Inserisci username'); if (userEl && !(window.tiIsMobileLike && window.tiIsMobileLike())) userEl.focus(); return; }\n        if (!hardCodedAdmin1978 && !dbVal) { window.tiAlert('Seleziona una ditta nella finestra di login.'); return; }\n        const hiddenDb = gE('l-db-hidden');\n        if (hiddenDb && dbVal) hiddenDb.value = dbVal;\n        if (window.tiLoginInProgress) return;\n        window.tiLoginInProgress = true;\n        if (loginBtn) { loginBtn.disabled = true; loginBtn.textContent = 'Accesso...'; }\n        var loginProgressSeconds1281 = 0;\n        var loginProgressTimer1281 = setInterval(function(){\n            loginProgressSeconds1281 += 5;\n            if (loginBtn && window.tiLoginInProgress) loginBtn.textContent = 'Accesso... (' + loginProgressSeconds1281 + 's)';\n        }, 5000);\n\n        const makeLoginFd = function() {\n            const f = new FormData();\n            f.append('action','ti_ai_login');\n            f.append('ti_action','ti_ai_login');\n            f.append('ti_mobile_login_redirect','0');\n            f.append('redirect','0');\n            f.append('user',u);\n            f.append('username',u);\n            const pwd = passEl ? passEl.value : '';\n            f.append('pass', pwd);\n            f.append('password', pwd);\n            f.append('db', dbVal);\n            f.append('current_db', dbVal);\n            f.append('_ti_mobile_ts', String(Date.now()));\n            return f;\n        };\n\n        const urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n\n        const loginVia = function(url) {\n            const fd = makeLoginFd();\n            if (window.mobileLoginXhr) return window.mobileLoginXhr(url, fd);\n            if (window.postFormDataJsonSafe) return window.postFormDataJsonSafe(url, fd, {tiNoLongProcessSignal:true, cache:'no-store'});\n            return window.fetchJsonSafe(url, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', tiNoLongProcessSignal:true});\n        };\n\n        const trySequence = function(i) {\n            return loginVia(urls[i] || window.tiUrl).catch(function(err){\n                if (i + 1 < urls.length) return trySequence(i + 1);\n                throw err;\n            });\n        };\n\n        trySequence(0).then(function(d){\n            if (d && d.success) {\n                try {\n                    if (dbVal) localStorage.setItem('ti_saved_db', dbVal);\n                    if (dbVal) localStorage.setItem('ti_last_login_db', dbVal);\n                    var canonicalLoginUser1994 = String((d && d.data && d.data.username) || u || '').trim();\n                    if (\/^(?:SSGlobalAdmin|SSGlobelAdmin|GlobalAdmin)$\/i.test(canonicalLoginUser1994)) localStorage.removeItem('ti_last_login_user');\n                    else localStorage.setItem('ti_last_login_user', canonicalLoginUser1994);\n                    sessionStorage.removeItem('ti_login_failed_clear');\n                    sessionStorage.removeItem('ti_failed_global_login_1997');\n                    localStorage.setItem('ti_login_ok_ts', String(Date.now()));\n                } catch(e) {}\n                window.closeModal && window.closeModal('ti-login-ov');\n                try { if (window.tiCloseDirectLoginFallback) window.tiCloseDirectLoginFallback(); } catch(e) {}\n                if (window.tiReloadAfterSuccessfulLogin) window.tiReloadAfterSuccessfulLogin(); else location.reload();\n                return;\n            }\n            const failMsg = (((d||{}).data||{}).message || 'Login non riuscito');\n            if (hardCodedAdmin1978) {\n                window.tiAlert('Accesso SSGlobalAdmin non riuscito. Verifica Username e Password. Dettaglio: ' + failMsg);\n                try { if (window.tiCleanupFailedGlobalLogin1995) window.tiCleanupFailedGlobalLogin1995(u); else if (passEl) passEl.value=''; } catch(e) {}\n                return;\n            }\n            window.tiAlert('Accesso non riuscito. Verifica username, password e ditta selezionata. Ti propongo Accesso diretto Shop & Service. Dettaglio: ' + failMsg);\n            try {\n                if (window.tiClearLoginFieldsAfterFailure) window.tiClearLoginFieldsAfterFailure(false);\n                else if (passEl) passEl.value = '';\n                if (window.revealDirectLoginFallback) window.revealDirectLoginFallback('login-non-riuscito', failMsg);\n                else if (window.openModal) window.openModal('ti-login-ov');\n            } catch(e) {}\n        }).catch(function(err){\n            const msg = err && err.message ? err.message : 'Errore di connessione durante il login.';\n            if (hardCodedAdmin1978) {\n                window.tiAlert('Accesso SSGlobalAdmin non completato. Dettaglio: ' + msg);\n                try { if (window.tiCleanupFailedGlobalLogin1995) window.tiCleanupFailedGlobalLogin1995(u); else if (passEl) passEl.value=''; } catch(e) {}\n                return;\n            }\n            window.tiAlert('Accesso tramite tasto Accedi non completato. Ti propongo Accesso diretto Shop & Service. Dettaglio: ' + msg);\n            try {\n                if (window.tiClearLoginFieldsAfterFailure) window.tiClearLoginFieldsAfterFailure(false);\n                if (window.revealDirectLoginFallback) window.revealDirectLoginFallback('login-non-completato', msg);\n                else if (window.openModal) window.openModal('ti-login-ov');\n            } catch(e) {}\n        }).finally(function(){\n            try { clearInterval(loginProgressTimer1281); } catch(e) {}\n            window.tiLoginInProgress = false;\n            if (loginBtn) { loginBtn.disabled = false; loginBtn.textContent = 'Accedi'; }\n        });\n    };\n\n    window.tiForgotPasswordFromLogin = function(source) {\n        const modalUser = gE('l-user');\n        const directUser = gE('ti-direct-login-user');\n        const modalDb = gE('l-db');\n        const directDb = gE('ti-direct-login-db');\n        const hiddenDb = gE('l-db-hidden');\n        const user = ((source === 'direct' && directUser) ? directUser.value : (modalUser ? modalUser.value : (directUser ? directUser.value : ''))).trim();\n        const db = (source === 'direct' && directDb && directDb.value) ? directDb.value : ((window.getLoginDbValue ? window.getLoginDbValue() : '') || (modalDb ? modalDb.value : '') || (hiddenDb ? hiddenDb.value : '') || (directDb ? directDb.value : ''));\n        if (!user) { window.tiAlert ? window.tiAlert('Inserisci username prima di richiedere il cambio password.') : alert('Inserisci username prima di richiedere il cambio password.'); return false; }\n        if (user === 'SSGlobalAdmin') { window.tiAlert ? window.tiAlert('Il recupero via email e disponibile per gli utenti registrati della ditta, non per SSGlobalAdmin.') : alert('Il recupero via email e disponibile per gli utenti registrati della ditta, non per SSGlobalAdmin.'); return false; }\n        if (!db) { window.tiAlert ? window.tiAlert('Seleziona la ditta prima di richiedere il cambio password.') : alert('Seleziona la ditta prima di richiedere il cambio password.'); return false; }\n        const ok = window.confirm('Inviare una password temporanea all indirizzo email registrato per l utente ' + user + '?');\n        if (!ok) return false;\n        const btn = gE('ti-forgot-password-btn');\n        const oldText = btn ? btn.textContent : '';\n        if (btn) { btn.disabled = true; btn.textContent = 'Invio email...'; }\n        const fd = new FormData();\n        fd.append('action','ti_ai_forgot_password');\n        fd.append('ti_action','ti_ai_forgot_password');\n        fd.append('user', user);\n        fd.append('username', user);\n        fd.append('db', db);\n        fd.append('db_select', db);\n        fd.append('current_db', db);\n        const urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        const post = function(url) {\n            if (window.postFormDataJsonSafe) return window.postFormDataJsonSafe(url, fd, {tiNoLongProcessSignal:true, cache:'no-store'});\n            return fetch(url, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', headers:{'X-Requested-With':'XMLHttpRequest'}}).then(function(resp){ return resp.text().then(function(raw){ if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + raw.slice(0, 180)); try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non valida: ' + raw.slice(0, 180)); } }); });\n        };\n        let chain = Promise.reject(new Error('init'));\n        urls.forEach(function(url){ chain = chain.catch(function(){ return post(url); }); });\n        chain.then(function(res){\n            const msg = res && res.data && res.data.msg ? res.data.msg : (res && res.data && res.data.message ? res.data.message : 'Richiesta completata.');\n            if (res && res.success) {\n                window.tiAlert ? window.tiAlert(msg) : alert(msg);\n                const pass = gE('l-pass') || gE('ti-direct-login-pass');\n                if (pass) try { pass.focus(); } catch(e) {}\n            } else {\n                window.tiAlert ? window.tiAlert('Errore: ' + msg) : alert('Errore: ' + msg);\n            }\n        }).catch(function(err){\n            const msg = err && err.message ? err.message : 'Errore invio richiesta password.';\n            window.tiAlert ? window.tiAlert('Errore recupero password: ' + msg) : alert('Errore recupero password: ' + msg);\n        }).finally(function(){\n            if (btn) { btn.disabled = false; btn.textContent = oldText || 'Password dimenticata? Cambia tramite email'; }\n        });\n        return false;\n    };\n\n\n    window.tiBindStableLoginUsername = function() {\n        try {\n            const bindPair = function(userId, passId) {\n                const u = gE(userId);\n                const p = gE(passId);\n                if (!u || !p || p.dataset.tiStableUserBound) return;\n                p.dataset.tiStableUserBound = '1';\n                const remember = function() {\n                    try {\n                        u.dataset.tiStableUsername = String(u.value || '');\n                    } catch(e) {}\n                };\n                const restore = function() {\n                    try {\n                        const stable = String(u.dataset.tiStableUsername || '');\n                        if (stable !== '' && document.activeElement === p && String(u.value || '') !== stable) {\n                            u.value = stable;\n                            u.dispatchEvent(new Event('input', {bubbles:true}));\n                            u.dispatchEvent(new Event('change', {bubbles:true}));\n                        }\n                    } catch(e) {}\n                };\n                const scheduleRestore = function() {\n                    try {\n                        if (!u.dataset.tiStableUsername) remember();\n                        [0, 40, 120, 300, 700].forEach(function(ms){ setTimeout(restore, ms); });\n                    } catch(e) {}\n                };\n                ['input','change','blur'].forEach(function(ev){\n                    u.addEventListener(ev, remember, false);\n                });\n                ['focus','keydown','input','paste','keyup'].forEach(function(ev){\n                    p.addEventListener(ev, scheduleRestore, false);\n                });\n                remember();\n            };\n            bindPair('l-user', 'l-pass');\n            bindPair('ti-direct-login-user', 'ti-direct-login-pass');\n        } catch(e) {}\n    };\n\n\n    window.bindMobileLoginButton = function() {\n        try {\n            const form = gE('ti-login-form');\n            const btn = gE('l-do');\n            const openBtn = gE('ti-login-btn');\n            const outBtn = gE('ti-logout-btn');\n            if (form && !form.dataset.tiSubmitBound) {\n                form.dataset.tiSubmitBound = '1';\n                form.addEventListener('submit', function(ev){ ev.preventDefault(); ev.stopPropagation(); if (window.doLogin) window.doLogin(); return false; }, false);\n            }\n            if (btn && !btn.dataset.tiClickBound) {\n                btn.dataset.tiClickBound = '1';\n                btn.addEventListener('click', function(ev){ ev.preventDefault(); ev.stopPropagation(); if (window.doLogin) window.doLogin(); return false; }, false);\n            }\n            if (openBtn && !openBtn.dataset.tiClickBound) {\n                openBtn.dataset.tiClickBound = '1';\n                const openPrimaryLogin = function(){ if (window.openLoginModalSafe) window.openLoginModalSafe(); else if (window.openModal) window.openModal('ti-login-ov'); };\n                openBtn.addEventListener('click', function(ev){ ev.preventDefault(); ev.stopPropagation(); openPrimaryLogin(); return false; }, false);\n                openBtn.addEventListener('touchend', function(ev){ ev.preventDefault(); ev.stopPropagation(); openPrimaryLogin(); return false; }, {passive:false});\n            }\n            if (outBtn && !outBtn.dataset.tiClickBound) {\n                outBtn.dataset.tiClickBound = '1';\n                outBtn.addEventListener('click', function(ev){ ev.preventDefault(); ev.stopPropagation(); if (window.doLogout) window.doLogout(); return false; }, false);\n                outBtn.addEventListener('touchend', function(ev){ ev.preventDefault(); ev.stopPropagation(); if (window.doLogout) window.doLogout(); return false; }, {passive:false});\n            }\n            if (window.syncLoginDbSelect) window.syncLoginDbSelect();\n            if (window.tiBindStableLoginUsername) window.tiBindStableLoginUsername();\n        } catch(e) {}\n    };\n    try {\n        \/\/ 30.9.1997: un errore SSGlobalAdmin non deve riaprire automaticamente il popup login.\n        \/\/ Il vecchio timer a 250 ms poteva partire prima che la URL fosse ripulita e lasciare\n        \/\/ ti-login-ov sopra la Main senza piu alcun marker di errore riconoscibile.\n        var tiLoginParams1997 = new URLSearchParams(window.location.search || '');\n        var tiGlobalLoginError1997 = tiLoginParams1997.has('ti_login_error') && String(tiLoginParams1997.get('ti_login_scope') || '').toLowerCase() === 'global';\n        if (tiLoginParams1997.has('ti_login_error') && !tiGlobalLoginError1997) {\n            setTimeout(function(){ if (window.openLoginModalSafe) window.openLoginModalSafe(); else if (window.openModal) window.openModal('ti-login-ov'); }, 250);\n        }\n        setTimeout(window.bindMobileLoginButton, 0);\n        setTimeout(window.bindMobileLoginButton, 800);\n        setTimeout(window.bindMobileLoginButton, 1800);\n        document.addEventListener('DOMContentLoaded', window.bindMobileLoginButton, {once:true});\n    } catch(e) {}\n\n    window.tiMobileUnlockScroll = function() {\n        try {\n            if (window.tiIsMobileLike && !window.tiIsMobileLike()) return;\n            document.documentElement.classList.remove('ti-no-scroll');\n            document.body.classList.remove('ti-no-scroll');\n            document.documentElement.style.overflowY = 'auto';\n            document.body.style.overflowY = 'auto';\n            document.documentElement.style.overflowX = 'hidden';\n            document.body.style.overflowX = 'hidden';\n            document.documentElement.style.height = 'auto';\n            document.body.style.height = 'auto';\n            document.documentElement.style.position = 'static';\n            document.body.style.position = 'static';\n            document.documentElement.style.touchAction = 'pan-y';\n            document.body.style.touchAction = 'pan-y';\n            const root = document.getElementById('ti-ai-outer');\n            if (root) {\n                root.style.overflowY = 'visible';\n                root.style.touchAction = 'pan-y';\n                root.style.webkitOverflowScrolling = 'touch';\n            }\n        } catch(e) {}\n    };\n    try {\n        window.addEventListener('pageshow', window.tiMobileUnlockScroll, {passive:true});\n        window.addEventListener('resize', window.tiMobileUnlockScroll, {passive:true});\n        if (window.visualViewport) window.visualViewport.addEventListener('resize', window.tiMobileUnlockScroll, {passive:true});\n        document.addEventListener('touchstart', window.tiMobileUnlockScroll, {passive:true});\n    } catch(e) {}\n\n    window.forceSessionCloseNow = function() {\n        window.idleForceClosing = true;\n        if (window.clearIdleTimers) window.clearIdleTimers();\n        try { document.cookie = 'ti_ai_ss_session=; Max-Age=0; path=\/; SameSite=Lax'; document.cookie = 'ti_ai_ss_session_2042=; Max-Age=0; path=\/; SameSite=Lax'; } catch(e) {}\n        try {\n            if (gE('ti-chat-box')) gE('ti-chat-box').innerHTML = '';\n            if (gE('ti-msg')) gE('ti-msg').value = '';\n            if (gE('ti-user-name')) gE('ti-user-name').textContent = 'Cliente\/Utente';\n            if (gE('ti-user-role')) gE('ti-user-role').textContent = '';\n        } catch(e) {}\n        const hardReload = function(){ try { location.reload(); } catch(e) { window.location.href = window.location.href.split('#')[0]; } };\n        const failSafe = setTimeout(hardReload, 1500);\n        try {\n            const fd = new FormData();\n            fd.append('ti_action','ti_ai_logout');\n            fd.append('action','ti_ai_logout');\n            fetch(window.tiUrl, {method:'POST', body:fd, credentials:'same-origin', keepalive:true})\n                .then(function(){ clearTimeout(failSafe); hardReload(); })\n                .catch(function(){ clearTimeout(failSafe); hardReload(); });\n        } catch(e) {\n            clearTimeout(failSafe); hardReload();\n        }\n    };\n\n    window.doLogout = function(silentReset = false) {\n        window.idleForceClosing = true;\n        clearTimeout(window.idleTimer1); clearTimeout(window.idleTimer2); clearTimeout(window.idleTimer3);\n        const hardReload = function(){\n            try {\n                if (gE('ti-chat-box')) gE('ti-chat-box').innerHTML = '';\n                if (gE('ti-msg')) gE('ti-msg').value = '';\n                if (gE('ti-user-name')) gE('ti-user-name').textContent = 'Cliente\/Utente';\n                if (gE('ti-user-role')) gE('ti-user-role').textContent = '';\n                try {\n                    var pathParts1059 = window.location.pathname.split('\/').filter(function(p){ return p.length; });\n                    var pathsToClear1059 = ['\/'];\n                    var cur1059 = '';\n                    for (var i1059 = 0; i1059 < Math.min(pathParts1059.length, 6); i1059++) {\n                        cur1059 += '\/' + pathParts1059[i1059];\n                        pathsToClear1059.push(cur1059 + '\/');\n                    }\n                    pathsToClear1059.forEach(function(p1059){\n                        document.cookie = 'ti_ai_ss_session=; Max-Age=0; path=' + p1059 + '; SameSite=Lax';\n                    });\n                } catch (eCookiePaths1059) {\n                    document.cookie = 'ti_ai_ss_session=; Max-Age=0; path=\/; SameSite=Lax';\n                }\n                ['ti-show-upload-log-1035', 'ti-show-server-diag-1043'].forEach(function(bid){ var b = gE(bid); if (b) b.remove(); });\n            } catch(e) {}\n            try { location.reload(); } catch(e) { window.location.href = window.location.href.split('#')[0]; }\n        };\n        const failSafe = setTimeout(hardReload, 6000);\n        const makeLogoutFd = function(actionName) {\n            const fd = new FormData();\n            fd.append('ti_action', actionName || 'ti_ai_logout');\n            fd.append('action', actionName || 'ti_ai_logout');\n            fd.append('_ti_mobile_ts', String(Date.now()));\n            return fd;\n        };\n        const postSafe = function(actionName) {\n            const urls = [];\n            if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n            if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n            const run = function(i) {\n                const fd = makeLogoutFd(actionName);\n                if (window.postFormDataJsonSafe) {\n                    return window.postFormDataJsonSafe(urls[i] || window.tiUrl, fd, {tiNoLongProcessSignal:true, cache:'no-store'}).catch(function(err){\n                        if (i + 1 < urls.length) return run(i + 1);\n                        throw err;\n                    });\n                }\n                return fetch(urls[i] || window.tiUrl, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'}).catch(function(err){\n                    if (i + 1 < urls.length) return run(i + 1);\n                    throw err;\n                });\n            };\n            return run(0);\n        };\n        postSafe('ti_ai_logout').then(function(){\n            if (silentReset) return postSafe('ti_ai_reset_flow');\n        }).finally(function(){ clearTimeout(failSafe); hardReload(); });\n    };\n\n    window.doRestart = function() { window.tiConfirm(dict[window.currLang].restartConfirm, function(){ window.doLogout(true); }); };\n\n\n    window.resetNewRegistrationProfileForm = function() {\n        const clearIds = ['p-utente','p-user','p-pass','p-ragione_sociale','p-email','p-tel','p-ind','p-piva_vat','p-cod_fisc','p-ade','p-sesso','p-dato_1','p-dato_2','p-dato_3','p-nota','p-foto'];\n        clearIds.forEach(function(id){\n            const el = gE(id);\n            if (!el) return;\n            try {\n                if (el.type === 'checkbox' || el.type === 'radio') el.checked = false;\n                else el.value = '';\n                if (id === 'p-pass' || \/pass\/i.test(id)) el.setAttribute('autocomplete', 'new-password');\n                else el.setAttribute('autocomplete', 'off');\n                if (el.removeAttribute) el.removeAttribute('value');\n                window.forceWhiteEditStyle && window.forceWhiteEditStyle(el);\n            } catch(e) {}\n        });\n        const eta = gE('p-eta');\n        if (eta) { eta.value = ''; eta.setAttribute('autocomplete', 'off'); }\n        ['p-com_mail','p-com_email','p-com_sms','p-com_tel'].forEach(function(id){ const el = gE(id); if (el) el.checked = true; });\n        const user = gE('p-user'); if (user) { user.readOnly = false; user.value = ''; }\n        const pass = gE('p-pass'); if (pass) { pass.required = true; pass.value = ''; }\n        const prev = gE('p-foto-preview'); if (prev) { prev.removeAttribute('src'); prev.style.display = 'none'; }\n        const form = gE('ti-profile-form'); if (form) form.setAttribute('autocomplete', 'off');\n    };\n\n    window.openProfileModal = function(isNew = false) {\n        const ditta = gE('ti-ditta'); if(!ditta || !ditta.value || ditta.value === 'NEW_DB' || ditta.value === '') { window.tiAlert(\"Seleziona una ditta prima di registrarti.\"); return; }\n        gE('lbl-profile-title').innerText = isNew ? \"Crea Profilo Cliente\/Utente\" : \"Dati Cliente\/Utente\";\n        gE('lbl-p-pass').innerText = isNew ? \"Password*\" : \"Nuova Password (lascia vuoto per mantenere)\";\n        gE('p-pass').required = isNew;\n        \n        const cancelBtn = gE('ti-profile-cancel-btn');\n        if(isNew) {\n            if (cancelBtn) cancelBtn.style.display = 'none';\n            window.resetNewRegistrationProfileForm();\n            window.openModal('ti-profile-ov');\n            window.resetNewRegistrationProfileForm();\n            setTimeout(window.resetNewRegistrationProfileForm, 80);\n            setTimeout(window.resetNewRegistrationProfileForm, 350);\n            window.bindProfileUsernameDuplicatePopup && window.bindProfileUsernameDuplicatePopup();\n        } else {\n            if (cancelBtn) cancelBtn.style.display = '';\n            gE('p-user').value = window.tiUser; gE('p-user').readOnly = true; gE('p-utente').value = window.tiUserDisplay;\n            if(window.tiUserFoto) { gE('p-foto').value = window.tiUserFoto; const fotoDb = window.tiUserFotoDb || gE('ti-ditta').value; const safeUserFoto = window.getSafePreviewUrl(window.tiUserFoto, fotoDb, 'Utenti', 'Immagine', (gE('p-user').value || window.tiUser || 'utente')); if(safeUserFoto){ gE('p-foto-preview').src = safeUserFoto; gE('p-foto-preview').style.display = 'block'; } else { gE('p-foto-preview').style.display = 'none'; } }\n            \n            const fd = new FormData(); fd.append('ti_action', 'ti_ai_get_db_data'); fd.append('db', ditta.value);\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n                if(d.success && d.data && d.data.Tabelle && d.data.Tabelle.Utenti) {\n                    let myU = d.data.Tabelle.Utenti.find(u => (u.Username||u.user||'').toLowerCase() === window.tiUser.toLowerCase());\n                    if(myU) {\n                        if(gE('p-utente')) gE('p-utente').value = myU['Utente'] || myU['Nome'] || window.tiUserDisplay;\n                        if(gE('p-email')) gE('p-email').value = myU['Email'] || '';\n                        if(gE('p-ragione_sociale')) gE('p-ragione_sociale').value = myU['Ragione sociale'] || '';\n                        if(gE('p-ind')) gE('p-ind').value = myU['Indirizzo'] || '';\n                        if(gE('p-piva_vat')) gE('p-piva_vat').value = myU['PIVA_VAT'] || myU['P.IVA'] || '';\n                        if(gE('p-cod_fisc')) gE('p-cod_fisc').value = myU['COD_FISC'] || '';\n                        if(gE('p-ade')) gE('p-ade').value = myU['ADE'] || '';\n                        if(gE('p-tel')) gE('p-tel').value = myU['Telefono'] || myU['Tel'] || '';\n                        if(gE('p-sesso')) gE('p-sesso').value = myU['Sesso'] || '';\n                        if(gE('p-eta')) gE('p-eta').value = myU['Et\u00e0'] || '0';\n                        if(gE('p-dato_1')) gE('p-dato_1').value = myU['Dato 1'] || '';\n                        if(gE('p-dato_2')) gE('p-dato_2').value = myU['Dato 2'] || '';\n                        if(gE('p-dato_3')) gE('p-dato_3').value = myU['Dato 3'] || '';\n                        if(gE('p-nota')) gE('p-nota').value = myU['Nota'] || '';\n                        if(gE('p-com_mail')) gE('p-com_mail').checked = (myU['Com Mail'] !== 'NO');\n                        if(gE('p-com_email')) gE('p-com_email').checked = (myU['Com Email'] !== 'NO');\n                        if(gE('p-com_sms')) gE('p-com_sms').checked = (myU['Com SMS'] !== 'NO');\n                        if(gE('p-com_tel')) gE('p-com_tel').checked = (myU['Com Tel'] !== 'NO');\n                    }\n                }\n                window.openModal('ti-profile-ov');\n                window.bindProfileUsernameDuplicatePopup && window.bindProfileUsernameDuplicatePopup();\n            });\n        }\n    };\n\n    window.createDbSubmit = function(ev) {\n        if (ev) {\n            try { ev.preventDefault(); } catch(e) {}\n            try { ev.stopPropagation(); } catch(e) {}\n        }\n\n        const form = gE('ti-new-db-form') || (gE('nd-name') && gE('nd-name').closest ? gE('nd-name').closest('form') : null);\n        const btn = gE('ti-new-db-submit') || (form ? form.querySelector('button[type=\"submit\"],input[type=\"submit\"]') : null);\n        const statusBox = gE('ti-new-db-status');\n        let redirecting = false;\n\n        function setStatus(message, type) {\n            if (!statusBox) return;\n            statusBox.style.display = message ? 'block' : 'none';\n            statusBox.style.borderColor = type === 'error' ? '#ef4444' : (type === 'ok' ? '#10b981' : '#2563eb');\n            statusBox.style.color = type === 'error' ? '#fecaca' : (type === 'ok' ? '#bbf7d0' : '#dbeafe');\n            statusBox.textContent = message || '';\n        }\n        function resetButton() {\n            if (!btn) return;\n            btn.disabled = false;\n            btn.style.pointerEvents = 'auto';\n            btn.style.opacity = '1';\n            btn.textContent = 'Crea e Accedi';\n        }\n        function fail(message) {\n            const msg = String(message || 'Errore creazione ditta.');\n            setStatus(msg, 'error');\n            if (window.tiAlert) window.tiAlert(msg);\n            else window.alert(msg);\n        }\n        function uniqueUrls() {\n            const urls = [];\n            \/\/ 30.9.1930: usa prima il router diretto Shop & Service. Su questo hosting\n            \/\/ admin-ajax puo essere molto piu lento e non deve ritardare l avvio di Nuova ditta.\n            [window.tiUrl, window.location.href.split('#')[0], window.tiAjaxUrl, window.ajaxurl].forEach(function(url){\n                url = String(url || '').trim();\n                if (url && urls.indexOf(url) === -1) urls.push(url);\n            });\n            return urls;\n        }\n        function buildPayload(dbName, uName, uPass, uEmail) {\n            const fd = window.buildAjaxFormData ? window.buildAjaxFormData('ti_ai_create_db') : new FormData();\n            if (!fd.has('action')) fd.append('action', 'ti_ai_create_db');\n            if (!fd.has('ti_action')) fd.append('ti_action', 'ti_ai_create_db');\n            fd.set('name', dbName);\n            fd.set('username', uName);\n            fd.set('password', uPass);\n            fd.set('nome', uName);\n            fd.set('email', uEmail);\n            fd.set('_ti_create_company_1483', String(Date.now()));\n            return fd;\n        }\n        function sendAt(urls, index, values, previousError) {\n            if (index >= urls.length) return Promise.reject(previousError || new Error('Nessun endpoint disponibile.'));\n            const fd = buildPayload(values.dbName, values.uName, values.uPass, values.uEmail);\n            const options = {\n                method: 'POST',\n                body: fd,\n                credentials: 'same-origin',\n                cache: 'no-store',\n                tiNoLongProcessSignal: true,\n                tiTimeoutMs: 45000\n            };\n            let request;\n            if (window.fetchJsonSafe) {\n                request = window.fetchJsonSafe(urls[index], options);\n            } else {\n                const ctl1930 = (typeof AbortController !== 'undefined') ? new AbortController() : null;\n                let timer1930 = null;\n                if (ctl1930) timer1930 = setTimeout(function(){ try { ctl1930.abort(); } catch(e) {} }, 45000);\n                const nativeOptions1930 = Object.assign({}, options, {signal: ctl1930 ? ctl1930.signal : undefined});\n                request = fetch(urls[index], nativeOptions1930).then(function(response){\n                    return response.text().then(function(raw){\n                        if (!response.ok) throw new Error('HTTP ' + response.status + ': ' + raw.slice(0, 180));\n                        try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non valida: ' + raw.slice(0, 180)); }\n                    });\n                }).finally(function(){ if (timer1930) clearTimeout(timer1930); });\n            }\n            return request.catch(function(err){ return sendAt(urls, index + 1, values, err); });\n        }\n\n        if (window.__tiCreateDbRunning1483) {\n            const started1930 = Number(window.__tiCreateDbStartedAt1930 || 0);\n            if (started1930 > 0 && (Date.now() - started1930) < 60000) {\n                setStatus('Creazione ditta gia in corso. Attendi la risposta del server.', 'wait');\n                return false;\n            }\n            \/\/ Recupera un flag rimasto attivo dopo una richiesta abortita\/vecchia.\n            window.__tiCreateDbRunning1483 = false;\n            window.__tiCreateDbStartedAt1930 = 0;\n        }\n\n        const nameEl = gE('nd-name');\n        const userEl = gE('nd-user');\n        const passEl = gE('nd-pass');\n        const emailEl = gE('nd-email');\n        const dbName = nameEl ? String(nameEl.value || '').trim() : '';\n        const uName = userEl ? String(userEl.value || '').trim() : '';\n        const uPass = passEl ? String(passEl.value || '') : '';\n        const uEmail = emailEl ? String(emailEl.value || '').trim() : '';\n\n        if (!dbName || !uName || !uPass) {\n            fail('Compila Nome ditta, Username e Password.');\n            const first = !dbName ? nameEl : (!uName ? userEl : passEl);\n            if (first) setTimeout(function(){ try { first.focus(); } catch(e) {} }, 50);\n            return false;\n        }\n        if (uPass.length < 4) {\n            fail('La password deve contenere almeno 4 caratteri.');\n            if (passEl) setTimeout(function(){ try { passEl.focus(); } catch(e) {} }, 50);\n            return false;\n        }\n        if (emailEl && uEmail && typeof emailEl.checkValidity === 'function' && !emailEl.checkValidity()) {\n            fail('Indirizzo email non valido.');\n            setTimeout(function(){ try { emailEl.focus(); } catch(e) {} }, 50);\n            return false;\n        }\n\n        window.__tiCreateDbRunning1483 = true;\n        window.__tiCreateDbStartedAt1930 = Date.now();\n        if (btn) {\n            btn.disabled = true;\n            btn.style.pointerEvents = 'none';\n            btn.style.opacity = '0.78';\n            btn.textContent = 'Creazione in corso...';\n        }\n        setStatus('Creazione archivio e accesso automatico in corso. Non chiudere la finestra.', 'wait');\n\n        const values = {dbName: dbName, uName: uName, uPass: uPass, uEmail: uEmail};\n        sendAt(uniqueUrls(), 0, values, null).then(function(d){\n            if (!d || !d.success) {\n                const msg = d && d.data && d.data.message ? d.data.message : 'Errore creazione ditta.';\n                throw new Error(msg);\n            }\n            const data = d.data || {};\n            const newDb = String(data.db || '').trim();\n            if (!newDb) throw new Error('Ditta creata ma nome archivio non restituito dal server.');\n\n            try {\n                localStorage.setItem('ti_saved_db', newDb);\n                localStorage.setItem('ti_last_login_db', newDb);\n                localStorage.setItem('ti_last_login_user', String(data.username || uName));\n                \/\/ 30.9.1775: una nuova ditta nasce in Configurazione; forza l elenco completo e una rilettura no-cache al rientro.\n                localStorage.setItem('ti_ditte_state_filter', 'all');\n                localStorage.setItem('ti_show_suspended_ditte', '1');\n                sessionStorage.setItem('ti_force_company_list_refresh_1775', newDb);\n                sessionStorage.removeItem('tiPendingNewDb');\n                sessionStorage.removeItem('tiNewDbOpen');\n            } catch(e) {}\n\n            setStatus(String(data.msg || 'Ditta creata. Accesso automatico in corso...'), 'ok');\n            if (btn) btn.textContent = 'Accesso in corso...';\n            redirecting = true;\n            window.__tiCreateDbRedirecting2075 = true;\n\n            let redirect = String(data.redirect || '').trim();\n            if (!redirect) {\n                try {\n                    const u = new URL(window.tiUrl || window.location.href, window.location.href);\n                    u.searchParams.set('ti_ai_db', newDb);\n                    u.searchParams.set('ti_new_company', '1');\n                    u.searchParams.set('ti_v', String(Date.now()));\n                    redirect = u.toString();\n                } catch(e) {\n                    redirect = (window.tiUrl || window.location.href.split('?')[0]) + '?ti_ai_db=' + encodeURIComponent(String(newDb||'')).replace(\/[!'()*]\/g,function(c){return '%'+c.charCodeAt(0).toString(16).toUpperCase();}) + '&ti_new_company=1&ti_v=' + Date.now();\n                }\n            }\n            setTimeout(function(){ window.location.replace(redirect); }, 120);\n        }).catch(function(err){\n            const msg = err && err.message ? err.message : 'Errore di connessione durante la creazione della ditta.';\n            fail(msg);\n            if (\/username\/i.test(msg) && \/(gi\u00e0|gia|esistent|uso|duplicat)\/i.test(msg) && userEl) {\n                setTimeout(function(){ try { userEl.focus(); userEl.select && userEl.select(); } catch(e) {} }, 120);\n            }\n        }).finally(function(){\n            window.__tiCreateDbRunning1483 = false;\n            window.__tiCreateDbStartedAt1930 = 0;\n            if (!redirecting) resetButton();\n        });\n        return false;\n    };\n\n    window.tiBindNewDbForm1483 = function() {\n        const form = gE('ti-new-db-form');\n        if (!form) return;\n        if (form.dataset.tiCreateBound1483 !== '1') {\n            form.dataset.tiCreateBound1483 = '1';\n            form.addEventListener('submit', function(ev){ return window.createDbSubmit(ev); }, true);\n        }\n        \/\/ 30.9.1930: avvio esplicito anche dal click. Alcuni wrapper\/modal legacy possono\n        \/\/ intercettare il submit nativo prima che arrivi al gestore della form.\n        const createBtn1930 = gE('ti-new-db-submit');\n        if (createBtn1930 && createBtn1930.dataset.tiCreateClick1930 !== '1') {\n            createBtn1930.dataset.tiCreateClick1930 = '1';\n            createBtn1930.addEventListener('click', function(ev){\n                try {\n                    if (form.reportValidity && !form.reportValidity()) return;\n                } catch(e) {}\n                try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n                return window.createDbSubmit(ev);\n            }, true);\n        }\n    };\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', window.tiBindNewDbForm1483, {once:true});\n    else window.tiBindNewDbForm1483();\n\n    if(gE('p-foto')) gE('p-foto').addEventListener('change', function() { \n        const prev = gE('p-foto-preview'); \n        if(this.value) { \n            prev.src = window.getSafePreviewUrl(this.value, gE('ti-ditta').value, 'Utenti', 'Immagine', (gE('p-user').value || window.tiUser || 'utente')); \n            prev.style.display = 'block'; \n        } else { prev.style.display = 'none'; } \n    });\n\n    window.saveProfile = function() {\n        const submitBtn = gE('ti-profile-save-btn') || document.querySelector('#ti-profile-form button[type=\"submit\"]');\n        if (submitBtn) { submitBtn.disabled = true; submitBtn.innerText = 'Salvataggio...'; }\n        const fd = new FormData(); fd.append('ti_action','ti_ai_save_profile'); fd.append('db', gE('ti-ditta').value); \n        fd.append('utente', gE('p-utente').value); fd.append('username', gE('p-user').value); fd.append('password', gE('p-pass').value); \n        fd.append('ragione_sociale', gE('p-ragione_sociale').value); fd.append('email', gE('p-email').value); fd.append('tel', gE('p-tel').value); \n        fd.append('indirizzo', gE('p-ind').value); fd.append('piva_vat', gE('p-piva_vat').value); fd.append('cod_fisc', gE('p-cod_fisc').value); \n        fd.append('ade', gE('p-ade').value); fd.append('sesso', gE('p-sesso').value); fd.append('eta', gE('p-eta').value); \n        fd.append('dato_1', gE('p-dato_1').value); fd.append('dato_2', gE('p-dato_2').value); fd.append('dato_3', gE('p-dato_3').value); \n        fd.append('com_mail', gE('p-com_mail').checked ? 'SI' : 'NO'); fd.append('com_email', gE('p-com_email').checked ? 'SI' : 'NO'); \n        fd.append('com_sms', gE('p-com_sms').checked ? 'SI' : 'NO'); fd.append('com_tel', gE('p-com_tel').checked ? 'SI' : 'NO'); \n        fd.append('nota', gE('p-nota').value); fd.append('foto', gE('p-foto').value); fd.append('immagine', gE('p-foto').value);\n        window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n            if(d.success) { window.tiAlert(d.data.msg); location.reload(); }\n            else {\n                if (submitBtn) { submitBtn.disabled = false; submitBtn.innerText = 'Salva'; }\n                const msg = (d && d.data && d.data.message) ? d.data.message : 'Errore salvataggio profilo.';\n                if (\/username\/i.test(msg) && \/(gi\u00e0|gia|esistent|uso|duplicat)\/i.test(msg)) {\n                    const userEl = gE('p-user');\n                    window.tiAlert('Username gi\u00e0 esistente.<br>Cambia username perch\u00e9 \u00e8 gi\u00e0 esistente.');\n                    if (userEl) {\n                        userEl.style.setProperty('border-color', '#ef4444', 'important');\n                        userEl.style.setProperty('box-shadow', '0 0 0 2px rgba(239,68,68,.55)', 'important');\n                        window.forceWhiteEditStyle && window.forceWhiteEditStyle(userEl);\n                        setTimeout(function(){ try { userEl.focus(); userEl.select && userEl.select(); } catch(e) {} }, 120);\n                    }\n                } else {\n                    window.tiAlert(msg);\n                }\n            }\n        }).catch(e=>{ if (submitBtn) { submitBtn.disabled = false; submitBtn.innerText = 'Salva'; } window.tiAlert('Errore di rete durante il salvataggio profilo.'); });\n    };\n\n    window.bindProfileUsernameDuplicatePopup = function() {\n        const el = gE('p-user');\n        if (!el || el.dataset.dupBound === '1') return;\n        el.dataset.dupBound = '1';\n        const run = function(){\n            if (el.readOnly) return;\n            const ov = gE('ti-profile-ov');\n            const regMode = !!(window.__tiProfileRegistrationMode384 || window.__tiProfileRegistrationMode385);\n            if (!regMode || !ov) return;\n            try { const cs = getComputedStyle(ov); if (cs.display === 'none' || cs.visibility === 'hidden') return; } catch(e) {}\n            const username = String(el.value || '').trim();\n            if (!username) return;\n            const currentUser = String(window.tiUser || window.currentUser || '').trim();\n            if (currentUser && currentUser.toLowerCase() === username.toLowerCase()) return;\n            if (window.currentDbData && window.currentDbData.Tabelle) {\n                const dup = window.findDuplicateUsernameInConfig ? window.findDuplicateUsernameInConfig(username, '', -1) : null;\n                if (dup) {\n                    window.showDuplicateUsernamePopup(username, dup);\n                    el.style.setProperty('border-color', '#ef4444', 'important');\n                    el.style.setProperty('box-shadow', '0 0 0 2px rgba(239,68,68,.55)', 'important');\n                    window.forceWhiteEditStyle && window.forceWhiteEditStyle(el);\n                }\n            }\n        };\n        el.addEventListener('change', run);\n        el.addEventListener('blur', run);\n        el.addEventListener('input', function(){ window.forceWhiteEditStyle && window.forceWhiteEditStyle(el); });\n    };\n\n    window.bindProfileUsernameDuplicatePopup();\n\n    window.cancelProfile = function() {\n        const username = gE('p-user') ? gE('p-user').value.trim() : '';\n        if (!username) { window.tiAlert('Nessun utente selezionato.'); return; }\n        window.tiConfirm('Confermi la cancellazione logica del profilo? Lo stato verra impostato su Cancellato.', function(){\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_delete_profile');\n            fd.append('db', gE('ti-ditta').value);\n            fd.append('username', username);\n            fd.append('mode', 'soft');\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n                if(d.success) {\n                    window.tiAlert(d.data.msg || 'Profilo cancellato.');\n                    if (d.data.logout) { setTimeout(()=> location.reload(), 400); }\n                    else { window.closeModal('ti-profile-ov'); location.reload(); }\n                } else {\n                    window.tiAlert(d.data.message || 'Errore durante la cancellazione del profilo.');\n                }\n            }).catch(()=> window.tiAlert('Errore di rete durante la cancellazione del profilo.'));\n        });\n    };\n\n    window.tiCompanyHelpEscape = function(v) {\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; });\n    };\n    window.tiGetCompanyConfigRow = function() {\n        const data = window.currentDbData || window.currentDbViewData || null;\n        const tables = data && data.Tabelle ? data.Tabelle : {};\n        const cfgRows = tables.Config || tables.config || tables.CONFIG || [];\n        return Array.isArray(cfgRows) && cfgRows[0] && typeof cfgRows[0] === 'object' ? cfgRows[0] : {};\n    };\n    window.tiPickCompanyVal = function(row, names) {\n        row = row || {};\n        const keys = Object.keys(row);\n        const norm = function(x){ return String(x || '').toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[_\\-]+\/g, ' ').replace(\/\\s+\/g, ' ').trim(); };\n        for (const name of names) {\n            if (Object.prototype.hasOwnProperty.call(row, name) && String(row[name] || '').trim() !== '') return String(row[name]).trim();\n            const wanted = norm(name);\n            const found = keys.find(k => norm(k) === wanted);\n            if (found && String(row[found] || '').trim() !== '') return String(row[found]).trim();\n        }\n        return '';\n    };\n    window.tiBuildCompanyInfoLinksHtml = function() {\n        const data = window.currentDbData || window.currentDbViewData || null;\n        const tables = data && data.Tabelle ? data.Tabelle : {};\n        const infoRows = tables.Informazioni || tables.informazioni || [];\n        if (!Array.isArray(infoRows)) return '';\n        const wanted = [\n            {key:'commerciali', label:'Condizioni commerciali', re:\/commercial|vendita|pagament|offert|listin|prezz|recess|reso|spedizion\/i},\n            {key:'contrattuali', label:'Condizioni contrattuali', re:\/contratt|termini|accord|fornitura|garanzi|clausol\/i},\n            {key:'privacy', label:'Privacy', re:\/privacy|gdpr|dati personal|informativa|cookie\/i}\n        ];\n        const found = {};\n        const clean = function(v){ return String(v == null ? '' : v).trim(); };\n        const firstUrl = function(txt) { const m = String(txt || '').match(\/https?:\\\/\\\/[^\\s<>'\")]+\/i); return m ? m[0].replace(\/[\\],.;]+$\/,'') : ''; };\n        infoRows.forEach(function(row){\n            if (!row || typeof row !== 'object') return;\n            const flat = Object.keys(row).map(k => k + ' ' + clean(row[k])).join(' ');\n            const tipo = clean(row.Tipo || row.tipo || row.Type || '').toUpperCase();\n            const doc = clean(row.Doc || row.Docs || row.File || row.URL || row.Url || row.Link || row.Descrizione || '');\n            const url = firstUrl(doc) || firstUrl(flat);\n            wanted.forEach(function(w){\n                if (found[w.key]) return;\n                if ((tipo === 'DOC' || tipo === 'URL' || tipo === 'WEB' || tipo === '') && w.re.test(flat)) {\n                    found[w.key] = url ? `<a href=\"${window.tiCompanyHelpEscape(url)}\" target=\"_blank\" rel=\"noopener\" style=\"color:#93c5fd;text-decoration:underline;\">${w.label}<\/a>` : `<span style=\"color:#cbd5e1;\">${w.label}<\/span>`;\n                }\n            });\n        });\n        const links = wanted.map(w => found[w.key]).filter(Boolean);\n        return links.length ? `<div>${links.join(' &nbsp;|&nbsp; ')}<\/div>` : '';\n    };\n    window.tiUpdateColumnHelpCompanyHeader = function() {\n        const box = document.getElementById('col-help-company');\n        if (!box) return;\n        const cfg = window.tiGetCompanyConfigRow ? window.tiGetCompanyConfigRow() : {};\n        const pick = window.tiPickCompanyVal || function(){ return ''; };\n        const lines = [];\n        const rag = pick(cfg, ['Ragione sociale','Ragione Sociale','Ditta','Nome ditta']);\n        const indirizzo = pick(cfg, ['Indirizzo','Sede','Indirizzo ditta']);\n        const piva = pick(cfg, ['PIVA_VAT','PIVA VAT','Partita IVA','P. IVA','PIva','PIVA']);\n        const email = pick(cfg, ['Email ditta','Email principale','Email','E-mail','Mail']);\n        const tel = pick(cfg, ['Tel','Telefono','Telefono ditta','Cellulare']);\n        if (rag) lines.push(`<div><b>${window.tiCompanyHelpEscape(rag)}<\/b><\/div>`);\n        if (indirizzo) lines.push(`<div>${window.tiCompanyHelpEscape(indirizzo)}<\/div>`);\n        if (piva) lines.push(`<div>Partita IVA: ${window.tiCompanyHelpEscape(piva)}<\/div>`);\n        if (email) lines.push(`<div>Email: <a href=\"mailto:${window.tiCompanyHelpEscape(email)}\" style=\"color:#93c5fd;\">${window.tiCompanyHelpEscape(email)}<\/a><\/div>`);\n        if (tel) lines.push(`<div>Tel: <a href=\"tel:${window.tiCompanyHelpEscape(tel)}\" style=\"color:#93c5fd;\">${window.tiCompanyHelpEscape(tel)}<\/a><\/div>`);\n        const links = window.tiBuildCompanyInfoLinksHtml ? window.tiBuildCompanyInfoLinksHtml() : '';\n        if (links) lines.push(links);\n        box.innerHTML = lines.join('');\n        box.style.display = lines.length ? 'block' : 'none';\n        try { rewriteLocalDocAnchors(document.getElementById('ti-help-ov') || document); } catch(e) {}\n    };\n\n    window.tiSanitizeColumnHelpText357 = window.tiSanitizeColumnHelpText357 || function(text) {\n        return String(text || '')\n            .replace(\/[#*]+\/g, '')\n            .replace(\/[ \\t]+\\n\/g, '\\n')\n            .replace(\/\\n{3,}\/g, '\\n\\n')\n            .trim();\n    };\n    window.copyColumnHelpText357 = window.copyColumnHelpText357 || function() {\n        const modal = document.querySelector('#ti-col-help-ov .ti-modal');\n        const title = gE('col-help-title');\n        const company = gE('col-help-company');\n        const box = gE('col-help-content');\n        const btn = gE('ti-col-help-copy');\n        const cleanText = function(node) {\n            if (!node) return '';\n            try {\n                const clone = node.cloneNode(true);\n                clone.querySelectorAll('button, .ti-btn, script, style').forEach(function(el){ el.remove(); });\n                return String(clone.innerText || clone.textContent || '').replace(\/\\n{3,}\/g, '\\n\\n').trim();\n            } catch(e) { return String(node.innerText || node.textContent || '').trim(); }\n        };\n        let parts = [];\n        if (title) parts.push(cleanText(title));\n        if (company && String(company.innerText || company.textContent || '').trim() !== '') parts.push(cleanText(company));\n        if (box) parts.push(cleanText(box));\n        let text = parts.filter(Boolean).join('\\n\\n').trim();\n        if (!text && modal) text = cleanText(modal);\n        const done = function(ok){\n            if (!btn) return;\n            const old = btn.innerText;\n            btn.innerText = ok ? 'Testo copiato' : 'Copia non riuscita';\n            setTimeout(function(){ btn.innerText = old || 'Copia testo'; }, 1200);\n        };\n        if (!text) return done(false);\n        if (navigator.clipboard && navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){ done(false); });\n        } else {\n            try {\n                const ta = document.createElement('textarea');\n                ta.value = text; ta.style.position = 'fixed'; ta.style.left = '-9999px';\n                document.body.appendChild(ta); ta.focus(); ta.select();\n                const ok = document.execCommand('copy'); document.body.removeChild(ta); done(!!ok);\n            } catch(e) { done(false); }\n        }\n    };\n\n    window.tiColumnHelpFallbackHtml436 = function(cleanTbl, cleanCol, helpIsEn, helpRequest) {\n        const esc = window.tiCompanyHelpEscape || function(v){ return String(v || '').replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#039;'}[c]; }); };\n        const norm = function(v){ try { return String(v || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').toLowerCase().replace(\/[^a-z0-9]+\/g,''); } catch(e){ return String(v||'').toLowerCase().replace(\/[^a-z0-9]+\/g,''); } };\n        const tblNorm = norm(cleanTbl), colNorm = norm(cleanCol);\n        const desc = (cleanCol && window.getConfigFieldDescription) ? window.getConfigFieldDescription(cleanTbl, cleanCol) : '';\n        const relationMeta = (cleanCol && window.getConfigRelationMeta) ? window.getConfigRelationMeta(cleanTbl, cleanCol, {}) : null;\n        let relationLine = '';\n        let relationExamples = '';\n        try {\n            if (relationMeta) {\n                const opts = window.getConfigRelationOptions ? window.getConfigRelationOptions(cleanTbl, cleanCol, {}, -1) : [];\n                const sourceLabel = relationMeta.sourceLabel || relationMeta.label || relationMeta.table || 'tabella sorgente';\n                relationLine = helpIsEn ? ('Suggested source: choose from ' + sourceLabel + '.') : ('Scelta consigliata: selezionare un valore da ' + sourceLabel + '.');\n                if (opts && opts.length) {\n                    relationExamples = opts.slice(0, 8).map(function(o){ return String((o && (o.label || o.value)) || '').trim(); }).filter(Boolean).join(', ');\n                } else {\n                    relationExamples = helpIsEn ? ('No active records found in ' + sourceLabel + '.') : ('Nessun record attivo trovato in ' + sourceLabel + '.');\n                }\n            }\n        } catch(e) {}\n        const pickCfg = function(names){\n            try {\n                const cfgTbl = window.findConfigTableName ? window.findConfigTableName('Config') : 'Config';\n                const rows = window.currentDbData && window.currentDbData.Tabelle ? window.currentDbData.Tabelle[cfgTbl] : [];\n                const row = Array.isArray(rows) ? (rows[0] || {}) : (Object.values(rows || {})[0] || {});\n                const keys = Object.keys(row || {});\n                for (const name of names) { const k = keys.find(x => norm(x) === norm(name)); if (k && row[k] != null && String(row[k]).trim() !== '') return String(row[k]).trim(); }\n            } catch(e) {}\n            return '';\n        };\n        const activity = pickCfg(['Attivita','Attivit\u00e0','Tipo attivit\u00e0','Settore']);\n        const exampleFromTable = function(){\n            try {\n                const rows = window.currentDbData && window.currentDbData.Tabelle ? window.currentDbData.Tabelle[cleanTbl] : [];\n                const arr = Array.isArray(rows) ? rows : Object.values(rows || {});\n                for (const r of arr) {\n                    if (!r || typeof r !== 'object') continue;\n                    const k = Object.keys(r).find(x => norm(x) === colNorm);\n                    if (k && String(r[k] == null ? '' : r[k]).trim() !== '') return String(r[k]).trim();\n                }\n            } catch(e) {}\n            return '';\n        };\n        const scrubHelpSensitive = function(v){\n            v = String(v || '').trim();\n            if (!v) return '';\n            v = v.replace(\/[A-Z0-9._%+\\-]+@[A-Z0-9.\\-]+\\.[A-Z]{2,}\/ig, '[email omessa]');\n            v = v.replace(\/\\b(?:https?:\\\/\\\/|www\\.)\\S+\/ig, '[link omesso]');\n            v = v.replace(\/\\b(?:\\+?39[\\s.\\-]?)?(?:\\d[\\s.\\-]?){8,13}\\b\/g, '[telefono omesso]');\n            v = v.replace(\/\\b(?:IT)?\\s*\\d{11}\\b\/ig, '[PIVA omessa]');\n            v = v.replace(\/\\b[A-Z]{6}\\d{2}[A-Z]\\d{2}[A-Z]\\d{3}[A-Z]\\b\/ig, '[codice fiscale omesso]');\n            return v.trim();\n        };\n        const sensitiveField = function(name){\n            const n = norm(name);\n            return \/(ditta|ragionesociale|nome|cognome|utente|username|password|email|tel|telefono|cellulare|indirizzo|piva|partitaiva|codfisc|codicefiscale|iban|bic|beneficiary|bankname|clientid|clientsecret|webhookid|activeid|wcorderid)\/.test(n);\n        };\n        let example = relationExamples || exampleFromTable();\n        if (cleanCol && sensitiveField(cleanCol)) example = '';\n        example = scrubHelpSensitive(example);\n        if (\/\\[(email|telefono|PIVA|codice fiscale|IBAN) omess[ao]\\]\/i.test(example)) example = '';\n        const operationalExample = function(){\n            const key = tblNorm + ':' + colNorm;\n            const gen = helpIsEn ? {\n                'prodotti:prodotto':'Operational example: use a short recognizable product name, then keep description, price, VAT, availability and commercial instructions in their own fields.',\n                'prodotti:istruzioni':'Manual-based example: \"10% discount until 30\/04\/2026\". Keep temporary rules in Instructions and do not change the base price if the discount is temporary.',\n                'prodotti:disponibilita':'Operational example: enter real availability or a coherent quantity; if unavailable, the flow may propose a pre-booking or contact request.',\n                'prodotti:quantita':'Operational example: update the real available quantity and verify that orders and availability use the corrected value.',\n                'servizi:servizio':'Operational example: use a clear service name; complete duration, price, available days\/times and linked resources if the service is bookable.',\n                'servizi:prodotto':'Operational example: link the product or material used by the service from Products; in similar setups, only resources truly needed to deliver the service are linked.',\n                'servizi:prodotti':'Operational example: link one or more products\/materials required by the service, avoiding generic values not present in the catalog.',\n                'servizi:operatore':'Operational example: link an operator only when the service requires a specific skill or resource; otherwise it may remain available for compatible operators.',\n                'servizi:dispositivo':'Operational example: link a technical resource only when it blocks slot availability, such as equipment, workstation or technical room.',\n                'servizi:sito':'Operational example: enter the site when the service can be delivered only in a specific office, room or department.',\n                'servizi:istruzioni':'Manual-based example: add rules such as consent required, temporary promotion, user preparation or booking constraints.'\n            } : {\n                'prodotti:prodotto':'Esempio operativo: usare un nome breve e riconoscibile, poi gestire descrizione, prezzo, IVA, disponibilit\u00e0 e istruzioni commerciali nei rispettivi campi.',\n                'prodotti:istruzioni':'Esempio operativo dal manuale: \"Sconto 10% fino al 30\/04\/2026\". La regola deve restare nel campo Istruzioni e non modificare il prezzo base se \u00e8 temporanea.',\n                'prodotti:disponibilita':'Esempio operativo: indicare una disponibilit\u00e0 reale o una quantit\u00e0 coerente; se il prodotto non \u00e8 disponibile, il flusso pu\u00f2 proporre pre-prenotazione o contatto.',\n                'prodotti:quantita':'Esempio operativo: aggiornare la quantit\u00e0 reale disponibile e verificare che ordini e disponibilit\u00e0 mostrino il dato corretto.',\n                'servizi:servizio':'Esempio operativo: usare un nome servizio chiaro; completare durata, prezzo, giorni\/orari disponibili e risorse collegate se il servizio \u00e8 prenotabile.',\n                'servizi:prodotto':'Esempio operativo: associare il prodotto o materiale usato dal servizio scegliendolo da Prodotti; nei casi analoghi si collega solo ci\u00f2 che serve davvero per erogare il servizio.',\n                'servizi:prodotti':'Esempio operativo: associare uno o pi\u00f9 materiali\/prodotti necessari al servizio, evitando valori generici non presenti in catalogo.',\n                'servizi:operatore':'Esempio operativo: collegare un operatore solo quando il servizio richiede una competenza o una risorsa precisa; altrimenti il servizio pu\u00f2 restare disponibile per gli operatori compatibili.',\n                'servizi:dispositivo':'Esempio operativo: collegare una risorsa tecnica solo se blocca la disponibilit\u00e0 dello slot, ad esempio attrezzatura, postazione o sala tecnica.',\n                'servizi:sito':'Esempio operativo: indicare il sito quando il servizio pu\u00f2 essere eseguito solo in una sede, stanza o reparto specifico.',\n                'servizi:istruzioni':'Esempio operativo dal manuale: inserire regole come consenso informato, promozione temporanea, preparazione utente o vincoli di prenotazione.'\n            };\n            const tableGen = helpIsEn ? {\n                dispositivi:'Operational example: register equipment, workstations, technical rooms or instruments that can enable or restrict a service or appointment.',\n                siti:'Operational example: use this table for offices, rooms, departments or service locations, linking them to services when they affect availability or user directions.',\n                operatori:'Operational example: fill skills, availability and instructions for the operator; do not use this table for non-operational data.',\n                appuntamenti:'Operational example: a slot should include date, time and busy resources; only active or confirmed statuses should block availability.',\n                prenotazioni:'Operational example: store requests or pre-bookings with context, status and notes, confirming them only when data is complete.',\n                istruzioni:'Manual-based example: a temporary rule should state what to do and until when, such as a discount, priority or operational constraint.',\n                informazioni:'Operational example: use information records or documents to give the AI verifiable content about products, services, conditions or procedures.',\n                attivita:'Operational example: track results and operational events, separating customer activity, configuration and management checks.'\n            } : {\n                dispositivi:'Esempio operativo: registrare attrezzature, postazioni, sale tecniche o strumenti che possono limitare o abilitare un servizio o un appuntamento.',\n                siti:'Esempio operativo: usare la tabella per sedi, stanze, reparti o luoghi di erogazione, collegandoli ai servizi quando incidono su disponibilit\u00e0 o indicazioni utente.',\n                operatori:'Esempio operativo: indicare competenze, disponibilit\u00e0 e istruzioni dell\u2019operatore; non usare questa tabella per dati non operativi.',\n                appuntamenti:'Esempio operativo: uno slot deve riportare data, ora e risorse impegnate; solo stati attivi o confermati devono bloccare la disponibilit\u00e0.',\n                prenotazioni:'Esempio operativo: salvare richieste o pre-prenotazioni con contesto, stato e note operative, confermando solo quando i dati sono completi.',\n                istruzioni:'Esempio operativo dal manuale: una regola temporanea deve indicare cosa fare e fino a quando, ad esempio uno sconto, una priorit\u00e0 o un vincolo operativo.',\n                informazioni:'Esempio operativo: usare record informativi o documenti per dare alla AI contenuti verificabili su prodotti, servizi, condizioni o procedure.',\n                attivita:'Esempio operativo: registrare esiti e tracciamenti operativi, distinguendo attivit\u00e0 cliente, configurazione e controlli gestionali.'\n            };\n            if (gen[key]) return gen[key];\n            if (!cleanCol && tableGen[tblNorm]) return tableGen[tblNorm];\n            if (example) return helpIsEn ? ('Operational example: use an existing valid value such as \"' + example + '\" only if it is still active.') : ('Esempio operativo: puoi usare un valore reale gi\u00e0 presente come \"' + example + '\" solo se \u00e8 ancora valido e attivo.');\n            return helpIsEn ? 'Operational example: use real data already present in the company database, avoiding company-identifying details unless the field explicitly requires them.' : 'Esempio operativo: usare dati reali gi\u00e0 presenti nella ditta, evitando dati anagrafici o identificativi se il campo non li richiede espressamente.';\n        };\n        const isProductField = tblNorm === 'prodotti' && colNorm === 'prodotto';\n        const isServiceProduct = tblNorm === 'servizi' && (colNorm === 'prodotto' || colNorm === 'prodotti' || \/^prodotto[123]$\/.test(colNorm));\n        const tableFields = function(){\n            try {\n                const rows = window.currentDbData && window.currentDbData.Tabelle ? window.currentDbData.Tabelle[cleanTbl] : [];\n                const arr = Array.isArray(rows) ? rows : Object.values(rows || {});\n                const r = arr.find(function(x){ return x && typeof x === 'object'; }) || {};\n                return Object.keys(r).map(function(k){ return String(k || '').trim(); }).filter(Boolean).slice(0, 20).join(', ');\n            } catch(e) { return ''; }\n        };\n        const tableExamples = function(){\n            try {\n                const rows = window.currentDbData && window.currentDbData.Tabelle ? window.currentDbData.Tabelle[cleanTbl] : [];\n                const arr = (Array.isArray(rows) ? rows : Object.values(rows || {})).filter(function(r){ return r && typeof r === 'object'; });\n                const out = [];\n                arr.slice(0, 3).forEach(function(r){\n                    const vals = [];\n                    Object.keys(r).forEach(function(k){\n                        if (vals.length >= 3) return;\n                        const v = String(r[k] == null ? '' : r[k]).trim();\n                        if (String(k || '').trim() && v) vals.push(String(k).trim() + ': ' + v);\n                    });\n                    if (vals.length) out.push(vals.join(' | '));\n                });\n                return out.join(' \/ ');\n            } catch(e) { return ''; }\n        };\n        const tableGuide = function(){\n            const it = {\n                config:'contiene parametri principali della ditta: stato, dati identificativi, contatti, attivit\u00e0, istruzioni generali, chiavi e opzioni operative. Va verificata per prima perch\u00e9 orienta AI, login, ordini e messaggi.',\n                utenti:'contiene utenti, ruoli, contatti e preferenze operative. Serve per login, permessi, notifiche email\/SMS e dati utente nei flussi ordine o prenotazione.',\n                operatori:'contiene persone o risorse operative associabili a servizi, appuntamenti e attivit\u00e0. Compilare contatti, competenze, disponibilit\u00e0 e istruzioni quando servono nei flussi di prenotazione.',\n                prodotti:'contiene articoli vendibili o collegabili ai servizi. Verificare nome, descrizione, prezzo, IVA, disponibilit\u00e0, immagine e istruzioni commerciali o operative.',\n                servizi:'contiene prestazioni prenotabili o vendibili. Collegare operatori, siti, dispositivi e prodotti\/materiali quando previsti, indicando durata, disponibilit\u00e0, prezzo, istruzioni e stato.',\n                dispositivi:'contiene attrezzature, strumenti, sale tecniche, postazioni o risorse materiali associabili a servizi, appuntamenti e attivit\u00e0. Serve a evitare conflitti e a proporre solo combinazioni disponibili.',\n                siti:'contiene sedi, reparti, sale, punti vendita o luoghi operativi. Serve per indirizzare prenotazioni, appuntamenti, disponibilit\u00e0 e indicazioni all\u2019utente.',\n                informazioni:'contiene contenuti informativi, documenti, URL e riferimenti che l\u2019AI usa per risposte e assistenza. Compilare Tipo, descrizione, file o link in modo chiaro.',\n                istruzioni:'contiene regole operative per AI e flussi Shop-Service: sconti, priorit\u00e0, comportamenti, vincoli, promozioni e istruzioni tecniche. Le istruzioni devono essere chiare e datate quando temporanee.',\n                appuntamenti:'contiene appuntamenti e impegni fissati. Serve a verificare conflitti su data, ora, operatore, dispositivo, sito e prodotto, e a generare riepiloghi\/notifiche.',\n                prenotazioni:'contiene richieste di prenotazione o pre-prenotazione. Deve riportare servizio\/prodotto, contatto utente, data\/ora quando note, stato e note operative.',\n                attivita:'contiene eventi, report e tracciamenti operativi. Serve per storico, statistiche, controllo esiti e attivit\u00e0 di configurazione.'\n            };\n            const en = {\n                config:'stores the company\u2019s main settings: status, identity data, contacts, activity context, general instructions, keys and behavior options. Review it first because it drives AI, login, orders and messages.',\n                utenti:'stores users, roles, contacts and preferences. It supports login, permissions, email\/SMS notifications and user data in order or booking flows.',\n                operatori:'stores people or operational resources linked to services, bookings and activities. Fill contacts, skills, availability and instructions when used in booking flows.',\n                prodotti:'stores sellable items or items linked to services. Check product name, description, price, VAT, availability, image and commercial or operating instructions.',\n                servizi:'stores bookable or sellable services. Link operators, sites, devices and products\/materials when required, and set duration, availability, price, instructions and status.',\n                dispositivi:'stores equipment, instruments, technical rooms, workstations or material resources linked to services, bookings and activities. It helps avoid conflicts and propose only available combinations.',\n                siti:'stores locations, departments, rooms, shops or operating places. It supports bookings, appointments, availability and user directions.',\n                informazioni:'stores informational content, documents, URLs and references used by the AI for answers and assistance. Fill Type, description, file or link clearly.',\n                istruzioni:'stores operational rules for AI and Shop-Service flows: discounts, priorities, behaviors, constraints, promotions and technical instructions. Instructions should be clear and dated when temporary.',\n                appuntamenti:'stores fixed appointments and commitments. It is used to check conflicts on date, time, operator, device, site and product, and to generate summaries\/notifications.',\n                prenotazioni:'stores booking or pre-booking requests. It should include service\/product, user contact, date\/time when known, status and operational notes.',\n                attivita:'stores events, reports and operational tracking. It supports history, statistics, result control and configuration activities.'\n            };\n            return (helpIsEn ? en : it)[tblNorm] || '';\n        };\n        const fieldList = tableFields();\n        const tableExampleLine = tableExamples();\n        const tableGuideText = tableGuide();\n        const lines = [];\n        if (helpIsEn) {\n            lines.push(cleanCol ? `Field info: ${esc(cleanCol)} [${esc(cleanTbl)}]` : `Table info: ${esc(cleanTbl)}`);\n            if (activity) lines.push('Company context: ' + esc(activity) + '.');\n            if (cleanCol) {\n                lines.push('What it is for: ' + esc(desc || (isProductField ? 'Short product name used in catalog, order flows, search and AI replies.' : (isServiceProduct ? 'Product or material associated with the service.' : 'Field used by this Shop-Service workflow.'))));\n                if (relationLine) lines.push(esc(relationLine));\n                if (isProductField) lines.push('How to fill it in: use a clear, short, recognizable product name. Put details in Description, price in Price\/Prezzo and commercial rules in Instructions\/Istruzioni.');\n                else if (isServiceProduct) lines.push('How to fill it in: select one or more products\/materials used by the service from the Products table, or write a clear manual value if needed.');\n                else lines.push('How to fill it in: use a clear value consistent with the table and the other existing records.');\n                const ex = operationalExample(); if (ex) lines.push(esc(ex));\n                lines.push('Checks: after saving, verify catalog\/search, order or booking flow, and linked images\/documents if used.');\n            } else {\n                lines.push('Operational use: ' + esc(tableGuideText || 'this table feeds configuration, AI replies and Shop-Service workflows.'));\n                const ex = operationalExample(); if (ex) lines.push(esc(ex));\n            }\n            return lines.join('<br>');\n        }\n        lines.push(cleanCol ? `Info campo: ${esc(cleanCol)} [${esc(cleanTbl)}]` : `Info tabella: ${esc(cleanTbl)}`);\n        if (activity) lines.push('Contesto attivit\u00e0 ditta: ' + esc(activity) + '.');\n        if (cleanCol) {\n            lines.push('A cosa serve: ' + esc(desc || (isProductField ? 'Nome breve del prodotto usato in catalogo, ordini, ricerca e risposte AI.' : (isServiceProduct ? 'Prodotto o materiale associato al servizio.' : 'Campo usato dal flusso operativo Shop-Service.'))));\n            if (relationLine) lines.push(esc(relationLine));\n            if (isProductField) lines.push('Come compilarlo: usare un nome prodotto breve, chiaro e riconoscibile. Mettere i dettagli in Descrizione, il prezzo in Prezzo e le regole commerciali in Istruzioni.');\n            else if (isServiceProduct) lines.push('Come compilarlo: selezionare uno o pi\u00f9 prodotti\/materiali usati dal servizio dalla tabella Prodotti, oppure scrivere un valore manuale chiaro se necessario.');\n            else lines.push('Come compilarlo: usare un valore chiaro, coerente con la tabella e con gli altri record presenti.');\n            const ex = operationalExample(); if (ex) lines.push(esc(ex));\n            lines.push('Controlli: dopo il salvataggio verificare ricerca\/catalogo, flusso ordine o prenotazione e immagini\/documenti collegati se presenti.');\n        } else {\n            lines.push('Uso operativo: ' + esc(tableGuideText || 'la tabella alimenta configurazione, risposte AI e flussi Shop-Service.'));\n            const ex = operationalExample(); if (ex) lines.push(esc(ex));\n        }\n        return lines.join('<br>');\n    };\n\n    window.askColumnHelp = function(tbl, col) {\n        const dbVal = gE('ti-ditta').value || 'NEW_DB';\n        const cleanTbl = window.tiSanitizeColumnHelpText357(String(tbl || '').trim());\n        const cleanCol = window.tiSanitizeColumnHelpText357(String(col || '').replace(\/\\\\'\/g, \"'\").replace(\/[\"\u201c\u201d]\/g, '').trim());\n        const helpIsEn = String(window.currLang || 'it').toLowerCase().indexOf('en') === 0;\n        const helpOv = gE('ti-col-help-ov');\n        const helpReqId = String(Date.now()) + '-' + Math.random().toString(36).slice(2);\n        window.tiColumnHelpActiveRequestId = helpReqId;\n        if (helpOv) {\n            helpOv.setAttribute('data-ti-help-request-id', helpReqId);\n            helpOv.setAttribute('data-ti-help-table', cleanTbl);\n            helpOv.setAttribute('data-ti-help-column', cleanCol);\n        }\n        gE('col-help-title').innerText = cleanCol\n            ? (helpIsEn ? `Field info: ${cleanCol} [${cleanTbl}]` : `Info campo: ${cleanCol} [${cleanTbl}]`)\n            : (helpIsEn ? `Table info: ${cleanTbl}` : `Info tabella: ${cleanTbl}`);\n        if (window.tiUpdateColumnHelpCompanyHeader) window.tiUpdateColumnHelpCompanyHeader();\n        const contentBox = gE('col-help-content');\n        contentBox.innerHTML = cleanCol\n            ? (helpIsEn ? `<i>\u23f3 I am checking the manual, schema and available data for field <b>${cleanCol}<\/b> in table <b>${cleanTbl}<\/b>...<\/i>` : `<i>\u23f3 Consulto manuale, schema e dati disponibili per il campo <b>${cleanCol}<\/b> della tabella <b>${cleanTbl}<\/b>...<\/i>`)\n            : (helpIsEn ? `<i>\u23f3 I am checking the manual, schema and available data for table <b>${cleanTbl}<\/b>...<\/i>` : `<i>\u23f3 Consulto manuale, schema e dati disponibili per la tabella <b>${cleanTbl}<\/b>...<\/i>`);\n        window.openModal('ti-col-help-ov');\n        if (window.tiPromoteModalFront355) window.tiPromoteModalFront355('ti-col-help-ov');\n        const fd = new FormData(); fd.append('ti_action', 'ti_ai_chat_start'); fd.append('db', dbVal);\n        const langInstruction = helpIsEn ? ' Rispondi in inglese, senza aggiungere la versione italiana.' : ' Rispondi in italiano, senza aggiungere la versione inglese.';\n        const helpRequest = cleanCol\n            ? `AI_MANUAL_HELP: Dai una risposta operativa reale e specifica sul campo \"${cleanCol}\" nella tabella \"${cleanTbl}\". Indica a cosa serve, come compilarlo e aggiungi se utile un Esempio operativo tratto dal manuale, dai dati non sensibili disponibili o da pattern analoghi aggregati di altre ditte. Non citare mai dati anagrafici o identificativi di altre ditte: no nomi ditta, ragioni sociali, persone, email, telefoni, indirizzi, PIVA, codici fiscali, username, IBAN, link privati o codici attivazione. Non citare campi vuoti, colonne senza nome o frasi di comodo tipo risposta rapida locale. Non citare privacy, anonimizzazione, fonti, prompt o questa istruzione: mostra solo la risposta operativa per l'utente.${langInstruction}`\n            : `AI_MANUAL_HELP: Dai una risposta operativa reale e specifica sulla tabella \"${cleanTbl}\". Indica a cosa serve e aggiungi se utile un Esempio operativo tratto dal manuale, dai dati non sensibili disponibili o da pattern analoghi aggregati di altre ditte. Non citare mai dati anagrafici o identificativi di altre ditte: no nomi ditta, ragioni sociali, persone, email, telefoni, indirizzi, PIVA, codici fiscali, username, IBAN, link privati o codici attivazione. Non citare campi vuoti, colonne senza nome o frasi di comodo tipo risposta rapida locale. Non citare privacy, anonimizzazione, fonti, prompt o questa istruzione: mostra solo la risposta operativa per l'utente.${langInstruction}`;\n        fd.append('text', helpRequest);\n        try {\n            if (contentBox && window.tiColumnHelpFallbackHtml436) {\n                contentBox.innerHTML = window.tiColumnHelpFallbackHtml436(cleanTbl, cleanCol, helpIsEn, helpRequest);\n                if (window.tiPromoteModalFront355) window.tiPromoteModalFront355('ti-col-help-ov');\n            }\n        } catch(e) {}\n        let helpFallbackShown = true;\n        const helpFallbackTimer = setTimeout(function(){\n            try {\n                if (window.tiColumnHelpActiveRequestId !== helpReqId) return;\n                if (helpOv && helpOv.getAttribute('data-ti-help-request-id') !== helpReqId) return;\n                if (!contentBox) return;\n                helpFallbackShown = true;\n                contentBox.innerHTML = window.tiColumnHelpFallbackHtml436 ? window.tiColumnHelpFallbackHtml436(cleanTbl, cleanCol, helpIsEn, helpRequest) : contentBox.innerHTML;\n                if (window.tiPromoteModalFront355) window.tiPromoteModalFront355('ti-col-help-ov');\n            } catch(e) {}\n        }, 2500);\n        const helpAjaxPromise = (window.postFormDataJsonSafe\n            ? window.postFormDataJsonSafe(window.tiUrl, fd, {tiNoLongProcessSignal: true})\n            : window.fetchJsonSafe(window.tiUrl, {method: 'POST', body: fd, tiNoLongProcessSignal: true}));\n        helpAjaxPromise.then(res => {\n            clearTimeout(helpFallbackTimer);\n            if (window.tiColumnHelpActiveRequestId !== helpReqId) return;\n            if (helpOv && helpOv.getAttribute('data-ti-help-request-id') !== helpReqId) return;\n            if(res.success) {\n                gE('col-help-title').innerText = cleanCol\n                    ? (helpIsEn ? `Field info: ${cleanCol} [${cleanTbl}]` : `Info campo: ${cleanCol} [${cleanTbl}]`)\n                    : (helpIsEn ? `Table info: ${cleanTbl}` : `Info tabella: ${cleanTbl}`);\n                const rawReply = String((res.data && res.data.reply) ? res.data.reply : '');\n                const replyHtml = window.tiSanitizeColumnHelpText357(rawReply).replace(\/\\n\/g, '<br>');\n                const aiUsed = !!(res.data && (res.data.field_help_ai_used === true || String(res.data.field_help_source || '').toLowerCase() === 'ai'));\n                if (contentBox) contentBox.setAttribute('data-ti-help-source', aiUsed ? 'ai' : 'fallback');\n                contentBox.innerHTML = replyHtml || (window.tiColumnHelpFallbackHtml436 ? window.tiColumnHelpFallbackHtml436(cleanTbl, cleanCol, helpIsEn, helpRequest) : '');\n                try { if (window.applyLayoutLanguage) window.applyLayoutLanguage(false); } catch(e) {}\n                if (window.tiPromoteModalFront355) window.tiPromoteModalFront355('ti-col-help-ov');\n            } else {\n                if (contentBox) contentBox.setAttribute('data-ti-help-source', 'fallback');\n                contentBox.innerHTML = window.tiColumnHelpFallbackHtml436 ? window.tiColumnHelpFallbackHtml436(cleanTbl, cleanCol, helpIsEn, helpRequest) : (helpIsEn ? \"<span style='color:#ef4444;'>Error while searching the manual.<\/span>\" : \"<span style='color:#ef4444;'>Errore durante la ricerca nel manuale.<\/span>\");\n                if (window.tiPromoteModalFront355) window.tiPromoteModalFront355('ti-col-help-ov');\n            }\n        }).catch(e => {\n            clearTimeout(helpFallbackTimer);\n            if (window.tiColumnHelpActiveRequestId !== helpReqId) return;\n            if (helpOv && helpOv.getAttribute('data-ti-help-request-id') !== helpReqId) return;\n            if (contentBox) contentBox.setAttribute('data-ti-help-source', 'fallback');\n            contentBox.innerHTML = window.tiColumnHelpFallbackHtml436 ? window.tiColumnHelpFallbackHtml436(cleanTbl, cleanCol, helpIsEn, helpRequest) : (helpIsEn ? \"<span style='color:#ef4444;'>Error while searching the manual.<\/span>\" : \"<span style='color:#ef4444;'>Errore durante la ricerca nel manuale.<\/span>\");\n            if (window.tiPromoteModalFront355) window.tiPromoteModalFront355('ti-col-help-ov');\n        });\n\n    };\n\n    window.globalActionProgressState = { timer: null, percent: 0, target: 92, active: false };\n    window.setGlobalActionProgress = function(percent, text) {\n        const wrap = gE('global-action-progress-wrap'); const bar = gE('global-action-progress-bar'); const label = gE('global-action-progress-text');\n        if (wrap) wrap.style.display = 'block';\n        const pct = Math.max(0, Math.min(100, parseInt(percent, 10) || 0));\n        if (bar) bar.style.width = pct + '%';\n        if (label) label.innerText = pct + '% - ' + (text || 'Elaborazione in corso...');\n        window.globalActionProgressState.percent = pct;\n    };\n    window.startGlobalActionProgress = function(text) {\n        clearInterval(window.globalActionProgressState.timer);\n        window.globalActionProgressState.active = true;\n        window.globalActionProgressState.percent = 3;\n        window.globalActionProgressState.target = 94;\n        window.setGlobalActionProgress(3, text || 'Avvio elaborazione globale...');\n        window.globalActionProgressState.timer = setInterval(function(){\n            if (!window.globalActionProgressState.active) return;\n            let pct = window.globalActionProgressState.percent;\n            if (pct >= window.globalActionProgressState.target) return;\n            pct += (pct < 20 ? 5 : (pct < 45 ? 4 : (pct < 70 ? 3 : 1)));\n            if (pct > window.globalActionProgressState.target) pct = window.globalActionProgressState.target;\n            window.setGlobalActionProgress(pct, 'Analisi AI e scrittura sui database in corso...');\n        }, 650);\n    };\n    window.finishGlobalActionProgress = function(success, text) {\n        clearInterval(window.globalActionProgressState.timer);\n        window.globalActionProgressState.active = false;\n        window.setGlobalActionProgress(success ? 100 : Math.max(0, window.globalActionProgressState.percent || 0), text || (success ? 'Operazione completata' : 'Operazione interrotta'));\n    };\n    window.resetGlobalActionProgress = function() {\n        clearInterval(window.globalActionProgressState.timer);\n        window.globalActionProgressState.active = false;\n        window.globalActionProgressState.percent = 0;\n        const wrap = gE('global-action-progress-wrap'); const bar = gE('global-action-progress-bar'); const label = gE('global-action-progress-text');\n        if (wrap) wrap.style.display = 'none';\n        if (bar) bar.style.width = '0%';\n        if (label) label.innerText = '0% - In attesa di avvio...';\n    };\n\n    (function installTiRobustGlobalProgress327(){\n        if (window.__tiRobustGlobalProgress327Installed) return;\n        window.__tiRobustGlobalProgress327Installed = true;\n        function gpClamp(v){ v = parseInt(v, 10); if (!isFinite(v) || isNaN(v)) v = 0; return Math.max(0, Math.min(100, v)); }\n        function gpSet(pct, text){\n            pct = gpClamp(pct);\n            const st = window.globalActionProgressState || (window.globalActionProgressState = {});\n            const cur = gpClamp(st.percent || 0);\n            if (pct < 100 && cur > pct) pct = cur;\n            const wrap = gE('global-action-progress-wrap'); const bar = gE('global-action-progress-bar'); const label = gE('global-action-progress-text');\n            if (wrap) wrap.style.display = 'block';\n            if (bar) bar.style.width = pct + '%';\n            if (label) label.innerText = pct + '% - ' + (text || 'Elaborazione in corso...');\n            st.percent = pct;\n        }\n        if (typeof window.startGlobalActionProgress === 'function' && !window.startGlobalActionProgress.__tiRobustProgress327) {\n            const prevStart = window.startGlobalActionProgress;\n            window.startGlobalActionProgress = function(text){\n                const ret = prevStart.apply(this, arguments);\n                const st = window.globalActionProgressState || (window.globalActionProgressState = {});\n                st.startedAt327 = Date.now();\n                clearInterval(st.watchdog327);\n                st.watchdog327 = setInterval(function(){\n                    if (!st.active) { clearInterval(st.watchdog327); return; }\n                    const elapsed = Math.max(0, Date.now() - (st.startedAt327 || Date.now()));\n                    let pct = 3 + Math.min(1, elapsed \/ 60000) * 91;\n                    if (elapsed > 60000) pct = 94 + Math.min(1, (elapsed - 60000) \/ 90000) * 5;\n                    gpSet(Math.floor(pct), elapsed > 90000 ? 'Elaborazione lunga ancora in corso. Verifico il completamento lato server...' : 'Analisi AI e scrittura sui database in corso...');\n                }, 1000);\n                return ret;\n            };\n            window.startGlobalActionProgress.__tiRobustProgress327 = true;\n        }\n        if (typeof window.setGlobalActionProgress === 'function' && !window.setGlobalActionProgress.__tiRobustProgress327) {\n            const prevSet = window.setGlobalActionProgress;\n            window.setGlobalActionProgress = function(percent, text){\n                const st = window.globalActionProgressState || {};\n                let pct = gpClamp(percent);\n                const cur = gpClamp(st.percent || 0);\n                if (pct < 100 && cur > pct) pct = cur;\n                return prevSet.call(this, pct, text);\n            };\n            window.setGlobalActionProgress.__tiRobustProgress327 = true;\n        }\n        if (typeof window.finishGlobalActionProgress === 'function' && !window.finishGlobalActionProgress.__tiRobustProgress327) {\n            const prevFinish = window.finishGlobalActionProgress;\n            window.finishGlobalActionProgress = function(success, text){\n                const st = window.globalActionProgressState || {};\n                if (st.watchdog327) clearInterval(st.watchdog327);\n                return prevFinish.call(this, success, text || (success ? 'Operazione completata' : 'Operazione interrotta'));\n            };\n            window.finishGlobalActionProgress.__tiRobustProgress327 = true;\n        }\n    })();\n\n    window.doGlobalAction = function() {\n        const prompt = gE('global-action-prompt').value.trim();\n        if(!prompt) { window.tiAlert(\"Inserisci l'operazione che vuoi eseguire.\"); return; }\n        const warning = '<b>Attenzione: modifica globale database<\/b><br><br>' +\n            'Questa operazione puo modificare piu database delle ditte in una sola volta.<br>' +\n            'Prima dell esecuzione viene escluso sempre il template standard <b>shopservicemain.json<\/b>, che non verra modificato.<br><br>' +\n            '<b>Operazione richiesta:<\/b><br><span style=\"color:#fbbf24;white-space:pre-wrap;display:block;margin-top:6px;\">' + window.escapeHtml(prompt) + '<\/span><br>' +\n            'Confermi di voler procedere con cautela?';\n        window.tiConfirmYesNoAction(warning, function(){\n            window.doGlobalActionConfirmed(prompt);\n        }, null, 'CONFERMA MODIFICA', 'ANNULLA');\n    };\n\n    window.doGlobalActionConfirmed = function(prompt, previewToken, definitiveConfirm, tableScope) {\n        const btn = gE('global-action-btn'); const resBox = gE('global-action-res');\n        btn.innerText = definitiveConfirm ? \"\u23f3 Esecuzione definitiva in corso...\" : \"\u23f3 Generazione preview...\";\n        btn.disabled = true; resBox.style.display = 'block';\n        resBox.innerHTML = definitiveConfirm ? \"Esecuzione definitiva su tutti i database dopo preview approvata. Non chiudere la pagina.\" : \"Genero una preview di modifica della struttura del database su un database campione. Nessuna struttura del database viene modificata in questa fase. Sono eventualmente modificati i soli valori dei campi del database.\";\n        window.startGlobalActionProgress(definitiveConfirm ? 'Avvio modifica globale definitiva...' : 'Generazione preview obbligatoria...');\n        const fd = new FormData(); fd.append('ti_action', 'ti_ai_global_action'); fd.append('prompt', prompt); fd.append('global_confirm', '1');\n        if (previewToken) fd.append('global_template_preview_token', previewToken);\n        if (definitiveConfirm) fd.append('global_template_confirm', '1');\n        if (tableScope) fd.append('global_table_scope', tableScope);\n        window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n            btn.innerText = \"Esegui Modifica su Tutti i DB\"; btn.disabled = false;\n            if(d.success) {\n                if (d.data && d.data.requires_table_scope) {\n                    window.finishGlobalActionProgress(false, 'Ambito tabelle richiesto. Nessun database modificato.');\n                    resBox.innerHTML = d.data.reply || 'Indica le tabelle prima di eseguire la modifica globale.';\n                    const answer = window.prompt(d.data.scope_prompt || 'Scrivi TUTTE oppure elenca le tabelle separate da virgola:', '');\n                    if (answer && String(answer).trim()) {\n                        window.doGlobalActionConfirmed(prompt, previewToken, definitiveConfirm, String(answer).trim());\n                    } else {\n                        resBox.innerHTML += '<br><br><span style=\"color:#f59e0b;\">Operazione sospesa. Nessun database e stato modificato.<\/span>';\n                    }\n                    return;\n                }\n                if (d.data && d.data.requires_template_preview) {\n                    window.finishGlobalActionProgress(false, 'Preview generata. In attesa di approvazione.');\n                    resBox.innerHTML = d.data.reply || 'Preview generata. Nessun database modificato.';\n                    const previewHtml = d.data.preview_html || 'Preview generata. Confermi la modifica definitiva?';\n                    const token = d.data.preview_token || '';\n                    window.tiConfirmYesNoAction(previewHtml, function(){\n                        window.doGlobalActionConfirmed(prompt, token, true);\n                    }, function(){\n                        resBox.innerHTML = '<span style=\"color:#f59e0b;\">Operazione annullata. Nessun database e stato modificato.<\/span>';\n                    }, 'APPROVA MODIFICA DEFINITIVA', 'ANNULLA');\n                    return;\n                }\n                let finalMsg = 'Modifica globale completata';\n                if (d.data && d.data.stats) {\n                    const s = d.data.stats;\n                    finalMsg = 'Completato: DB ' + (s.db_modified || 0) + ', tabelle ' + (s.tables_touched || 0) + ', campi ' + (s.fields_touched || 0);\n                }\n                window.finishGlobalActionProgress(true, finalMsg);\n                resBox.innerHTML = d.data.reply;\n            } else {\n                window.finishGlobalActionProgress(false, 'Errore modifica globale');\n                resBox.innerHTML = \"<span style='color:#ef4444;'>Errore: \" + d.data.message + \"<\/span>\";\n            }\n        }).catch(e => {\n            btn.innerText = \"Esegui Modifica su Tutti i DB\"; btn.disabled = false;\n            if (e && (e.userCancelled || window.isLongAIProcessCancelled())) {\n                window.clearLongAIProcess();\n                window.finishGlobalActionProgress(false, 'Operazione interrotta dall utente');\n                resBox.innerHTML = \"<span style='color:#f59e0b;'>Operazione interrotta dall utente.<\/span>\";\n                return;\n            }\n            window.finishGlobalActionProgress(false, 'Errore di rete');\n            resBox.innerHTML = \"<span style='color:#ef4444;'>Errore di rete.<\/span>\";\n        });\n    };\n\n\n    window.activityReportStorageKey = function() {\n        const u = window.tiUser || 'guest';\n        const db = (gE('ti-ditta') && gE('ti-ditta').value) ? gE('ti-ditta').value : (window.tiForced || 'global');\n        return 'ti_activity_report_flags_' + u + '_' + db;\n    };\n    window.activityReportMetricOptions = ['Prezzo','Quantit\u00e0','Totale'];\n    window.getDefaultActivityMetricFlags = function() {\n        return { Prezzo: false, Quantit\u00e0: false, Totale: true };\n    };\n    window.userCanSeeConfigurationActivities = function() {\n        const role = String(window.tiRole || '').toLowerCase();\n        const user = String(window.tiUser || '').toLowerCase();\n        return user === 'ssglobaladmin' || role.includes('amministratore') || role.includes('configuratore');\n    };\n    window.isConfigurationActivityLike = function(row) {\n        if (!row || typeof row !== 'object') return false;\n        const vals = [];\n        Object.keys(row).forEach(function(k){\n            if (\/(descrizione|attivit|attivit\u00e0|dettaglio|note|nota|tipo|stato)\/i.test(String(k || ''))) vals.push(row[k]);\n        });\n        return vals.some(function(v){\n            if (v === null || v === undefined) return false;\n            const txt = String(v).trim().toLowerCase();\n            return \/^configurazione\\b\/.test(txt) || txt.indexOf('attivit\u00e0 di configurazione') !== -1 || txt.indexOf('attivita di configurazione') !== -1;\n        });\n    };\n    window.getDefaultActivityExcludeConfig = function() { return false; };\n    window.loadActivityReportPrefs = function() {\n        try {\n            const raw = localStorage.getItem(window.activityReportStorageKey());\n            if (!raw) return {colFlags:{}, rowFlags:{}, metricFlags: window.getDefaultActivityMetricFlags(), groupField: 'Username', excludeConfigActivities: window.getDefaultActivityExcludeConfig(), sortCol:'DataOra', sortDir:'desc', view:'table'};\n            const d = JSON.parse(raw);\n            const metricFlags = Object.assign(window.getDefaultActivityMetricFlags(), d && d.metricFlags ? d.metricFlags : {});\n            return { colFlags: d && d.colFlags ? d.colFlags : {}, rowFlags: d && d.rowFlags ? d.rowFlags : {}, metricFlags, groupField: (d && d.groupField ? d.groupField : 'Username'), excludeConfigActivities: !!(d && d.excludeConfigActivities), sortCol:(d && d.sortCol ? d.sortCol : 'DataOra'), sortDir:(d && d.sortDir === 'asc' ? 'asc' : 'desc'), view:(d && ['table','pie','bar','trend'].includes(d.view) ? d.view : 'table') };\n        } catch(e) { return {colFlags:{}, rowFlags:{}, metricFlags: window.getDefaultActivityMetricFlags(), groupField: 'Username', excludeConfigActivities: window.getDefaultActivityExcludeConfig(), sortCol:'DataOra', sortDir:'desc', view:'table'}; }\n    };\n    window.saveActivityReportPrefs = function() {\n        try {\n            localStorage.setItem(window.activityReportStorageKey(), JSON.stringify({\n                colFlags: (window.activityReportState && window.activityReportState.colFlags) || {},\n                rowFlags: (window.activityReportState && window.activityReportState.rowFlags) || {},\n                metricFlags: (window.activityReportState && window.activityReportState.metricFlags) || window.getDefaultActivityMetricFlags(),\n                groupField: (window.activityReportState && window.activityReportState.groupField) || 'Username',\n                excludeConfigActivities: !!(window.activityReportState && window.activityReportState.excludeConfigActivities),\n                sortCol: (window.activityReportState && window.activityReportState.sortCol) || 'DataOra',\n                sortDir: (window.activityReportState && window.activityReportState.sortDir) || 'desc',\n                view: (window.activityReportState && window.activityReportState.view) || 'table'\n            }));\n        } catch(e) {}\n    };\n    window.activityReportState = { sortCol: 'DataOra', sortDir: 'desc', filters: {}, view: 'table', colFlags: {}, rowFlags: {}, metricFlags: window.getDefaultActivityMetricFlags(), groupField: 'Username', excludeConfigActivities: window.getDefaultActivityExcludeConfig() };\n    window.activityReportCols = ['Username','Descrizione','ID QRcode','Prezzo','Quantit\u00e0','Esito','Operatore','Dispositivo','Sito','Prodotto','Istruzioni','Durata','Data','Ora','Nota','Stato','Totale'];\n    window.activityReportGroupOptions = window.activityReportCols.slice();\n    window.getActivityAvailableGroupFields = function() {\n        const visibleCols = window.getActivityVisibleCols();\n        const allowed = window.activityReportGroupOptions.filter(k => visibleCols.includes(k));\n        return allowed.length ? allowed : ['Username'];\n    };\n    window.getActivitySelectedGroupField = function() {\n        const available = window.getActivityAvailableGroupFields();\n        const current = (window.activityReportState && window.activityReportState.groupField) || 'Username';\n        return available.includes(current) ? current : (available[0] || 'Prodotto');\n    };\n    window.setActivityGroupField = function(field) {\n        window.activityReportState.groupField = field;\n        window.saveActivityReportPrefs();\n        window.renderActivityReport();\n    };\n    window.getActivityAvailableMetrics = function() {\n        const visibleCols = window.getActivityVisibleCols();\n        const allowed = window.activityReportMetricOptions.filter(k => visibleCols.includes(k));\n        return allowed.length ? allowed : ['Totale'];\n    };\n    window.getActivitySelectedMetrics = function() {\n        const flags = (window.activityReportState && window.activityReportState.metricFlags) || window.getDefaultActivityMetricFlags();\n        const available = window.getActivityAvailableMetrics();\n        const selected = available.filter(k => !!flags[k]);\n        return selected.length ? selected : [available[0] || 'Totale'];\n    };\n    window.setActivityMetricFlag = function(metric, checked) {\n        if (!window.activityReportState.metricFlags) window.activityReportState.metricFlags = window.getDefaultActivityMetricFlags();\n        window.activityReportState.metricFlags[metric] = !!checked;\n        const available = window.getActivityAvailableMetrics();\n        const hasSelected = available.some(k => !!window.activityReportState.metricFlags[k]);\n        if (!hasSelected && available.length) window.activityReportState.metricFlags[available[0]] = true;\n        window.saveActivityReportPrefs();\n        window.renderActivityReport();\n    };\n    window.setActivityExcludeConfigActivities = function(checked) {\n        if (!window.activityReportState) window.activityReportState = {};\n        window.activityReportState.excludeConfigActivities = !!checked;\n        window.saveActivityReportPrefs();\n        window.renderActivityReport();\n    };\n    window.parseReportNum = function(v, defVal) {\n        if (v === null || v === undefined || v === '') return defVal || 0;\n        let s = String(v).trim();\n        if (!s) return defVal || 0;\n        s = s.replace(\/[^\\d,\\.\\-]\/g, '');\n        if (s.indexOf(',') !== -1 && s.indexOf('.') !== -1) s = s.replace(\/\\.\/g, '').replace(',', '.');\n        else if (s.indexOf(',') !== -1) s = s.replace(',', '.');\n        const n = parseFloat(s);\n        return isNaN(n) ? (defVal || 0) : n;\n    };\n    window.getActivityRowsNormalized = function() {\n        if(!window.currentDbData || !window.currentDbData.Tabelle) return [];\n        const raw = window.currentDbData.Tabelle['Attivita'] || window.currentDbData.Tabelle['Attivit\u00e0'] || [];\n        const rows = Array.isArray(raw) ? raw : Object.values(raw || {});\n        const normalized = rows.map((r, idx) => {\n            r = r || {};\n            const isConfigActivity = window.isConfigurationActivityLike ? window.isConfigurationActivityLike(r) : false;\n            const prezzo = window.parseReportNum(r.Prezzo || r.Totale || 0, 0);\n            const qta = window.parseReportNum(r['Quantit\u00e0'] || r.Quantita || 1, 1);\n            const data = r.Data || '';\n            const ora = r.Ora || '';\n            const descrizione = r['Descrizione attivit\u00e0'] || r['Descrizione attivita'] || r.Descrizione || r.Dettaglio || r.Note || r.Nota || '';\n            let dataora = 0;\n            const m = String(data).match(\/^(\\d{2})\\\/(\\d{2})\\\/(\\d{4})$\/);\n            const hm = String(ora).match(\/^(\\d{2}):(\\d{2})\/);\n            if (m) dataora = new Date(parseInt(m[3],10), parseInt(m[2],10)-1, parseInt(m[1],10), hm?parseInt(hm[1],10):0, hm?parseInt(hm[2],10):0, 0).getTime();\n            const rowKey = String(r.ID || '') + '|' + String(r.Username || r.Utente || r.user || '') + '|' + String(data) + '|' + String(ora) + '|' + String(descrizione || '') + '|' + idx;\n            return {\n                Username: r.Username || r.Utente || r.user || '',\n                Descrizione: descrizione,\n                Prezzo: prezzo,\n                Quantit\u00e0: qta,\n                Esito: r.Esito || '',\n                Operatore: r.Operatore || '',\n                Dispositivo: r.Dispositivo || '',\n                Sito: r.Sito || '',\n                Prodotto: r.Prodotto || '',\n                Istruzioni: r.Istruzioni || '',\n                Durata: r.Durata || '',\n                Data: data,\n                Ora: ora,\n                Nota: r.Nota || '',\n                Stato: r.Stato || '',\n                Totale: prezzo * qta,\n                'ID QRcode': r['ID QRcode'] || r['ID QR code'] || r.ID_QRcode || r.QRcode_ID || '',\n                __dataora: dataora,\n                __rowKey: rowKey,\n                __isConfigActivity: isConfigActivity\n            };\n        });\n        if (!(window.userCanSeeConfigurationActivities && window.userCanSeeConfigurationActivities())) {\n            return normalized.filter(function(r){ return !r.__isConfigActivity; });\n        }\n        return normalized;\n    };\n    window.findActivityRowByQrCode = function(qrCode) {\n        qrCode = String(qrCode || '').trim();\n        if (!qrCode || !window.currentDbData || !window.currentDbData.Tabelle) return null;\n        const tables = window.currentDbData.Tabelle;\n        const raw = tables['Attivita'] || tables['Attivit\u00e0'] || tables['attivita'] || tables['attivit\u00e0'] || [];\n        const rows = Array.isArray(raw) ? raw : Object.values(raw || {});\n        const norm = function(v){ return String(v == null ? '' : v).trim(); };\n        const keyMatch = function(k){ return \/^(id\\s*qr\\s*code|id\\s*qrcode|id_qrcode|qrcode\\s*id)$\/i.test(String(k || '').replace(\/[_-]+\/g,' ')); };\n        for (let i = 0; i < rows.length; i++) {\n            const r = rows[i] || {};\n            for (const k of Object.keys(r)) {\n                if (!keyMatch(k)) continue;\n                if (norm(r[k]) === qrCode) return {row:r, index:i, key:k};\n            }\n        }\n        return null;\n    };\n    window.showActivityFromQrIfRequested = function() {\n        const qrCode = String(window.tiForcedActivityQr || '').trim();\n        if (!qrCode || window.__tiActivityQrShown) return;\n        const show = function() {\n            const hit = window.findActivityRowByQrCode ? window.findActivityRowByQrCode(qrCode) : null;\n            if (!hit || !hit.row) return false;\n            window.__tiActivityQrShown = true;\n            const esc = window.tiCompanyHelpEscape || function(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); };\n            const r = hit.row;\n            const pick = function(names){ for (const n of names) { if (r[n] !== undefined && String(r[n]).trim() !== '') return String(r[n]); const found = Object.keys(r).find(k => String(k).toLowerCase() === String(n).toLowerCase()); if (found && String(r[found]).trim() !== '') return String(r[found]); } return ''; };\n            const lines = [];\n            lines.push('<b>Attivit\u00e0 richiamata da QRcode<\/b>');\n            lines.push('ID QRcode: ' + esc(qrCode));\n            const id = pick(['ID','Id','id']); if (id) lines.push('ID attivit\u00e0: ' + esc(id));\n            const data = pick(['Data','Data attivit\u00e0','Data attivita']); const ora = pick(['Ora','Ora attivit\u00e0','Ora attivita']); if (data || ora) lines.push('Data\/Ora: ' + esc((data + ' ' + ora).trim()));\n            const desc = pick(['Descrizione attivit\u00e0','Descrizione attivita','Descrizione','Attivita','Attivit\u00e0','Dettaglio','Note','Nota']); if (desc) lines.push('Descrizione: ' + esc(desc));\n            const esito = pick(['Esito','Stato']); if (esito) lines.push('Esito\/Stato: ' + esc(esito));\n            const user = pick(['Username','Utente','user']); if (user) lines.push('Utente: ' + esc(user));\n            const prod = pick(['Prodotto','Servizio']); if (prod) lines.push('Prodotto\/Servizio: ' + esc(prod));\n            if (typeof window.tiAlert === 'function') window.tiAlert(lines.join('<br>'));\n            else alert(lines.map(function(x){ return x.replace(\/<[^>]+>\/g,''); }).join('\\n'));\n            return true;\n        };\n        if (show()) return;\n        const dbSel = document.getElementById('ti-ditta');\n        const db = dbSel ? String(dbSel.value || '').trim() : (window.tiForced || '');\n        if (!db || db === 'NEW_DB' || !window.fetchJsonSafe) return;\n        const fd = new FormData(); fd.append('ti_action','ti_ai_get_db_data'); fd.append('db', db);\n        window.fetchJsonSafe(window.tiUrl || window.location.href, {method:'POST', body:fd, tiNoLongProcessSignal:true}).then(function(res){\n            if (res && res.success && res.data) { window.currentDbData = res.data; show(); }\n        }).catch(function(){});\n    };\n    window.getActivityIncludedRows = function() {\n        return window.getFilteredActivityRows(false);\n    };\n    window.getActivityVisibleCols = function() {\n        const colFlags = (window.activityReportState && window.activityReportState.colFlags) || {};\n        const visible = window.activityReportCols.filter(c => !colFlags[c]);\n        return visible.length ? visible : ['Username','Descrizione','Prezzo','Quantit\u00e0','Totale'];\n    };\n    window.getActivityReportTitle = function(rows) {\n        rows = rows || window.getActivityIncludedRows();\n        let minTs = null, maxTs = null;\n        rows.forEach(r => {\n            if (r && typeof r.__dataora === 'number' && r.__dataora > 0) {\n                if (minTs === null || r.__dataora < minTs) minTs = r.__dataora;\n                if (maxTs === null || r.__dataora > maxTs) maxTs = r.__dataora;\n            }\n        });\n        const ditta = (window.currentDittaName && String(window.currentDittaName).trim()) ? String(window.currentDittaName).trim() : 'Ditta';\n        const fmtDate = function(ts) {\n            if (!ts) return '';\n            const d = new Date(ts);\n            return String(d.getDate()).padStart(2,'0') + '\/' + String(d.getMonth()+1).padStart(2,'0') + '\/' + d.getFullYear();\n        };\n        const fromDate = fmtDate(minTs);\n        const toDate = fmtDate(maxTs);\n        return (fromDate && toDate) ? ('Report attivit\u00e0 \u2013 ' + ditta + ' periodo ' + fromDate + ' - ' + toDate) : ('Report attivit\u00e0 \u2013 ' + ditta);\n    };\n    window.getFilteredActivityRows = function(includeExcludedRows) {\n        let rows = window.getActivityRowsNormalized();\n        const state = window.activityReportState || {filters:{}, rowFlags:{}};\n        const rowFlags = state.rowFlags || {};\n        if (state.excludeConfigActivities && window.userCanSeeConfigurationActivities && window.userCanSeeConfigurationActivities()) {\n            rows = rows.filter(function(r){ return !r.__isConfigActivity; });\n        }\n        rows = rows.filter(r => Object.entries(state.filters || {}).every(([k,v]) => {\n            if (!v) return true;\n            return String(r[k] ?? '').toLowerCase().includes(String(v).toLowerCase());\n        }));\n        if (!includeExcludedRows) rows = rows.filter(r => !rowFlags[r.__rowKey]);\n        const dir = state.sortDir === 'asc' ? 1 : -1;\n        const col = state.sortCol || 'DataOra';\n        rows.sort((a,b) => {\n            const av = col === 'DataOra' ? a.__dataora : a[col];\n            const bv = col === 'DataOra' ? b.__dataora : b[col];\n            if (typeof av === 'number' && typeof bv === 'number') return (av - bv) * dir;\n            return String(av ?? '').localeCompare(String(bv ?? ''), 'it', {numeric:true, sensitivity:'base'}) * dir;\n        });\n        return rows;\n    };\n    window.setActivityReportFilter = function(col, val, inputEl) {\n        window.activityReportState.filters[col] = val;\n        window.activityReportState.filterFocus = {\n            col,\n            start: inputEl && typeof inputEl.selectionStart === 'number' ? inputEl.selectionStart : null,\n            end: inputEl && typeof inputEl.selectionEnd === 'number' ? inputEl.selectionEnd : null\n        };\n        window.renderActivityReport();\n    };\n    window.sortActivityReport = function(col) {\n        if (window.activityReportState.sortCol === col) window.activityReportState.sortDir = window.activityReportState.sortDir === 'asc' ? 'desc' : 'asc';\n        else { window.activityReportState.sortCol = col; window.activityReportState.sortDir = 'asc'; }\n        if (window.saveActivityReportPrefs) window.saveActivityReportPrefs();\n        window.renderActivityReport();\n    };\n    window.setActivityReportView = function(view) { window.activityReportState.view = view; if (window.saveActivityReportPrefs) window.saveActivityReportPrefs(); window.renderActivityReport(); };\n    window.toggleActivityReportColumn = function(col, ev) {\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); }\n        window.activityReportState.colFlags[col] = !window.activityReportState.colFlags[col];\n        window.saveActivityReportPrefs();\n        window.renderActivityReport();\n    };\n    window.toggleActivityReportRow = function(rowKey, ev) {\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); }\n        window.activityReportState.rowFlags[rowKey] = !window.activityReportState.rowFlags[rowKey];\n        window.saveActivityReportPrefs();\n        window.renderActivityReport();\n    };\n    window.exportActivityReportCsv = function() {\n        const rows = window.getFilteredActivityRows(false);\n        const cols = window.getActivityVisibleCols();\n        const csv = cols.join(';') + '\\n' + rows.map(r => cols.map(c => '\"' + String((c === 'Prezzo' || c === 'Quantit\u00e0' || c === 'Totale') ? window.fmtNum(r[c] || 0) : (r[c] ?? '')).replace(\/\"\/g,'\"\"') + '\"').join(';')).join('\\n');\n        const blob = new Blob([csv], {type:'text\/csv;charset=utf-8;'});\n        const a = document.createElement('a');\n        a.href = URL.createObjectURL(blob);\n        a.download = 'report-attivita.csv';\n        a.click();\n        setTimeout(() => URL.revokeObjectURL(a.href), 500);\n    };\n    window.printActivityReport = function() {\n        const view = (window.activityReportState && window.activityReportState.view) || 'table';\n        const w = window.open('', '_blank'); if(!w) return;\n        let bodyHtml = '';\n        if (view === 'table') {\n            const rows = window.getFilteredActivityRows(false);\n            const cols = window.getActivityVisibleCols();\n            const totals = {\n                Prezzo: rows.reduce((s,r)=>s+(r.Prezzo||0),0),\n                Quantit\u00e0: rows.reduce((s,r)=>s+(r.Quantit\u00e0||0),0),\n                Totale: rows.reduce((s,r)=>s+(r.Totale||0),0)\n            };\n            bodyHtml += '<h2>' + window.escapeHtml(window.getActivityReportTitle(rows)) + '<\/h2>';\n            bodyHtml += '<table><thead><tr>' + cols.map(c => '<th>' + window.escapeHtml(c) + '<\/th>').join('') + '<\/tr><\/thead><tbody>';\n            rows.forEach(r => {\n                bodyHtml += '<tr>' + cols.map(c => {\n                    const val = (c === 'Prezzo' || c === 'Quantit\u00e0' || c === 'Totale') ? window.fmtNum(r[c] || 0) : (r[c] || '');\n                    return '<td>' + window.escapeHtml(String(val)) + '<\/td>';\n                }).join('') + '<\/tr>';\n            });\n            bodyHtml += '<\/tbody><tfoot><tr>' + cols.map(c => {\n                if (c === 'Descrizione') return '<td>Righe: ' + rows.length + '<\/td>';\n                if (c === 'Prezzo') return '<td>' + window.fmtNum(totals.Prezzo) + '<\/td>';\n                if (c === 'Quantit\u00e0') return '<td>' + window.fmtNum(totals.Quantit\u00e0) + '<\/td>';\n                if (c === 'Totale') return '<td>' + window.fmtNum(totals.Totale) + '<\/td>';\n                return '<td><\/td>';\n            }).join('') + '<\/tr><\/tfoot><\/table>';\n        } else {\n            const rows = window.getFilteredActivityRows(false);\n            const canvasId = view === 'pie' ? 'ti-report-pie' : (view === 'bar' ? 'ti-report-bar' : 'ti-report-trend');\n            const canvas = gE(canvasId);\n            const dataUrl = canvas ? canvas.toDataURL('image\/png') : '';\n            const title = window.getActivityReportTitle(rows);\n            bodyHtml += '<h2>' + window.escapeHtml(title) + '<\/h2>';\n            bodyHtml += dataUrl ? ('<div style=\"text-align:center;\"><img decoding=\"async\" src=\"' + dataUrl + '\" style=\"max-width:100%;height:auto;\" \/><\/div>') : '<p>Grafico non disponibile.<\/p>';\n        }\n        const printDocTitle = window.escapeHtml(window.getActivityReportTitle(window.getFilteredActivityRows(false)));\n        w.document.write('<html><head><title>' + printDocTitle + '<\/title><style>@page{size:A4 landscape;margin:12mm;} html,body{background:#fff!important;} body{font-family:Arial,sans-serif;padding:0;margin:0} body,body *{color:#000!important;-webkit-print-color-adjust:exact;print-color-adjust:exact} h2{margin:0 0 12px 0;color:#000!important} table{border-collapse:collapse;width:100%;table-layout:auto;color:#000!important} th,td{border:1px solid #bbb;padding:6px;font-size:11px;text-align:left;vertical-align:top;word-break:break-word;color:#000!important} th{background:#eee!important;color:#000!important} tfoot td{font-weight:bold;background:#f3f4f6!important;color:#000!important} a,a:visited{color:#000!important;text-decoration:none} img{display:block;margin:0 auto;}<\/style><\/head><body>' + bodyHtml + '<\/body><\/html>');\n        w.document.close(); w.focus(); setTimeout(function(){ w.print(); }, 250);\n    };\n    window.getActivityMetricLabel = function(metrics) {\n        const arr = Array.isArray(metrics) && metrics.length ? metrics : ['Totale'];\n        if (arr.length === 1) {\n            if (arr[0] === 'Prezzo') return 'Prezzo';\n            if (arr[0] === 'Quantit\u00e0') return 'Quantit\u00e0';\n            if (arr[0] === 'Totale') return 'Totale';\n            return String(arr[0]);\n        }\n        return 'Somma valori (' + arr.join(', ') + ')';\n    };\n\n    window.drawPie3D = function(canvasId, rows) {\n        const cv = gE(canvasId); if(!cv) return; const ctx = cv.getContext('2d');\n        const selectedMetrics = window.getActivitySelectedMetrics();\n        const groupField = window.getActivitySelectedGroupField();\n        const metrics = (Array.isArray(selectedMetrics) && selectedMetrics.length) ? selectedMetrics : ['Totale'];\n        const cols = metrics.length > 1 ? 2 : 1;\n        const rowsCount = Math.ceil(metrics.length \/ cols);\n        const blockW = 400;\n        const blockH = 280;\n        cv.width = Math.max(860, cols * blockW + 40);\n        cv.height = Math.max(340, rowsCount * blockH + 40);\n        ctx.clearRect(0,0,cv.width,cv.height);\n\n        const colors=['#38bdf8','#22c55e','#f59e0b','#ef4444','#a855f7','#14b8a6','#f97316','#06b6d4','#84cc16','#fb7185','#f97316','#60a5fa'];\n\n        const buildEntriesForMetric = function(metric) {\n            const groups = {};\n            rows.forEach(r => {\n                const label = String(r[groupField] || 'N\/D').trim() || 'N\/D';\n                const value = window.parseReportNum(r[metric], 0) || 0;\n                groups[label] = (groups[label] || 0) + value;\n            });\n            return Object.entries(groups).filter(e => e[1] > 0).sort((a,b) => b[1]-a[1]).slice(0, 10);\n        };\n\n        let drewAtLeastOne = false;\n\n        metrics.forEach((metric, metricIndex) => {\n            const entries = buildEntriesForMetric(metric);\n            const col = metricIndex % cols;\n            const row = Math.floor(metricIndex \/ cols);\n            const originX = 20 + col * blockW;\n            const originY = 20 + row * blockH;\n            const cx = originX + 120;\n            const cy = originY + 120;\n            const rad = 72;\n            const depth = 14;\n\n            ctx.fillStyle = '#fff';\n            ctx.font = 'bold 13px Arial';\n            ctx.fillText(window.getActivityMetricLabel([metric]), originX + 8, originY + 18);\n\n            if (!entries.length) {\n                ctx.fillStyle = '#cbd5e1';\n                ctx.font = '12px Arial';\n                ctx.fillText('Nessun dato per ' + window.getActivityMetricLabel([metric]), originX + 8, originY + 42);\n                return;\n            }\n\n            drewAtLeastOne = true;\n            const total = entries.reduce((a,b)=>a+b[1],0);\n            let start = -Math.PI\/2;\n\n            entries.forEach(([label,val],i) => {\n                const ang = total > 0 ? (val\/total)*Math.PI*2 : 0;\n                ctx.fillStyle='rgba(0,0,0,0.35)';\n                ctx.beginPath(); ctx.moveTo(cx, cy+depth); ctx.arc(cx, cy+depth, rad, start, start+ang); ctx.closePath(); ctx.fill();\n                ctx.fillStyle=colors[i%colors.length];\n                ctx.beginPath(); ctx.moveTo(cx, cy); ctx.arc(cx, cy, rad, start, start+ang); ctx.closePath(); ctx.fill();\n\n                const mid = start + ang\/2;\n                const labelX = cx + Math.cos(mid) * (rad + 18);\n                const labelY = cy + Math.sin(mid) * (rad + 18);\n                const textX = labelX + (Math.cos(mid) >= 0 ? 8 : -150);\n\n                ctx.fillStyle='#fff';\n                ctx.font='12px Arial';\n                ctx.fillText(label, textX, labelY - 10);\n                ctx.fillStyle='#cbd5e1';\n                ctx.font='11px Arial';\n                ctx.fillText(window.getActivityMetricLabel([metric]) + ': ' + window.fmtNum(val), textX, labelY + 4);\n                start += ang;\n            });\n\n            ctx.fillStyle = '#94a3b8';\n            ctx.font = '11px Arial';\n            ctx.fillText('Raggruppa per: ' + groupField, originX + 8, originY + blockH - 12);\n        });\n\n        if (!drewAtLeastOne) {\n            ctx.fillStyle='#fff'; ctx.font='14px Arial'; ctx.fillText('Nessun dato',20,20);\n        }\n    };\n    window.drawBar3D = function(canvasId, rows) {\n        const cv = gE(canvasId); if(!cv) return; const ctx = cv.getContext('2d');\n        const selectedMetrics = window.getActivitySelectedMetrics();\n        const groupField = window.getActivitySelectedGroupField();\n        const metrics = (Array.isArray(selectedMetrics) && selectedMetrics.length) ? selectedMetrics : ['Totale'];\n        const blockW = 920;\n        const blockH = 330;\n        cv.width = Math.max(980, blockW + 40);\n        cv.height = Math.max(380, metrics.length * blockH + 40);\n        ctx.clearRect(0,0,cv.width,cv.height);\n        const colors=['#38bdf8','#22c55e','#f59e0b','#ef4444','#a855f7','#14b8a6','#f97316','#06b6d4','#84cc16','#fb7185','#60a5fa','#e879f9'];\n        function entries(metric){\n            const groups={};\n            (rows||[]).forEach(function(r){\n                const label=String((r&&r[groupField])||'N\/D').trim()||'N\/D';\n                const value=window.parseReportNum ? (window.parseReportNum(r&&r[metric],0)||0) : (parseFloat(r&&r[metric])||0);\n                groups[label]=(groups[label]||0)+value;\n            });\n            return Object.entries(groups).filter(function(e){return e[1]>0;}).sort(function(a,b){return b[1]-a[1];}).slice(0,12);\n        }\n        let drew=false;\n        metrics.forEach(function(metric,mi){\n            const data=entries(metric), ox=20, oy=20+mi*blockH;\n            ctx.fillStyle='#fff'; ctx.font='bold 13px Arial'; ctx.fillText(window.getActivityMetricLabel([metric]),ox+8,oy+18);\n            if(!data.length){ctx.fillStyle='#cbd5e1';ctx.font='12px Arial';ctx.fillText('Nessun dato per '+window.getActivityMetricLabel([metric]),ox+8,oy+42);return;}\n            drew=true;\n            const max=Math.max(1,...data.map(function(e){return e[1]||0;}));\n            const labelW=210, valueW=95, left=ox+labelW, top=oy+42, chartW=blockW-labelW-valueW-25;\n            const gap=6, barH=Math.max(12,Math.min(23,Math.floor((blockH-82)\/data.length)-gap));\n            data.forEach(function(entry,i){\n                const y=top+i*(barH+gap), w=Math.max(2,Math.round(chartW*(entry[1]\/max)));\n                ctx.fillStyle='#e5e7eb';ctx.font='11px Arial';\n                let lab=String(entry[0]); if(lab.length>28) lab=lab.slice(0,27)+'\u2026';\n                ctx.fillText(lab,ox+8,y+barH-3);\n                ctx.fillStyle='rgba(0,0,0,.28)';ctx.fillRect(left+4,y+4,w,barH);\n                ctx.fillStyle=colors[i%colors.length];ctx.fillRect(left,y,w,barH);\n                ctx.fillStyle='#fff';ctx.font='11px Arial';ctx.fillText(window.fmtNum(entry[1]),left+w+8,y+barH-3);\n            });\n            ctx.fillStyle='#94a3b8';ctx.font='11px Arial';ctx.fillText('Raggruppa per: '+groupField,ox+8,oy+blockH-12);\n        });\n        if(!drew){ctx.fillStyle='#fff';ctx.font='14px Arial';ctx.fillText('Nessun dato',20,20);}\n    };\n    window.drawTrend3D = function(canvasId, rows) {\n        const cv = gE(canvasId); if(!cv) return; const ctx = cv.getContext('2d');\n        const selectedMetrics = window.getActivitySelectedMetrics();\n        const groupField = window.getActivitySelectedGroupField();\n        const metrics = (Array.isArray(selectedMetrics) && selectedMetrics.length) ? selectedMetrics : ['Totale'];\n        const cols = metrics.length > 1 ? 2 : 1;\n        const rowsCount = Math.ceil(metrics.length \/ cols);\n        const blockW = 460;\n        const blockH = 320;\n        cv.width = Math.max(980, cols * blockW + 40);\n        cv.height = Math.max(380, rowsCount * blockH + 40);\n        ctx.clearRect(0,0,cv.width,cv.height);\n\n        const colors=['#38bdf8','#22c55e','#f59e0b','#ef4444','#a855f7','#14b8a6'];\n\n        const buildMetricTimeline = function(metric) {\n            const timeline = {};\n            const groupTotals = {};\n            rows.forEach(r => {\n                const timeKey = (r.Data || '') + ' ' + (r.Ora || '00:00');\n                const grp = String(r[groupField] || 'N\/D').trim() || 'N\/D';\n                const value = window.parseReportNum(r[metric], 0) || 0;\n                if (!timeline[timeKey]) timeline[timeKey] = {};\n                timeline[timeKey][grp] = (timeline[timeKey][grp] || 0) + value;\n                groupTotals[grp] = (groupTotals[grp] || 0) + value;\n            });\n            const entries = Object.entries(timeline).sort((a,b)=>a[0].localeCompare(b[0])).slice(-12);\n            const groups = Object.entries(groupTotals).sort((a,b)=>b[1]-a[1]).slice(0,4).map(e => e[0]);\n            return { entries, groups };\n        };\n\n        let drewAtLeastOne = false;\n\n        metrics.forEach((metric, metricIndex) => {\n            const data = buildMetricTimeline(metric);\n            const entries = data.entries;\n            const groups = data.groups;\n            const col = metricIndex % cols;\n            const row = Math.floor(metricIndex \/ cols);\n            const originX = 20 + col * blockW;\n            const originY = 20 + row * blockH;\n\n            ctx.fillStyle = '#fff';\n            ctx.font = 'bold 13px Arial';\n            ctx.fillText(window.getActivityMetricLabel([metric]), originX + 8, originY + 18);\n\n            if (!entries.length || !groups.length) {\n                ctx.fillStyle='#cbd5e1';\n                ctx.font='12px Arial';\n                ctx.fillText('Nessun dato per ' + window.getActivityMetricLabel([metric]), originX + 8, originY + 42);\n                return;\n            }\n\n            drewAtLeastOne = true;\n            const max = Math.max(1, ...entries.flatMap(e => groups.map(g => e[1][g] || 0)));\n            const baseY = originY + 240;\n            const left = originX + 52;\n            const step = 32;\n            const barW = Math.max(8, Math.floor(34 \/ Math.max(1, groups.length)));\n\n            ctx.strokeStyle='#94a3b8';\n            ctx.beginPath();\n            ctx.moveTo(left, originY + 32);\n            ctx.lineTo(left, baseY);\n            ctx.lineTo(left + step * (entries.length), baseY);\n            ctx.stroke();\n\n            entries.forEach(([label, metricsAtTime], i)=>{\n                const groupX = left + 10 + i * step;\n                groups.forEach((grp, gi) => {\n                    const val = metricsAtTime[grp] || 0;\n                    const h = (val\/max)*160;\n                    const x = groupX + gi*(barW+3);\n                    ctx.fillStyle='rgba(0,0,0,0.25)';\n                    ctx.fillRect(x+4, baseY-h+4, barW, h);\n                    ctx.fillStyle=colors[gi%colors.length];\n                    ctx.fillRect(x, baseY-h, barW, h);\n                    if (h > 0) {\n                        ctx.fillStyle='#fff';\n                        ctx.font='10px Arial';\n                        ctx.fillText(window.fmtNum(val), x-2, baseY-h-6);\n                    }\n                });\n                ctx.save();\n                ctx.fillStyle='#fff';\n                ctx.font='10px Arial';\n                ctx.translate(groupX, baseY+14);\n                ctx.rotate(-0.6);\n                ctx.fillText(label.slice(0,16),0,0);\n                ctx.restore();\n            });\n\n            groups.forEach((grp, gi) => {\n                const lx = originX + 8 + gi * 104;\n                const ly = originY + 34;\n                ctx.fillStyle = colors[gi%colors.length];\n                ctx.fillRect(lx, ly, 12, 12);\n                ctx.fillStyle = '#fff';\n                ctx.font = '11px Arial';\n                ctx.fillText(grp, lx + 18, ly + 10);\n            });\n\n            ctx.fillStyle = '#cbd5e1';\n            ctx.font = '11px Arial';\n            ctx.fillText('Raggruppa per: ' + groupField, originX + 8, originY + blockH - 12);\n        });\n\n        if (!drewAtLeastOne) {\n            ctx.fillStyle='#fff';\n            ctx.font='14px Arial';\n            ctx.fillText('Nessun dato',20,20);\n        }\n    };\n    window.renderActivityReport = function() {\n        const box = gE('ti-report-cnt'); if(!box) return;\n        const allRows = window.getFilteredActivityRows(true);\n        const rowFlags = (window.activityReportState && window.activityReportState.rowFlags) || {};\n        const includedRows = allRows.filter(r => !rowFlags[r.__rowKey]);\n        const titleEl = gE('ti-report-title');\n        if (titleEl) titleEl.innerText = '\ud83d\udcca ' + window.getActivityReportTitle(includedRows);\n        const allCols = window.activityReportCols;\n        const visibleCols = window.getActivityVisibleCols();\n        const hiddenCols = allCols.filter(c => !visibleCols.includes(c));\n        const view = window.activityReportState.view || 'table';\n        const availableMetrics = window.getActivityAvailableMetrics();\n        const selectedMetrics = window.getActivitySelectedMetrics();\n        const totals = {\n            Prezzo: includedRows.reduce((s,r)=>s+(r.Prezzo||0),0),\n            Quantit\u00e0: includedRows.reduce((s,r)=>s+(r.Quantit\u00e0||0),0),\n            Totale: includedRows.reduce((s,r)=>s+(r.Totale||0),0)\n        };\n        let html = '<div class=\"ti-report-toolbar\">'\n            + '<button type=\"button\" class=\"ti-btn\" onclick=\"window.setActivityReportView(\\'table\\')\">Elenco dati<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" onclick=\"window.setActivityReportView(\\'pie\\')\">Torte<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" onclick=\"window.setActivityReportView(\\'bar\\')\">Barre<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" onclick=\"window.setActivityReportView(\\'trend\\')\">Andamento<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" onclick=\"window.exportActivityReportCsv()\">Export CSV<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" onclick=\"window.printActivityReport()\">Stampa<\/button>'\n            + ((window.userCanSeeConfigurationActivities && window.userCanSeeConfigurationActivities())\n                ? '<label class=\"ti-report-config-filter\" title=\"Esclude dal report le righe attivit\u00e0 create dalla configurazione\"><input type=\"checkbox\" ' + ((window.activityReportState && window.activityReportState.excludeConfigActivities) ? 'checked' : '') + ' onchange=\"window.setActivityExcludeConfigActivities(this.checked)\"><span>Escludi configurazione<\/span><\/label>'\n                : '<span class=\"ti-report-config-filter\" title=\"Le attivit\u00e0 di configurazione sono visibili solo ad amministratori e configuratori\">Configurazione nascosta<\/span>')\n            + '<\/div>';\n        if (view !== 'table') {\n            const groupFields = window.getActivityAvailableGroupFields();\n            const selectedGroupField = window.getActivitySelectedGroupField();\n            html += '<div class=\"ti-report-hidden-cols\" style=\"display:flex;gap:10px;align-items:center;flex-wrap:wrap;\">';\n            if (view === 'pie' || view === 'bar' || view === 'trend') {\n                html += '<label class=\"ti-report-col-chip\" style=\"display:inline-flex;align-items:center;gap:6px;\">'\n                    + '<span>Raggruppa per<\/span>'\n                    + '<select class=\"ti-in\" style=\"width:auto;min-width:160px;padding:6px 8px;\" onchange=\"window.setActivityGroupField(this.value)\">'\n                    + groupFields.map(function(field){ return '<option value=\"' + window.escapeHtml(field) + '\" ' + (field === selectedGroupField ? 'selected' : '') + '>' + window.escapeHtml(field) + '<\/option>'; }).join('')\n                    + '<\/select>'\n                    + '<\/label>';\n            }\n            availableMetrics.forEach(function(metric){\n                const checked = selectedMetrics.includes(metric);\n                const metricJs = JSON.stringify(String(metric));\n                html += '<label class=\"ti-report-col-chip\" style=\"display:inline-flex;align-items:center;gap:6px;\">'\n                    + '<input type=\"checkbox\" ' + (checked ? 'checked' : '') + ' onchange=\"window.setActivityMetricFlag(' + metricJs.replace(\/\"\/g, '&quot;') + ', this.checked)\">'\n                    + '<span>' + window.escapeHtml(metric) + '<\/span>'\n                    + '<\/label>';\n            });\n            html += '<\/div>';\n        }\n        if (hiddenCols.length) {\n            html += '<div class=\"ti-report-hidden-cols\">' + hiddenCols.map(c => `<span class=\"ti-report-col-chip\"><button type=\"button\" class=\"ti-report-flag-btn is-off\" onclick='window.toggleActivityReportColumn(${JSON.stringify(c)}, event)'>X<\/button>${window.escapeHtml(c)}<\/span>`).join('') + '<\/div>';\n        }\n        if (view === 'table') {\n            html += '<div class=\"ti-report-table-wrap\"><table class=\"ti-report-table\"><thead><tr>';\n            html += '<th class=\"ti-report-row-flag-cell head\">X<\/th>';\n            visibleCols.forEach(c => {\n                const sortKey = (c === 'Data' || c === 'Ora') ? 'DataOra' : c;\n                html += `<th onclick='window.sortActivityReport(${JSON.stringify(sortKey)})'><button type=\"button\" class=\"ti-report-flag-btn\" onclick='window.toggleActivityReportColumn(${JSON.stringify(c)}, event)'>X<\/button>${window.escapeHtml(c)}<br><input class=\"ti-report-filter\" data-col=\"${window.escapeHtml(c)}\" value=\"${window.escapeHtml(window.activityReportState.filters[c] || '')}\" onclick=\"event.stopPropagation()\" oninput='window.setActivityReportFilter(${JSON.stringify(c)}, this.value, this)'><\/th>`;\n            });\n            html += '<\/tr><\/thead><tbody>';\n            allRows.forEach(r => {\n                const rowExcluded = !!rowFlags[r.__rowKey];\n                html += '<tr class=\"' + (rowExcluded ? 'ti-report-row-excluded' : '') + '\">';\n                html += `<td class=\"ti-report-row-flag-cell\"><button type=\"button\" class=\"ti-report-flag-btn ${rowExcluded ? 'is-off' : ''}\" onclick='window.toggleActivityReportRow(${JSON.stringify(r.__rowKey)}, event)'>X<\/button><\/td>`;\n                visibleCols.forEach(c => {\n                    const val = (c === 'Prezzo' || c === 'Quantit\u00e0' || c === 'Totale') ? window.fmtNum(r[c] || 0) : (r[c] || '');\n                    html += '<td class=\"' + ((c === 'Prezzo' || c === 'Quantit\u00e0' || c === 'Totale') ? 'ti-report-num' : '') + '\">' + window.escapeHtml(String(val)) + '<\/td>';\n                });\n                html += '<\/tr>';\n            });\n            html += '<\/tbody><tfoot><tr><td class=\"ti-report-row-flag-cell\">Incl.<\/td>';\n            visibleCols.forEach(c => {\n                if (c === 'Descrizione') html += '<td>Righe: ' + includedRows.length + '<\/td>';\n                else if (c === 'Prezzo') html += '<td class=\"ti-report-num\">' + window.fmtNum(totals.Prezzo) + '<\/td>';\n                else if (c === 'Quantit\u00e0') html += '<td class=\"ti-report-num\">' + window.fmtNum(totals.Quantit\u00e0) + '<\/td>';\n                else if (c === 'Totale') html += '<td class=\"ti-report-num\">' + window.fmtNum(totals.Totale) + '<\/td>';\n                else html += '<td><\/td>';\n            });\n            html += '<\/tr><\/tfoot><\/table><\/div>';\n        } else if (view === 'pie') {\n            html += '<div class=\"ti-chart-wrap\"><canvas id=\"ti-report-pie\" width=\"860\" height=\"340\"><\/canvas><\/div>';\n        } else if (view === 'bar') {\n            html += '<div class=\"ti-chart-wrap\"><canvas id=\"ti-report-bar\" width=\"980\" height=\"380\"><\/canvas><\/div>';\n        } else {\n            html += '<div class=\"ti-chart-wrap\"><canvas id=\"ti-report-trend\" width=\"980\" height=\"380\"><\/canvas><\/div>';\n        }\n        box.innerHTML = html;\n        const focus = window.activityReportState.filterFocus;\n        if (focus && focus.col && view === 'table') {\n            setTimeout(() => {\n                const inp = box.querySelector('.ti-report-filter[data-col=\"' + CSS.escape(focus.col) + '\"]');\n                if (inp) {\n                    inp.focus();\n                    if (typeof focus.start === 'number' && typeof focus.end === 'number' && inp.setSelectionRange) {\n                        try { inp.setSelectionRange(focus.start, focus.end); } catch(e) {}\n                    }\n                }\n            }, 0);\n        }\n        if(view === 'pie') setTimeout(() => window.drawPie3D('ti-report-pie', includedRows), 30);\n        if(view === 'bar') setTimeout(() => window.drawBar3D('ti-report-bar', includedRows), 30);\n        if(view === 'trend') setTimeout(() => window.drawTrend3D('ti-report-trend', includedRows), 30);\n    };\n    window.tiReportPick = function(row, keys, defVal) {\n        row = row || {}; keys = Array.isArray(keys) ? keys : [keys];\n        for (const k of keys) {\n            if (row[k] !== undefined && row[k] !== null && String(row[k]).trim() !== '') return String(row[k]).trim();\n            const found = Object.keys(row).find(x => String(x).toLowerCase() === String(k).toLowerCase());\n            if (found && row[found] !== undefined && row[found] !== null && String(row[found]).trim() !== '') return String(row[found]).trim();\n        }\n        return defVal || '';\n    };\n    window.tiReportBelongsToCurrentUser = function(row) {\n        if (window.tiIsPrivilegedCurrentUser && window.tiIsPrivilegedCurrentUser()) return true;\n        const user = String(window.tiUser || '').trim().toLowerCase();\n        const display = String(window.tiUserDisplay || '').trim().toLowerCase();\n        if (!user && !display) return false;\n        const names = [\n            window.tiReportPick(row, ['Username','Utente','user']),\n            window.tiReportPick(row, ['Nome','Cliente','Display'])\n        ].map(v => String(v || '').trim().toLowerCase()).filter(Boolean);\n        return names.some(v => v === user || v === display || (!!user && v.indexOf(user) !== -1) || (!!display && v.indexOf(display) !== -1));\n    };\n    window.tiReportTableRows = function(tNames) {\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return [];\n        for (const t of tNames) {\n            const raw = window.currentDbData.Tabelle[t];\n            if (!raw) continue;\n            return Array.isArray(raw) ? raw : Object.values(raw || {});\n        }\n        return [];\n    };\n    window.tiBuildPublicActivityReportRows = function() {\n        const rows = [];\n        const escNum = function(v, defVal) { const n = window.parseReportNum ? window.parseReportNum(v, defVal || 0) : parseFloat(String(v || '0').replace(',', '.')); return isNaN(n) ? (defVal || 0) : n; };\n        const canFull = window.tiIsPrivilegedCurrentUser && window.tiIsPrivilegedCurrentUser();\n        const appRows = window.tiReportTableRows(['Appuntamenti','Prenotazioni']);\n        appRows.forEach(function(r){\n            r = r || {};\n            if (!canFull && !window.tiReportBelongsToCurrentUser(r)) return;\n            const st = window.tiReportPick(r, ['Stato','Status']);\n            const lowerSt = String(st || '').toLowerCase();\n            if (lowerSt.indexOf('cancell') !== -1 || lowerSt.indexOf('annull') !== -1) return;\n            rows.push({kind:'appointment', title:'Dettaglio appuntamento', fields:{\n                'Username': window.tiReportPick(r, ['Username','Utente','user']),\n                'Servizio': window.tiReportPick(r, ['Servizio','Prestazione','Trattamento','Descrizione']),\n                'Data appuntamento': window.tiReportPick(r, ['Data_appuntamento','Data appuntamento','Data prenotazione','Giorno']),\n                'Ora appuntamento': window.tiReportPick(r, ['Ora_appuntamento','Ora appuntamento','Ora prenotazione','Orario']),\n                'Quantit\u00e0': window.tiReportPick(r, ['Quantit\u00e0','Quantita','Qta','Q.t\u00e0']),\n                'Email': window.tiReportPick(r, ['Email_utente','Email utente','Email','E-mail']),\n                'Tel': window.tiReportPick(r, ['Tel_Utente','Tel Utente','Tel','Telefono','Cellulare']),\n                'Data': window.tiReportPick(r, ['Data']),\n                'Ora': window.tiReportPick(r, ['Ora']),\n                'Nota': window.tiReportPick(r, ['Nota','Note']),\n                'Stato': st\n            }});\n        });\n        const actRows = window.tiReportTableRows(['Attivita','Attivit\u00e0']);\n        actRows.forEach(function(r){\n            r = r || {};\n            if (!canFull && !window.tiReportBelongsToCurrentUser(r)) return;\n            const st = window.tiReportPick(r, ['Stato','Status']);\n            const lowerSt = String(st || '').toLowerCase();\n            if (lowerSt.indexOf('cancell') !== -1 || lowerSt.indexOf('annull') !== -1) return;\n            const prezzo = window.tiReportPick(r, ['Prezzo','Importo','Costo'], '0');\n            const qta = window.tiReportPick(r, ['Quantit\u00e0','Quantita','Qta','Q.t\u00e0'], '1');\n            let totale = window.tiReportPick(r, ['Totale','Importo totale','Totale riga'], '');\n            if (!totale) totale = window.fmtNum ? window.fmtNum(escNum(prezzo, 0) * (escNum(qta, 1) || 1)) : String((escNum(prezzo, 0) * (escNum(qta, 1) || 1)).toFixed(2));\n            rows.push({kind:'activity', title:'Dettaglio attivit\u00e0', fields:{\n                'Username': window.tiReportPick(r, ['Username','Utente','user']),\n                'Descrizione': window.tiReportPick(r, ['Descrizione attivit\u00e0','Descrizione attivita','Descrizione','Dettaglio','Note','Nota','Prodotto','Servizio']),\n                'Prezzo': prezzo,\n                'Quantit\u00e0': qta,\n                'Esito': window.tiReportPick(r, ['Esito']),\n                'Data': window.tiReportPick(r, ['Data','Data attivit\u00e0','Data attivita','Data creazione']),\n                'Ora': window.tiReportPick(r, ['Ora','Ora attivit\u00e0','Ora attivita','Ora creazione']),\n                'Totale': totale\n            }});\n        });\n        return rows;\n    };\n    window.buildActivityReportChatHtml = function() {\n        const esc = window.escapeHtml || function(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); };\n        const rows = window.tiBuildPublicActivityReportRows ? window.tiBuildPublicActivityReportRows() : [];\n        if (!rows.length) return '<b>Report attivit\u00e0<\/b><br>Non trovo attivit\u00e0 o appuntamenti da mostrare per l utente corrente nel database selezionato.';\n        let html = '<b>Report attivit\u00e0<\/b><br>Visualizzazione in chatbot.<br><ol style=\"margin:8px 0 0 20px;padding:0;\">';\n        rows.forEach(function(item){\n            html += '<li style=\"margin:8px 0;\"><b>' + esc(item.title) + '<\/b><br><ol style=\"margin:4px 0 0 18px;padding:0;\">';\n            Object.keys(item.fields || {}).forEach(function(k){\n                html += '<li><b>' + esc(k) + '<\/b>: ' + esc(item.fields[k] || '') + '<\/li>';\n            });\n            html += '<\/ol><\/li>';\n        });\n        html += '<\/ol>';\n        return html;\n    };\n    window.openActivityReport = function() {\n        const prefs = window.loadActivityReportPrefs ? window.loadActivityReportPrefs() : {};\n        window.activityReportState = {\n            sortCol: prefs.sortCol || 'DataOra',\n            sortDir: prefs.sortDir === 'asc' ? 'asc' : 'desc',\n            filters: {},\n            view: (prefs.view && ['table','pie','bar','trend'].includes(prefs.view)) ? prefs.view : 'table',\n            colFlags: prefs.colFlags || {},\n            rowFlags: prefs.rowFlags || {},\n            metricFlags: prefs.metricFlags || (window.getDefaultActivityMetricFlags ? window.getDefaultActivityMetricFlags() : {}),\n            groupField: prefs.groupField || 'Username',\n            excludeConfigActivities: !!prefs.excludeConfigActivities\n        };\n        if (window.renderActivityReport) window.renderActivityReport();\n        if (window.openModal) window.openModal('ti-report-ov');\n    };\n\n    window.hasInstructionText = function(row) {\n        if (!row || typeof row !== 'object') return false;\n        const wanted = ['istruzioni','istruzione','istruzioni ai','istruzione ai','indicazioni ai','condizioni','prompt ai','prompt','regola','regole'];\n        return Object.keys(row).some((k) => {\n            const key = String(k).toLowerCase().trim();\n            if (!wanted.includes(key)) return false;\n            const val = row[k];\n            return val !== undefined && val !== null && String(val).trim() !== '';\n        });\n    };\n\n    window.buildInstructionsViewDb = function(fullDb) {\n        if (!fullDb || !fullDb.Tabelle) return null;\n        const view = Object.assign({}, fullDb, { Tabelle: {} });\n        let tableCount = 0;\n        let rowCount = 0;\n        Object.keys(fullDb.Tabelle).forEach((tName) => {\n            const raw = fullDb.Tabelle[tName];\n            const rows = Array.isArray(raw) ? raw : Object.values(raw || {});\n            const matched = [];\n            rows.forEach(function(row, idx){\n                if (!window.hasInstructionText(row)) return;\n                const copy = Object.assign({}, row);\n                try { Object.defineProperty(copy, '__ti_original_idx', {value: idx, enumerable: false, configurable: true}); }\n                catch(e) { copy.__ti_original_idx = idx; }\n                matched.push(copy);\n            });\n            if (matched.length) {\n                view.Tabelle[tName] = matched;\n                tableCount += 1;\n                rowCount += matched.length;\n            }\n        });\n        view.__instructionStats = { tables: tableCount, rows: rowCount };\n        return view;\n    };\n\n\n    window.tiAiSsIsDatabaseFullAdmin1562 = function() {\n        const role1562 = String(window.tiRole || window.tiUserRole || window.currentUserRole || '').toLowerCase();\n        const user1562 = String(window.tiUser || '').toLowerCase();\n        return user1562 === 'ssglobaladmin' || user1562 === 'globaladmin' || user1562 === 'targetai' || \/(^|[^a-z0-9])(amministratore|administrator|globaladmin|global admin|ssglobaladmin|sysadmin|admin)([^a-z0-9]|$)\/i.test(role1562);\n    };\n    window.isAdminUser = function() {\n        return window.tiAiSsIsDatabaseFullAdmin1562 ? window.tiAiSsIsDatabaseFullAdmin1562() : (\/amministratore|administrator\/i.test(String(window.tiRole || '')) || String(window.tiUser || '') === 'SSGlobalAdmin');\n    };\n\n    window.canRunLocalOrphanCleanup = function() {\n        const roleNow = String(window.tiRole || '').toLowerCase();\n        const userNow = String(window.tiUser || '').toLowerCase();\n        return userNow === 'ssglobaladmin' || \/amministratore|configuratore|responsabile|globale\/.test(roleNow);\n    };\n    window.canRunGlobalOrphanCleanup = function() {\n        return String(window.tiUser || '').toLowerCase() === 'ssglobaladmin';\n    };\n    window.refreshOrphanCleanupButton = function() {\n        const localBtn = gE('ti-clean-orphans-btn');\n        const globalBtn = gE('ti-clean-orphans-global-btn');\n        if (localBtn) localBtn.style.display = (window.canRunLocalOrphanCleanup && window.canRunLocalOrphanCleanup()) ? 'inline-block' : 'none';\n        if (globalBtn) globalBtn.style.display = (window.canRunGlobalOrphanCleanup && window.canRunGlobalOrphanCleanup()) ? 'block' : 'none';\n        if (window.refreshPrivilegedActionsRow) window.refreshPrivilegedActionsRow();\n    };\n\n    window.orphanCleanupState = window.orphanCleanupState || { active:false, stopRequested:false, total:0, processed:0, deleted:0, currentPath:'' };\n\n    window.restoreDefaultLoaderActions = function() {\n        const actions = gE('ti-loader-actions');\n        if (!actions) return;\n        actions.innerHTML = '<button type=\"button\" id=\"ti-loader-close\" class=\"ti-btn\" style=\"width:100%; background:#b91c1c; color:#fff;\" onclick=\"window.cancelLongAIProcess()\">Esci<\/button>';\n    };\n\n    window.showOrphanCleanupEmergencyButton = function() {\n        const actions = gE('ti-loader-actions');\n        if (!actions) return;\n        actions.style.display = 'block';\n        actions.innerHTML = '<button type=\"button\" id=\"ti-orphan-emergency-stop\" class=\"ti-btn\" style=\"width:100%; background:#dc2626; color:#fff; font-weight:800;\" onclick=\"window.requestStopOrphanFileCleanup()\">\ud83d\uded1 Esci d\\'emergenza - interrompi cancellazione<\/button>'\n            + '<div style=\"margin-top:6px; color:#fecaca; font-size:11px; line-height:1.35;\">Il file eventualmente in cancellazione termina. I file successivi non verranno cancellati.<\/div>';\n    };\n\n    window.requestStopOrphanFileCleanup = function() {\n        const st = window.orphanCleanupState || {};\n        if (!st.active) {\n            window.tiAlert('Nessun processo di pulizia file non associati in corso.');\n            return;\n        }\n        st.stopRequested = true;\n        window.orphanCleanupState = st;\n        const btn = gE('ti-orphan-emergency-stop');\n        if (btn) { btn.disabled = true; btn.innerText = 'Interruzione richiesta...'; }\n        window.updateProgressPopup(\n            Math.max(1, Math.min(99, parseInt(st.lastPercent || 50, 10) || 50)),\n            'Pulizia file non associati',\n            'Esci d emergenza richiesto. Attendo la fine dell eventuale cancellazione in corso.',\n            st.currentPath || 'Interruzione richiesta'\n        );\n    };\n\n    window.runOrphanFileCleanup = function() {\n        if (!(window.canRunLocalOrphanCleanup && window.canRunLocalOrphanCleanup())) {\n            window.tiAlert('Funzione non disponibile con il profilo corrente.');\n            return;\n        }\n        const dbVal = gE('ti-ditta') ? (gE('ti-ditta').value || '') : '';\n        if (!dbVal) { window.tiAlert('Seleziona una ditta prima di avviare la pulizia.'); return; }\n        const ask = 'Questa funzione elimina fisicamente dallo storage i file non associati a nessuna tabella della ditta selezionata e rimuove anche dal database\/schermata le associazioni a file non piu presenti.<br><br>Prima verra eseguita una scansione delle associazioni fantasma e dei file fisici. Durante la cancellazione vedrai il path completo dell elemento eliminato.<br><br>Confermi di procedere?';\n        const start = function() { window.startOrphanFileCleanup(dbVal); };\n        if (typeof window.tiConfirmYesNoAction === 'function') window.tiConfirmYesNoAction(ask, start, null, 'AVVIA PULIZIA', 'ANNULLA');\n        else window.tiConfirm(ask.replace(\/<br\\s*\\\/?>\/gi, '\\n'), start);\n    };\n\n\n\n    window.forceCleanupMissingMediaRefs610 = function(dbVal) {\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_force_cleanup_missing_media_refs');\n        fd.append('db', dbVal);\n        return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true}).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) ? res.data.message : 'Pulizia diretta riferimenti fantasma non riuscita.');\n            return res.data || {};\n        });\n    };\n\n    window.startOrphanFileCleanup = function(dbVal) {\n        window.orphanCleanupState = { active:true, stopRequested:false, total:0, processed:0, deleted:0, currentPath:'Scansione file della ditta', lastPercent:2, startedAt:Date.now() };\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_scan_orphan_files');\n        fd.append('db', dbVal);\n        window.showProgressPopup('Pulizia file non associati', 'Scansione file della ditta in corso.', {startPercent: 2, targetPercent: 18, stepMs: 350, cancellable:false, currentItem:'Scansione file della ditta'});\n        window.showOrphanCleanupEmergencyButton();\n        window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true}).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) ? res.data.message : 'Scansione non riuscita.');\n            const files = (res.data && Array.isArray(res.data.files)) ? res.data.files : [];\n            if (!files.length) {\n                window.updateProgressPopup(35, 'Pulizia file non associati', 'Nessun file fisico trovato. Verifico associazioni fantasma nei campi database.', 'Scansione diretta campi database');\n                return window.forceCleanupMissingMediaRefs610(dbVal).then(function(forceRes){\n                    const removed = parseInt((forceRes && forceRes.removed) || 0, 10) || 0;\n                    if (window.orphanCleanupState) window.orphanCleanupState.active = false;\n                    window.restoreDefaultLoaderActions();\n                    if (removed > 0) {\n                        const msg = 'Pulizia completata. Rimosse ' + removed + ' associazioni fantasma dai campi database.';\n                        window.updateProgressPopup(100, 'Pulizia file non associati', msg, msg);\n                        window.hideProgressPopup(true, 'Associazioni fantasma rimosse', {notifyUser:true, successMessage:msg});\n                        setTimeout(function(){\n                            window.tiAlert(msg + '<br><br>La Configurazione e la schermata Gestione File Associati vengono aggiornate automaticamente.');\n                        }, 300);\n                    } else {\n                        window.hideProgressPopup(true, 'Nessun file non associato trovato', {notifyUser:true, successMessage:'Pulizia completata. Nessun file non associato o associazione fantasma da eliminare.'});\n                        setTimeout(function(){ window.tiAlert('Pulizia completata.<br>Nessun file non associato o associazione fantasma da eliminare.'); }, 300);\n                    }\n                }).catch(function(err){\n                    if (window.orphanCleanupState) window.orphanCleanupState.active = false;\n                    window.restoreDefaultLoaderActions();\n                    window.hideProgressPopup(false, 'Errore pulizia associazioni fantasma');\n                    window.tiAlert('Errore durante la pulizia diretta delle associazioni fantasma: ' + ((err && err.message) ? err.message : 'errore sconosciuto'));\n                });\n            }\n            if (window.orphanCleanupState) { window.orphanCleanupState.total = files.length; window.orphanCleanupState.currentPath = 'File trovati: ' + files.length; window.orphanCleanupState.lastPercent = 20; }\n            window.updateProgressPopup(20, 'Pulizia file non associati', 'Trovati ' + files.length + ' file non associati. Avvio cancellazione.', 'File trovati: ' + files.length);\n            window.showOrphanCleanupEmergencyButton();\n            window.deleteOrphanFilesSequential(dbVal, files, 0, 0, [], []);\n        }).catch(function(e){\n            if (window.orphanCleanupState) window.orphanCleanupState.active = false;\n            window.restoreDefaultLoaderActions();\n            window.hideProgressPopup(false, 'Errore pulizia file');\n            window.tiAlert('Errore durante la scansione file non associati: ' + ((e && e.message) ? e.message : 'errore sconosciuto'));\n        });\n    };\n\n    window.showOrphanCleanupFinalReport = function(deletedPaths, errors, total, deleted, interrupted, processed, scopeInfo) {\n        const paths = Array.isArray(deletedPaths) ? deletedPaths : [];\n        const errList = Array.isArray(errors) ? errors : [];\n        const scope = scopeInfo && typeof scopeInfo === 'object' ? scopeInfo : {};\n        const proc = Math.max(0, parseInt(processed || deleted + errList.length, 10) || 0);\n        const scopeLabel = scope.label || ((window.orphanCleanupState && window.orphanCleanupState.globalMode) ? 'Pulizia globale su tutte le ditte' : 'Pulizia ditta selezionata');\n        const ditteProcessed = parseInt(scope.ditteProcessed || 0, 10) || 0;\n        const ditteTotal = parseInt(scope.ditteTotal || 0, 10) || 0;\n        const summary = (interrupted ? 'Pulizia interrotta su richiesta amministratore. ' : '') + 'File eliminati: ' + deleted + ' su ' + total + '. File processati: ' + proc + ' su ' + total + (ditteTotal ? '. Ditte processate: ' + ditteProcessed + ' su ' + ditteTotal : '') + (errList.length ? '. Errori: ' + errList.length : '.');\n        const reportLines = [];\n        reportLines.push('Report pulizia file non associati');\n        reportLines.push('Ambito: ' + scopeLabel);\n        reportLines.push('Versione plugin: ' + (window.tiVersion || '') + ' - ' + (window.tiVersionDateTime || ''));\n        if (interrupted) reportLines.push('Esito: processo interrotto con Esci d emergenza');\n        reportLines.push(summary);\n        reportLines.push('');\n        reportLines.push('Path file cancellati:');\n        if (paths.length) paths.forEach(function(path, idx){ reportLines.push((idx + 1) + '. ' + path); });\n        else reportLines.push('Nessun file cancellato.');\n        if (errList.length) {\n            reportLines.push('');\n            reportLines.push('Errori o file non cancellati:');\n            errList.forEach(function(err, idx){ reportLines.push((idx + 1) + '. ' + err); });\n        }\n        window.lastOrphanCleanupReportText = reportLines.join('\\n');\n        let html = '<div class=\"ti-orphan-report-wide\" style=\"text-align:left; max-height:72vh; overflow:auto; font-size:11px; line-height:1.35;\">';\n        html += '<div style=\"font-weight:800; font-size:14px; margin-bottom:8px;\">Report pulizia file non associati<\/div>';\n        html += '<div style=\"margin-bottom:6px; color:#93c5fd; font-size:11px;\"><b>Ambito:<\/b> ' + window.escapeHtml(scopeLabel) + '<\/div>';\n        if (interrupted) html += '<div style=\"margin-bottom:8px; color:#fbbf24; font-weight:800;\">Processo interrotto con Esci d emergenza.<\/div>';\n        html += '<div style=\"margin-bottom:8px; color:#cbd5e1; font-size:11px;\">' + window.escapeHtml(summary) + '<\/div>';\n        html += '<div style=\"font-weight:700; margin:10px 0 5px; font-size:12px;\">Path file cancellati<\/div>';\n        if (paths.length) {\n            html += '<ol style=\"padding-left:18px; margin:0; color:#e5e7eb; font-size:10.5px; line-height:1.35; word-break:break-all;\">';\n            paths.forEach(function(path){ html += '<li>' + window.escapeHtml(path) + '<\/li>'; });\n            html += '<\/ol>';\n        } else {\n            html += '<div style=\"color:#e5e7eb; font-size:11px;\">Nessun file cancellato.<\/div>';\n        }\n        if (errList.length) {\n            html += '<div style=\"font-weight:700; margin:12px 0 5px; color:#fecaca; font-size:12px;\">Errori o file non cancellati<\/div>';\n            html += '<ol style=\"padding-left:18px; margin:0; color:#fecaca; font-size:10.5px; line-height:1.35; word-break:break-all;\">';\n            errList.forEach(function(err){ html += '<li>' + window.escapeHtml(err) + '<\/li>'; });\n            html += '<\/ol>';\n        }\n        html += '<div style=\"margin-top:10px; font-size:11px; color:#93c5fd;\">Usa il pulsante Copia testo per copiare il report e incollarlo dove serve.<\/div>';\n        html += '<\/div>';\n        window.tiAlert(html);\n        setTimeout(function(){\n            const reportModal = document.querySelector('#ti-alert-ov .ti-modal');\n            const reportMsg = gE('ti-alert-msg');\n            if (reportModal) { reportModal.style.width = 'min(94vw, 1080px)'; reportModal.style.maxWidth = '1080px'; reportModal.style.padding = '16px'; }\n            if (reportMsg) { reportMsg.style.fontSize = '11px'; reportMsg.style.lineHeight = '1.35'; reportMsg.style.marginBottom = '12px'; }\n            const okBtn = gE('ti-alert-no');\n            if (okBtn && !okBtn.dataset.orphanReportWideClose) {\n                okBtn.dataset.orphanReportWideClose = '1';\n                const oldClose = okBtn.onclick;\n                okBtn.onclick = function(){\n                    if (reportModal) { reportModal.style.width = '300px'; reportModal.style.maxWidth = ''; reportModal.style.padding = '20px'; }\n                    if (reportMsg) { reportMsg.style.fontSize = '15px'; reportMsg.style.lineHeight = '1.4'; reportMsg.style.marginBottom = '20px'; }\n                    okBtn.dataset.orphanReportWideClose = '';\n                    if (typeof oldClose === 'function') oldClose.call(this);\n                    else window.closeModal('ti-alert-ov');\n                };\n            }\n            if (gE('ti-alert-copy')) {\n                gE('ti-alert-copy').onclick = function() {\n                    const text = window.lastOrphanCleanupReportText || window.getAlertPlainText();\n                    const done = function(ok) {\n                        const btn = gE('ti-alert-copy');\n                        if (!btn) return;\n                        const old = btn.innerText || 'Copia testo';\n                        btn.innerText = ok ? 'Copiato' : 'Errore copia';\n                        setTimeout(function(){ btn.innerText = old; }, 1200);\n                    };\n                    if (navigator.clipboard && navigator.clipboard.writeText) {\n                        navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){ done(false); });\n                    } else {\n                        try {\n                            const ta = document.createElement('textarea');\n                            ta.value = text; ta.style.position = 'fixed'; ta.style.left = '-9999px';\n                            document.body.appendChild(ta); ta.focus(); ta.select();\n                            const ok = document.execCommand('copy'); document.body.removeChild(ta); done(ok);\n                        } catch(e) { done(false); }\n                    }\n                };\n            }\n        }, 0);\n    };\n\n    window.deleteOrphanFilesSequential = function(dbVal, files, index, deleted, errors, deletedPaths) {\n        const total = files.length;\n        deletedPaths = Array.isArray(deletedPaths) ? deletedPaths : [];\n        const st = window.orphanCleanupState || {};\n        if (st.stopRequested) {\n            st.active = false;\n            st.processed = index;\n            window.orphanCleanupState = st;\n            window.restoreDefaultLoaderActions();\n            const msgStop = 'Pulizia interrotta. File eliminati: ' + deleted + ' su ' + total + '. File non ancora elaborati: ' + Math.max(0, total - index) + '.';\n            window.updateProgressPopup(Math.max(20, Math.min(99, parseInt(st.lastPercent || 20, 10) || 20)), 'Pulizia file non associati', msgStop, st.currentPath || 'Interruzione richiesta');\n            window.hideProgressPopup(false, 'Pulizia interrotta', {notifyUser:false});\n            setTimeout(function(){ window.showOrphanCleanupFinalReport(deletedPaths, errors, total, deleted, true, index); }, 500);\n            return;\n        }\n        if (index >= total) {\n            if (window.orphanCleanupState) { window.orphanCleanupState.active = false; window.orphanCleanupState.processed = total; }\n            window.restoreDefaultLoaderActions();\n            const ok = errors.length === 0;\n            const title = ok ? 'Pulizia file completata' : 'Pulizia completata con avvisi';\n            const msg = 'File eliminati: ' + deleted + ' su ' + total + (errors.length ? '. Errori: ' + errors.length : '.');\n            window.updateProgressPopup(100, 'Pulizia file non associati', msg, msg);\n            window.hideProgressPopup(ok, title, {notifyUser:true, successMessage:msg});\n            setTimeout(function(){ window.showOrphanCleanupFinalReport(deletedPaths, errors, total, deleted, false, total); }, 500);\n            return;\n        }\n        const file = files[index] || {};\n        const pathTxt = file.path || file.relative_path || file.name || 'file';\n        const rowInfo = file.table ? ('Tabella ' + file.table + (typeof file.row_index !== 'undefined' ? ', riga ' + (parseInt(file.row_index, 10) + 1) : '') + (file.field ? ', campo ' + file.field : '') + ' - ') : '';\n        const workLine = 'Elemento ' + (index + 1) + ' \/ ' + total + ' - ' + rowInfo + pathTxt;\n        const pct = Math.max(20, Math.min(99, Math.round(20 + ((index) \/ Math.max(1, total)) * 78)));\n        if (window.orphanCleanupState) { window.orphanCleanupState.currentPath = workLine; window.orphanCleanupState.lastPercent = pct; window.orphanCleanupState.processed = index; }\n        window.updateProgressPopup(pct, 'Pulizia file non associati', 'Cancellazione elemento ' + (index + 1) + ' \/ ' + total, workLine);\n        window.showOrphanCleanupEmergencyButton();\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_delete_orphan_file');\n        fd.append('db', dbVal);\n        fd.append('rel', file.rel || '');\n        (function(){\n            const p = window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true});\n            const t = new Promise(function(_, reject){ setTimeout(function(){ reject(new Error('timeout cancellazione elemento: il server non ha risposto entro 25 secondi')); }, 25000); });\n            return Promise.race([p, t]);\n        })().then(function(res){\n            if (res && res.success) {\n                const deletedPath = (res.data && res.data.path) ? res.data.path : pathTxt;\n                const doneLine = 'Elemento ' + (index + 1) + ' \/ ' + total + ' completato - ' + rowInfo + deletedPath;\n                const pct2 = Math.max(pct, Math.min(99, Math.round(20 + ((index + 1) \/ Math.max(1, total)) * 78)));\n                window.updateProgressPopup(pct2, 'Pulizia file non associati', 'Eliminato elemento ' + (index + 1) + ' \/ ' + total, doneLine);\n                if (window.orphanCleanupState) { window.orphanCleanupState.currentPath = doneLine; window.orphanCleanupState.lastPercent = pct2; window.orphanCleanupState.processed = index + 1; window.orphanCleanupState.deleted = deleted + 1; }\n                deletedPaths.push(deletedPath);\n                setTimeout(function(){ window.deleteOrphanFilesSequential(dbVal, files, index + 1, deleted + 1, errors, deletedPaths); }, 80);\n            } else {\n                errors.push(pathTxt + ' - ' + ((res && res.data && res.data.message) ? res.data.message : 'errore eliminazione'));\n                if (window.orphanCleanupState) { window.orphanCleanupState.processed = index + 1; }\n                setTimeout(function(){ window.deleteOrphanFilesSequential(dbVal, files, index + 1, deleted, errors, deletedPaths); }, 80);\n            }\n        }).catch(function(e){\n            errors.push(pathTxt + ' - ' + ((e && e.message) ? e.message : 'errore rete'));\n            if (window.orphanCleanupState) { window.orphanCleanupState.processed = index + 1; }\n            setTimeout(function(){ window.deleteOrphanFilesSequential(dbVal, files, index + 1, deleted, errors, deletedPaths); }, 80);\n        });\n    };\n\n\n    window.getGlobalOrphanCleanupDitte = function() {\n        const normalize = function(list) {\n            return (Array.isArray(list) ? list : []).filter(function(d){\n                const db = d && d.db ? String(d.db) : '';\n                return db && db !== 'Global' && db !== 'NEW_DB' && db !== 'shopservicemain.json';\n            });\n        };\n        const existing = normalize(window.ditteData || []);\n        if (existing.length) return Promise.resolve(existing);\n        const url = window.tiUrl + '?ti_action=ti_ai_list_ditte&current_db=&show_suspended=1';\n        return window.fetchJsonSafe(url, {method:'GET', tiNoLongProcessSignal:true}).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) ? res.data.message : 'Elenco ditte non disponibile.');\n            const list = normalize(res.data && res.data.ditte);\n            window.ditteData = list;\n            return list;\n        });\n    };\n\n    window.scanOrphanFilesForDb = function(dbVal, label) {\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_scan_orphan_files');\n        fd.append('db', dbVal);\n        if (window.orphanCleanupState) window.orphanCleanupState.currentPath = 'Scansione ditta: ' + (label || dbVal);\n        return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true}).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) ? res.data.message : 'Scansione non riuscita.');\n            return (res.data && Array.isArray(res.data.files)) ? res.data.files : [];\n        });\n    };\n\n    window.deleteSingleOrphanFile = function(dbVal, file) {\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_delete_orphan_file');\n        fd.append('db', dbVal);\n        fd.append('rel', (file && file.rel) ? file.rel : '');\n        const p = window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true});\n        const t = new Promise(function(_, reject){ setTimeout(function(){ reject(new Error('timeout cancellazione elemento: il server non ha risposto entro 25 secondi')); }, 25000); });\n        return Promise.race([p, t]);\n    };\n\n    window.runGlobalOrphanFileCleanup = function() {\n        if (String(window.tiUser || '') !== 'SSGlobalAdmin') {\n            window.tiAlert('Funzione globale non disponibile con il profilo corrente.');\n            return;\n        }\n        const ask = 'Questa funzione elimina fisicamente dallo storage i file non associati di tutte le ditte visibili al Global Admin.<br><br>Prima verra eseguita una scansione globale. Durante la cancellazione vedrai ditta e path completo del file eliminato.<br><br>Confermi di procedere?';\n        const start = function(){ window.startGlobalOrphanFileCleanup(); };\n        if (typeof window.tiConfirmYesNoAction === 'function') window.tiConfirmYesNoAction(ask, start, null, 'AVVIA PULIZIA GLOBALE', 'ANNULLA');\n        else window.tiConfirm(ask.replace(\/<br\\s*\\\/?>\/gi, '\\n'), start);\n    };\n\n    window.startGlobalOrphanFileCleanup = function() {\n        window.orphanCleanupState = { active:true, globalMode:true, stopRequested:false, total:0, processed:0, deleted:0, currentPath:'Scansione globale ditte', lastPercent:2, startedAt:Date.now(), ditteTotal:0, ditteProcessed:0 };\n        window.showProgressPopup('Pulizia globale file non associati', 'Scansione ditte in corso.', {startPercent: 2, targetPercent: 18, stepMs: 350, cancellable:false, currentItem:'Scansione globale ditte'});\n        window.showOrphanCleanupEmergencyButton();\n        window.getGlobalOrphanCleanupDitte().then(function(ditte){\n            if (!ditte.length) throw new Error('Nessuna ditta disponibile per la pulizia globale.');\n            if (window.orphanCleanupState) { window.orphanCleanupState.ditteTotal = ditte.length; window.orphanCleanupState.currentPath = 'Ditte trovate: ' + ditte.length; }\n            window.updateProgressPopup(8, 'Pulizia globale file non associati', 'Ditte trovate: ' + ditte.length + '. Avvio scansione file.', 'Ditte trovate: ' + ditte.length);\n            const allFiles = [];\n            const scanErrors = [];\n            const scanNext = function(i){\n                const st = window.orphanCleanupState || {};\n                if (st.stopRequested) {\n                    st.active = false; window.orphanCleanupState = st; window.restoreDefaultLoaderActions(); window.hideProgressPopup(false, 'Pulizia globale interrotta', {notifyUser:false});\n                    setTimeout(function(){ window.showOrphanCleanupFinalReport([], scanErrors, 0, 0, true, 0, {label:'Pulizia globale su tutte le ditte', ditteProcessed:i, ditteTotal:ditte.length}); }, 400);\n                    return;\n                }\n                if (i >= ditte.length) {\n                    if (!allFiles.length) {\n                        if (window.orphanCleanupState) window.orphanCleanupState.active = false;\n                        window.restoreDefaultLoaderActions();\n                        window.hideProgressPopup(true, 'Nessun file non associato trovato', {notifyUser:true, successMessage:'Pulizia globale completata. Nessun file non associato da eliminare.'});\n                        setTimeout(function(){ window.showOrphanCleanupFinalReport([], scanErrors, 0, 0, false, 0, {label:'Pulizia globale su tutte le ditte', ditteProcessed:ditte.length, ditteTotal:ditte.length}); }, 400);\n                        return;\n                    }\n                    if (window.orphanCleanupState) { window.orphanCleanupState.total = allFiles.length; window.orphanCleanupState.lastPercent = 35; window.orphanCleanupState.currentPath = 'File non associati totali: ' + allFiles.length; }\n                    window.updateProgressPopup(35, 'Pulizia globale file non associati', 'Trovati ' + allFiles.length + ' file non associati. Avvio cancellazione.', 'File non associati totali: ' + allFiles.length);\n                    window.deleteGlobalOrphanFilesSequential(allFiles, 0, 0, scanErrors, [], ditte.length, ditte.length);\n                    return;\n                }\n                const d = ditte[i] || {};\n                const db = d.db || '';\n                const label = d.label || d.nome_pura || db;\n                const pct = Math.max(8, Math.min(34, Math.round(8 + (i \/ Math.max(1, ditte.length)) * 26)));\n                if (window.orphanCleanupState) { window.orphanCleanupState.lastPercent = pct; window.orphanCleanupState.currentPath = 'Scansione: ' + label; window.orphanCleanupState.ditteProcessed = i; }\n                window.updateProgressPopup(pct, 'Pulizia globale file non associati', 'Scansione ditta ' + (i + 1) + ' \/ ' + ditte.length, label + ' - ' + db);\n                window.showOrphanCleanupEmergencyButton();\n                window.scanOrphanFilesForDb(db, label).then(function(files){\n                    files.forEach(function(f){ allFiles.push({db:db, label:label, file:f}); });\n                    if (window.orphanCleanupState) window.orphanCleanupState.ditteProcessed = i + 1;\n                    setTimeout(function(){ scanNext(i + 1); }, 40);\n                }).catch(function(e){\n                    scanErrors.push(label + ' [' + db + '] - scansione: ' + ((e && e.message) ? e.message : 'errore'));\n                    if (window.orphanCleanupState) window.orphanCleanupState.ditteProcessed = i + 1;\n                    setTimeout(function(){ scanNext(i + 1); }, 40);\n                });\n            };\n            scanNext(0);\n        }).catch(function(e){\n            if (window.orphanCleanupState) window.orphanCleanupState.active = false;\n            window.restoreDefaultLoaderActions();\n            window.hideProgressPopup(false, 'Errore pulizia globale');\n            window.tiAlert('Errore durante la pulizia globale file non associati: ' + ((e && e.message) ? e.message : 'errore sconosciuto'));\n        });\n    };\n\n    window.deleteGlobalOrphanFilesSequential = function(items, index, deleted, errors, deletedPaths, ditteProcessed, ditteTotal) {\n        const total = items.length;\n        deletedPaths = Array.isArray(deletedPaths) ? deletedPaths : [];\n        const st = window.orphanCleanupState || {};\n        if (st.stopRequested) {\n            st.active = false; st.processed = index; window.orphanCleanupState = st;\n            window.restoreDefaultLoaderActions();\n            const msgStop = 'Pulizia globale interrotta. File eliminati: ' + deleted + ' su ' + total + '. File non ancora elaborati: ' + Math.max(0, total - index) + '.';\n            window.updateProgressPopup(Math.max(35, Math.min(99, parseInt(st.lastPercent || 35, 10) || 35)), 'Pulizia globale file non associati', msgStop, st.currentPath || 'Interruzione richiesta');\n            window.hideProgressPopup(false, 'Pulizia globale interrotta', {notifyUser:false});\n            setTimeout(function(){ window.showOrphanCleanupFinalReport(deletedPaths, errors, total, deleted, true, index, {label:'Pulizia globale su tutte le ditte', ditteProcessed:ditteProcessed || 0, ditteTotal:ditteTotal || 0}); }, 500);\n            return;\n        }\n        if (index >= total) {\n            if (window.orphanCleanupState) { window.orphanCleanupState.active = false; window.orphanCleanupState.processed = total; }\n            window.restoreDefaultLoaderActions();\n            const ok = errors.length === 0;\n            const title = ok ? 'Pulizia globale completata' : 'Pulizia globale completata con avvisi';\n            const msg = 'File eliminati: ' + deleted + ' su ' + total + (errors.length ? '. Errori: ' + errors.length : '.');\n            window.updateProgressPopup(100, 'Pulizia globale file non associati', msg, msg);\n            window.hideProgressPopup(ok, title, {notifyUser:true, successMessage:msg});\n            setTimeout(function(){ window.showOrphanCleanupFinalReport(deletedPaths, errors, total, deleted, false, total, {label:'Pulizia globale su tutte le ditte', ditteProcessed:ditteProcessed || 0, ditteTotal:ditteTotal || 0}); }, 500);\n            return;\n        }\n        const item = items[index] || {};\n        const file = item.file || {};\n        const db = item.db || '';\n        const label = item.label || db;\n        const pathTxt = file.path || file.relative_path || file.name || 'file';\n        const rowInfo = file.table ? ('Tabella ' + file.table + (typeof file.row_index !== 'undefined' ? ', riga ' + (parseInt(file.row_index, 10) + 1) : '') + (file.field ? ', campo ' + file.field : '') + ' - ') : '';\n        const pct = Math.max(35, Math.min(99, Math.round(35 + (index \/ Math.max(1, total)) * 63)));\n        const current = 'Elemento ' + (index + 1) + ' \/ ' + total + ' - ' + label + ' [' + db + '] - ' + rowInfo + pathTxt;\n        if (window.orphanCleanupState) { window.orphanCleanupState.currentPath = current; window.orphanCleanupState.lastPercent = pct; window.orphanCleanupState.processed = index; }\n        window.updateProgressPopup(pct, 'Pulizia globale file non associati', 'Cancellazione elemento ' + (index + 1) + ' \/ ' + total, current);\n        window.showOrphanCleanupEmergencyButton();\n        window.deleteSingleOrphanFile(db, file).then(function(res){\n            if (res && res.success) {\n                const deletedPath = (res.data && res.data.path) ? res.data.path : pathTxt;\n                const fullLine = 'Elemento ' + (index + 1) + ' \/ ' + total + ' completato - ' + label + ' [' + db + '] - ' + rowInfo + deletedPath;\n                const pct2 = Math.max(pct, Math.min(99, Math.round(35 + ((index + 1) \/ Math.max(1, total)) * 63)));\n                window.updateProgressPopup(pct2, 'Pulizia globale file non associati', 'Eliminato elemento ' + (index + 1) + ' \/ ' + total, fullLine);\n                if (window.orphanCleanupState) { window.orphanCleanupState.currentPath = fullLine; window.orphanCleanupState.lastPercent = pct2; window.orphanCleanupState.processed = index + 1; window.orphanCleanupState.deleted = deleted + 1; }\n                deletedPaths.push(fullLine);\n                setTimeout(function(){ window.deleteGlobalOrphanFilesSequential(items, index + 1, deleted + 1, errors, deletedPaths, ditteProcessed, ditteTotal); }, 80);\n            } else {\n                errors.push(current + ' - ' + ((res && res.data && res.data.message) ? res.data.message : 'errore eliminazione'));\n                if (window.orphanCleanupState) window.orphanCleanupState.processed = index + 1;\n                setTimeout(function(){ window.deleteGlobalOrphanFilesSequential(items, index + 1, deleted, errors, deletedPaths, ditteProcessed, ditteTotal); }, 80);\n            }\n        }).catch(function(e){\n            errors.push(current + ' - ' + ((e && e.message) ? e.message : 'errore rete'));\n            if (window.orphanCleanupState) window.orphanCleanupState.processed = index + 1;\n            setTimeout(function(){ window.deleteGlobalOrphanFilesSequential(items, index + 1, deleted, errors, deletedPaths, ditteProcessed, ditteTotal); }, 80);\n        });\n    };\n\n    window.refreshConfigHeaderButtons = function() {\n        const box = gE('ti-conf-global-btn');\n        if (!box) return;\n        let html = '<div style=\"display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end;\">';\n        if (window.configInstructionCheckActive) {\n            html += '<button type=\"button\" class=\"ti-btn\" style=\"background:#4b5563; color:#fff;\" onclick=\"window.showAllConfigTables()\">\u21a9 Mostra tutto<\/button>';\n        }\n        html += '<\/div>';\n        box.innerHTML = html;\n        if (window.refreshOrphanCleanupButton) window.refreshOrphanCleanupButton();\n    };\n\n    window.verifyInstructionsArchive = function() {\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return;\n        const view = window.buildInstructionsViewDb(window.currentDbData);\n        window.currentDbViewData = view;\n        window.configInstructionCheckActive = true;\n        window.renderConfig();\n        const stats = (view && view.__instructionStats) ? view.__instructionStats : {tables:0, rows:0};\n        if (!stats.rows) {\n            window.tiAlert('Nessuna riga con Istruzioni o Istruzione compilata trovata nell archivio della ditta.');\n        } else {\n            window.tiAlert('Verifica istruzioni completata.<br>Tabelle con istruzioni: <b>' + stats.tables + '<\/b><br>Righe selezionate: <b>' + stats.rows + '<\/b>');\n        }\n    };\n\n    window.showAllConfigTables = function() {\n        window.currentDbViewData = null;\n        window.configInstructionCheckActive = false;\n        window.renderConfig();\n    };\n\n\n    window.__ensurePluginDateInputs = function() {\n        if (typeof window.initPluginDateInputs === 'function') return;\n        window.initPluginDateInputs = function(root) {\n            const scope = root || document;\n            scope.querySelectorAll('input[type=\"date\"], input[type=\"time\"]').forEach(function(inp){\n                const v = String(inp.value || '').trim();\n                if (inp.type === 'date' && !\/^\\d{4}-\\d{2}-\\d{2}$\/.test(v)) inp.value = '';\n                if (inp.type === 'time' && !\/^\\d{2}:\\d{2}$\/.test(v)) inp.value = '';\n                if (inp.type === 'date') { inp.placeholder = 'gg\/mm\/aaaa'; inp.title = inp.title || 'Seleziona una data'; }\n                if (inp.type === 'time') { inp.placeholder = 'hh:mm'; inp.title = inp.title || 'Seleziona un orario'; }\n            });\n        };\n    };\n\n    window.initConfigTopScrollbars = function(root) {\n        try {\n            const scope = root || document;\n            scope.querySelectorAll('.ti-sync-hscroll-wrap').forEach(function(wrap){\n                if (!wrap || !wrap.querySelector) return;\n                const table = wrap.querySelector('table');\n                if (!table) return;\n                const topBar = wrap.previousElementSibling && wrap.previousElementSibling.classList && wrap.previousElementSibling.classList.contains('ti-sync-hscroll-top') ? wrap.previousElementSibling : null;\n                const bottomBar = wrap.nextElementSibling && wrap.nextElementSibling.classList && wrap.nextElementSibling.classList.contains('ti-sync-hscroll-bottom') ? wrap.nextElementSibling : null;\n                const bars = [topBar, bottomBar].filter(Boolean);\n                const width = Math.max(table.scrollWidth || 0, table.offsetWidth || 0, wrap.scrollWidth || 0, wrap.clientWidth || 0, (table.tHead && table.tHead.scrollWidth) || 0, (table.tBodies && table.tBodies[0] && table.tBodies[0].scrollWidth) || 0);\n                const wrapClientWidth = Math.max(0, wrap.clientWidth || 0);\n                bars.forEach(function(bar){\n                    const inner = bar.querySelector('.ti-cfg-top-scroll-inner, .ti-sync-hscroll-inner');\n                    if (!inner) return;\n                    \/\/ 30.9.1777: se il contenitore tabella ha una scrollbar verticale, la sua clientWidth e'\n                    \/\/ inferiore a quella della barra orizzontale esterna. Compensiamo la differenza affinche'\n                    \/\/ maxScrollLeft sia identico e non si crei un feedback progressivo verso destra\/sinistra.\n                    const barClientWidth = Math.max(0, bar.clientWidth || 0);\n                    const viewportCompensation = Math.max(0, barClientWidth - wrapClientWidth);\n                    inner.style.width = Math.ceil(width + viewportCompensation) + 'px';\n                    bar.style.display = 'block';\n                    bar.style.setProperty('scroll-behavior', 'auto', 'important');\n                    bar.style.setProperty('overflow-anchor', 'none', 'important');\n                });\n                wrap.style.setProperty('scroll-behavior', 'auto', 'important');\n                wrap.style.setProperty('overflow-anchor', 'none', 'important');\n                if (wrap.dataset.syncBound !== '1777') {\n                    let syncBusy1777 = false;\n                    let release1777 = 0;\n                    const clamp1777 = function(el, left){\n                        const max = Math.max(0, (el.scrollWidth || 0) - (el.clientWidth || 0));\n                        return Math.max(0, Math.min(max, left));\n                    };\n                    const syncBars = function(source){\n                        if (syncBusy1777) return;\n                        let left = source && typeof source.scrollLeft === 'number' ? source.scrollLeft : wrap.scrollLeft;\n                        \/\/ Evita differenze sub-pixel tra browser\/tema che possono alimentare nuovi eventi scroll.\n                        left = Math.round((Number(left) || 0) * 10) \/ 10;\n                        syncBusy1777 = true;\n                        const wrapLeft = clamp1777(wrap, left);\n                        if (Math.abs((wrap.scrollLeft || 0) - wrapLeft) > 0.25) wrap.scrollLeft = wrapLeft;\n                        bars.forEach(function(bar){\n                            if (!bar) return;\n                            const barLeft = clamp1777(bar, left);\n                            if (Math.abs((bar.scrollLeft || 0) - barLeft) > 0.25) bar.scrollLeft = barLeft;\n                        });\n                        if (release1777) clearTimeout(release1777);\n                        release1777 = setTimeout(function(){ syncBusy1777 = false; release1777 = 0; }, 0);\n                    };\n                    wrap.addEventListener('scroll', function(){ syncBars(wrap); }, { passive:true });\n                    bars.forEach(function(bar){ bar.addEventListener('scroll', function(){ syncBars(bar); }, { passive:true }); });\n                    wrap.dataset.syncBound = '1777';\n                }\n                const startLeft1777 = Math.round((wrap.scrollLeft || 0) * 10) \/ 10;\n                bars.forEach(function(bar){\n                    if (!bar) return;\n                    const max = Math.max(0, (bar.scrollWidth || 0) - (bar.clientWidth || 0));\n                    const left = Math.max(0, Math.min(max, startLeft1777));\n                    if (Math.abs((bar.scrollLeft || 0) - left) > 0.25) bar.scrollLeft = left;\n                });\n            });\n        } catch(e) {}\n    };\n\n    window.bindConfigTableUX = function(root) {\n        try {\n            const scope = root || document;\n            scope.querySelectorAll('details.ti-cfg-details').forEach(function(det){\n                if (det.dataset.uxBound !== '1') {\n                    det.addEventListener('toggle', function(){ setTimeout(function(){ window.initConfigTopScrollbars(scope); }, 60); });\n                    det.dataset.uxBound = '1';\n                }\n            });\n            scope.querySelectorAll('.ti-cfg-filter').forEach(function(inp){\n                inp.removeAttribute('readonly'); inp.removeAttribute('disabled'); inp.readOnly = false; inp.disabled = false; if (inp.style) inp.style.setProperty('pointer-events', 'auto', 'important');\n                if (inp.dataset.filterBound435 === '1') return;\n                const read = function(){\n                    return {\n                        tbl: inp.getAttribute('data-tbl') || '',\n                        key: inp.getAttribute('data-key') || '',\n                        value: inp.value || ''\n                    };\n                };\n                inp.addEventListener('click', function(ev){ ev.stopPropagation(); });\n                inp.addEventListener('mousedown', function(ev){ ev.stopPropagation(); });\n                inp.addEventListener('keydown', function(ev){ ev.stopPropagation(); if (ev.key === 'Enter') { ev.preventDefault(); const x = read(); if (window.toggleConfigTableFilterManual522) window.toggleConfigTableFilterManual522(x.tbl, x.key, inp, null, ev); else if (window.applyConfigTableFilterImmediate) window.applyConfigTableFilterImmediate(x.tbl, x.key, x.value, inp); } });\n                inp.addEventListener('input', function(ev){ ev.stopPropagation(); const x = read(); if (window.scheduleConfigTableFilter) window.scheduleConfigTableFilter(x.tbl, x.key, x.value, inp); });\n                inp.addEventListener('change', function(ev){ ev.stopPropagation(); const x = read(); if (window.scheduleConfigTableFilter) window.scheduleConfigTableFilter(x.tbl, x.key, x.value, inp); });\n                inp.dataset.filterBound435 = '1';\n            });\n            if (!window.__cfgResizeBound) {\n                window.addEventListener('resize', function(){ window.initConfigTopScrollbars(document); }, { passive:true });\n                window.__cfgResizeBound = true;\n            }\n        } catch(e) {}\n    };\n\n\n    window.tiConfigSchemaDescriptions = {\"_meta\": {\"source\": \"Shop-Service - Struttura standard database.docx\", \"database\": \"shopservicemain\", \"version\": \"30.9.664\", \"note\": \"Descrizioni operative dei campi principali usate da configurazione, AI, validazioni, alias e relazioni ufficiali. Payments ristrutturata per Metodo.\"}, \"global_fields\": {\"Data\": \"Data di ultima variazione nel formato DD\/MM\/YYYY.\", \"Ora\": \"Ora di ultima variazione nel formato HH:MM.\", \"Nota\": \"Note generali.\", \"Stato\": \"Stato di disponibilit\u00e0 del set dati.\", \"Username\": \"Username univoco che individua l'utente registrato\/loggato.\", \"PIVA_VAT\": \"Partita IVA per fatturazione B2B.\", \"IVA_VAT\": \"Percentuale IVA applicata oppure scorporata dai prezzi comprensivi IVA.\", \"ADE\": \"Codice ADE per fatturazione elettronica Italia.\"}, \"tables\": {\"Config\": {\"Ditta\": \"Nome ditta.\", \"Attivita\": \"Attivit\u00e0 economica ditta con ricerca ATECO.\", \"Ragione sociale\": \"Ragione sociale della ditta.\", \"Logo\": \"Logo della ditta.\", \"COD_FISC\": \"Codice fiscale se necessario.\", \"Sez_ordine\": \"Sezionale per la numerazione ordini.\", \"Num_ordine\": \"Ultimo numero ordine oppure maschera numeratore, es. [SS\/AAAA####0] produce SS\/20260001 e incrementa il contatore.\", \"Sez_fattura\": \"Sezionale per la numerazione fatture.\", \"Num_fattura\": \"Ultimo numero fattura oppure maschera numeratore, es. [SS\/AAAA####0] produce SS\/20260001 e incrementa il contatore.\", \"Sez_Corrispettivo\": \"Sezionale per la numerazione corrispettivi.\", \"Num_Corrispettivo\": \"Ultimo numero corrispettivi oppure maschera numeratore, es. [SS\/AAAA####0] produce SS\/20260001 e incrementa il contatore.\", \"Email ditta\": \"Email principale della ditta.\", \"Email prodotti\": \"Email di riferimento per prodotti.\", \"Email servizi\": \"Email di riferimento per servizi.\", \"Email amministrazione\": \"Email amministrazione.\", \"Tel\": \"Telefono ditta, anche per SMS.\", \"Indirizzo\": \"Indirizzo ditta.\", \"Descrizione\": \"Descrizione breve della ditta e della sua attivit\u00e0.\", \"Accoglienza\": \"Messaggio di accoglienza utente standard.\", \"Istruzioni\": \"Istruzioni per AI relative alla ditta.\", \"Tab_tab\": \"Formato visualizzazione righe tabella ordine: Tabella.\", \"Tab_sma\": \"Formato visualizzazione righe tabella ordine: Small.\", \"Tab_med\": \"Formato visualizzazione righe tabella ordine: Medium.\", \"Tab_lar\": \"Formato visualizzazione righe tabella ordine: Large.\", \"Data creazione\": \"Data creazione ditta. Periodo test 30 giorni successivi.\", \"Stato\": \"Stato Shop & Service della ditta: Attivo, Operativo, Configurazione, Sospesa, Demo.\",\n      \"TotAIActs\": \"Plafond di attivit\u00e0 AI abilitate. SHOP-SERVICE-1 concede 200 attivit\u00e0 una tantum, utilizzabili fino a esaurimento anche dopo i 30 giorni di copertura; SHOP-SERVICE e SHOP-SERVICE-2 concedono ciascuno 200 attivit\u00e0 per ogni periodo pagato di 30 giorni.\",\n      \"AIActs\": \"Contatore puntuale delle attivit\u00e0 AI consumate sulle quote attualmente utilizzabili. Si incrementa per ogni richiesta AI riuscita; le quote seguono i periodi commerciali di 30 giorni e non il mese di calendario.\"}, \"Payments\": {\"Metodo\": \"Metodo di pagamento: bank_transfer, PayPal o altro metodo supportato.\", \"enabled\": \"Abilita\/disabilita il metodo di pagamento.\", \"beneficiary\": \"Beneficiario bonifico.\", \"iban\": \"IBAN bonifico.\", \"bic\": \"BIC\/SWIFT bonifico.\", \"bank_name\": \"Nome banca.\", \"payment_terms\": \"Condizioni di pagamento, es. Bonifico.\", \"instructions\": \"Istruzioni di pagamento per l'utente.\", \"merchant_mode\": \"Modalit\u00e0 merchant PayPal.\", \"environment\": \"Ambiente PayPal: live o sandbox.\", \"client_id\": \"Client ID PayPal.\", \"client_secret_ref\": \"Riferimento sicuro al client secret.\", \"webhook_id\": \"ID webhook PayPal.\", \"currency\": \"Valuta, es. EUR.\", \"intent\": \"Intent PayPal, es. CAPTURE.\", \"ui_mode\": \"Modalit\u00e0 UI pagamento, es. buttons.\", \"brand_name\": \"Nome brand mostrato nel pagamento.\", \"locale\": \"Locale interfaccia, es. it_IT.\", \"invoice_prefix\": \"Prefisso fattura.\", \"debug\": \"Abilita log\/debug pagamento.\"}, \"Informazioni\": {\"Tipo\": \"Tipo di informazione: WEB, URL sito e sotto-URL.\", \"Descrizione\": \"Descrizione o URL del sito, es. https:\/\/www.tisoft.it.\", \"Doc\": \"Documento collegato TXT, PDF ecc.\", \"Istruzioni\": \"Istruzioni per AI relative all'informazione.\"}, \"Istruzioni\": {\"Istruzione\": \"Istruzione particolare per la AI, es. sconto 10% fino al 31\/12\/2026.\", \"Doc\": \"Documento collegato TXT, PDF ecc.\", \"Da gg\": \"Data inizio validit\u00e0 istruzione.\", \"Da ora\": \"Ora inizio validit\u00e0 istruzione.\", \"A gg\": \"Data fine validit\u00e0 istruzione.\", \"A ora\": \"Ora fine validit\u00e0 istruzione.\"}, \"Utenti\": {\"Utente\": \"Cognome nome o username.\", \"Password\": \"Password.\", \"Ruolo\": \"Ruolo utente: Amministratore, Configuratore, Responsabile, Utente.\", \"Ragione sociale\": \"Ragione sociale utente\/cliente.\", \"Indirizzo\": \"Indirizzo utente\/cliente.\", \"Email\": \"Email utente.\", \"Tel\": \"Telefono utente.\", \"Sesso\": \"Sesso utente se utile.\", \"Et\u00e0\": \"Et\u00e0 utente.\", \"Eta\": \"Et\u00e0 utente.\", \"Immagine\": \"Avatar utente.\", \"Istruzioni\": \"Istruzioni particolari ad AI per l'utente.\", \"Dato 1\": \"Informazione utile per gestire il rapporto.\", \"Dato 2\": \"Informazione utile per gestire il rapporto.\", \"Dato 3\": \"Informazione utile per gestire il rapporto.\", \"Esito\": \"Esito della prima interazione con l'utente.\", \"Com Mail\": \"Autorizzazione comunicazione postale.\", \"Com Email\": \"Autorizzazione comunicazione email.\", \"Com SMS\": \"Autorizzazione comunicazione SMS.\", \"Com Tel\": \"Autorizzazione comunicazione telefonica.\", \"COD_FISC\": \"Codice fiscale utente se necessario.\"}, \"Operatori\": {\"Utente\": \"Cognome nome o username operatore.\", \"Ruolo\": \"Ruolo operatore.\", \"Competenze\": \"Competenze professionali dell'operatore.\", \"Disponibilita\": \"Limiti di disponibilit\u00e0 dell'operatore.\", \"Disponibilit\u00e0\": \"Limiti di disponibilit\u00e0 dell'operatore.\", \"Costo_orario\": \"Costo orario per la ditta.\", \"Prezzo_orario\": \"Prezzo orario per l'utente finale.\", \"Istruzioni\": \"Istruzioni AI relative all'operatore.\"}, \"Siti\": {\"Descrizione\": \"Locazione di esecuzione delle attivit\u00e0 della ditta.\", \"Indirizzo\": \"Indirizzo del sito\/sede.\", \"Quantit\u00e0\": \"Quantit\u00e0 disponibile.\", \"Quantita\": \"Quantit\u00e0 disponibile.\", \"Disponibilit\u00e0\": \"Disponibilit\u00e0 del sito, es. SI\/NO.\", \"Disponibilita\": \"Disponibilit\u00e0 del sito, es. SI\/NO.\", \"Istruzioni\": \"Istruzioni AI relative al sito.\"}, \"Dispositivi\": {\"Descrizione\": \"Strumento\/macchinario per l'esecuzione delle attivit\u00e0 della ditta.\", \"Quantit\u00e0\": \"Quantit\u00e0 disponibile.\", \"Quantita\": \"Quantit\u00e0 disponibile.\", \"Disponibilit\u00e0\": \"Disponibilit\u00e0 del dispositivo.\", \"Disponibilita\": \"Disponibilit\u00e0 del dispositivo.\", \"Istruzioni\": \"Istruzioni AI relative al dispositivo.\"}, \"Prodotti\": {\"Prodotto\": \"Nome breve prodotto.\", \"Descrizione\": \"Descrizione estesa prodotto.\", \"Prezzo\": \"Prezzo prodotto.\", \"Costo\": \"Costo prodotto.\", \"Quantit\u00e0\": \"Giacenza\/quantit\u00e0 prodotto.\", \"Quantita\": \"Giacenza\/quantit\u00e0 prodotto.\", \"Un\": \"Unit\u00e0 di misura.\", \"Fascia\": \"Eventuale fascia di riferimento.\", \"Immagine\": \"Immagine prodotto.\", \"Indicazioni\": \"Specifiche indicazioni d'uso del prodotto.\", \"Istruzioni\": \"Istruzioni AI relative al prodotto.\", \"Disponibilita\": \"Giacenza prodotto disponibile.\", \"Disponibilit\u00e0\": \"Giacenza prodotto disponibile.\", \"Riordino\": \"Giorni di riordino o consegna del fornitore.\"}, \"Servizi\": {\"Servizio\": \"Nome breve servizio.\", \"Descrizione\": \"Descrizione estesa servizio.\", \"Prezzo\": \"Prezzo servizio.\", \"Costo\": \"Costo servizio.\", \"Giorni_disponibilita\": \"Periodo di disponibilit\u00e0, es. giorni della settimana.\", \"Ora_disponibilita\": \"Periodo di disponibilit\u00e0, es. orari giornalieri.\", \"Data_variazione\": \"Data dell'ultima variazione del servizio.\", \"Ora_variazione\": \"Ora dell'ultima variazione del servizio.\", \"Durata standard\": \"Durata standard del servizio, es. 00:00:30 mezzora.\", \"Fascia\": \"Eventuale fascia di riferimento.\", \"Operatore1\": \"Operatore standard dedicato al servizio.\", \"Operatore2\": \"Operatore standard dedicato al servizio.\", \"Operatore3\": \"Operatore standard dedicato al servizio.\", \"Dispositivo1\": \"Dispositivo standard dedicato al servizio.\", \"Dispositivo2\": \"Dispositivo standard dedicato al servizio.\", \"Dispositivo3\": \"Dispositivo standard dedicato al servizio.\", \"Prodotto1\": \"Prodotto standard utilizzato per erogare il servizio.\", \"Prodotto2\": \"Prodotto standard utilizzato per erogare il servizio.\", \"Prodotto3\": \"Prodotto standard utilizzato per erogare il servizio.\", \"Sito1\": \"Locazione standard per erogare il servizio.\", \"Sito2\": \"Locazione standard per erogare il servizio.\", \"Sito3\": \"Locazione standard per erogare il servizio.\", \"Istruzioni\": \"Istruzioni AI relative al servizio.\"}, \"Appuntamenti\": {\"Username\": \"Username utente di riferimento.\", \"Servizio\": \"Descrizione breve servizio.\", \"Data_appuntamento\": \"Data dell'appuntamento.\", \"Ora_appuntamento\": \"Ora dell'appuntamento.\", \"Operatore1\": \"Operatore standard o assegnato al servizio.\", \"Operatore2\": \"Operatore standard o assegnato al servizio.\", \"Operatore3\": \"Operatore standard o assegnato al servizio.\", \"Dispositivo1\": \"Dispositivo standard o assegnato al servizio.\", \"Dispositivo2\": \"Dispositivo standard o assegnato al servizio.\", \"Dispositivo3\": \"Dispositivo standard o assegnato al servizio.\", \"Prodotto1\": \"Prodotto standard o assegnato al servizio.\", \"Prodotto2\": \"Prodotto standard o assegnato al servizio.\", \"Prodotto3\": \"Prodotto standard o assegnato al servizio.\", \"Sito1\": \"Locazione standard o assegnata al servizio.\", \"Sito2\": \"Locazione standard o assegnata al servizio.\", \"Sito3\": \"Locazione standard o assegnata al servizio.\", \"Preparazione\": \"Eventuali note all'utente di preparazione al servizio.\", \"Istruzioni\": \"Istruzioni AI relative all'appuntamento.\"}, \"Attivita\": {\"Username\": \"Username utente.\", \"Descrizione\": \"Descrizione dettagliata dell'attivit\u00e0, es. acquisizione prodotti e servizi.\", \"Prezzo\": \"Prezzo dell'attivit\u00e0.\", \"Quantit\u00e0\": \"Quantit\u00e0 dell'attivit\u00e0.\", \"Quantita\": \"Quantit\u00e0 dell'attivit\u00e0.\", \"Esito\": \"Esito dell'attivit\u00e0.\", \"Operatore\": \"Operatore utilizzato.\", \"Dispositivo\": \"Dispositivo utilizzato.\", \"Sito\": \"Locazione dell'attivit\u00e0.\", \"Prodotto\": \"Prodotto fornito.\", \"Istruzioni\": \"Istruzioni AI relative all'attivit\u00e0 svolta.\", \"Durata\": \"Durata complessiva dell'attivit\u00e0 svolta.\"}}, \"aliases\": {\"Disponibilita\": [\"Disponibilita\", \"Disponibilit\u00e0\"], \"Quantita\": [\"Quantita\", \"Quantit\u00e0\"], \"Eta\": [\"Eta\", \"Et\u00e0\"], \"Attivita\": [\"Attivita\", \"Attivit\u00e0\"], \"Email amministrazione\": [\"Email amministrazione\", \"Email amministrativa\"], \"Data creazione\": [\"Data creazione\", \"Data_creazione\"], \"Data_appuntamento\": [\"Data_appuntamento\", \"Data appuntamento\"], \"Ora_appuntamento\": [\"Ora_appuntamento\", \"Ora appuntamento\"]}, \"relations\": {\"Servizi\": {\"Operatore\": \"Operatori\", \"Operatori\": \"Operatori\", \"Operatore1\": \"Operatori\", \"Operatore2\": \"Operatori\", \"Operatore3\": \"Operatori\", \"Dispositivo\": \"Dispositivi\", \"Dispositivi\": \"Dispositivi\", \"Dispositivo1\": \"Dispositivi\", \"Dispositivo2\": \"Dispositivi\", \"Dispositivo3\": \"Dispositivi\", \"Prodotto\": \"Prodotti\", \"Prodotti\": \"Prodotti\", \"Prodotto1\": \"Prodotti\", \"Prodotto2\": \"Prodotti\", \"Prodotto3\": \"Prodotti\", \"Sito\": \"Siti\", \"Siti\": \"Siti\", \"Sito1\": \"Siti\", \"Sito2\": \"Siti\", \"Sito3\": \"Siti\"}, \"Appuntamenti\": {\"Operatore\": \"Operatori\", \"Operatori\": \"Operatori\", \"Operatore1\": \"Operatori\", \"Operatore2\": \"Operatori\", \"Operatore3\": \"Operatori\", \"Dispositivo\": \"Dispositivi\", \"Dispositivi\": \"Dispositivi\", \"Dispositivo1\": \"Dispositivi\", \"Dispositivo2\": \"Dispositivi\", \"Dispositivo3\": \"Dispositivi\", \"Prodotto\": \"Prodotti\", \"Prodotti\": \"Prodotti\", \"Prodotto1\": \"Prodotti\", \"Prodotto2\": \"Prodotti\", \"Prodotto3\": \"Prodotti\", \"Sito\": \"Siti\", \"Siti\": \"Siti\", \"Sito1\": \"Siti\", \"Sito2\": \"Siti\", \"Sito3\": \"Siti\", \"Servizio\": \"Servizi\"}, \"Attivita\": {\"Operatore\": \"Operatori\", \"Dispositivo\": \"Dispositivi\", \"Sito\": \"Siti\", \"Prodotto\": \"Prodotti\"}}};\n    window.normalizeConfigSchemaName = function(v) { return window.compactConfigRelationName ? window.compactConfigRelationName(v) : String(v == null ? '' : v).normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').toLowerCase().replace(\/[^a-z0-9]+\/g,''); };\n    window.getConfigFieldAliasCandidates = function(field) {\n        const schema = window.tiConfigSchemaDescriptions || {};\n        const aliases = schema.aliases || {};\n        const wanted = window.normalizeConfigSchemaName(field);\n        for (const canonical in aliases) {\n            const list = [canonical].concat(Array.isArray(aliases[canonical]) ? aliases[canonical] : []);\n            if (list.some(a => window.normalizeConfigSchemaName(a) === wanted)) return Array.from(new Set(list));\n        }\n        return [String(field || '')];\n    };\n    window.getConfigFieldDescription = function(tbl, key) {\n        const schema = window.tiConfigSchemaDescriptions || {};\n        const aliases = window.getConfigFieldAliasCandidates ? window.getConfigFieldAliasCandidates(key) : [key];\n        const tables = schema.tables || {};\n        const tKey = Object.keys(tables).find(t => window.normalizeConfigSchemaName(t) === window.normalizeConfigSchemaName(tbl)) || tbl;\n        const map = tables[tKey] || {};\n        for (const alias of aliases) {\n            const k = Object.keys(map).find(x => window.normalizeConfigSchemaName(x) === window.normalizeConfigSchemaName(alias));\n            if (k && map[k]) return String(map[k]);\n        }\n        const globals = schema.global_fields || {};\n        for (const alias of aliases) {\n            const k = Object.keys(globals).find(x => window.normalizeConfigSchemaName(x) === window.normalizeConfigSchemaName(alias));\n            if (k && globals[k]) return String(globals[k]);\n        }\n        return '';\n    };\n    window.getOfficialConfigRelationTarget = function(tbl, key) {\n        const schema = window.tiConfigSchemaDescriptions || {};\n        const rels = schema.relations || {};\n        const tKey = Object.keys(rels).find(t => window.normalizeConfigSchemaName(t) === window.normalizeConfigSchemaName(tbl));\n        if (!tKey) return '';\n        const map = rels[tKey] || {};\n        const k = Object.keys(map).find(f => window.normalizeConfigSchemaName(f) === window.normalizeConfigSchemaName(key));\n        return k ? String(map[k] || '') : '';\n    };\n\n    window.normalizeConfigRelationName = function(v) {\n        try {\n            return String(v == null ? '' : v).normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/[_\\-]+\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n        } catch(e) {\n            return String(v == null ? '' : v).toLowerCase().replace(\/[_\\-]+\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n        }\n    };\n\n    window.compactConfigRelationName = function(v) {\n        return window.normalizeConfigRelationName(v).replace(\/[^a-z0-9]+\/g, '');\n    };\n\n    window.getConfigRelationCatalog = function() {\n        return {\n            sito: {type:'sito', label:'Siti', tables:['Siti','Sito','Sedi','Sede'], picks:['Sito','Sede','Nome','Titolo','Descrizione','Indirizzo']},\n            operatore: {type:'operatore', label:'Operatori', tables:['Operatori','Operatore'], picks:['Operatore','Utente','Username','Nome','Cognome','Titolo','Descrizione']},\n            dispositivo: {type:'dispositivo', label:'Dispositivi', tables:['Dispositivi','Dispositivo','Risorse','Risorsa'], picks:['Dispositivo','Risorsa','Nome','Titolo','Descrizione','Codice']},\n            prodotto: {type:'prodotto', label:'Prodotti', tables:['Prodotti','Prodotto'], picks:['Prodotto','Articolo','Nome','Titolo','Descrizione','Codice']},\n            servizio: {type:'servizio', label:'Servizi', tables:['Servizi','Servizio'], picks:['Servizio','Nome','Titolo','Descrizione','Codice']},\n            voce: {type:'voce', label:'Prodotti\/Servizi', tables:['Prodotti','Servizi'], picks:['Prodotto','Servizio','Articolo','Nome','Titolo','Descrizione','Codice']}\n        };\n    };\n\n    window.getConfigRelationTypeFromKey = function(tbl, key) {\n        const nContact = window.normalizeConfigRelationName(key);\n        const cContact = window.compactConfigRelationName(key);\n        \/\/ I campi di contatto\/comunicazione sono campi liberi di edit, anche se nel nome contengono\n        \/\/ parole come prodotti o servizi. Esempio: Config > Email prodotti \/ Email servizi.\n        if (\/^(email|mail|pec|telefono|tel|cellulare|cell|sms|whatsapp)\/.test(cContact) || \/\\b(email|mail|pec|telefono|tel|cellulare|sms|whatsapp)\\b\/.test(nContact)) return '';\n        const officialTarget = window.getOfficialConfigRelationTarget ? window.getOfficialConfigRelationTarget(tbl, key) : '';\n        if (officialTarget) {\n            const oc = window.compactConfigRelationName(officialTarget);\n            if (oc.indexOf('siti') !== -1 || oc.indexOf('sede') !== -1) return 'sito';\n            if (oc.indexOf('operator') !== -1) return 'operatore';\n            if (oc.indexOf('dispositiv') !== -1 || oc.indexOf('risors') !== -1) return 'dispositivo';\n            if (oc.indexOf('prodott') !== -1) return 'prodotto';\n            if (oc.indexOf('serviz') !== -1) return 'servizio';\n        }\n        const n = window.normalizeConfigRelationName(key);\n        const c = window.compactConfigRelationName(key);\n        if (!c || c === 'id') return '';\n        const padded = ' ' + n + ' ';\n        const matchWord = function(words) {\n            return words.some(function(w){ return padded.indexOf(' ' + w + ' ') !== -1 || c === w || c === w + '1' || c === w + '2' || c === w + '3'; });\n        };\n        if (\/^voce[123]?$\/.test(c) || \/^voci[123]?$\/.test(c) || \/^(voce|voci) [123]$\/.test(n)) return 'voce';\n        if (matchWord(['sito','siti','sede','sedi','luogo','location'])) return 'sito';\n        if (matchWord(['operatore','operatori','tecnico','tecnici','addetto','addetti','incaricato','incaricati'])) return 'operatore';\n        if (matchWord(['dispositivo','dispositivi','risorsa','risorse','macchina','macchine','attrezzatura','attrezzature','postazione','postazioni'])) return 'dispositivo';\n        if (matchWord(['prodotto','prodotti','articolo','articoli','materiale','materiali'])) return 'prodotto';\n        if (matchWord(['servizio','servizi','prestazione','prestazioni'])) return 'servizio';\n        return '';\n    };\n\n    window.findConfigTableName = function(names) {\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return '';\n        const all = Object.keys(window.currentDbData.Tabelle || {});\n        const wanted = (Array.isArray(names) ? names : [names]).map(function(x){ return window.compactConfigRelationName(x); });\n        return all.find(function(t){ return wanted.includes(window.compactConfigRelationName(t)); }) || '';\n    };\n\n    window.shouldUseMultiConfigRelation = function(tbl, key, row, meta) {\n        const n = window.normalizeConfigRelationName(key);\n        const v = (row && Object.prototype.hasOwnProperty.call(row, key)) ? String(row[key] == null ? '' : row[key]) : '';\n        if (\/[;,\\n]\/.test(v)) return true;\n        if (\/\\b(lista|elenco|ammessi|abilitati|disponibili|associati|selezionabili|multipli|multiplo)\\b\/.test(n)) return true;\n        if (\/\\b(siti|operatori|dispositivi|prodotti|servizi|risorse)\\b\/.test(n)) return true;\n        if (window.compactConfigRelationName(tbl) === 'servizi' && ['sito','operatore','dispositivo','prodotto'].includes(meta.type)) return true;\n        return false;\n    };\n\n    window.getConfigRelationMeta = function(tbl, key, row) {\n        const type = window.getConfigRelationTypeFromKey(tbl, key);\n        if (!type) return null;\n        const catalog = window.getConfigRelationCatalog();\n        const base = catalog[type];\n        if (!base) return null;\n        const currentTable = window.compactConfigRelationName(tbl);\n        const sameTarget = (base.tables || []).some(function(t){ return window.compactConfigRelationName(t) === currentTable; });\n        if (sameTarget && type !== 'voce') return null;\n        const meta = Object.assign({}, base);\n        meta.tables = (base.tables || []).slice();\n        meta.picks = (base.picks || []).slice();\n        meta.table = meta.tables[0] || '';\n        meta.realTables = meta.tables.map(function(t){ return window.findConfigTableName(t); }).filter(Boolean);\n        meta.sourceLabel = meta.realTables.length ? Array.from(new Set(meta.realTables)).join('\/') : (meta.label || meta.table || 'tabella sorgente');\n        meta.missingSource = !meta.realTables.length;\n        meta.multiple = window.shouldUseMultiConfigRelation(tbl, key, row || {}, meta);\n        return meta;\n    };\n\n    window.splitConfigRelationValues = function(raw) {\n        return String(raw == null ? '' : raw)\n            .split(\/[;,\\n]+\/)\n            .map(function(v){ return String(v || '').trim(); })\n            .filter(Boolean);\n    };\n\n    window.getConfigRowValueByNames = function(row, names) {\n        if (!row || typeof row !== 'object') return '';\n        const keys = Object.keys(row);\n        const wanted = (Array.isArray(names) ? names : [names]).map(function(n){ return window.compactConfigRelationName(n); });\n        const realKey = keys.find(function(k){ return wanted.includes(window.compactConfigRelationName(k)); });\n        return realKey ? String(row[realKey] == null ? '' : row[realKey]).trim() : '';\n    };\n\n    window.getConfigRelationRowLabel = function(row, meta) {\n        if (!row || typeof row !== 'object') return '';\n        let value = '';\n        (meta.picks || []).some(function(pick) {\n            const found = window.getConfigRowValueByNames(row, pick);\n            if (found) { value = found; return true; }\n            return false;\n        });\n        if (!value && (meta.type === 'operatore')) {\n            const nome = window.getConfigRowValueByNames(row, ['Nome']);\n            const cognome = window.getConfigRowValueByNames(row, ['Cognome']);\n            value = (nome + ' ' + cognome).trim();\n        }\n        if (!value) {\n            const skip = {id:1, stato:1, status:1, immagine:1, foto:1, file:1, password:1, pass:1};\n            const firstKey = Object.keys(row).find(function(k){ return !skip[window.compactConfigRelationName(k)] && String(row[k] == null ? '' : row[k]).trim() !== ''; });\n            if (firstKey) value = String(row[firstKey]).trim();\n        }\n        return value;\n    };\n\n    window.isConfigRelationRowAvailable = function(row) {\n        if (!row || typeof row !== 'object') return false;\n        const negative = \/(cancellat|eliminat|sospes|disabilit|inattiv|non disponibile|non attiv|scadut|chius|\\bno\\b|\\bfalse\\b|^0$)\/i;\n        let available = true;\n        Object.keys(row).forEach(function(k) {\n            const ck = window.compactConfigRelationName(k);\n            if (!\/(stato|status|attivo|attiva|abilitato|abilitata|disponibile|visibile|sospeso|cancellato)\/.test(ck)) return;\n            const v = String(row[k] == null ? '' : row[k]).trim();\n            if (v !== '' && negative.test(v)) available = false;\n        });\n        return available;\n    };\n\n    window.getConfigRelationSupportText = function() {\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return '';\n        const version = String((window.currentDbData && window.currentDbData.__db_version) || '') + '|' + Object.keys(window.currentDbData.Tabelle || {}).length;\n        if (window.__configRelationSupportCache && window.__configRelationSupportCache.version === version) return window.__configRelationSupportCache.text || '';\n        const aliases = ['Informazioni','Istruzioni','Appuntamenti'];\n        let out = '';\n        aliases.forEach(function(alias){\n            const real = window.findConfigTableName(alias);\n            const rows = real && window.currentDbData.Tabelle[real] ? window.currentDbData.Tabelle[real] : [];\n            (Array.isArray(rows) ? rows : Object.values(rows || {})).slice(0, 350).forEach(function(row){\n                if (!row || typeof row !== 'object') return;\n                out += ' ' + Object.keys(row).map(function(k){ return String(row[k] == null ? '' : row[k]); }).join(' ');\n                if (out.length > 60000) out = out.slice(0, 60000);\n            });\n        });\n        out = window.normalizeConfigRelationName(out);\n        window.__configRelationSupportCache = {version: version, text: out};\n        return out;\n    };\n\n    window.countConfigRelationMentions = function(text, value) {\n        const needle = window.normalizeConfigRelationName(value);\n        if (!needle || !text) return 0;\n        let count = 0;\n        let pos = 0;\n        while ((pos = text.indexOf(needle, pos)) !== -1) { count++; pos += Math.max(needle.length, 1); if (count > 20) break; }\n        return count;\n    };\n\n    window.normalizeConfigDateToken = function(v) {\n        const s = String(v == null ? '' : v).trim();\n        let m = s.match(\/^(\\d{4})-(\\d{2})-(\\d{2})\/);\n        if (m) return m[1] + '-' + m[2] + '-' + m[3];\n        m = s.match(\/^(\\d{1,2})\\\/(\\d{1,2})\\\/(\\d{4})$\/);\n        if (m) return m[3] + '-' + String(m[2]).padStart(2, '0') + '-' + String(m[1]).padStart(2, '0');\n        return '';\n    };\n\n    window.normalizeConfigTimeToken = function(v) {\n        const s = String(v == null ? '' : v).trim();\n        const m = s.match(\/^(\\d{1,2})[:.](\\d{2})\/);\n        if (!m) return '';\n        return String(m[1]).padStart(2, '0') + ':' + m[2];\n    };\n\n    window.getConfigRelationRowDate = function(row) {\n        if (!row || typeof row !== 'object') return '';\n        const keys = Object.keys(row);\n        const k = keys.find(function(key){ const c = window.compactConfigRelationName(key); return c === 'data' || c === 'giorno' || c === 'dataappuntamento' || c === 'date'; });\n        return k ? window.normalizeConfigDateToken(row[k]) : '';\n    };\n\n    window.getConfigRelationRowTime = function(row) {\n        if (!row || typeof row !== 'object') return '';\n        const keys = Object.keys(row);\n        const k = keys.find(function(key){ const c = window.compactConfigRelationName(key); return c === 'ora' || c === 'orario' || c === 'daora' || c === 'orainizio' || c === 'time'; });\n        return k ? window.normalizeConfigTimeToken(row[k]) : '';\n    };\n\n    window.getConfigRelationBusyValues = function(meta, currentRow, currentTbl, currentIdx) {\n        const busy = new Set();\n        if (!meta || !['operatore','sito','dispositivo'].includes(meta.type)) return busy;\n        const cDate = window.getConfigRelationRowDate(currentRow);\n        const cTime = window.getConfigRelationRowTime(currentRow);\n        if (!cDate || !cTime) return busy;\n        const real = window.findConfigTableName('Appuntamenti');\n        const rows = real && window.currentDbData && window.currentDbData.Tabelle ? window.currentDbData.Tabelle[real] : [];\n        (Array.isArray(rows) ? rows : Object.values(rows || {})).forEach(function(app, appIdx){\n            if (!app || typeof app !== 'object') return;\n            if (window.compactConfigRelationName(currentTbl) === window.compactConfigRelationName(real) && parseInt(currentIdx,10) === appIdx) return;\n            if (!window.isConfigRelationRowAvailable(app)) return;\n            if (window.getConfigRelationRowDate(app) !== cDate || window.getConfigRelationRowTime(app) !== cTime) return;\n            Object.keys(app).forEach(function(k){\n                if (window.getConfigRelationTypeFromKey(real, k) !== meta.type) return;\n                window.splitConfigRelationValues(app[k]).forEach(function(v){ if (v) busy.add(String(v).toLowerCase()); });\n            });\n        });\n        return busy;\n    };\n\n    window.getConfigRelationOptions = function(tbl, key, row, idx) {\n        const meta = window.getConfigRelationMeta(tbl, key, row || {});\n        const dbData = window.currentDbData;\n        if (!meta || !dbData || !dbData.Tabelle) return [];\n        const supportText = window.getConfigRelationSupportText();\n        const busy = window.getConfigRelationBusyValues(meta, row || {}, tbl, idx);\n        const out = [];\n        const seen = new Set();\n        const addOption = function(value, sourceTable, rowObj, force) {\n            value = String(value == null ? '' : value).trim();\n            if (!value) return;\n            const lower = value.toLowerCase();\n            if (seen.has(lower)) return;\n            if (!force && busy.has(lower)) return;\n            seen.add(lower);\n            const mentions = window.countConfigRelationMentions(supportText, value);\n            out.push({\n                value: value,\n                label: value,\n                sourceTable: sourceTable || '',\n                score: mentions,\n                title: (sourceTable ? ('Tabella: ' + sourceTable + '. ') : '') + (mentions ? ('Citato in Informazioni\/Istruzioni\/Appuntamenti: ' + mentions + ' volte.') : 'Record disponibile.')\n            });\n        };\n        (meta.tables || []).forEach(function(tblAlias){\n            const real = window.findConfigTableName(tblAlias);\n            if (!real) return;\n            let rows = dbData.Tabelle[real];\n            rows = Array.isArray(rows) ? rows : Object.values(rows || {});\n            rows.forEach(function(srcRow){\n                if (!window.isConfigRelationRowAvailable(srcRow)) return;\n                addOption(window.getConfigRelationRowLabel(srcRow, meta), real, srcRow, false);\n            });\n        });\n        window.splitConfigRelationValues(row && Object.prototype.hasOwnProperty.call(row, key) ? row[key] : '').forEach(function(v){ addOption(v, 'Valore attuale', null, true); });\n        out.sort(function(a, b){\n            if ((b.score || 0) !== (a.score || 0)) return (b.score || 0) - (a.score || 0);\n            return String(a.label || a.value).localeCompare(String(b.label || b.value), 'it');\n        });\n        return out;\n    };\n\n    window.updateMemFieldFromRelationSelect = function(tbl, idx, key, sel) {\n        if (!sel) return;\n        const protNorm = v => String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[^a-z0-9]\/g, '');\n        if (!(window.tiAiSsIsDatabaseFullAdmin1562 && window.tiAiSsIsDatabaseFullAdmin1562()) && protNorm(tbl) === 'config' && ['stato','datacreazione','dataattivazione','wcorderid','wcactivateid'].includes(protNorm(key))) {\n            if (window.tiAlert) window.tiAlert('Campo riservato: modificabile solo da sistema, globaladmin o attivazione WooCommerce.');\n            return;\n        }\n        let values = [];\n        if (sel.multiple) values = Array.from(sel.selectedOptions || []).map(function(opt){ return String(opt.value || '').trim(); }).filter(Boolean);\n        else values = [String(sel.value || '').trim()].filter(Boolean);\n        const joined = values.join(', ');\n        if (window.currentDbData && window.currentDbData.Tabelle[tbl] && window.currentDbData.Tabelle[tbl][idx]) {\n            window.currentDbData.Tabelle[tbl][idx][key] = joined;\n            window.__configRelationSupportCache = null;\n            window.forceWhiteEditStyle && window.forceWhiteEditStyle(sel);\n            sel.style.setProperty('border-color', '#fbbf24', 'important');\n            if (!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(`${tbl}-${idx}-${key}`);\n            if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n        }\n        const hint = sel.parentElement ? sel.parentElement.querySelector('.ti-rel-summary') : null;\n        if (hint) hint.textContent = joined || 'Nessun record associato';\n    };\n\n    window.updateMemFieldFromMultiSelect = window.updateMemFieldFromRelationSelect;\n\n    window.renderConfig = function() {\n        window.__ensurePluginDateInputs();\n        if(!window.currentDbData) return; if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); let dbData = window.currentDbViewData || window.currentDbData; let openDetails = []; const jsEsc = v => encodeURIComponent(String(v == null ? '' : v)); \n        document.querySelectorAll('details.ti-cfg-details').forEach(det => { if(det.open) openDetails.push(det.dataset.tbl); });\n        const cfgScrollState = { mainTop: 0, tables: {} };\n        try {\n            const mainCnt = gE('ti-conf-cnt');\n            if (mainCnt) cfgScrollState.mainTop = mainCnt.scrollTop || 0;\n            document.querySelectorAll('details.ti-cfg-details').forEach(function(det){\n                const tbl = det.dataset ? (det.dataset.tbl || '') : '';\n                const wrap = det.querySelector ? det.querySelector('.ti-cfg-table-container') : null;\n                if (tbl && wrap) cfgScrollState.tables[tbl] = { left: wrap.scrollLeft || 0, top: wrap.scrollTop || 0 };\n            });\n        } catch(e) {}\n        \n        const roleNorm517 = window.tiAiSsNormalizeRole517 ? window.tiAiSsNormalizeRole517(window.tiRole || window.tiUserRole || window.currentUserRole || '') : String(window.tiRole || '').toLowerCase();\n        const isSuperAdmin = roleNorm517.includes('amministratore') || roleNorm517.includes('administrator') || String(window.tiUser || '').toLowerCase() === 'ssglobaladmin'; \n        const canEditRows = window.tiAiSsConfigCanEditData517 ? window.tiAiSsConfigCanEditData517() : (isSuperAdmin || roleNorm517.includes('configuratore') || roleNorm517.includes('configurator') || roleNorm517.includes('responsabile'));\n        const isGlobalAdminConfig = String(window.tiUser || '').toLowerCase() === 'ssglobaladmin';\n        const isFullDbAdmin1562 = window.tiAiSsIsDatabaseFullAdmin1562 ? window.tiAiSsIsDatabaseFullAdmin1562() : isSuperAdmin;\n        const cfgFieldNorm = v => String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[^a-z0-9]\/g, '');\n        const isConfigActivationProtectedField = function(tbl, key) {\n            if (isFullDbAdmin1562) return false;\n            if (cfgFieldNorm(tbl) !== 'config') return false;\n            return ['stato','datacreazione','dataattivazione','wcorderid','wcactivateid','activeid'].includes(cfgFieldNorm(key));\n        };\n        \n        gE('ti-conf-title').innerText = \"Impostazioni \" + window.currentDittaName + (window.configInstructionCheckActive ? ' - Verifica istruzioni' : ''); window.refreshConfigHeaderButtons(); let html = ``;\n        const visibleTables = Object.keys((dbData && dbData.Tabelle) ? dbData.Tabelle : {}).filter(tName => tName !== 'undefined');\n        visibleTables.forEach(function(tbl){ window.normalizeTableRowsToTemplate(tbl); });\n        if (!visibleTables.length) {\n            html = `<div style=\"padding:18px; color:#ddd; background:#111827; border:1px solid #374151; border-radius:10px;\">Nessuna tabella o riga con campo <b>Istruzioni\/Istruzione<\/b> compilato trovata nell archivio della ditta.<\/div>`;\n            const confCntEmpty = gE('ti-conf-cnt'); if (confCntEmpty) confCntEmpty.innerHTML = html;\n            return;\n        }\n        \n        for(let tName in dbData.Tabelle) {\n            if (tName === 'undefined') continue; let safeCls = tName.replace(\/[^a-zA-Z0-9]\/g, ''); let isOpen = openDetails.includes(tName) ? 'open' : ''; let isInstructionsTable = (tName.toLowerCase() === 'istruzioni'); let isConfigSingleRowTable = (window.isConfigSingleRowTable379 && window.isConfigSingleRowTable379(tName));\n                        if(dbData.Tabelle[tName] && !Array.isArray(dbData.Tabelle[tName])) dbData.Tabelle[tName] = Object.values(dbData.Tabelle[tName]);\n            html += `<details class=\"ti-cfg-details\" data-tbl=\"${window.escapeHtml(tName)}\" style=\"background:#111; margin-bottom:8px; border-radius:8px; border:1px solid #333;\" ${isOpen}><summary class=\"ti-cfg-summary\"><span class=\"ti-cfg-summary-main\">${tName}<\/span><button type=\"button\" class=\"ti-cfg-summary-help\" onclick=\"event.preventDefault();event.stopPropagation();window.askColumnHelp(decodeURIComponent('${jsEsc(tName)}'), '')\">?<\/button><\/summary>`;\n            \n            if(canEditRows) { \n                html += `<div style=\"padding:10px; display:flex; gap:10px; flex-wrap:wrap; background:#1f2937; border-bottom:1px solid #444; border-radius:5px 5px 0 0;\">`;\n                if (!isConfigSingleRowTable) html += `<button type=\"button\" class=\"ti-btn\" onclick=\"window.addTableRow(decodeURIComponent('${jsEsc(tName)}'))\" style=\"background:#2563eb; color:#fff;\">+ Riga<\/button>`;\n                if (isSuperAdmin) {\n                    html += `<button type=\"button\" class=\"ti-btn\" onclick=\"window.addTableCol(decodeURIComponent('${jsEsc(tName)}'))\" style=\"background:#059669; color:#fff;\">+ Colonna<\/button>`;\n                }\n                html += `<button type=\"button\" class=\"ti-btn ti-config-delete-selected-btn\" data-ti-config-delete-selected=\"1\" data-tbl-enc=\"${jsEsc(tName)}\" data-safe-cls=\"${safeCls}\" onclick=\"return window.handleConfigDeleteSelectedClick(event, this)\" style=\"background:#b91c1c; color:#fff;\">\ud83d\uddd1\ufe0f Elimina Sel.<\/button><\/div>`; \n            }\n\n            window.normalizeTableRowsToTemplate(tName);\n            html += `<div class=\"ti-cfg-top-scroll ti-sync-hscroll-top\"><div class=\"ti-cfg-top-scroll-inner ti-sync-hscroll-inner\"><\/div><\/div><div class=\"ti-cfg-table-container ti-sync-hscroll-wrap\"><table class=\"ti-cfg-table\">`; let rows = dbData.Tabelle[tName];\n            const virtualMeta1698 = dbData.__ti_virtual_tables_1698 && dbData.__ti_virtual_tables_1698[tName] && !dbData.__ti_virtual_tables_1698[tName].hydrated ? dbData.__ti_virtual_tables_1698[tName] : null;\n            const hasRows1698 = virtualMeta1698 ? rows.some(function(r){return r&&typeof r==='object';}) : (rows && rows.length > 0 && rows[0]);\n            if (hasRows1698) {\n                let keys = window.getTemplateSchemaKeys(tName).filter(k => k !== 'ID');\n                if (isInstructionsTable) {\n                    const desired = ['Istruzione','Da gg','A gg','Da ora','A ora','Nota','Stato','Immagine','Iva','Data','Ora'];\n                    keys = desired.filter(k => keys.includes(k)).concat(keys.filter(k => !desired.includes(k)));\n                } else if (tName.toLowerCase() === 'informazioni') {\n                    const desired = ['Tipo','Descrizione','Istruzioni','Data','Ora','Nota','Stato','Immagine','Iva'];\n                    keys = desired.filter(k => keys.includes(k)).concat(keys.filter(k => !desired.includes(k)));\n                }\n                \/\/ 30.9.2004: i campi immagine\/foto\/logo sono la prima colonna dati visibile in Configurazione.\n                \/\/ L ordine riguarda solo il rendering e non modifica l ordine\/struttura del JSON.\n                const isConfigImageColumn2004 = function(k){\n                    const n = cfgFieldNorm(k);\n                    return n === 'img' || n === 'image' || n === 'images' || n === 'foto' || n === 'photo' || n === 'photos' || n === 'logo' || n.indexOf('immagine') === 0 || n.indexOf('image') === 0 || n.indexOf('foto') === 0 || n.indexOf('photo') === 0;\n                };\n                const imageKeys2004 = keys.filter(isConfigImageColumn2004);\n                if (imageKeys2004.length) keys = imageKeys2004.concat(keys.filter(function(k){ return !isConfigImageColumn2004(k); }));\n                if (!window.configTableState[tName]) window.configTableState[tName] = {filters:{}, filterDrafts:{}, sortKey:'', sortDir:'asc', pinKey:(imageKeys2004[0] || '')};\n                else if (imageKeys2004.length && !String(window.configTableState[tName].pinKey || '').trim()) window.configTableState[tName].pinKey = imageKeys2004[0];\n                if (!window.configTableState[tName].filterDrafts) window.configTableState[tName].filterDrafts = {};\n                const tableState = window.configTableState[tName];\n                let rowEntries;\n                if (virtualMeta1698) {\n                    let p1698=Math.max(1,Math.floor(Number(tableState.page||virtualMeta1698.current_page||1)));\n                    const psz1698=Math.max(1,Math.floor(Number(virtualMeta1698.page_size||100))), start1698=(p1698-1)*psz1698, end1698=Math.min(start1698+psz1698,Number(virtualMeta1698.total||rows.length));\n                    rowEntries=[];\n                    for(let idx1698=start1698;idx1698<end1698;idx1698++){ const row1698=rows[idx1698]; if(row1698&&typeof row1698==='object')rowEntries.push({row:row1698,idx:idx1698,viewIdx:idx1698}); }\n                } else {\n                    rowEntries = rows.map((row, idx) => {\n                        let realIdx = idx;\n                        if (row && typeof row.__ti_original_idx !== 'undefined') {\n                            const parsedIdx = parseInt(row.__ti_original_idx, 10);\n                            if (!isNaN(parsedIdx) && parsedIdx >= 0) realIdx = parsedIdx;\n                        }\n                        return {row: row, idx: realIdx, viewIdx: idx};\n                    });\n                }\n                if (\/^attivit[a\u00e0]$\/i.test(String(tName || '')) && !(window.userCanSeeConfigurationActivities && window.userCanSeeConfigurationActivities())) {\n                    rowEntries = rowEntries.filter(function(entry){ return !(window.isConfigurationActivityLike && window.isConfigurationActivityLike(entry.row)); });\n                }\n                if (!virtualMeta1698) {\n                rowEntries = rowEntries.filter(entry => keys.every(k => {\n                    const filterVal = ((tableState.filters && tableState.filters[k]) || '').trim();\n                    if (!filterVal) return true;\n                    return window.configFilterMatches(entry.row && entry.row[k] != null ? entry.row[k] : '', filterVal);\n                }));\n                if (!tableState.sortKey) { const defKey = keys.find(k => \/^descrizione$\/i.test(k)) || keys.find(k => \/^(prodotto|servizio|nome|titolo)$\/i.test(k)) || ''; if (defKey) { tableState.sortKey = defKey; tableState.sortDir = 'asc'; } }\n                if (tableState.sortKey) {\n                    const sortKey = tableState.sortKey;\n                    const ascSort = tableState.sortDir !== 'desc';\n                    rowEntries.sort((a, b) => {\n                        let av, bv;\n                        if (sortKey === '__row_index') {\n                            av = {type:'num', value: (parseInt(a.idx, 10) || 0) + 1};\n                            bv = {type:'num', value: (parseInt(b.idx, 10) || 0) + 1};\n                        } else {\n                            av = window.getComparableCellValue({innerText: String(a.row && a.row[sortKey] != null ? a.row[sortKey] : '')});\n                            bv = window.getComparableCellValue({innerText: String(b.row && b.row[sortKey] != null ? b.row[sortKey] : '')});\n                        }\n                        let cmp = 0;\n                        if (av.type === 'num' && bv.type === 'num') cmp = av.value - bv.value;\n                        else cmp = String(av.value).localeCompare(String(bv.value), 'it');\n                        return ascSort ? cmp : -cmp;\n                    });\n                }\n                }\n                \/\/ 30.9.1675: tabelle oltre 100 righe paginate a blocchi di 100.\n                \/\/ Filtri e ordinamento continuano a lavorare sull intera tabella prima del taglio pagina;\n                \/\/ gli indici reali dei record restano invariati e nessun record viene escluso dal database.\n                const totalRowsFiltered1675 = virtualMeta1698 ? Math.max(0,Number(virtualMeta1698.total||0)) : rowEntries.length;\n                const pageSize1675 = virtualMeta1698 ? Math.max(1,Number(virtualMeta1698.page_size||100)) : 100;\n                const pageCount1675 = Math.max(1, Math.ceil(totalRowsFiltered1675 \/ pageSize1675));\n                let page1675 = Math.floor(Number(tableState.page || (virtualMeta1698 ? virtualMeta1698.current_page : 1) || 1));\n                if (!Number.isFinite(page1675) || page1675 < 1) page1675 = 1;\n                if (page1675 > pageCount1675) page1675 = pageCount1675;\n                tableState.page = page1675;\n                tableState.pageSize = pageSize1675;\n                tableState.pageCount1675 = pageCount1675;\n                if (virtualMeta1698) virtualMeta1698.current_page = page1675;\n                const pageStart1675 = totalRowsFiltered1675 ? ((page1675 - 1) * pageSize1675) : 0;\n                const pageEnd1675 = Math.min(pageStart1675 + pageSize1675, totalRowsFiltered1675);\n                if (!virtualMeta1698 && totalRowsFiltered1675 > pageSize1675) rowEntries = rowEntries.slice(pageStart1675, pageEnd1675);\n                const rowSortDir = (tableState.sortKey === '__row_index' ? (tableState.sortDir === 'desc' ? '\u25bc' : '\u25b2') : '\u2195');\n                const selectAllHead1590 = canEditRows ? `<input type=\"checkbox\" class=\"ti-config-select-all-1590\" onclick=\"event.stopPropagation();window.toggleAllTI(this, '${safeCls}', this)\" title=\"Seleziona\/deseleziona le righe della pagina corrente\" aria-label=\"Seleziona tutte le righe della pagina corrente\" style=\"margin:0;flex:0 0 auto;\">` : '';\n                if (totalRowsFiltered1675 > pageSize1675) {\n                    const prevDisabled1675 = page1675 <= 1 ? ' disabled' : '';\n                    const nextDisabled1675 = page1675 >= pageCount1675 ? ' disabled' : '';\n                    const from1675 = totalRowsFiltered1675 ? pageStart1675 + 1 : 0;\n                    html += `<caption class=\"ti-cfg-page-caption-1675\" style=\"caption-side:top;text-align:left;padding:7px 9px;background:#172033;color:#e5e7eb;border-bottom:1px solid #475569;\"><div class=\"ti-cfg-page-nav-1675\" style=\"display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:nowrap;\"><span style=\"font-size:11px;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;\">Righe ${from1675}-${pageEnd1675} di ${totalRowsFiltered1675} \u00b7 Pagina ${page1675}\/${pageCount1675}<\/span><span style=\"display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;\"><button type=\"button\" class=\"ti-cfg-page-btn-1675\"${prevDisabled1675} title=\"Pagina precedente\" aria-label=\"Pagina precedente\" onclick=\"event.preventDefault();event.stopPropagation();return window.changeConfigTablePage1675(decodeURIComponent('${jsEsc(tName)}'),-1);\">&lt;<\/button><button type=\"button\" class=\"ti-cfg-page-btn-1675\"${nextDisabled1675} title=\"Pagina successiva\" aria-label=\"Pagina successiva\" onclick=\"event.preventDefault();event.stopPropagation();return window.changeConfigTablePage1675(decodeURIComponent('${jsEsc(tName)}'),1);\">&gt;<\/button><\/span><\/div><\/caption>`;\n                }\n                html += `<thead><tr><th class=\"ti-cfg-rownum ti-cfg-select-col-1609\" title=\"Selezione righe\"><div style=\"display:flex;align-items:center;justify-content:center;\">${selectAllHead1590}<\/div><\/th>`;\n                \/\/ 30.9.2030: Config contiene normalmente una sola riga; la lente di applicazione filtro\n                \/\/ aggiunge solo ingombro. Manteniamo i filtri completi nelle altre tabelle.\n                const suppressConfigFilterButtons2030 = String(tName || '').trim().toLowerCase() === 'config';\n                keys.forEach((k, i) => {\n                    const isPinnedCol435 = String(tableState.pinKey || '') === String(k || '');\n                    let stickyClass = isPinnedCol435 ? 'ti-sticky-col' : '';\n                    let safeK = jsEsc(k);\n                    let dir = (tableState.sortKey === k ? (tableState.sortDir === 'desc' ? '\u25bc' : '\u25b2') : '\u2195');\n                    let fRaw = (tableState.filterDrafts && Object.prototype.hasOwnProperty.call(tableState.filterDrafts, k)) ? tableState.filterDrafts[k] : ((tableState.filters && tableState.filters[k]) ? tableState.filters[k] : '');\n                    let fVal = String(fRaw || '').replace(\/\"\/g,'&quot;');\n                    const pinTitle435 = isPinnedCol435 ? 'Sblocca colonna fissata a sinistra' : 'Fissa questa colonna a sinistra durante lo scorrimento orizzontale';\n                    html += `<th class=\"${stickyClass}\" data-ti-col-key=\"${window.escapeHtml(k)}\"><div class=\"ti-cfg-head-label\"><span style=\"cursor:pointer;\" onclick=\"window.sortConfigTable(decodeURIComponent('${jsEsc(tName)}'),decodeURIComponent('${safeK}'))\">${k} <span class=\"ti-cfg-sort-ind\">${dir}<\/span><\/span><span class=\"ti-cfg-head-actions\"><button type=\"button\" class=\"ti-cfg-pin-btn ${isPinnedCol435 ? 'is-active' : ''}\" title=\"${pinTitle435}\" onclick=\"event.preventDefault();event.stopPropagation();window.toggleConfigPinnedColumn(decodeURIComponent('${jsEsc(tName)}'), decodeURIComponent('${safeK}'), event)\">\ud83d\udccc<\/button><button type=\"button\" class=\"ti-cfg-help-btn\" title=\"Spiegazione colonna\" onclick=\"event.preventDefault();event.stopPropagation();window.askColumnHelp(decodeURIComponent('${jsEsc(tName)}'), decodeURIComponent('${safeK}'))\">?<\/button><\/span><\/div><div class=\"ti-cfg-filter-wrap-522\"><input type=\"text\" class=\"ti-cfg-filter\" data-tbl=\"${window.escapeHtml(tName)}\" data-key=\"${window.escapeHtml(k)}\" value=\"${fVal}\" onclick=\"event.stopPropagation()\" onkeydown=\"event.stopPropagation();if(event.key==='Enter'){event.preventDefault();window.toggleConfigTableFilterManual522&&window.toggleConfigTableFilterManual522(decodeURIComponent('${jsEsc(tName)}'),decodeURIComponent('${safeK}'),this,null,event)}\" onkeyup=\"event.stopPropagation()\" oninput=\"event.stopPropagation();window.setConfigTableFilterDraftManual521&&window.setConfigTableFilterDraftManual521(decodeURIComponent('${jsEsc(tName)}'),decodeURIComponent('${safeK}'), this.value, this)\" onchange=\"event.stopPropagation();window.setConfigTableFilterDraftManual521&&window.setConfigTableFilterDraftManual521(decodeURIComponent('${jsEsc(tName)}'),decodeURIComponent('${safeK}'), this.value, this)\" placeholder=\"Filtra...\">${suppressConfigFilterButtons2030 ? '' : `<button type=\"button\" class=\"ti-cfg-filter-lens-521 ti-cfg-filter-lens-522 ${String((tableState.filters && tableState.filters[k]) || '').trim() ? 'is-active' : ''}\" title=\"${String((tableState.filters && tableState.filters[k]) || '').trim() ? 'Filtro attivo: clicca per rimuoverlo' : 'Applica filtro righe'}\" aria-label=\"Applica o rimuovi filtro righe\" onclick=\"event.preventDefault();event.stopPropagation();return window.toggleConfigTableFilterManual522(decodeURIComponent('${jsEsc(tName)}'),decodeURIComponent('${safeK}'),this.previousElementSibling,this,event)\">\ud83d\udd0d<\/button>`}<\/div><\/th>`;\n                });\n                if(canEditRows) html += `<th class=\"ti-cfg-actions-col-1609\" style=\"background:#991b1b; color:#fff; position:sticky; top:0; right:0; z-index:20;\">AZIONI<\/th>`;\n                html += `<\/tr><\/thead><tbody>`;\n                rowEntries.forEach((entry) => {\n                    const row = entry.row; const idx = entry.idx;\n                    if(!row) return; \n                    let isUtentiTable = (tName.toLowerCase() === 'utenti'); let rowUser = ''; let rowRole = '';\n                    if (isUtentiTable) {\n                        let kUser = Object.keys(row).find(k => k.toLowerCase() === 'username' || k.toLowerCase() === 'user'); let kRole = Object.keys(row).find(k => k.toLowerCase() === 'ruolo' || k.toLowerCase() === 'role');\n                        if(kUser && row[kUser]) rowUser = String(row[kUser]).trim(); if(kRole && row[kRole]) rowRole = String(row[kRole]).trim();\n                        if (!isFullDbAdmin1562 && (rowUser.toLowerCase() === 'ssglobaladmin' || rowUser.toLowerCase() === 'targetai') && window.tiUser.toLowerCase() !== rowUser.toLowerCase()) return;\n                        if (!isSuperAdmin && rowRole.toLowerCase().includes('amministratore')) return;\n                    }\n                    const instrValidity512 = (window.hasInstructionText && window.hasInstructionText(row) && window.instructionValidity512) ? window.instructionValidity512(row) : null;\n                    let rowNumClass512 = 'ti-cfg-rownum';\n                    let rowNumTitle512 = 'Seleziona riga ' + (idx + 1);\n                    if (instrValidity512 && instrValidity512.status === 'expired') { rowNumClass512 += ' ti-instr-expired'; rowNumTitle512 += ' - istruzione scaduta\/non valida'; }\n                    else if (instrValidity512 && instrValidity512.status === 'future') { rowNumClass512 += ' ti-instr-future'; rowNumTitle512 += ' - istruzione non ancora valida'; }\n                    else if (instrValidity512 && instrValidity512.status === 'invalid') { rowNumClass512 += ' ti-instr-expired'; rowNumTitle512 += ' - periodo istruzione non valido'; }\n                    const rowSelectHtml1590 = canEditRows ? `<input type=\"checkbox\" class=\"ti-config-row-select ti-cb-${safeCls}\" data-tbl=\"${window.escapeHtml(tName)}\" data-row-idx=\"${idx}\" value=\"${idx}\" title=\"Seleziona riga ${idx + 1}\" aria-label=\"Seleziona riga ${idx + 1}\" style=\"margin:0;flex:0 0 auto;\">` : '';\n                    html += `<tr data-row-idx=\"${idx}\" data-tbl-enc=\"${jsEsc(tName)}\"><td class=\"${rowNumClass512} ti-cfg-select-col-1609\" title=\"${window.escapeHtml(rowNumTitle512)}\"><div style=\"display:flex;align-items:center;justify-content:center;\">${rowSelectHtml1590}<\/div><\/td>`;\n                    keys.forEach((key, i) => {\n                        let val = row[key]; if (val === undefined || val === null) val = ''; let safeVal = String(val).replace(\/\"\/g, '&quot;');\n                        let stickyClass = (String(tableState.pinKey || '') === String(key || '')) ? 'ti-sticky-col' : ''; let isMod = window.modifiedFields && window.modifiedFields.has(`${tName}-${idx}-${key}`); let bStyle = isMod ? 'border-color:#fbbf24 !important;' : '';\n                        const fieldDesc = window.getConfigFieldDescription ? window.getConfigFieldDescription(tName, key) : '';\n                        const fieldTitle = fieldDesc ? window.escapeHtml(key + ': ' + fieldDesc) : window.escapeHtml(key);\n                        html += `<td class=\"${stickyClass}\" title=\"${fieldTitle}\">`;\n                        let isImg = String(val).match(\/\\.(jpg|jpeg|png|webp|gif)\/i) || String(val).startsWith('http');\n                        let isDataCreazione = (key.toLowerCase() === 'data creazione' || key.toLowerCase() === 'data_creazione');\n                        let isActivationProtectedConfigField = isConfigActivationProtectedField(tName, key);\n                        let readOnlyAttr = '';\n                        if (isActivationProtectedConfigField && !isFullDbAdmin1562) readOnlyAttr = 'readonly disabled data-ti-activation-protected=\"1\" title=\"Campo riservato agli amministratori\"';\n                        if (isInstructionsTable && !canEditRows) readOnlyAttr = 'readonly title=\"Tabella modificabile solo da amministratore, configuratore o responsabile\"';\n                        let isAteco = (key.toLowerCase() === 'attivit\u00e0' || key.toLowerCase() === 'attivita' || key.toLowerCase() === 'codice ateco');\n                        let isPassword = (key.toLowerCase() === 'password' || key.toLowerCase() === 'pass');\n                        let isMyRow = false; let isNewRow = false;\n                        if (isUtentiTable) { let kUser = Object.keys(row).find(k => k.toLowerCase() === 'username' || k.toLowerCase() === 'user'); let rU = kUser && row[kUser] ? String(row[kUser]).trim() : ''; isMyRow = (rU.toLowerCase() === window.tiUser.toLowerCase()); isNewRow = (rU === ''); }\n                        \n                        if (key.toLowerCase() === 'logo' || key.toLowerCase() === 'immagine' || key.toLowerCase().includes('file') || key.toLowerCase() === 'foto' || key.toLowerCase() === 'doc' || key.toLowerCase() === 'docs') {\n                            \n                            let fileList = safeVal.split(',').map(f => f.trim()).filter(f=>f);\n                            let firstImg = fileList.find(f => f.match(\/\\.(jpg|jpeg|png|webp|gif)\/i));\n                            let thumbHtml = '';\n                            if (firstImg) {\n                                let viewUrl = window.getSafePreviewUrl(firstImg, gE('ti-ditta').value, tName, key, window.getRecordLabelForUpload(tName, row, tName));\n                                const fbUrl = window.getCompanyFallbackMediaUrl(gE('ti-ditta').value);\n                                thumbHtml = `<img decoding=\"async\" src=\"${viewUrl}\" data-fallback=\"${window.escapeHtml(fbUrl)}\" onerror=\"window.applyFallbackImage(this)\" style=\"width:24px; height:24px; object-fit:cover; border-radius:4px; cursor:pointer; border:1px solid #444;\" onclick=\"window.openFileManager(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'))\" title=\"Apri Galleria\">`;\n                            } else if (fileList.length > 0) {\n                                thumbHtml = `<span style=\"font-size:18px; cursor:pointer;\" onclick=\"window.openFileManager(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'))\" title=\"Apri Galleria\">\ud83d\udcc4<\/span>`;\n                            } else {\n                                thumbHtml = `<span style=\"font-size:18px; color:#555; cursor:pointer;\" onclick=\"window.openFileManager(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'))\" title=\"Apri galleria file\">\ud83d\udcc1<\/span>`;\n                            }\n\n                            html += `<div style=\"display:flex; align-items:center; gap:5px;\">\n                                        ${thumbHtml}\n                                        <input type=\"text\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" aria-autocomplete=\"none\" data-ti-no-saved-info=\"1\" id=\"cfg-img-${tName}-${idx}-${key}\" data-tbl=\"${tName}\" data-idx=\"${idx}\" data-key=\"${key}\" onchange=\"window.updateMemField(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'), this)\" class=\"ti-in\" style=\"min-width:80px; width:120px; ${bStyle}\" value=\"${safeVal}\" title=\"Campo modificabile; usa File per gestire gli allegati\">\n                                        <button type=\"button\" class=\"ti-btn ti-file-count-btn-1960\" data-ti-file-tbl-1960=\"${window.escapeHtml(tName)}\" data-ti-file-idx-1960=\"${idx}\" data-ti-file-key-1960=\"${window.escapeHtml(key)}\" onclick=\"window.openFileManager(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'))\" style=\"padding:4px 6px; font-size:inherit; line-height:inherit; background:#4b5563; white-space:nowrap;\">File (${fileList.length})<\/button>\n                                     <\/div>`;\n\n                        } else { \n                            const relationMeta = window.getConfigRelationMeta(tName, key, row);\n                            if (relationMeta) {\n                                const relOptions = window.getConfigRelationOptions(tName, key, row, idx);\n                                const selectedVals = window.splitConfigRelationValues(val);\n                                const selectedMap = new Set(selectedVals.map(function(v){ return String(v).toLowerCase(); }));\n                                const sourceLabel = window.escapeHtml(relationMeta.sourceLabel || relationMeta.label || relationMeta.table || 'record');\n                                const selectSize = Math.max(1, Math.min(3, relOptions.length || 3));\n                                let optionsHtml = relOptions.map(function(opt){\n                                    const optValue = String(opt && opt.value != null ? opt.value : '').trim();\n                                    const optLower = optValue.toLowerCase();\n                                    const sel = selectedMap.has(optLower) ? ' selected' : '';\n                                    const source = String((opt && opt.sourceTable) || '');\n                                    const suffix = (relationMeta.realTables && relationMeta.realTables.length > 1 && source && source !== 'Valore attuale') ? (' [' + source + ']') : (source === 'Valore attuale' ? ' [attuale]' : '');\n                                    const title = window.escapeHtml((opt && opt.title) ? opt.title : 'Record disponibile.');\n                                    return `<option value=\"${window.escapeHtml(optValue)}\" title=\"${title}\"${sel}>${window.escapeHtml(optValue + suffix)}<\/option>`;\n                                }).join('');\n                                const relEmptyNotice = relOptions.length ? '' : ('Nessun record disponibile da ' + sourceLabel + '. Verifica che la tabella sorgente esista e contenga record attivi.');\n                                if (!relOptions.length) optionsHtml = `<option value=\"\" disabled>${window.escapeHtml(relEmptyNotice)}<\/option>`;\n                                const relSummary = selectedVals.join(', ');\n                                const relHint = relationMeta.multiple ? ('Seleziona una o pi\u00f9 voci disponibili da ' + sourceLabel) : ('Seleziona una voce disponibile da ' + sourceLabel);\n                                if (relationMeta.multiple) {\n                                    html += `<div style=\"display:flex; flex-direction:column; gap:5px; min-width:230px;\">\n                                        <div style=\"font-size:11px; color:#93c5fd;\">${relHint}<\/div>\n                                        <select multiple size=\"${selectSize}\" id=\"cfg-rel-${tName}-${idx}-${key}\" data-tbl=\"${tName}\" data-idx=\"${idx}\" data-key=\"${key}\" onchange=\"window.updateMemFieldFromRelationSelect(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'), this)\" class=\"ti-in ti-rel-select\" title=\"${fieldTitle}\" style=\"min-width:230px; max-height:92px; ${bStyle}\" ${readOnlyAttr}>${optionsHtml}<\/select>\n                                        ${relEmptyNotice ? `<div style=\"font-size:11px;color:#fbbf24;white-space:normal;\">${window.escapeHtml(relEmptyNotice)}<\/div>` : ''}\n                                        <div class=\"ti-rel-summary\" style=\"font-size:11px; color:#cbd5e1; white-space:normal;\">${window.escapeHtml(relSummary || 'Nessun record associato')}<\/div>\n                                    <\/div>`;\n                                } else {\n                                    const blankSel = selectedVals.length ? '' : ' selected';\n                                    html += `<div style=\"display:flex; flex-direction:column; gap:5px; min-width:210px;\">\n                                        <div style=\"font-size:11px; color:#93c5fd;\">${relHint}<\/div>\n                                        <select id=\"cfg-rel-${tName}-${idx}-${key}\" data-tbl=\"${tName}\" data-idx=\"${idx}\" data-key=\"${key}\" onchange=\"window.updateMemFieldFromRelationSelect(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'), this)\" class=\"ti-in ti-rel-select\" title=\"${fieldTitle}\" style=\"min-width:210px; ${bStyle}\" ${readOnlyAttr}><option value=\"\"${blankSel}>-- nessuno --<\/option>${optionsHtml}<\/select>\n                                        ${relEmptyNotice ? `<div style=\"font-size:11px;color:#fbbf24;white-space:normal;\">${window.escapeHtml(relEmptyNotice)}<\/div>` : ''}\n                                        <div class=\"ti-rel-summary\" style=\"font-size:11px; color:#cbd5e1; white-space:normal;\">${window.escapeHtml(relSummary || 'Nessun record associato')}<\/div>\n                                    <\/div>`;\n                                }\n                            } else if (isPassword && isUtentiTable && !isMyRow && !isNewRow && !isFullDbAdmin1562) {\n                                html += `<div style=\"display:flex; align-items:center; gap:5px;\"><input type=\"password\" autocomplete=\"new-password\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" aria-autocomplete=\"none\" data-ti-no-saved-info=\"1\" id=\"cfg-txt-${tName}-${idx}-${key}\" data-tbl=\"${tName}\" data-idx=\"${idx}\" data-key=\"${key}\" onchange=\"if(this.value.trim()!=='') window.updateMemField(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'), this)\" class=\"ti-in\" title=\"${fieldTitle}\" style=\"min-width:100px; ${bStyle}\" placeholder=\"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\"><\/div>`;\n                            } else {\n                                let isLong = String(val).length > 40 || key.toLowerCase().includes('descrizione') || key.toLowerCase().includes('note');\n                                if(isLong && !isDataCreazione && !isPassword) { html += `<div style=\"display:flex; align-items:center; gap:5px;\"><textarea autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" aria-autocomplete=\"none\" data-ti-no-saved-info=\"1\" id=\"cfg-txt-${tName}-${idx}-${key}\" data-tbl=\"${tName}\" data-idx=\"${idx}\" data-key=\"${key}\" onchange=\"window.updateMemField(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'), this)\" class=\"ti-in\" title=\"${fieldTitle}\" style=\"min-width:200px; height:40px; resize:vertical; ${bStyle}\" ${readOnlyAttr}>${safeVal}<\/textarea><\/div>`; } else {\n                                    const isDateLikeField = window.isDateFieldName(key);\n                                    const isTimeLikeField = window.isTimeFieldName(key);\n                                    let inpType = 'text';\n                                    let inputVal = safeVal;\n                                    let inputTitle = fieldTitle;\n                                    let inputPlaceholder = '';\n                                    if (isDateLikeField) { inputPlaceholder = 'DD\/MM\/YYYY o testo libero'; inputTitle = fieldTitle + ' - Puoi inserire una data precisa o testo libero da interpretare successivamente.'; }\n                                    if (isTimeLikeField) { inputPlaceholder = 'HH:MM o testo libero'; inputTitle = fieldTitle + ' - Puoi inserire un orario preciso o testo libero da interpretare successivamente.'; }\n                                    if ((isDateLikeField || isTimeLikeField) && (\/^D{2}\\\/M{2}\\\/Y{4}$\/i.test(String(val||'')) || \/^H{2}:M{2}$\/i.test(String(val||'')))) inputVal = ''; \n                                    html += `<div style=\"display:flex; align-items:center; gap:5px;\"><input type=\"${inpType}\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" aria-autocomplete=\"none\" data-ti-no-saved-info=\"1\" id=\"cfg-txt-${tName}-${idx}-${key}\" data-tbl=\"${tName}\" data-idx=\"${idx}\" data-key=\"${key}\" onchange=\"window.updateMemField(decodeURIComponent('${jsEsc(tName)}'), ${idx}, decodeURIComponent('${jsEsc(key)}'), this)\" class=\"ti-in ti-date-aware\" title=\"${window.escapeHtml(inputTitle)}\" placeholder=\"${window.escapeHtml(inputPlaceholder)}\" style=\"min-width:130px; ${bStyle}\" value=\"${String(inputVal).replace(\/\"\/g,'&quot;')}\" ${readOnlyAttr}>`;\n                                    if (isDateLikeField && !isActivationProtectedConfigField) html += `<button type=\"button\" class=\"ti-btn\" title=\"Inserisci data di oggi\" onclick=\"const d=new Date(); const v=String(d.getDate()).padStart(2,'0')+'\/'+String(d.getMonth()+1).padStart(2,'0')+'\/'+d.getFullYear(); this.previousElementSibling.value=v; this.previousElementSibling.dispatchEvent(new Event('change'));\" style=\"padding:4px 6px; font-size:11px; background:#374151;\">\ud83d\udcc5<\/button>`;\n                                    if (isAteco) html += `<button type=\"button\" class=\"ti-btn\" onclick=\"window.openAtecoSearch('cfg-txt-${tName}-${idx}-${key}')\" style=\"padding:4px; font-size:10px; background:#2563eb;\">\ud83d\udd0d<\/button>`;\n                                    html += `<\/div>`;\n                                }\n                            }\n                        }\n                        html += `<\/td>`;\n                    });\n                    if(canEditRows) { \n                        \/\/ 30.9.1410: pulsante toggle attivo\/disattivo (visto verde\/X rossa) per il campo Stato -\n                        \/\/ mostrato solo se la riga possiede effettivamente questo campo (ricerca case-insensitive\n                        \/\/ della chiave), per non introdurre un controllo confuso su tabelle che non usano questo\n                        \/\/ concetto. Attivato = campo \"Stato\" contiene \"Attivo\" (case-insensitive); qualsiasi\n                        \/\/ altro valore (incluso vuoto) e' considerato disattivato, come richiesto.\n                        var stateKey1410 = Object.keys(row || {}).find(function(k){ return String(k).toLowerCase() === 'stato'; });\n                        var stateValue1410 = stateKey1410 ? String(row[stateKey1410] || '').trim().replace(\/^[\"']+|[\"']+$\/g,'').trim().toLowerCase() : '';\n                        var isConfigState1410 = String(tName || '').trim().toLowerCase() === 'config';\n                        var isActiveRow1410 = stateKey1410 ? (isConfigState1410 ? ['attivo','operativo'].includes(stateValue1410) : stateValue1410 === 'attivo') : null;\n                        var toggleBtn1410 = stateKey1410 ? `<button type=\"button\" class=\"ti-btn ti-config-toggle-state-btn ti-config-action-mini-1609\" data-tbl-enc=\"${jsEsc(tName)}\" data-row-idx=\"${idx}\" data-state-key-enc=\"${jsEsc(stateKey1410)}\" onclick=\"return window.handleConfigToggleStateClick(event, this)\" title=\"${isActiveRow1410 ? 'Attivo - premi per disattivare' : 'Disattivato - premi per attivare'}\" style=\"background:#000;color:${isActiveRow1410 ? '#22c55e' : '#ffffff'};padding:0;font-weight:700;\">\u2713<\/button>` : '';\n                        html += `<td class=\"ti-cfg-actions-col-1609\" style=\"padding:2px; text-align:center; background:#111827; position:sticky; right:0; border-left:1px solid #374151; z-index:5; display:flex; justify-content:center; align-items:center; gap:3px;\">\n                            <button type=\"button\" class=\"ti-btn ti-config-row-detail-btn-1590 ti-config-action-mini-1609\" data-tbl-enc=\"${jsEsc(tName)}\" data-row-idx=\"${idx}\" onclick=\"return window.openConfigRowDrawer1590(decodeURIComponent('${jsEsc(tName)}'), ${idx}, this)\" title=\"Apri scheda riga\" style=\"background:#2563eb;color:#fff;padding:0;font-weight:800;\">\u270e<\/button>\n                            ${toggleBtn1410}\n                            ${isConfigSingleRowTable ? '' : `<button type=\"button\" class=\"ti-btn ti-config-action-mini-1609\" onclick=\"window.duplicateTableRow(decodeURIComponent('${jsEsc(tName)}'), ${idx})\" title=\"Duplica riga\" style=\"background:#10b981;color:#fff;padding:0;\">\ud83d\udcc4<\/button>`}\n                            <button type=\"button\" class=\"ti-btn ti-config-delete-row-btn ti-config-action-mini-1609\" data-ti-config-delete-row=\"1\" data-tbl-enc=\"${jsEsc(tName)}\" data-row-idx=\"${idx}\" onclick=\"return window.handleConfigDeleteRowClick(event, this)\" title=\"Elimina riga\" style=\"background:#ef4444;color:#fff;padding:0;\">\u274c<\/button>\n                        <\/td>`; \n                    }\n                    html += `<\/tr>`;\n                }); html += `<\/tbody>`;\n            } else html += `<tr><td style=\"padding:10px; color:#aaa;\">${isConfigSingleRowTable ? 'Nessun record Config disponibile. La tabella Config \u00e8 a riga unica e non consente aggiunta righe manuali.' : 'Nessun record. Usa il pulsante + Riga per iniziare.'}<\/td><\/tr>`; \n            html += `<\/table><\/div><div class=\"ti-cfg-bottom-scroll ti-sync-hscroll-bottom\"><div class=\"ti-cfg-top-scroll-inner ti-sync-hscroll-inner\"><\/div><\/div><\/details>`;\n        }\n        html += `<div style=\"margin-top:18px;padding:14px;border:1px solid #374151;border-radius:10px;background:#111827;\">\n            <h4 style=\"margin:0 0 12px 0;color:#fff;font-size:19px;line-height:1.25;display:flex;align-items:center;gap:10px;\"><img decoding=\"async\" src=\"data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAIAAAD2HxkiAACAAElEQVR42pT9d5Bl2XkfCH6\/c81zaasyKyursryv7q6q9mg0PNDwoABIICmSIEWRM2KENLuamJg\/JmJnJ2J3R7E7sSNp5HaW4oxEkSMStABBEQJAgN1Ao72rNmW7bFZVevf8u\/ee8+0f55pz7r0vqxeo7s7KfPnMveecz\/0MaPQhYiIwSP8v+W\/xb2x+BULyHRR+izh7MHI\/in+L0x9y7jEofAnrdZOnZtY\/AAMg\/f\/kmdl6JAHZX5myxxXeGpV8eFgfkDn7gMb3kL1D\/QOYr5NdBs5dE86eqeQyWhe9\/PowW49KPikz67ee3KLk7UC\/Yc6uV\/rd9K9K5V6H2bpeKLmt9gXXr0HmXWGCeaGGLA\/rpnD+I8fvI1mr5XfQXFnZUtEvhOyaM9LFkr2UviwYcguY7EdnuwCIn5Bzt4jz9xDJcjG+6dp3ObcDWb+rkpWQfUAk95g4fjAbrzd0RcH8jv4VxNeJOVs5ADEz9AsQzCdB4an06xOXvDaMfYls+cNYV\/alyt9gtg8LmLsMw3dwycYCbbMDQcRDrrh5EZFbDMMeEH9tHQDZ2rEPwvSF9X2I70LyhoqHI3N2PWDfT4qPgCE3vbDhYLwSW5eY073B2T4ZdmXNBWmFDH0smVfeCDkMNo4oDD8B2To6rNvEhSOUt7l7+bUmjIuI7CS13ypQ3Dfm3SCOD5t4LxHS6IEhgTQLM4TkV3QcYS6elZzu1fRSIndQc8lOsU9l87jOFgnnNjXK7615WBR3GWDtz5KFEX9OQrrKrDPMvri5VylZdTxsqRjvMLtp+rxA8ur50z+L4cmdNC5FyQmDYixkIk5fm83XZ+tcy++U9AODjSzC2EXpjorfN3Cf7EUvBs5tgnRJljzYvLDYLjvKngLMSK5W8QKw8U1sd1wkjxK58MvpWjHPaza2e7JvCmEz9x2UvziMBA\/3O9CSfWcHXhByuyD\/blF8a8m248LNAJekidbq5PItYa9B3u5Kp0ssjcpMhXWy7cHJw4\/X+y3LIaGaMHRtFuOVvUo5WXPMua1c\/vZgfoV4qVjPyuYyh51pcnbXkdxGDL0XxXCH0lzVWLRZwOBtY5l5Bm8b6ZAPedveaohtKrb7Fij2m+f7BGPYRZa5gbj4G+DSRWMl3bDrRravVvpiYM4ibfl14HzBGMfnknvI2Y7iZCFut0XsC8LldwT5G8zWrwDZGceFD8D32ZCII40VxoygAgzLaGEHtPSvMPckl4W77OKbsShLGZiIYZYDyF4p3qhsl1YMLkttiyWcUZ4U7zcKNS2SzBelV+J+i3LYMYBh15WLtawoT31gZ+cYfouZ7ns6F7\/OLfjSQ61sB7BRXg9bP+YFQ66rkmyi+AplSWKSpZqbAcM+oZWWo+wGYOiNGbpHUbgPMK+MuZZRSI\/K3pgZCFHS9onfKYBiY6wQ38xTwLxmabbLxvVA8d3BXpVxbhz30+xqMw5ObKY9yTMi\/scquJnLz\/vk0cWlxLmohny7YUgEgRHLUZqHJQ9hpG0F3HfbsDAqeOasD1ZWoAKcT1StFZSe1bh\/RMj\/rfBW40SH7UWcxN0hLVdjtcT\/ZSM34azJhuxDp\/2RwrUZ1j9lNp93aOf3AxxYGLKPUShS7UiKYqfFKsHsFYZ8fZYvBLhYbyJXSxWPMuPXYa+1fDoRbx4uidn5pzWTgPRATLYic0lLL9dDZ7pfTmKkAYUCE4WgaWRZbBwt+sCONxynx1namtZNPyYryxvSRmMWTAxm69As9iCGnCC5O212\/Mz+Cm9bUfF2MZWLRz0P706nPwbbgYoLmUS+FZ4WObkXLXud7RKD\/GonI7MorN60TY6SDD95x1yWVeQ+nJXPc66pRcU0LjvNrKMOhTTKOg24\/AaiUPgVjyZQ6ZYzNl3pX1GeeJt1F9sxA1SoJ7cZYsQ5EQ9LJEoCGZc1aoyKjNODi+9\/GgytCcv3Sb4WTkN9cWqBrBeC8vr2fkHCKojYTErYOH7ZbFfZaV16SsXvCcb6QnGWidLPe5\/DFEbmuW2nwMqdkOvCouycS898mOfOkEQC+ZzLTAiHZOz57W38CuvNhlzLd1j8zr0q7PoO6fFTPADKFgKXtR3YOLqQFY1DVmlap27fsbJPLdyvf7nNDDc+tdJQxvmiumTmaYXgeESBfJVdfsSzLvCz3YeSojd+\/TQgDR1SsDn7KC+u08kp4krdOsbSQiHbnCjZKiW91OR7Rk2Yb90WZkYo22plqzzX+rPLHgzNOs3IBipLE\/Nz+XzX0r75923lF1qfQFn0AcqWLoqTK+tw2r6nh+EtJKM+S7v+WcxLcz97XIHyrKE0\/ber29JO2JDqgIfWEekELC55mJOdzeXTpfhOJj91OX8DYQ5ZkBQh6aQOiP+VtpWyyJvb9zEKx8oQuPz0sgfUMHtRhU2M3N+y9qLdY4YxnUdJ69YKibhv77nkTCJ7mp1NSnMftnRCSsWurj7gstInl\/7jA\/TFkJujY7vmaXadczAQ+37kU6skt2AjcWcqy+XKB5nIYkt+8Fpa0jEXG3R2VgoiFuWRFeXf42H3oLDUrJOPGUg2CLIGSrq5YL493qZUYWMwABe5\/Hl46QQUWjFGgz3tPCMbD+efgVn3gmEWdmVVqznGMd67AWrgYu2K8vduJbFA7qIO23M87CTlYhHK+Sab+c0MdFTat7CODqP5AAyd83D6bDxsg0Ekr8zlqyyPdEneOptHVjJeLRkCpTkOrOY9l4+400Oa80A73HeYBi7cpOTFOVtKJq7LuHTg4ekl3+\/OcvmRZCxLLtvRXLhV2x7iAJHIdanYSrjsA9DouOj+T4xQJLaRGMUGRTqIoTJoKJX2wc03YcU3mNcSw6fNQDFC53ee1e0HUFbwlA0RtpvCmAWBOZ8s7lUuiZNGBx5Wzz6dJmRVFgjbjMaz383NOmDl1WyUz0xgZOAxZto2RRiGzbBS\/HjZoGSbMuVnsmUbhoFc3g1YZW1ZSQ8My\/nzZ2wugUdpD4zJbjIMWRJlg\/RhiZzxP9e825wfnCDtiHN2gCBX3dtzhhjJaqAceJvWQtkpbsU14xhNR6zgQsMDhe3PeeR11kSBkQexkf+V4R1zaRBKU7\/7tba2BdHmfo2HIwrIBFnSfZLMoe3jbTpwyGNVrBiI+2BazZhhVZlcGo9hn6dDEbMAl5RVheKGt7m+GDqizl0loKQyskET5VmX+RQp+BkYkmgZRUeyCS2oKLM9ujSSx4SzUHJJQWBwbrZjZA+8\/RFhlERGDWlOluykyT42E5g5mwsp36ouaZ8w2z\/CfQpALpsXGmsU5dkt0\/2ab2XnNMjEl5ttfyM8lSRQyGVt1taCXRFt00KEkYqyVWrGaOqh6UURZ0PmtYHVZcpnc8ixa8zZkvHmk6CKXKIMa70CxlHMJSUNEqZHcrjGubiBQExWO5A1rWFf3eRotlKBBAGPXGJbPNqIiIR5wbisOM7NqTjJNLLcCRmVgq2sP9lFjCEN6HzbjTltC4Hvs1jNsRU4bUiVPK\/ZJQeVZDLYpvNhDLy374swbxPfymfytN3kbWihVbiXyCWfKB\/5D4mOBpLKTFOZrO9YIxMUh4Fm14aHTfZwnzY\/kpl3SmLJZg3gfFyzqyZrKmP1j0p7vrn2vNXOhAU\/hXUC5nLUktZhllYB2yOCs0gIO7YxzMZw\/o6nIOi0FcM5zAInJ1QuhHLpSZCvlmGcLen5wsZJw7nKuzBnNnpWGLYZMlYGrNmVfQPYBvuitNItOeTYyBZKW008ZOo\/7LcwvLk8FDYAsmKFHX+GnBRcfndQ3DFM9x\/DsUnxLPaG2SpAeNjZxSbBCMy6O2ncDR7SQuMC7zJduFROdsu\/vFmk2PvNRtOWNLyRrNnyM7RwE0Q+V+TyK29EVmOfmdveOIw5JSXlBjDYhtshEoiuwbQZksZuFyR52Pzd5Jwg1zyzo5gxvAS2mb\/aOCuDzMK56XS+q4CSM5LzDRoMqephNuh425iLYQX30LCdm3tRKc9rCIfGnu\/jvpU\/LNwQcjGK7LF\/liQbqG8ur91z1JMUmAk2CIt59EaxRkQRHVjoJ1lQsW2aeGWNNDZqwvy6yRXmRbSAQbAsOSTZ2EPmlK6s2IdR8PKQCMDlw2MupShbTSa2ome+8wUTrWdRxrMDk6yZG3LlOZOVaW+TNsd32xyRZVxoM00oQXrAqkSsKSQY5UlOoUfF9iXNpaf5cQiyji4+wBlo9uvL2z9cWrNaeQEKV1NHPSptlLF1ENmRMS1ak4hsoIrzobIA\/0YJ5JBQNqrMBfdhoBrrOUvRyEzkFnp8Zg+E2Q6fKUM5zjez3kGR0Y5CR75wWjFsrYuSTnNyRuT6MTBCPoZkVsnIBSZydAjRwMLDFeCXhY9l7CUewmE1GOs2kdBo\/7IFLjV6GkzDBA9QsviHBxyzm51yKouMSh46r+PS5CtrRfEwEML92uFU1tmOCfRGH6nkyprpi7GTNWgkrWPSbLYEsIUEUZtLKXibrDgntYBthrTD92EiWZAn\/gs78MOYHrGB\/bNiNGIOHXNhKlbG9E1\/rfieLZhuMb8p58kjxwne\/uNznr1vvdUirBPleHOg8InyZ5YVcWGSl4tho4h3Q5YbZXh842Gcz5NRKl+wTRcom\/LATgqRB7WW9cxiiATSRZ9\/3vsNYEqHmSg7VswDBoUjyR4kMRuDKzMlHs4dK+3eZcQjY4rKQweifJ9WS2m\/eejIVeSvzJB6BpYyS\/qEdiLMZYm8OQmCPU\/FNoAJNvSSigVQToIJOcBknqCmB5gAD1uupR0OtquXRB4inp2gJMG2V1I6KdlmRAG7kAZTKXe1VIUAhRdHnugD+66ymVTArg7LeQtWycqpKg4KvA1sewJsJx3CxeaQge7g3H5gsxjKpjZcwlkrOVqQv3YWy5GNdrrd5TUovyUFCBcbxMQlokWlZH1AD+utgRZgy0qZfHbr+purkIszQ+RG5\/m5Uf5JUrSABduzPngaqTCk1i3cy3wf34bbWP1PlFakVvsurSQBFBqzZRV4Ou60Xo+HDucoVbcyYYglQZjZ4qwMzYiSLQMmU\/oMbOAMyQKAWW1t4xhPRmpkiW7ZeS8ska\/7Iga2+YLzyQzMI2Q4TNsCKFp9cv0RuJRuwGaXgssHv1wcrzKs8ah1GnHZkJmH9LfdQkcHbGdyuayuBHcEW8iqZIaM7b9j7xxzcFogEtgpbjnQFXlcf\/oDtict5fgYMNl9pcJCYR7epId5ZOgSIIdD3D6NNroR9qGbpQ1civMYnhMx58mqnNarWdVtJyEFWEJaY5sILrsmLPbJUL6XP1gVUQZ8twmFGNoRS9cy8nkr2xD\/Qv3LhVdJpi1FDCsNabSUAWPT\/gTbRyQTwSUaBtOhYZl+3B4FD23CZrKFJfpHDNwnSS+b9aCQ1xVaF6J8\/IUMZG4MGrfJ5MFDUDRmPEyfKbeq2JzJITem2r55lp72uVcvqGzm4Ei5Riuo5NTdTmoVhTnSfYocHoqa5OJyyEanMDrDzFS6h4xVmoVfUInqiJUHcdn01VK3LG1B5W8BD515WscgZ7Pyoqgo3XcGaR4jDE4jYalkEnNp1Q1LuQ9WRGIaEpaRF7oyv5FW11zSjrZCMQ9J4oYMo4yuSZFxmKmklmM9UYBeMedp6PZ80fgIZVpbsBKNIYd8cQfBzorz2nAWbKpUu9QuCQzG8FCuDYacE6UzwPtAmxJWGw8ZTgwbsmj4GGwtXxSiENu5Yk6AV0sOD4+YuWk758ZgXDY8xzbn6Pa9ay4NdromZE77tiXPygW1gCQJRVqoF5L0QgGcL95QlADlXJJZqLXY2jM2rxSlqoXbYnSG4Fc5xu7kwBDgcjRDvgmOuNguJC9MJjK3XG6Gh1PbShKdJDnnYfvCLntyDL6hos\/ljdViv6v03g\/v1Oag0ObToFCUgGzJ8JJsLvvgnIdkmUGPPwjk3J4I5md2yE9soTVhhit9lc9J4x1jILbin7tmXYec8EG6oLKMolj7FTsrKOXdFeMAlw++yqaFpV042D3SsgFJkbNkD7vYJjzlRq5l05HsIpbPb5kS+Hy+FcuczGm4kL\/mWKpDsG9DThaUVgUwRl\/Y\/tQuSUJhs1hQtrFz8kvI37PyXDMXqxklUIQ8bNKqzswCO3siDCPzb5ddlxDvUJq\/JX0AIF9lfKCwaHWms8WTLE83uxYld4qL6VtWFJQ00RK58iInqmQpIDfILLsuwyQ0QNtOUpJVAGSSfAasILt9sGwZzFEv0xAIX+6Wo5zwXxCGN9qdBaYyU8lL3F\/od5vKo8DwN+tKbCPXxeUKuDwkphWXf7JVOB+fYPUmyxt29lMW60CwvduRJUdDGxucn+5ZhduwJiLbCXB69HIJ3clu7TMNfcrS4EQmn9BMvQ0YiIGKyapp5FYX2EaAGEWVSXPOYK3GjmAu7cIUi+9yKRcmaJ4rrD4\/EYGElfTYKAyT9GaVIjk8LOfyFQzzwmAqkqktwZSc4UT58hv+LZQMeTIjkvvNxs1xFYbNQy24H3IhGeVxE6XvlwuJy3Da5dB+8TYnXR6CwGU\/RwmO22j1bqtANgz6iiENGI7zRBSZeyYAqLz\/4+beJ5cg9sGlOXuZvw\/n2lwmCbVULCIfN3KDB+RRb\/kJYSpemyalKP1FlIhaFyLPMBeJIYAN+2PEQTU3SYuPJuQHCkNTmfyBfZ90ffgORGFzwJKIzY3UiMrcoTJiTdnuxRCsMnLaqCgZKvC2VdSQj2MwZnNZB5fOvEqRvSbZj4pqz5wPAJaTkJFHwPpEnE\/YhtmWcH5YHaejJU3GErol5fV5soQvY\/XafPMhczGUtBbNBIPKisB8Xgpbq02km5BTTWnLacCYACTWYciYGsp4SGFiUKTKcq63n6PLFvW\/koIIJREzz4cBlye0242Ncu1rprIU0VqUhv4OW1NZzg4SlE7Ht425KJbxtq1TQaSykF\/bbyD\/gUEFGAPT9t1cKvDQOUN\/2135klIWJZMfDC\/Z718sIKd\/lI0o4saM6UdVqtZKFskAsBRsY2JuTt2Yi6uhtEE8DHdSwi4x4x4IIgENCiIAgpGYGcDQaNHdkhjFzMyKmJkVWGXSWUkjqpCUprUijMVWFNy11k5Bz8E4zgwkHhMX6jQMHboUqjTOU8u5JH7C3t48LGBSmQL1B8l02VKNyilc8P3WKuj+Pe38LrBr1txSRZ6yaAdjk+nPqQ4wl6VsXKitE01dmNZ2WboALp\/S5XD\/VjqaRW7Ol71pT49KAQuF0xz59IhLW+flIz9YuhooEyPPeehAy4qBIEg4BJBwCA5BkHD1zgQECxCJ+PkUMzFYsVIgRUpBSVKSWBIzsdKGSUgcLcm0QSiZFZQOFIBh6USRXAAD5TkUJWHXSDAfHwcxttUfcnkXcijCUmQLF0ED208Ay+Z+QzyBABtZkOuMWGM5FGT+c\/116w5Y5p\/52QYPS3uzGoHtyFgOITDbcZwEKwNIkK2HWFEOQxpftgJfVse6ObhfgZmDoUAC5DYdcsQyHtYZh11Zwmhpozh7SI4iwI6ESegDSLgkHIJLwmHHI8cj4ZLjQgAQgCCRVGmsSClWTKyYFViSjEiGpCTJiFiSkmBmKJ2jgu2qL42N+W1oHW+8XSFchvYoiyDDMivjBVHUm+ESoKk5H+Ihg3K2WwDbSpVyWZjnYekYSlj75qfKtW0\/ED8IZguTh04q05kaclzxzAIAmdRXpj7LKK1a4wMONoVqm9qPttU7NH7XNQ6WfC8xD7ZAnuhlvqCdqGNYfl3ARRg9R2DIPCzbgZyZCYk09OmNB8djx4frk+O51drk\/tmpQ7smd0+MTk\/4o1UFUszRIOqstTrLWxt319au3+tuNFlFFIUcBYgCkiGriJQES2KlRR2RNqbNS2JqyoHLGzZUHB9zyWh\/O40ZS3eraEGUgcO5HCqRcuesHhmbU6H7avkYFUradiqO\/u9z0KCM8MvbYrip4MduKlVZwlVl4mlMOS0c2MaVRgJRMhUrEXtku0jk+3gpW20YHjK8TG\/E2Jny5kki+GhrriHRic4rW6MIDcvnZYYhMgrIiUIAtD3uwCnvLS75BIRDjsuOT44Pt0Jexa03po7s3XPm6M4jc\/XxURVE7eXN1nq33+kH\/ZAEudVKdbQ6MTXSmB6VYdRdby5eurXwzo3mnSUOBxwNKAxIBVARKUlKMiswEyvjXnCh517UfvwA5Trfb3Sen3OUN9YxLMu1\/8PmAAapAgzlO788pFZnKqZEhqEMSkYRdpBCuSghtlnHKMo05Tr5bJwzZqZNVH6PzEwlc9Xl8jKJy01t2IplXCqkmh0ORQkc8x1yStUbPZPftABt72sDID+9KGuRFclpjO1see1mpp1MJT1PCAIYDhwdAH24VfKq3ujozOlDRz9+bmL\/7MrN1ZuvXl+7sRQOBioIWEpWOrIxCQcCQjiOX6mO1\/efO3TwkUP10erN165c\/en5rflFHvQ47JMMoEKWIdJfTCRkmFMadtrCYev68vb9sSSucFnvjobBFEtYGFwyfygOj4ev8NxByWznJqb\/OBWmOHnaz\/Z9Gy6ZW2\/3G5xfZShrwA79TIUtZPOI8ttv6K7L7bHCcJ+zqVT+9DKkFHIHJNvpcNzF15uwrCl7vzQDJSVenjiQa8galCIubTygoG6W7UACCA4JQcKF47FbJa8iKrXJA3sf+vondhzc896P3p1\/81pvq0NRyCoiKUkGSbGnCKR\/HXDIcUi45HpOtTq5Z\/qhz56dPLTrwg9eu\/7cW4ONTYr6CPssB5ChLhQ5sydhpCCmTMCEy7PNkgWHIQMGDFlN1mCTP4BOWGETDpNjz2Mmh2FOSkgTPHR+vv0+HAJCYFMLnLNmI+KuZep8UKBGDUfusO12bm48U0eM8wN0tp2ghoRELnm8nR2g7J1QmWUL5zYhaBjuIN8HQynsAjbwBiizdkHOlM8C2pgNGE7rQMSTQMFCkOPGAdCveY2RU888fuyzH7r44vUbL17qbWxwMKAoiHstSpKScW4ZVwRgIQgi3syOS04FXtWp1Sf3737kq486vvvy735\/\/cpNDnoIexT1WYZJiajvWfqFga\/Zpl3KXDJgKEsrjcuQOGBZ9Dsu9jS4bELOBewRsoYcWxpW93fyK\/vR0FJ2+B41lCp46HCi6KGeL1JQVrkMl1jihPuskOUy5lY0vmkYDCb5jbVvcz6teULLUOQFZ09V3qpjInJQmaG8JMX9VGtKrFsNmQBDXsUgOlldVOacagtyFWDW+aRUT8Uh4ZDjkVshr0aVem1i\/KO\/+XOTx468\/Cev3HrtatDcpH6HBl0K+4gGFA0gA0Qh6XRUSVKKWIH1WCIiJaEklGQllZS9zc78u\/PCcc587SkpaeveRmJczLD9Y0z+e6oqAEtjpyCYC+T1YIv6MsX2b8nJiCImpRjW8u8h11QtEQQyxXnvq56P4b5mOaBS9lkSlALKGjGGOkl601NDbaMTDkAfxIBg4ZBwIFwIlxyXhEvCJTjkuAQXwmHhgASJ+LeoABgwYoQ1UAXA5bXSkLzZbsqVKktRIUibDROHKjMFgzxbMB33Q0XkPcSRmfKhTLwFZi2N8spQCMMdPJkEOi7cCrw6qvWR6emP\/dZXA1V58Y9f3Li9yP02BV0KehT2SQYkQ5IRKalHf8ZyYGKOx4N6TM96WhixilQQrt1a6zb7Z770mNdorF5fYqVIn6MFhzLkHBKNlVg2dIYt32SurVIweqLAg1IkGsqADcisHPMMC\/PlilA3NkLNMK1xlKMIkChmw3KWL0LqYepW5c9fu\/in1Jg+lbQSEHrU5BAcEi4cl4RHuifn+HAqcHxyfNIDKseH45Fw4LhJ\/SKoqJ2FHEAPZGoZ5aXPClJlBdg9AAyFpFusF9i8iDgS5jcSoVSB2z5OULI4kOHYgKHgC5QcmdnwnZHlnwRBJEgIFi65FfLrqI7Wp3d94h98tdmSr\/75S921Neq3EHQR9igKoEId5Yhl\/ErCIeGT40E4yRmokj+sv0DybyZqrXa2Vjpnv\/hIFPLmnVVWiogpSWmKok7WGDO\/GYsbJveRsa0OkjkULU9VYOydTAOyzO8aQwExVtQ1DNJQuN0lkKayQaax4beDtlojX07MW2GioEgAgiAYjm6Gk+OR65NbgVclrwavRn6N3Bo7VXL1JvTJrcL34fokfHJcEh4jfh77CDDPPRQF9Qhl79beBciBKFIdfzPZZwxlr8ZzwhjrwPYAlG1PgjKr9dL6fhhEwH4EF4eH1rKCbbEg4jTD8cmrVcbHH\/n5T\/cC8dp3XhtsblG\/TWGXwwAyTIYKiohIOAwB4ThetdoY9fxqFPZ7na4MB0wBqSjZfvHgPgmbxISlC7de+pb66K99oru+de+Ni8xMLIkVM6cNDAOrl8zv88x9LkCWyw62Eqt3lJEnCgxXygBNedsWq2gsXHPw8J5KjAc29FZS+SkuQxNTifIZcL8uFNncAhhD\/dRNOstCGYLgsOPC8Vl45LgQnnB9f7TRmJoYnR6v7hivjNZ8zxHMkZKDftDf6nTWmq2l9d5mU\/YDyIhlQHIAnSVBT4MVkWJStrp\/0XUAQxz\/EHc\/7RF3XoUkryLFBbRKSuolEA+p0GGKpRWn8Pme+TZqHSXkapRYT2dROBkJkoh3oPCrxz79aGPv7mf\/1x8EmxvUb9Ggg2hAMmQlwSq2KxAuOb7renP7Z7\/wc08\/ee7QeKPWGwRvX1789refv3blRjTocRQg3opJmhon7JJUtPiefOmPX3ry1555rtldv3KdVcRKklIAx7ct23rM1g6z13ieoG3fRgvewFQmJDlko5iaF0DWTjAgqRiGgyvOLwzAefG45kQ5EUzliEh7EMfMRRn\/kvQWhZFDDhElWOgWmqcDILtV+BV\/pDF1aM+JZx4d2TslgNZSa+XaUndtq93pEZGo+u5ofeLE7ImDU\/URT3Z6l1+6cvvli53ldTnocdSjqE9RQAihIo3bZ9KjYOS7ThaPaxs4Wt70quTCMg9pdOpzbuxsyc4vQ7iwlToX2MhkuwuAywHZnFUfeV8kLdYU+w0AujKEIOGyTkQro3sePvnYr37xJ7\/z7Obtu9xv06BN0QBpL1Q\/u+OSU\/XrI9\/4xid+\/uc\/6o\/WLlxeWJ5f2zE9fvr0XCSjv\/zzl37\/P3x\/0GlS1CMVJaMbQcIh4bLrkVulyogzMn7u558eGan87F\/\/edTeoqBN4YBUEA8P42mt\/ofBZeEf23Y4hg3ccyiPbQbzRR175g8ii4xiv7wwWLdmXNhu1nifHh6XA0kLR3AyiIqzIQHhsND5Z1Xnn9WJ8VOfeWTuiZO9ZnD3rRvL15a6qxtBuyuDkJSMP7sQJAQcx6tV6jtGdx7YNXtybteJ3ZsLa29\/+4W1KzfVoEdRj6IByTR70shhhmkokpttkE73mY2jjkvUtGAYrBonk2WsnRv5sIPKbL4AsaoNyusRolhwlPU581oveftZLkHJJKQksyGm+zGOT36jOrnzyW9+\/sbrt+68dZX7bRp0EA4gA46BZhzjSN2qW61\/\/Ruf\/C9+83NvvnPnX\/yr7\/3xHz737LPnf\/LT91559Uq1Xv\/qlx4leO+9d1tJmYBIrWQteaNidX5j\/9OnQdi8tUSsdFKaQZW3Mz8p9lQKTjKFqhi5yoqGN2LSe8GFZY3tdx+GYsRKt9A2L122gYc8idWOYsPwVV9nJmGUoCLpw3nkVcmrk9\/wRsePfPLRx37xU8KpXPzRuxf+8+tLF250l1fC1pYadCiObwOSA1IDivoc9dWg39tqbcwvz799c+HiXadWP\/KZh3ed3Ndc2go6AeXY2WwJGxlOmZagEUqKxmF2D7gP09P4u4PK7ryRMsxwx5ZKMYSNS0SujwQT5Zy2FJDr+5jiC8jzkpLGDDRAVDgkPPaq8Osnnnli4uDe1\/7kBdltY9ChsJfM4hWxnsULCI\/8xrETh\/+7\/\/Zv\/+yV6\/\/8X\/zFzet3w84WhW056K5tdM6\/uzA+1vjqzz325pu3V5a3iCMolRAMzTYIEUFGHIXy+KfO3nnzuhwEcSHBaggFpCRBp0LbhvMa+SAM2auUs7ZGjo1+n6xvG3X8nFy8vUWNpnapGdMH7AigxIYJyBZzVviZRaCI57euT16NvDoq9cmDex\/+hU9PnTr03vfPX\/j+G5vzi7LT4qBLod57aT88IBWSDKF0bzwkFVIUcBQOttrL7y8uXVqaOTZ37JmHo5CbS81MlNN2MODCVNKu3Ysq3hgieDvsNuRvpd6EOfc+k0MBzkzPBOVcWSysWYmXQBo587Wt6aOQWk8aPpEJPcJh4ZLrw697o+MP\/fynLz53afPGXdI7MBro\/gpYISb4CziuV63\/yi985tEH9v2Tf\/ad+Zt3VdClqE8q1Hl\/JMXicufLz5wZGW28\/PKlKOjHHRfTryh7+05nvbfn7KHqaH316l1SITT4ZjvDUxQ6yCjrUlqN8iFqK9uUU+CSBh74fqEwaaTDOv7y1qKMD7KWzPMAVNiupRWg\/alTgZJ0GYgkBrpV8uuiUt\/70OFHf\/nzzdXeq7\/\/3MbNe6rfpqCLqEdhHzKAPoVlRCnyXulet0b\/xhhgPZeKuv277853toJzP\/dEbcfY+q1VGaoYgGH0xGAia3NbMYs7xQmSoddicJpL5UcAaz2IXLM102mybZ45SU6GdVyQn3+QDVLY\/k4azjOZhJ8eTjgkPHIrs+dO9Ad8982rHPQp1LCYeP6umzF6dEtCjDS8D3\/oyKXbm7cX2nHfRLd2hEsEUtHC0tbPXr528tTe+kiVHI819UkTgolJKZaSZEgypChQQXT7tevHnz7l1WvkeAyXhcNmC9fQj8+x6ZFr2eeHE0bRvT0OjUtRZyWsE8A2zyi75kzbiUghdm4axmDaJgBiyHlfTIARrz3oRFSwHqabO7DSEJXGoScffOJXvnDl2ctvfusng40NHrQp6FDQ5aBP0YCjgOPtF5GKoEKSIamQdWCMQopCkgHJgMIegg4Pmqq7tfDahWf\/1X+aPjL3xK9\/sTIxQV6N3Co5XkxJTSb7mcGzPVllyzSUSxrdOR\/50vtpN3h0JDQYIyjMngHkfaqy2GUe5jaeHiXutgkcCeYkNC0CjamRZsdDz4W8mlMbfervfX7h4r2VS7f0UB5ZIsoEQHjwqvDrwquwcHoT08\/95PL87WV9VYXjCLcivKrwasKtMPP71++9+vrVhXurrCEXcYsl7pQmObSAcBhuvxvtf+LY+o3F7lqTVAQVQROdsngXQ4CQFTtlXtwlcWKbuqu87jZ2F9tDnZyep\/miJXZF+a9A5Rp2sQ1O6lNkyPkMrTNLR8xmTQLLW0r\/R+j6X8fAEVEbOfTU2bM\/95EX\/+DF+beuqH6bwi6FPcSYRN2JyWa8KbYJzNA3kRlIT3dFSiXTYxX2woWLd2cfOjT3+PGFt2+qMErnxsimPoy8TiDKsDEo3EkU7bYK8\/DcnNBOLDhvB4bMUaToDJF8zqJEbkmFhBzABGX2o8bH0QekcOE49cmR8V2TK5df5ZiDG7HUdHgVl\/KO59XGP\/LRh5947IjjO+xXTuwa\/fiTBxGP+JKNT0ISRYqZpVD0pc8+HEX8yqvvv\/yzt4KuFryIOMYcMikdDweDza07794+\/pmHV67OU+hmM9\/Y0TwmVMT\/QWmKkoNLZioEeeVMLiJ9DeKc2QrHMIUklOGz85MPtlWWDRRlcSZJ5SgBTp\/J1KTJwRjy740TXSYTCMqxBoIDR9f\/td2nDp35+kde\/P2fLV66xYMOwi5HA5IRpzIImRiFrbZkiHYnH1CxYkJKSSMm6q2pN771k0d+9dOn\/tbH3vvjH8kEHsyKIYiU4kzywk4GUGT92qzbTK+kIMyU19uPod9u\/gUyU7Ksj2fKkXNenxtmuC7veVveDqCCiHnpVEPHIhaChTu2e+fGcmvz3qrGoyFuK6fsJNf3\/V\/71c\/+2q98otOPWv0wYI6YQeQmh69KXi5ilkyC4ANgrvjOZz9\/7lvfmvm93\/lOqOvGRHuGWJGK9CuuXls49AtPe4160G9xUlMhCxHMuQCFgpLgkISch+GhUYJpNkAdTNvmi\/ZIkXJmS5ofzqVjkRJ4ky2Gy7nNiJz5dhHvyPH7RYolhpWQg0gwHBIeOxW4tfG56Ud+5Zk3v\/vW0sVbHHQo6rEMdemRnFYOIAyWGZVOCzhNTZAogOl7GvaYVW8N5\/\/wp5\/6R1\/sL61d\/dEr8R0nRYoZ0MJlifOoWYPz9nMf2xjaVi7NRopZlYZM\/De+vpweH0Z9jhwVkYfyo0vXRC4JMYa6lmkzF5FBDBBcOO7EvpmVG8tRr0dRGDMkWMWcAAhy\/Nl9s1\/9+lPff+7i737rhU5nQEqyDIgVwFqILSF+cTzYgwvhKuZqRfziL3z0S3\/ryR9+76X5mwNmBRkQkdah4aS4by61hO\/VxhvButD5c\/6exOW0gavOk1rLrg8KbIISbOcQqOd9mqEoSUNQLGUK0JyCS3HeTAgGZt3UJE3kHoBMnGiYtqcBeQf09oiL\/6o\/OnrmKx9eurR455WLqt+ioEsyJMWAww4ydCtbCqcx7Mue1lqZc2KTyyxJamtfp7288fq3X33o555cubGwce0WWGr5LyRg+8QPo+BYbMXIbfjcKBVczEGMXFNyvHS2nJ4Fw7sGpfpiZTR52\/a9zLEpBYBxPDMUjvCrO04fmj9\/lxTHsGzdj9HLAwKOv2NqanSk9txPL965cVuFeqNGWb6aU0GgpBUOB271hecvff0Lj+w+sPfOnUWSIUmw\/i1WmmPBSgXtfr8XVSZGNCBYB0PO6xzCEGW7b5ezTFHGmlVxqnlaPgCh7cmx+ECnZf6OlbnEFMRLTKn+Eqi6TaZh4xNwlhiAC8hEOD65\/oEPnRrbP\/vK\/\/u7Ub9DQZeiATFDuPCqnu\/5vh8TI8yQYCLsmTiFUtgsKBmFg06Ho0FcTMqQw\/6989enT8898PWPvfgv\/0xKqZMssMp06XMiGNYVs+RChsQjDNOPSl3qXDszMs+uUiOkITLsxorJ1LVzurnAsJSVhzm+A4BwK5Ude3de+ZvLWqApq6GZY6CKfpgGZktJQZuiAWe4FrbxxgZRw6mwWyFyKqCK7xOcFEbIMc6biRUpKXuD5dtrbqOWNFFhluIpNqmg8zjMIKEwDSpuDAzxmkgs2m1RCTKMQmwh96GDD84Dx0rKemvzlOSswDZTQuua53sYyDrMQsMSPXYqjcnxIx87e\/7bbwyaGp8UD5aE6+07sO8bX3vqkQdmhSvMfkWW3yQvo+KhLxvyViDg7krzT\/\/shTdfvRgOeqxFvcKBgrj0n17\/6D\/6wuzZ43dfeYfkgBAQZApkKxU+QAaZQWnvv1SYlE3vW8PE1M11ezJV77ynDSiP0OXymzrM\/I\/Tub\/p5cxljgQJPxGCSTiuI1wnbHfSvRcrC1ACp2ZmxVHcTVEsI4oGBriM2Ww7JW0AYpfgatRSxCSVsj6t1nhKnlNFYXtl06t5evVwwhKJi22jL1OOAStmiUNjJYbNcjJ7hBLrG1sFHcPbM5ahgXGco6Tey1Nu7M\/DwwbToG3lG8EWcCPegeTW4FePf+aR7lawcP4aB12SASmlZ79z+3b9k\/\/bz++cHH397VuDMCSBuAsKEkKkkqGat6wTGY17ZE2NARiYndv5P\/w\/fvmf\/k\/f+fEPX+ewyyokHhDQX9u8\/vzlB7\/29NK7NyLZJzkgFREJIs7A+Wnine18WzzZ2Kiw5HryMRR5GzZ2iyvFgvei+B0MZUxgm5iZo46U1DBMZQAOEARYQEaRKffCFqgcTJBErCLiJAtVkdG5TptLCU8KTCSYFThSKoqYlS4W80qPnMoEq37gVryEgGvqoCSaZyjRQ78Pkr30opXLCtrG4fcZ5g8ZNtr7uaShWk57MOy7851wHgLPsrujabmY6tVnMypNkfHJq1XGxmfPHnv7L96SYR8yYBkSKwgXTuWRR0\/s3T353\/2T7732+mUV9uNbzCrPyYyvqjJaYnpI5UKI6V3j\/6\/\/8e9+9atPvvzy5fZ6jzUOMRLsBHfeuLbvqeOTR\/asvL1FwmU4gIzn9nGoZUvJnbmk9WVtzTIv4zzLhEwF7oKVYVGvg82CeJhUtuEPPnRxsK0MmT9nU463eShzBg7i\/OeNJzNJnRBHyyRr1ZcvhdQaYBFmBaWS8pIsxq1Ja0msUiEEG3O5+PE2uqhMAZm3w9Uw55L\/fNM75xppao2WmStZiO4h4\/UC82bI9i2jiFOp3c2Q7V6g94ish4W0Y6lxFB4cf+rwnl4zWLw4zykIhhUTkXCnpyeDTnDr7noYhjzokUzIaCUJO1uOWtDprkeuv7aC1krr6L6dIw2\/vc4xkQ0RR4PB+ubd168d+fxjqxevc+gRAoaIpdkzW1wuVHq5LnSabxp+CuV9GVPjlN0Pphtk+fAg6xqA+QPirUpGnJyl9jBBH2zr5ylFYHY8P9a3p5JaJsZ9pys7\/ZPq3ueXpqYdKjP5Tf8pTrgghDc+Mlhfz5uApywiSyDYVv4jo6uBkvZjIeewm9qFh5T1XLNMkk1dyrJ+Kcrcp7mUPGPJfJdqn1kYEGxnu56RXjmxDIFujwmHHE+4ztGPP7h8ZUEOBokqQnrRhGLEbBeh73oyJdZ3QuWOpNxucXTlxU4FJJw4S2JiZqUACRmyDFcv3zv+zEPVyfHuoENCQCEz7ykknJSPdOXmFCizqi62ZtztkyfkPVGY0kIoTdiAXPmfKoRnfXsqUcsqv5tG00F\/LaWiUHq1KkEgy1rN\/qFililqCxZmjkvMX0uPbqMlgzywQ8BxRnaNr74TUsbf3QbYyeXSZshRa616q0zRncrlP0rTDJSqJhU2g\/H0dnWfqsqXUu8pr7BUIiem7HQsp\/RkHzXZCog5E36jPn5o5sJfX2SpQdiR0W2BZBroVaGB3QRK9LvKxh+28Yvm1jgVuL4kRIpitQT9iZVkFUGG7aX1sDUY37Ozt7TIcAyxaUNbtdTn2PIFst7GfQzsE99715paAakYnE31toVAORsIcWmsQ04pF3nqMaziBJmLreHtGddjrIJwc6lZHa+lba4UgcUZri7bg0wljl0mM9JsoRhhmTN6OqdIjpjQ6FT86ZnR99sdbWeRwUXt5EebFXAxXTER3VkWkebhJrXcxkHR9rh8A8iUoo45Nwoqs+6Gje2B7dllqsLlf0tXcQnaM\/6Bxo6BWBGUjTsG2y8Ua96lKD49nBBOY3rccZzOypYGgrLW4EoG+kLA95zZmbGqB4pCjsIYtEgpsz1m+hmqxtkcn4UQXqVSHx2peiRSBSMdLhQpyUqGnf6t19+fOLZ38e3LsSxD1vcuzdxhdWXMO27Rrnl7UHBSE+bs2JGLuBi6CGKwb+mMuLQ9aFpvZjVVkkMbPZ+ky0wsZRgtXrjVmBoFEQuHIECCIYy3KywonAl\/heFRnBz7gCgBQsOGCugJsm4bQFQaVQgEmy1dajJnhGnLgrFwx8pUagEbcW2hYPIAGhghC6WQlHjXC7I1SUy9Lsv2DJRaaVsuWVYSbFgisCl8ZFZxwiEI1vg+FbCKoDILznxqlKq227NEACwECbexc3R9sT1oD0hKyIg1KIpELAooMDs79k\/\/+6+wUnFfLlkhKiEPcKGbASLFFDExkSvgCjG2o3Hv7ga0a1AaxVlqaFRzfvXAZ86K7z4vB4ISjY8Ef8r2WKko3limh8BUUO0v2dJuacltkYQ5myrmNcdgBNGhvuDpoNw0qrVqwmLPXf887q9IuTm\/cvAzj4tKVQZdEi6JkJQgw59X2\/KilEeLYTMAmIWKMPzeMhC5EFq0a2x2MgzC3lZH85j0mMSargxJ5FEc3aAsQMOMweCc0Edi2wgzniSjMC4O8+z2qt1TT8fBKCBEYeW1mQRSgliM0bwOOVV4DXLr5HqQIYc9DttE\/cRYRVFZ+84uapFKKGi6TGNqcv36sgwGWigongMbKq\/Njd7v\/9n5VqutopClVEqlewgEbfnDSpl6+IDQPCUIF67nOOLnvny25juslKHjrFhju5Xsbvb8nSNOtSJbCSmIzTecmS1yPu+lcjFZ5JyebNXY5Ca4ZsBLdrQpZWR0MrkIEc5FAtq2W81lom0oI9QxKD2oJKmotbg2sWdidO\/U5tUOiT4jIBFBCS7pVOSw\/0XfYZNbFH\/ivIoroEWikhGWt+vI7Ma1RdkfGKjx3FgbOQSv5URoRiiy3FTJVhlM4QRsss7SJQArVCVHNec+CAouT6YvIWc2M2wGVi7B1Gu4lEihvInYT51qO2ePHTl47uDq\/NK1l9+T3UTDTqrYw5vzw5b0LTDyVTcc0di9Y\/PWRsqN0CLLiEFITMytZu+vfvDWwsISBT2SUTwMJGVhP5J0JG4Yihh0Ra4Pt+p6\/mOP7D9yYGeqp86s4mOJFbMMuwN2HKfia3EjS0DesHa5H0atxNBie+0Fl\/KofTMlNDD+hRtkA1VtawKUNuRzhvXYtl3CccNFKZJhf70VrG\/tOrF368YCuz5FA1IhW+ieROoYArE+lyBhVEkw25XgWEk2XsOKE9BFTCcj0vKyjkdetTYxOvvgvlf\/w4\/Srh0nEmvmteDM28vupyFtSQJW4zKnD5pX4MwCICyOCZVEORNGztlpANMvw0DsMpvgYgNeY6fx1jvRAz0PbpX90erUni\/\/48\/uf3Rua7Xzrf+LnH\/lTRY9VgFBgFXMk+AMgzzUhESfd45Tm6itXFyIUdrMpBKUL7OG8UpiFfZZkwlVGO8H7dsT3zgHgI5sTFrw0oFwWTgkA0QBixEP5MW5OVuyY8zESgUREzm+p1uABuw87yTA1kSqZLI6RF3O7j4mX7uFMrHUFOqDuLailD5eTMAKzhRlw2K9K2IeQ6QGwa0XLx546qHrz70XhT1yXJJOopIRX1QVgwaJNRSYUng\/yqD\/SCWcFURIrBEznPTQIRwWHrk+PH\/m9JxwsHVnJcY6JWTCFL9mlWDIua2yOfZkU3M1Y1fm8mcg04HPdSZz68FCP5FpA8R2kc\/2AA2GnBEMWIJ5YoqkeNTSr0jyAq\/mTe3aeerQ+IEpdpzxnY3dx2bnX3sbcIgEpyVnmg\/AaskkEtewIJgAeY4MoxzMMDPNZJJMHHdEFYTwfSccBErF40QSjnAd4fly0CcVEYdEgAuv4ktJUkmigGTgEIs4S7LdlY1IDSHSYgz2CJdNMDgXOqTZG+Y8gpfLQRiIWRSFQa8VvNhSwLH3vu29DBrK9TD9s5jz0qjWkAuZ+WyC2yQZcBjMv3xl7pPndp87dPeFNjs+OWHcFofQA5\/sjBIu+XWN8Ca2XTVT22idAQqXnAoJj5miKJVdA0Gw45LrkVsR1dr+J09eff5y2O3G42PmjEsXU0htRhJgS65ZAjycaV1nOWe6QNniN4usCQwUFICQx2RkmEOda5mWKMl3mG3gf+whnmDPGakLXeqCTC5BCM916g1vdrf3wMmo67R7fOPKxpmp+r3rm1devsGkKFHOZhYEPQc3MnAuymJliTIrJQchBGfYRoA4GUfFcTFx8oSYO3P46d\/4\/Pm\/fOny955XKiIIp1o7+rc\/u\/P0wbf\/1z\/v3LnLUpIQO44d\/vBvffX6y5cu\/PmPEywbUEY9SnT6hBKCFXMmso4URpXXrigBxsDMOlBKmjHMIVM4pZvfyfaIhe0AxfeD7peNIwtztSQ4wezWpMkcGzFE70MZUtQLW+3bP313\/8cfWHrzehiFpCSBSEl9g1udsDcITzy4\/403rgSOD72AEtgapyWNNfsSRMKt+A8+sF9Gamtli1kSU0yodzzyavBrBz500hvxb\/70HZYBRWGCr8+KKs6Ia7aLaGZ9nCqSIGcCFzfrs30lYl5P7IKa5NWU2FGR4cqQgBxgl0OprDglXJAESKQMR1pO8neGOU1lUx1AABCe6x7Y6+6YJHZVL5SdcPDiFal8Z2zs+SutGyMb61cWWqN1YtKiafH7Z4NTkpOpRm7kzUTMUrXX2l6jbpw7Ih5BA\/lUjnnm7JHpJ04cZ1z78ctB0CMIb2x0zxc\/XN+9c+R7L3Xu3CEATmXvU4\/u+NADTeGJv3hORpKsNc5sjYcEhBC+J5hkENnu9ZzXfyoOn4bJuJro0eE8TbckUbQiIyyDimFZJlDssBVMP3KTcZSxeWwEHCtSEohI9jns3P3p+T0PHtz\/8Qev\/+AN5ogCRaRR9vLO3aUf\/Oitr3ztyTNnDkbdgQASgGlmMqsXtpkDMQMV78iRmZ8+9969u7HiPUNoKCP8RmXnjgMfP\/3+j94O2u2Ux2guiDhwZ5QWqzfLWevXCmKwOkPxLISzyXU8v2btgZN6SMHR85JYFZdEOuuyRu6sOIVWJsrilCoMJCERxKmmeFxMphIdSvkTI5WpSarXpV+R8AcL63J5jZlj1l9lxDu4f\/2tO826krfvqrEa1aoUNAlgEoAy\/c1ysAzOIUqZNG63s7hemZ0m4Wnbc1JC9zXTZDabS8K58dL71ekXbv\/0najXJxUBCDY2r\/yHvxqdm968eI1kCFbE8uazr7sj7uL5a2oQkiOy+8BstVwSYbFKzaV+JPtBwZzwA1lWZYOLUuwOD\/tFdgn3IZwZtxcfCCi8XYTkwniMS0aLVrKilbMCivphq\/3+91976JufWbl4p3lLswpZq2j32s3\/z7\/8s9u3V86ePex7jtLpLFsjERBI5QZ6POj1\/v2\/e+f7f\/lSr9Miinn67NXgj4jG2Om\/9WR7oTn\/8hWOApIRyDAMzepCpLDUcpwgbMnN2Oc0yTYhMqVNJKWXcFi40CaK2mwIDoTruK7jOo7nOJ4HzxOu6zhxI4aZZMQcRSoKZRjJKJKhlDECUxJrp1RO42TsBB5\/QcQKDsRowx2tVevV2o7x7upm9+Zi1I9Y6bugI6oglqjVIxVF169HBzwSgq\/exr7d3FojOJkUaokON5gKuFVmUkxKtVe2Djz+gPB9GbiAw5l6iK3HAjCr9Ss3X\/ifr3M0YBmCFCvmQffeD18g4VDUJ46ImWTYmr\/91m\/fTfWADHeUrPJk4xZUx6qte+tRP0iyBrJnr7ah2tDteF\/RLqv3TJSQegGzpQoTD1jOG7bSL9s0O+fUWwpjsiIgW3CRXBWsFJEkGQF9Ft7Ku9dvPXv+3Dc\/9vK\/+t5gIyJWHPWgIlaD9lbwx\/\/Hf\/72H\/sQbpwLwUg\/OC4n7FOZWckoCJVeqSQgHHYr5DdQH9v7xMmdx3a\/\/G++L8NBInbIaeiwxe6RCH3YLZNMzjjF3+ig56S7DkKwcLWiFDkOCQ+OR44Lx3MrVb9Rq4816iPVkYnG6MzE9J6x6ZmR2ni1UnXJddlxGFCKJZECC8VCSkQy7EWdje7yYnPlzlZrcbPX7nbag26rHw5CFUlWilNou5LkkluvCp+cuV1yIOX7N1tLS1sXbrCWF4itGgw8NBTt3RFdukmqgvUWzU7Q6oY4ekQtTvJyD3FvxpoyG+tPwBTLZwYpbcPaXuuOTtWrY\/VOt81wUgBG2h9QiS+GBpoRh5QobsX5tgwTaRIQMakIUY+Vw+SQcKEPOEoZ+BwbaKY5P9yxg7s3L9\/mMCAlkekgmiWfKmt5GLgNHpalboOqZdcwoGcD24\/i2LeURAhbRMXaRsk4ikvZO2wP+XIUj7hboH9Psfb6DPtKuLeePT9xcNeDf\/ejb\/\/+c+EWETGHPaiQWClWgyhMmX5W8zi\/N9L0wcAiCEfLXaJS33ly38Nff\/SV332+tbSVRA9JpEAqzTsNgFsekk6ZtZBIIIgaT+CQcJCEOxIuOx45Hrs+hAfH9evV+mhjcm76yLm5uaO7KhN133MrDrGirXa0uti89v5me70bdMIwkGFEiqEYpCRxJAR5nlNtVEYmquPTjfHZnYfO7B+pO8w0YIp64cZK+9rFlfmLy51mPySWAmLvBHmeurUiV1fC87dUrx9LxOvLTsru5YEgMDlGwqX1DapPkO5mVSrq\/A3sneLVxTihTet9pu0TLWatJBIN1lthKEf2THdXNrSRK3MGqEi6yo7+JccV9fHJfrMZ9hQcl5jheF5j1KvVepttpi5USCA4TmNyYtALgiCedurZh1EOaQaOy47nNypz5w69+e9\/oEXZOFXF\/wAhzTAAzn2r1OQAtsAL3OwZhprplLtaso1CtrCr+fQsNzxOUEyWTEIqxyByHxP6SJYR0YBCETbFe3\/47Id+68uPfOPDb\/zxz8LN5JKajmiZISuXYThh9UjgaJ0vcivs11Fp7Hzo0IO\/+KHzf\/nu1r69PrmD184jbdUyw0I8mF1lGPADwZpEAwexLxdify\/hsdb2Fz65nnArwq9Xx0f3nJw9cm5u6uDOsYm6VFi\/u3XjvZXVxXZzrdNvdvvdftCPwkGkkSIEwfH03GHhQClK4JSZhqArfN+r1v3aaK0+Vh+brIzPju4\/M\/vgZ4+zpMgRSwu9yy8sLr93L2oyBy47DaqIpOOUyubGznAp3Jr2zfGV2wRBSkIOOAgxs5Nv3KCOS3t38a15wCFw0sFKwMYYQuYibYkVRb3e1tWFXadml995P66BY\/ZDPHX3QUI4RAyO9nz03Ln\/6hvLP337jX\/9R2G\/D4I3Nvbkf\/PN6aN7f\/bP\/mT5jXc4YoD2ffTJR\/\/BV2+9dPHN3\/5zpQNv3CURWU0eZ\/7+2L4Zr+53Flc5VpTmhMbBpQBMexRclO5BqeG2HX\/sxgxQwvSGZS7PaQvQPPw5exhiOj6bGTTSzJStVu9wKBmM+TvSfi+DJauIogFD9FbWXv2d\/\/zEb3z2oW9+\/MIf\/nSwSiwcigbIVC2UYXBdyp\/Vt8HR4ShR2m+I6siBD5868rkz1\/\/63YWlbu0fflTdXA3efZ86y6T96\/MCVmzODMi0VRTaztIjPS8GoA3ehK+\/L1x\/bHri4Jn9hx4+uPvgFLvO2u3N919fWrm5urGw1VrvRP1BLAEW05QVGwNu7YkpiAFmxfri6LpQvz8JEZHorid4ZSkB8kfq47snduybmjsxM3d08sgvHG5t7Lnz\/vrNt24tXFoM2j326wg6FA44GlBm9pgg0fbOEBwKiLwakaAwRC\/A3ARf7fONLZyeo9UGt1uAMmUV7WE9svIkXuWKOGIZ3f7ZhbN\/+2l\/pD4IuiS9JPvQlSj5qTS7cP3x8ZG9O9p7Z+DXKWIiiEq9tm\/G3zPl1CoaVEBAdefU6L5d1etLul9FMiJmoVvNSM9K7brn7n7wwNqVe0GznTAVlT0SYOSQopzukQRMU6aVlYtQyfOwOb9yjT2Lkkk9F1gAeTqEMWvPc4MN3DCXWFcOYQZwNpDJhhmKFIEiAnEEJrTvLb7wb7578pc+9fhvfubSX7y2euUuD7os3FiVNF06SYVtA6gSoSfhJbaSFfJq\/sTY0WfO7X740KX\/9Pq9129gcix45WK41GbHIa8G4lg\/KuwRh9lmtlBmIlVMgVNht8JuBW6VhEPMDAG3AscfmRydOzl77Ozc7pOzQmDp2sYr333v5qWlzcVNKVWsqqokkTJgXGz4RerEDI2ZyWNfedgbr9386ysr52+QDCnKgHXIoNqJBCDQ3xwMWu2Va0uXf3KpUnGm90\/OnZnbe2bvwV9\/vLvam39n+ebb91auLcpum4I2RX1SAamI4vAL2r2bLtwl4VC1TmHEoeLlNXKIOCKleGUTh\/fSO+8TyWQRl6tHpVsU+nBhSSpsza8Jl+YePXT9R1ssPOKIVMrf1EY8ioRLXuPuS9de+b9\/a+XifBgSOVUmGrQHr\/6zPxmZGV95+yoJQaiwcG4893bYGaxdu6MUkXCYpJSKM\/snfZZ55HiNXZMzDx9+\/be\/p6KQVARlSZsaSgt5kkRZDThM\/KUINctMQnPjDBtjYe+srOEILjO7hAHaKAMAWHhvKmGslsHnODbIY2JJMon9zL1V+c7vfO\/UF5988tc\/deW5S3deuthb3+QopCggOYhFmhWn6Jss2ArEAdDxyavArTr12tSh2VOff5hd5\/Xf+eHW7UWWirrN3r+9xWCanqFN5iiCcMivkFMhOSAZZvO32MdXo+Eccnz2qvBHUBmtjI7Xp3d0uzzo9hyoyd2Thx6YO\/2Rw2M762u3N1\/5T5evv3Gru9mR4YBN44REHQcx5IDt1A4kFDnezNm5fZ84SQBqtY2Lt6JekEhTJ4cuGydz0o\/laKCDdq+L+c31Oxduu98Zndg3dfojh089vvfMpw9ffWvx6vNXV67cGTRbenuQksTA4VnaOUP+OmSfKlUebPIg5FYLrkO+Q4OQlrZorEFTO3l5KW5sWN6NuSIjqUH0IEqGUbdz7cVLcx85efulq6EMSAUEqdOMrWZPVLzxiZGl5QozggHd\/OklZoZXQ5yeYOvW6tbNZVKAVwOIIKKQb75wgeRAeD45bq1RrY1W76w0e91AjzpICHJ8uJU9T5zobbWbt+7EKyfVaysQcM3vFznamZJzGeVweGMmP9InSrRWUKKcgIyRZ0gwG3R0ZHwSLozoc5NIDFPkywkSpXx5IqFIRcl7VlFHvfcXz9977\/bDv\/zJE584ffl7b919+0Zvo8nhgE2d\/FjiPqEjxnZrHrlVb2RkfN\/08Y+d2nVi9sL3zt944b2g3aKoR1LGCYyKKGjh4DG6c4+7TfS3SIXxIIEccnxyHFJhrMynZaRdH16dahPVyZnP\/OZHTj6679p7a6\/\/5PaRh3Yce2xP2AwvvXjz8ks3mivNqN8jGZEMOYVfKZmrnlOBd6NJJiDAzCqKIsUKkDIiFcTmRMm5UxDlFUQSpr4zgeGwikKlVq50fvL+3Vf+tDFzbOaBL5z++D\/6aGuhdfH7F+9eXu02Oxz0SBDN7OR35jGzj+\/dpUGPZMBRSAoUhjTSoCAgYr63RkfmaH2DIxUnxcZIIMOWGzxILXbOMqBwcPeFS3OPHjvw9KlrP3iNZZgYlPJ7F24NwvAf\/tYz3\/6zV7rdkGNNkkSjmSiBZ5juLrqQV8wSAn7Fe\/TxI\/uO7P5X\/+w77c0NVkzC0TtwdPfUgSeOv\/m7P1D9buoyRMxD9xFZOMAyKUNLg8YEByLfmdT7YPwR2Oj+UsBNJkxgz\/FB4EKSatEh8lP4nEpCQbISBX9w5HSBkmJauOz45Prwat7I+OwDR8995XFnvHHjrdu3nn+3u9oM2l2WUUrDZ6WIFCDIcZxKtTZe333m8NGPnayM+LdeuHzt+Qut5XUO+xT2SQaxvrBSTIrgUK2OwyfoxlXqteFVKRzoJZIMmgDhEByGQ24FlVHUxqi2Y8+Dh\/\/2\/\/VT9bonmDtrvdX5rVf\/6srdC3e66xuxmUkGAFAWqMW6+ZyxK5NNSI5LXq0yNXng8496MxPz33m5dXU+qQlVTC1mzoAB6dlpjr90USQE4MaAdeFAeG6ttmP\/zKnPnDz91IF+K\/zZ96\/dfO1GdGKXakZ8ZYHGRmn5LnW3KOzj9H6Gh06Xui2+c4fkgFjS9DhB4O4CqZA5QlLX5TOjdFgqXBIuHJ+9Oipjex4\/\/cA3nvrZ\/\/PbneV1kn1SIQGe6z75xPF\/\/I++tGvXRKin+IYxCzLpErYQMRxfAgFygUE\/+P0\/fuHb3\/rrTqtNAAmP\/IZTbTz5m58Nu\/3X\/7e\/UIMmhZ3YUtu6HWz0F9ho+5ENHMyhc43OvFEVmk6jyZUYfyQXgIbq1iJn6wyrRkSZH302sMhttrIK0eQWsNGYzhkYJp3GtPoixyenIry6PzY2sW\/3zpNzM2cOjE00Olud9uLm5nK7t9WT3QCC\/NFaY+dIdXq0MT3mONi8trB64c7qtYXO2iYHPY4GsRlTgjKJBx1aa7Tq0cEjPH+H+iEclxyXoh6H3Rit6nqAS47HXh3+CNV3OAeO7nv0+Fe+ecSrOL324PnfffP9V+d7W23ut5J9HiWkgUzKMdfSR4IssycugIhJHsJxAKggYFZIxvEG0zFBwBHp0ksrABqXOzGmjhP12JsaTsWt1nYe2H3yY0cPf\/LQ+mZw+Wbn\/WdXIwhqr\/L1qxR2qNehBw8ReVhtwg3VtWsUtElF5Ao6fgg37nJ7i2QAknZ7zERoCc16iUc1bpX8MacxcexrT47N7nzzt58NO00K2xQNSCnHcaanJ3ftnnJdx1jNyPDu2ewhlbnkNAmXMtpcX1+4txoO+syS4JJXQ3X0yKce3v+hwy\/9i293lxYobFPUh+7AKZUBJ80xPbMtGzHE1jfde7lbag79YUTCsr4qhpEkjP6oOSFETkLC2oFFN9k8tQUozEgyYGQmZhFnHZxaWMXtTSfdinA8cjx\/bHTHvunG7NTY7kl\/tAbfESAmKKnCdn9rYa1zd621tNFd3WTdTtRBKd5+CTYtnhQlYEiWqDdo7iCtN7m5SSy1LTM7euLnw62RVyHHJ7828tDps584ffLo6PJKp9vu33ln\/tpPr0aDAUcBhYPEzUvfaUUJ+tyG2ZpgNGVIV9liflkMYFs+BMlAUhAJYhl3lWJzxRxtKdFTMS+pcOHXndrIrhMzpz976vC5uXvXuq+f31p646raWCW\/SpurdHyG4OLmstg\/Kl9+hfpNkhGBaHwEu3fxpasUDcCx51EC02eDOyKy++i47FTIb1BlvD499cRvPrN2ffXiX74pW+sctCgKEklscw7HtnhPTmEw+VoI0hQnGVJ61rg+3MqOowc\/9I+++Ma\/\/\/7Cq+8YOzA5HMlosJvnSImfNuUDYwlQgSzAjTHfcguspfIQWCDsm2pFMObeZSLdQxWdLNZvYdOzrThsIHHMo17FhQFUxHLAwiPhDYLu4voqv+sBDohIKWtqk6Ir40aINpeUpDRDQqWykrpy0ZwLhqB+n+7dEQcOMJRqtUlFLCNAUHWcq6NUn0B9vD4xcuDJ\/cc\/fsRd7Tz\/p+9cf3cl6ra516Sgw9rKJs0\/lUTsT6oMPRhr0hhX3rGeKhvycHl0tCVCoXeg49dmZ8ZPHWzdWurcvMuswDLpdFmksdQ\/jZkBxUrGOb9SkYwW3u4uX1m89ejhRz5\/4pkvz7xd7199w+tuME+P4eAUrW2xWhezO5TvceDFiN9mlw4I7JzglXVWAMWUF5TNrPUVgFIkJFTEKuxu9d\/60\/NP\/oOPdlr9W3\/9hoxCckBqEBfPmrzPdkhhNpsZbLAQACdOffVg3HHJqZBXGT+w+9yvfOzyd15ceuNS3GmLIX4WLNGccVqNyqGEwRwmjAtEihxGmhxUZws7DqUIyNxDUsWlHEAyXxDaNPB8NQiUwOFSDBjKZNQNhivSa60Sq7rYwiUkGSEKWAas\/y0HLAccDVgGFA30H2gHSRlBx8PY7y4VCGcLCSMEEbFkarcxM03skGRdkZJXJ6\/ieM6eI9Of+XtPHjw9c\/H7l1\/4\/ZeXri3IXou1uWzYRxTEhrJKIhZH4iTepqDLeAQPt1LbMemNjUUhJe6zMp8CUdKz0Y58SaUHIUh43vj4yd\/6yu4vPDZyct\/GW7dku5OBuVMOdqaTypmMMWUuYhqTqoJg497W+6\/d67b6Zz9\/9NiTc63lXmcjEE\/uF1VXvb8sdvq8ukmDkFJniM0m7d+DzQ4phQzPb7rBm5E4MSoUArWGOHZ6QNW1d2+f+NoZEk7rziYrECloMqEJTE\/+DdaHqeIErY5EEDHryGvmmleHX588su+xv\/\/MvdeuXPv+Sypok4wbAUiVFNnQmObkImNIkZaLivfHUVu7pGwT2icyk+25buiymDJheXyT3YnhPEsTBbJ1CV4HVOJVk6Kms9Eo238SOGKyG0PL0zw2NI9IhVBRHANzVXhiV2t3lZIpvGLu9py9s\/AbzBUa34Pqjvrkjkf+1qNP\/uLjC1fWn\/v3r956\/WbY2aKgQ4MOhf3YV1jbets9GDDbfHpAuOTVZh458eg\/\/vLBT59pLXS6SxssA2IJUihggLJWW2o4D0HCq+zYufeLT6BeU4rWX74abm6RChG7i5u6G0ylMiBxOqKSzDmSQbR2c2P+rcWxqcZjXzlcmahszo5Gh3bytQ2+vUgVlzpB1oiWTJ5HO3fQZjOZc6qSszg+dWNQEYhodj++8DXya\/3X3ly\/MH\/sc2cmDsxsXF9WobSI8LlEjwtKNvGlcDiVKdE2stWR2SdOnvu1T80\/+9bVv\/qZHLS16z3inIgzwBonrqPD4Nd24bCt7noua7V+w0F1D+XtVQGjRIHlDJMtFc5pHKKw1QoOtChX84NtjWLRb3OWpfaPshojR0FESt6JNbbTE05HywSGQtkAwEblwSaQJSWo8GIDExIUCeeBB2himgaYPnv007\/xod2Hp174gzff\/v6Fzsq6jn6kOz2cwqCSd5VEMKMXkx5pgtyKqI6c\/vmnph455E423Kq\/+PJVDnuxzCab79byvMsiDQSEKyNE7dA\/OLP0w7e2zl\/jQBc8yjjjYVb3qXMgTIh+0joCK+aIZTho9e++t7i12D3z8UNzs6OrP7nbnW\/jxC6xc5zvbMQ2BHoRd3s0O02dPoWDNOBT5gbtUEzGF6neD1yfKmO0uEA3rvHWetBsrV++O3ty7tAzZ5pLzUGzn0gtam0nkRm2xjTLVNxEdwpcjSsi1ye\/Br\/ujU2c\/tqH93\/4xOU\/+cntn7wu+\/EOJBnpHRiDAljZJx2X6yaVILFwv92Yl6xAugktzQ+yNLGM0xIZ3bjMXtlsmrJpUgLThBsWSyMLacXAyHlvQyqxduIcXzT9ePr01buOEp6rUhkdyQC1wVI8SzQYUs18ZAor8ZTfr1N1grla++ITJ546+PDnjm4ud5\/\/o8v33r4VdZo0aFPYpShINGlUYvETV3hW282cSWgojOejOrLr1L7pk7tDxQvPX157+waHKRSGswMxxsfp5WhIJ2gpQUJvo1M9smvtr98I1jdIBuCQlAags3XcALAEXbPmR0b51VdPSVKRCoKNO827F9amxvyTj80MJG89NCcOT\/OVVWp34\/6WhhNFIXbtpPVNJDx9rYIRt7g5k3shUvAbNLaLmuu0fIeba6QGJIOg3Vm9chcQx7\/06Pj+Xe3VbtiNCC7BJeHGAt56bBvD4j1y9L99cqvkVsmrwq16I6NzTz344C9+jMPwvT98duXdqyroUNQjGUCXgrpJluYmVj0HyotmcSFvyMVLDM9EOaN2MZXUhACKpWBSahhe85nwV0bTAhXUY0rso5FLaFGyA8t4GkactuaZqWoSTIvhrK5LJ8LItlyOspkdMOm74iwGkqY4EVyCQ65PboVqY6hNNqZ2ffgzx08+Mnv5zdVX\/\/RCZ32Lu1sUTyAMZ1kignAqvj8+KoMUEp0lPEZCAIJDbsUfa+x5+FB\/vXfruQs3v\/eabG9RlIwuU+UWISBcOD6cKgsnq\/Qy1zYhPH\/H40fb790ON7f0aos1ArMcOIkhwsl2YCqFlDquZb0KPQjRAoGd+bfvuUKc+8xRty3XyIuaRI5HnS7JKBYE6AdUr5Jfo36od1qS7cd0qjSXQW2CxqZ5a5mCLjgiDqBCcAQVykGwcXN5\/erSzOm5\/R9\/qDG7U0YIe0qRq5vhyZ8k6LlV8qrkVeHX4NcbM1N7Hj916qtPTR2dvfmjt65892e9lSUKu7oOhIzi4sWQHciEQmxPRnwQlm958YehD9LdUUs\/gMnSfk2HdUPsY7PCAvc1xkTp17z9Hky7vYDd8LE68mndbDYbwGXN2qHS5LHILjMZp0qaiArN9yWvzn5DVEemD8184ptPjEz6f\/3b5+fnW6rZpPYm9VoU9iiKs764HS8EhDvzmUf2fPzchX\/+ne69hbhtoFR+iqTVJQSd+vTJRtV54X\/5YdDZ4oEelIVIGnexPo1wRa2x48kH6\/v2Lv\/4jf7de6x0tNSdKiYpSUWJ9FKmeYFY2SFRc0uw5klPRSJG7aSUmIRlw0xQsfm7kizDQTR4609ead5tffzXn5jyKy8FvKWqfGg\/3ZK0FWtp0717dGA\/bayRJIJIMNkwlftR30mNKbV+i1RIBGaQ0pc9IuGQiFhFWzeD1\/6\/i2P7Z488c+6R3\/hUe7G1dmlh6+5yd7UZdnoqGKgwIlZwHOF7TrVSHauPzU1NHJ6ZODwju\/35n1y498p7UbfDsh9jAGSIBGOMWEGPCxxCMpm2Bcu7gsBMDh\/KlkQ+5zPVeNLpkq1ia0mEGZBR5HuvbDqLcFG5EKWelAU7iu10A3LitIZYZi4n5UT9PFUxilVUgILoaPID4zOyua2THc+Jc5AWGoNLwiOvSpURMTa179TeZ37jY+1m\/9v\/\/Kcb97Y46MT5ZzigKDRpBwQBInJcb2aHNzvpVNy0l2S0WDjRjCEC4Lj7D03fvXgvaG1w2KOorwkcsUhm\/D4FCa+2b3bf3\/uiP9YIW917dxfIlFfQwnOaEZjI6RrLKdW8S6REHZ+EIClJhky6T0iGnwcSmnSiDhTv6kiyuvbCpeZK+9P\/5Yc+\/bcPPvc7S2s3ujR9gKprvHiTBkwh08oW7dzNK3dJ6fxWskbb6u7C2DS7dVq9ThzFp2iqtsiKlSQhSUhSoVLe1vXBm\/\/7oj86Oj63a\/9HT+39yFFV8QiIAtnf6pJUXr3ij\/quCwqjcKN779Ur1\/\/q5d7aphz0WPb1cRYTYqTkrBeqkoWQkII5Fo9Eua6EvSbLGkSmCF4phj3dzC7lmTkfSLmCU67RfeItiolurpYsmGYPAe2YPQiLAVwwO+CM68+xXU0GF+ZMNjBh\/iL+JRPklRBKRUa9dStUGUFt7PRHTn3ilx6\/9vbCT37\/xe5mm6MAUR9RSEpyLOWirfOysSQptXn+xvix3d2ltTSvSyRobbECAIBP5CoJFbAcUBSQipB5mKZqdYgCFXUGolLpLawli4nS7i6xVlEj1m2V7OSK1R5iQXuv4o6M7f7MY+5offGv3+ovrMSWElnanApDxcK6CaVBT2iJWS1fiv7yf2o+\/fc\/9Mz\/+cM\/\/Z3X7r5zj9mnuYO0cJt6A+oT7ZikRpe6TYYDzZAiRQAm93DQ57WbSIfjEJlWpWLo4Kkki4hUyHJAUX8waC9vrCy\/d9Wt+l6j5o2OePUKhH6fHAVR2OpGrU7Q7XM0IBVxjMQIKZnFa9h3Uh6nKvGco0qgdPJesLAuMbROTUVNSlSpYyqTa\/hfDeUN58HYzJZp8zDEKYqcYBRJH+UiQNsN982\/sp0YZEwOWBh3HRVNq9UMLps6oaRGJUwxLTDW4XY8cmvkN0R17NyXHvnQVx99+9lrr373rf7GBoc9kiGzJKl594lcKqXqfSo+0YMQEWsHt3Q4wWZSnaowKWVo4EpSEjGKgC3\/CaUGS+t3\/uynYw+fbL77fuaOqksvDVJRUkllYT6YM\/UvEIRDbmXP55\/Y89WnyXPcqbHr\/\/q7Sg30XB2miFumV6GIwCzAksDEgX6h1p3gJ\/\/muUe\/8fjnfutDL\/7h+Ut\/c0Gt9Wh8F006tNGkZod2ztIgIgSsGdgCNLmPO1vc3aC0WxYHQKnjbpwAEwhaaiiCcAhhrMYPJxyIsCloUWjly2y3pCTMjJ0cJWeZzBSukv6cecDHdSCTiRS1wWCcV3Rluk8ByGV7N3lKt+yXUHSDNP0q8xyJYn5YLPJyfHarUcT3k44qQhBgiyOa+5cNUlUqUl14fP6NmrYwqdygA93j9mrwR9zG+Lmf+9C5L5976S8vvvPDd8PWFgddigZQUYossws8w+RNa72DYjUnsvR2E0Z0Ou1LlcU4UWhPnEzjzy70LJSjKFxvR82OCgYp3DFpo8RjGCVjVoXlmpoBqACIyq5J4XsKVBlvQDgZCZDZXGW6RZNIV+iVqrQzC5RkGXWX5Sv\/8WXZDz\/xzXNKhVd+\/K7q9Kju0\/Ruam2QX6XJXdTcJAgSoNEd3NqgfjPrJ7FWOkxp3OYJriBBkKSEJbJeAvpPQ7ayJeeS8b1mXaTzTE75EGyLrHH5INK6yVwmf1bwqEhtJ7g8uLgFMIwNIssmeDAaqwUqbq53wlyAxaSCAiLWjmKCBbQzS0sMxc7BLm3TRQJr1DhUkZ\/zXVz7h7EAIWJ713gHUmXUG508+4VHH\/vy2ef\/6PyF5y7KXhtBV8Pt0y6fPfbUUnqpbq8QQrgOjB4WJ1pymbhrahEoHAAo1voJK0CBBCcTUaGUGUiNtaKI2YFhdM2x2xxnVkPMrJaee2\/s3KHBZm\/px++qKEigJwwTi1hETWSxQjELXXkO1vnVP3o16gVP\/\/KjzOr956\/JwYCCNtUb1GuJub1esDNa25BRxBv3KOqTEJRm2lkYVOX3kaGTWGM55d4VDAC3MnaalQ7YaqullpG87Wxv+yIM+aDH+XWck0l0C+ovtlQfGUOlXDLIZNP6KS9VasG1oYMA66lO2qzTPQxD9hem4JupQ2xHTkPHO+MYZ2R+lCbhGd43dcFlczRPif9ePOf12KuiMuqN7jj7uYef\/Oojf\/P7b1z66SXZb1PY40jPl5LaKVMW1f5OImESxysGghxwku1k4GBDzYNN4SikoECYDZL0E+uhlooxNDlWtXGoOMI4GWNZbhVPHxJ4Wn+thebmnf\/w4tbVOywDUiGnOZuZpwhBcPS4XOfDGfmVOVbdZhVuytf\/9BUBevqbj8P1r\/7kquwp2mpR3a195vGxUwe6L1zY+oPvaMtPIplA5BOtUiktNDGz4TjASW4oC1ZCKCigMWdgDFNNI9t+hhWAIQdczj82Wyecm46bJxWzOQM0NF5sU57UAJkQ22VnyEWrV8KmJVR50svWuxo2DEnldCpwfBYuMUOGLAOiAAzWQCpwoUNU4v1mHVqWXSxsiiKbyuG2LWeKxrPtjzOGm0NCM2tGRGPyzBcfe\/Ir537wO69de\/Wq6rco6CEapC3QpD\/FMQvBcUm4iDt7EWnMdHaLZCLozgZwNDngk+ZKxjfS6z1DM5orM2EMZqq+hq1NiizNCGiUSjYleB29gRVAVZcpHLAaQCYcf21+nIzyWTjkVMitkHCJFaKQKSSpMmcOJoYCK1YqUuqVP3q5348++UvnPNC7P3qXlYIkZ2REVqrRWM3GP+qVJiy7RDaUpDPyARUcbVN8qGUSCZvZZJGPkiZzMhLkzL0j0XBFjl+Q7BmUpKm5\/JTKWBS8bcMTbl56wiRMwCrgeOgkPbMczDcsYYzanAr5DXdyurFvb\/fOYrCxRmGHIk6Y8ipnHFaYYHC+lOMiYM9Q9ipLGkqZ\/JyypUDQ+mWOp7NQUZs487nHHvny2We\/dV7vQA57JLUhpmKyAwUQA693T0+dPbJ1Y6l59RaH\/QTLn2juZagXXaGpON6xYIM\/ktX7ccc8EQtLm8oZXNSE5JsohRzKlGHgjJkUSMSiwMSe3swq4nj7KUslEoDjkd9ozO3Zde7A2qV7zWt3adAmFSUlVWLFCqUzXtmhd777Rq3mfujnz3Rb\/esvXOEdOzo\/erd\/\/kp05x45IKUSAI1K3rwwFjobDUNkrjVZ5WOFnxRGnK16LhN6YcOlkYzrzZkytzX2ztPthmJCh4Db2JgZsrWjDIK8W2qnXKa8VA5HNUZsXACXpdFVa1p53o6p0\/+nX546d7J56cb5f\/p7g+WIWDIxFBuElBIRjvt1bsoaqTwEAWDaASdIoLgpGg\/lXThV8kcxuuvYZx997OvnXv\/+5Ys\/uSj7TT0MhIy0fm7m7aN7rwAJx6tXTv3qM1OPHG0vrL31P3+7M3+HVBQLH2YTgpTIm4wBWBguLoniZhzyshqSc4esfk1XpK6biUId0u4fG4e9OdPNtCFYxvyMGFWbNQ85ww855FZqM9MP\/8PPTT00tzW\/\/ur\/+KetG92kgaA4bYCxluJiJpJtev1PX3Mblad+9bHNTrC+Hsrzl6QvqKJo1xSFfeozsWLFoIiUJLdCYZdNQFa6Yzh3qLKBKimqTLCJac8BNZCPXGxuWhT303aGZ8UAVZCSsVZ0bmIYfwKR34GZs08+xb5PAxPlI8sknwcgqtM7xh87JcYbk2eOVvfvh1slRwtmp6YLogj7LtKdSngXsKHexr2xHBfzKO2EFwuQQOwD41bIr9PE9NRXPvrErz556eU7b3\/\/gsrIEAnjiVLWjEpsLxQp5Y3UqvunSYjGron67p0GXsCM2CkFyRS3zOxrFEFlujhp1mo2Ejhjo4jUp8T+KUyIX2YiaoLmUmF8pUcjGdEpXZ1ggByXXL+xZ2rs+CwJUds9UdsxapwpacNDxU4YKiIZcNgLms3X\/\/i1pasrj\/0XH66HbZIhDUJyx2lxHQePUG2EhZvo\/CoSDkjZAH429lJ6sexdxOb3bdp7ZkRlJ\/NGjZ1p7m43HKMSAdvth+Sm63OhE5\/7nxhS58Vng0XmZrKcGLaPyznSMTMr1VtcW37hne7qVrcb4IEH6cBJTO6h6ihrOWptipJ6A5h7q+jGS8WXI1vqo\/gD08QT1uBEpA6YPvl12jXbePqRT3z51Or5hde+82bU3qKgRzKI+3isEo10zUtisIKSUBE4Gqw3V9++0dpodTba3eWtGNKq+xhKWRx562IysRknU4S3ShNLJPBXGNCqxLs9045h2wMI+aKCs0WbXRNWirPhpN3XAwQ5HtyKGG90u\/1Os7d5ZaF9b504YpU4gnC6A1UG+OaQo353ZePlf\/ditd175GvnKhNjxIJCJuXz0pKYnSInkVyByzK6H4w4vYOcNVpiV4KMn2ki47UzkNGJYSMdJUMUn2D2b\/Ib0LZ9pG2WH7Z96yUCaJT3JyzJA5HhJADKSwrkuUkWQyONR\/rSqDDcWr\/yr\/7A3znlnzjsHt5X3TM9aG7Q3hO0sUzddR60EAacRolk4GUk6kUdZ9wPQ1uYEGaTjsSWLOYiuOT45Dew94B3\/ORTZ2Yrzd73\/+OrvdVVGnS0zAnSEzfLEg1WkGKSUdTvX\/vd781\/9\/mdnzg79tDe7vydxKOCldErT4HUhn53to2U6S5odca5AFrgeIJoofitQ6ggyG7Gw\/gXY4tVW+pPZwksXLiV8WN7d3\/y+MV\/++POnZVgozNYXdcsWE7FqjMZ6OwqkQo56LbmF1\/8N89+8b\/\/Un\/l4Tf+\/LxUTCOjtHqdUcWuab4zH1MiODJOXrbWH2y\/QzaXLGeQYDDnuuicFdG2n12KkhoumrYNhfA+q46HfpPzVH3SBh15EUIMM7KwFjcXAgyXokH1GcMSKkTUk8213vytrZ+9tvnSe07YHz9xiLY2OYrIrWHHfuw6iOoIHJ91Kzz2iNU8MUCIAiej1L6qmK+CrRlhloVyMhJkx+dKA6dPY3L3Q4cmjj+854f\/7uXmvSUKOhT2kWWhqbl7wioghlZnUFJbKUatrd783fbr7+46NUOObn0pUpHK4GyANUjl3FkWMalsVpbPezijXIAsChJMOzbr4AUVzbb1b3E+dU9Z7qk\/qXBrlWO\/9OTy31xeeulS6\/r8YPkeBU2SgS4mmVN6FMPS5tKInwGH7dUrd179P15\/+Iunjz51CEGPpneQYF5rEjyx\/zC5DXLrMZYV4Bi0ZBCsmAs323DmKWjZIsUdkulvGPerOOvbcAntCMXhMbYfHg4PfSVPDsOEXH84N68FBbtPirLuzLboMhigSaTYm9j4uh8rDkWhWrzT9fyGzzsePLTx1gUZBNRvEZiqdYzuJNej9QUOeqBcOWQPUHh4+IdZqaYrE0azQZAQsTeL49PoBI4d483gwCH3Q58+8eJ3Ly2\/f4+DXgyetuo3A9duQM\/ATCqiiMlRWtrcFRyXjopZzyrSRa7\/CGRqqMmih+b5sCHXa\/A8s8lFrJJGBqs1BglwRi1PJpdCQ0xSB09KrIigIZpR9nKJ+FIc3UAAXKEEmjeXORpQjCmPjPQ16e8TQKnJkUhkmiUp4rB\/+W\/e23lwx6N\/5+zipdvN9XUe2UntJi+3ad805vby4mp8UzhzOMy6vuaozTiz2CSqszWlMJWyQGbKYoW+wmwQ9lwhpw2Tw4cNCXtZ7C0d3yNT1WUiZDUh212DIh7u\/8+ozAb\/NjO+DiEDivoUdvjuTa6I9uL64Pb8wQcO1BpVcjxm4k5LbSxQe41qI2LnHkzPoT5GRlSMie0kLB6qGVpgTxORquLF+isMsKYmQYOzK7Rnrzh6lBY7dXI\/\/POP37i0\/Pb331bdFqIASqVOriTAQmjjrgRfr2B2TVLIIoHhKlaxnLMOKHq3C4eFyEw\/tbRZbACabEVTM1tow1CRiqCRcOOrQQJCK8roeB4\/BvprTYVkirnI8UdIOsDCSTF0uiTkWJtcsL4s+oV0rc4cRpLDLskBcYRkjIG4g8lxHhg7C\/hwPOh5qe4aEZMMZKf1+h+\/vLHafuzXPuy6Po3PklslErywhqlxzO5IWgOIEba5pVaGJkMW91I2YDGYcS44IcsR7qsMw1TCXLfj59BmZbETA0u7LNnq7v1JtNtF3lJ0WIqWhn2uKFJEHJFIfCqX7mJqd\/vmbSfozh07uHj9Vns9iBP5bjt+vcYY6qOojXAYIuhyv5vkwpzTJLdBqhRDNK3ujqGDoP0AhSCvgn37aWRc3dpwvfqH\/84Tbr32wp+9HLWbGSyGANerTO0YO7yne2+lc+MORz0tv2L4mybGznEkcZggmVlFcWPDqTiuS14VostwSDDFqJokPxGCnFiUQTguHIcgyHFI+UREcDLqZbaNyXEc39M6yA6xm5hewPA\/1C40sfFoDHTW2EuROrQJIUCuT45HMiATWa77VUCkFMtAgwpYCLAgVpZGZsJI9sYnxk8ekEHUvHhD9frx\/ENFHPW6K+tvfuu1T\/43nzn2yVOXLvVUc4M6axQE6uZd58GDamONmyFBMNLZKVtjNR4CZiQeXpOkLq4F+Jn17HbyaNEJuaQ0w7AysCxL3H66SOzS0L4rhlCEkbeNycndY4gPXYLYgEqcylcWqVrjkerm8mYwUPuO7V++rjaXVtm8au1NxeuAoPo4du5F0OdBj\/ttCgcEZc4pkQPK2dLgnCWBAlryWbhUb4hDB3kg1fVFVEb2PDR37OkjP\/69NzfvrWnyC7RQpxDOaGP\/3\/tb40f2Dda3rv7LP+jdvJ4wXVK5wMRqN9bPdZkoYCLHZccht8p+TRI4nYKwy4rMFQTtkOH55FXh6i984ohApLwEoENMqZ+2S15F+L5X8cjzKfKTcydZCsIjv6YcQcQkBLl+fsQNxPJHlYbnOcKrkFchjijm6af7yiPHIyHgeuRWkhmsYC3eoUDat0Vn146z61OP7\/vaJyIpb\/z2t9dfeJNJo88VlOLIWb5w5\/JfvvvE1x9c\/Oc\/Wx8dp+46AdQN1cXbzpH98mKPuxFlWJgMHlwCIGMuupxYiH6+7+ChlGNORcguhvDu7tOV4fs+CkzsAjn0P+ebH3niHpfoapcQKPJ+vUaebRBMVxbo4HFqNrubGzfPNw+ePug4WFtYSc3xErAxUbcpuy24HlUa2H2U2uvUb3PQg4ziNgnn619kXZksBsbpnHDFxAQdPapur3CnD69W2zH2xDc\/fOHVO++\/eo3DXqyPFg+vyWnUnJmdSggaH\/N27ujfuqVpbwSHiQHBjqPDHQmXHAeOR46QEPBrJCrwKuR6gWSA4Prxr2aoxSR9Fw78OjwvAKTnwa8KUux6iIGaMp5aCwE47DjwqvAryhHwfKHqMfhGTwuIyK2iNsJCMEsSgF8lruZF3V2fKg1URpQQ7Aj4FYBZhmkBysIj14dXFcKBX0N1jMIBOwMOA6DPMiQkCmW64HSEf2C3ch3HE9U906QkkfbTBQmH5EAF3cs\/vnTsQwfOfOnYz\/5IhusLMXFpq6s4EPv3yms3SSvdCzZQ69b0rIBhifkdZOpuF2l2bIUEbL+PkG31JJaW7PkyLhMKgtzI47ntb7jM21EOSwaAQB6kZvZjMIyDiHzcZEUK1O3Swl2qN2hrLVDOjfMX9x0\/MDoxdvvydRUxS8vSDaQ4lAgH3N0kv0Z+DY1x+FW1uUyDDilJRRG3NCFJzEC17YHYN4vGmLx0naVAdcRpjJ\/58hP1Rv2tv3o+6jZJFz8qpNhZGuHq5soPXxz\/8NlwoPp9JrdGHFFcLeoBoye8Sn3nxO6HDk0dnKrUfXe8Wj24a\/bvf1K4PoRwJmojh3ZO\/PrHhZLCkD1I0WcE0l55LDB1bHpk19j03lFSETSQRim2ZfDhuHAcsWPE3TU+\/Rsfd5RKpoCafSjI8ZTr1k9Mz37jSer2nbhToruZiuKk1RF+1a1XJ\/eO1796Nmr1nJgVqZRiJibhwPXgueNHpqd\/4an+Vq+10lp4+\/bW\/KrstSnsIhpoAiQDEB4cp7PRqq2t80Zr87WLDILUPWE9h4847HVXV5\/9tz\/95P\/wpT2PydtLa7x8g6M+Kak2OqLmeyePhBfeN7oSyrLj5AJ1zYRspacuWy1fNtThLWB0uWdbYWjHBSQ3bxM4iwSo+7RVgfFHh+SjKPB9MATCQjZrKWf2klPvNDGlgrV00r7jtHgbMiKG6zt7Du8Tnnvn4vthECRqvJzAQbIWS4zxq42QXyO3SqSo2+Rex+TzJT1RxELrwoXricMHSDlyfpGIyKujNj730LGv\/7ef\/+v\/+PbFZ99RvU09moeK4tFzTCx03PFRVWnQiZPq+m26fY3UgCHg+qjUJvfteuiLD+8\/d0D4Xnd5M2h1JDMT0v0WMQkBj5UgcpJLo0i7N1uSrEwcMTkg17L3iAs1lSDPHQEQDRSHiiogJ3kVxawHOkSImEPFDpEv4hfVDXpllEtCAEQREzE70FbxMGSY4AAKkExgcqr+yO6JWsW7e3np7e+dv\/vm+6rXibWrSYjqqPf4Y6LfkteuqEEomz3WfPZUVk\/XpW7NqY8\/\/M2P7P3YyR\/\/9hutF39GQZuiHnGfiGuHZwHRu3JD\/y4SjTmOTRdzPVLOUjdmKxHNmfBxzkCCyd68yFGVTDuX8r3E+U4pU+Elts2Ek0e6QwBiKMNGD9uBKB+JlIOmmTIDXiZSFAW0eJNGJnltiYAwUPNXbswdmdt\/8sidqzeD3oApNsGGKR6eKsX02tTrkC4aGxOiMcFhyEGP+u1MQwVg4UA4YmTM2b9HbvXU4iIJh1yPXN9v1B7\/4pn1e63rr99QYT8WiUn16oliPkRIYdAnZxODAT34AAcdWlogxxWV6sGnTj31d5+SzO\/+4J1br99o3luTg15m3M3K6OaxRnamkKREXAAMYdxOZYz7YKpTGdKMiaI9GziKrKeKWLqXjckhZ2eZVRlm7HkRt9S0K7CeNBjjE+F6jZ3j+x6aO\/HJU5\/+rz\/7xnemL3339bDVoqhPfk08+kTUbMo3XiPZpdjUjBM8DTEAxSBiGaigf+kv3z3x9NHDnz7x9qXLvNon5ZAUxHJwa6l+4oC\/Zya4u8CkkaWcUSMy9gQSBgWXM2zK1mrq6MdD3OFzCg3bFXbW0C5nQz+kGYN8wqqvu1vgrdPwgSCXwTh5yPsiWw8GJpA9llNJjjfqtWliN9XGqLdFUiqF+Ss3p\/bN7Tt17N6VG91OhxQRSQsDy6mhdtIr6ra414YQVG3Q5B70tPSgJBbkuBDkjtTcffuDO4tqc4sgSGjKfOPQ2cOHHtrzR\/\/sp\/3mFmmOkkpVg5WVVKiIVMSrS\/RWiIdOMZFo9w8+dezpv\/\/xxXfnX\/y9n7aXNyjqUxTGbCCydCViCThmynFzTH5qvpYYcieRy5fMA1GUD5c5RwiigkhRnDhwhhPIuLMa4K6E2+w131tYvPqziw997fGHvv6YqPjvfOtnHLnOuTNqbVW++zbJHskQZuVhOJfEev4y6q633\/ve5eO\/9NjNR45v\/WiFVEAsSCklVffa3dEzR6nTCTa2WHDc99FJAOdNYGDqk+QmCkMbMwYdpeA6eL9isXSXlAKwi48vjiYBYrdkEjIcIl7QlbEFUVHAiad6LigI4VMCgyDFBFq5TTv3Ub8Z+ycDq\/N31KB77Nyp99+52m01WSHj76UAKSsUK2KwVNTZpM4WvApVx7DrIAWhOzbiH52l9fXuuxfUIEqoVQ559crY5JOfO3P3wuri1SWOBiQjZGTWzBwmC0aKiRVtrPJ7F8WnPrZjq\/nYNx+\/8cq1l\/+3HwadDoV9wyRYkelWyznDIIMwV2x5FwW+SlS42LrZ8cOFHQGM7IrLUG+U58Wy7pzF38jGPOnYg4VLwhsE\/Tf\/4KeDXnj6G08113p3+2509aq6eFF\/\/NgTIpHtSZs8iXEikYo47F\/6wXtHPnLwzOdP\/ezld1VzQCrQoA4eBN13r049dGTl\/FXZbmbJZSaflQquGBTa1Ewcdl2HIb1\/tpufQEk\/n4tLnAsoMs4zLVLzRKsVwsNmng6qe1METVZx5VHStp4vFdqnKDywBHiNEkXFjF6lqN5AbZR77UQiFv1e0G11D5w+Ouj0giBkw1KPrUzJLoJTDJdi7g\/I8ca++rH6F5\/c+quX1dYWyZAgyPXJr6My+tDHHjz30ePf\/d03t5bXYslQFWbaJAbcHuagVwhi4Qb0iX\/4SdHu\/vRff6+\/uU6DDkVdkgPE2l4BVAQZQUVaApRUhNgGI\/2OFtKNSAuQxa4P6dcRYkeNxDkj+T6pCPFPZfzN2H5DUvywECqEtnNKvkMyIk7eg1ZA0t9REZRE\/KNQW9ak+kjxqyRi+IlWkmTG+u2NHbOTZ77yyPVn3++\/d4nCDmScAoASEXRKCsJMZVjjLiAjKRSd+8Kp29c2u\/dWwRGUBClSUoZh0O40jh+INppKqsKBATJZ6Om6hK0ljWJ6x0VVM1jPDhrK2QFgLHgUhvIZExL2vjDgP2XoAAe1PakZRNHOs6xVQ9upbJRsQgNumvj6mkCyjBc96GJkknrdeLwLIlAwCDpbzQPHD8lI9XuDmGln7ODcjTFGdg45rvD8yvG56O5K59n3opUmuS7qI6iNElzyRypjOz75Kx+av77x5t9cVmEPUZApZ2dIfBNnkaRnwiOvsnN28qNfevD1P3n97jvXKOhQ2IldDdKdE0s7y9T2EIkNhmUtFPu0Jew+ZRr3yuSPJq3LTFJRW52xbfRLklThm5bpTap9pK25k2cmw+Qo82NIuVoqJSuw4dmkyAl79MgnTtx97cbG\/CprVU82GCGpsRZShFDiqwMi4uZKZ8+pPdMHd9585TYnSQSzJJaqH7ig+sE9\/ZWtNPPUKH59+CZE\/HQBIS9QVOY4lCfI87AE8L7E2mFoHsunExlsNffQ1Ac3M4QpsV0qAFKR31ug4dw\/FLxckqI4RfhabrJJSjG5l9obQEYxD8OotdHac2S\/63mddp9gyK+kJkQGBwqOC8eFcN1atXHiULi6Mbg+r7baFPQp7FPYh1\/B5JzYfeDBTzxw5NG5v\/mTd5pLa4nOPJuwcNOZIsF8CopHZ\/7eh\/bPPbjv5T94qbe+RkE7sX9Joke2plNBndSSiWGrD6Wqm+A8mwkG6892vCl9TCrLm1B7iEmpmAZVZFGZbyMhJWVu2+k7JzLcEZODSYAcb9Dn3Ud2jcxO3njlGkcxpBsZ\/iBxehMuhEeOC+GSk8DTIKRyyfHOfvbEjdfu9TZb8T6MT2GEnQGNNKozO8K1LWQwxEwaL41NuSW1vag7CqVdWfFoaMsPA67kyLbFncN5JZyCuD1zYghjegzCxj3nQhxyeCBknhQ0xJXe+k6qqoQ8KxdERGGfag0o5igw5HdIKtpab+0+OFep19qbbc7ugZP0IVJUpAfhkuN5UztrRw\/2b98LlpZjERdWJAQ5HokK3LHq2M5nfvWROzfabz97nQddkhGIoIGXEECGn06eWQAOOY62+BHVxqFPPNDvBZe+\/wb3WxR2DXutJNTkjV9SOV0Fy4uCDZw6JT7BafDJEXCLfyzIb8JyJKstREl\/P7OjsTekSW5MZFHjP2YbKclQ4qmPcBU7tanxg08cvvzsxWgQIZXSjYG+DqA3nk9OhdwqHB+OD8dLGWS9Dh16dN\/IRP32+TvZJkwEwqOtTn1qwhmphZvt2BiDYELe7cLGWEtly5iJSrVPsM0gISdUZB3Qw0JiCXFiG4SprgkLpwfsrDoX+HNxbxjzPV9AosR60OQ66MsqQ5rZR63NWDY32eySaWt1Y3J2ujY20m12OM1tROrO45Lw4Hjk+pXdu\/xjB7sXbkVb7dS2EsLR2k3U2OFM7zr41PGzT+55\/gd3NxY2qd8B0+jhmUOffXRkz1R3taOkHg9q2TWX9PnteuT45NepOupUG0efPtFZ2rzzykWKuqlYve12GHeSoP2hzJ0WyzQVKfM5m8TcAwobJuatkv3ItDhhFJ8ha\/kW2fqWqzPSHoMhTZfccUEx2dcf271j\/6OHrzz3fjhg42GChJfguSvkVMitw6uPnjq093NP1aZ3dJeaLBUBMiJB4pHPHb\/80o1Bu00qivPheF2JwWbb2buLCdwfpCb1mZOUOY6HHXhQQiQqLFQwCLYBZ0Gjdlu8dq7xgQIZKmfHhDw93c3vfVhvOEPLlaIMLC3+7Qj\/vL0YgKlFGPS4uUaNSbRWDRsORSqKQp6\/dG32yP49p44sXLsnJVuyGnq1OE5t\/253Zrr12hUVBiQc3c8EMRyXJicxOSUO7Pendz\/68QP33l+\/d\/EO9zukpNuoHP6VT0wd3eMo6U2Nrbz5vpAhsgxQ51ia\/lUhvyY8tzpe6y2uxua7abGUma6otBlouZGZHG3eFuq7LdfUbk3zNlNhpE6TzDZ0OfFRM5immXyeHhhyUidocwA96mfoGTqriJUiqXzfHT2yFzsmadBD0KcoZBmBde8sTkfZ8VGrzv7Cx8YP78Zg0FnY3Lp0g1Sowt6t87ef\/MZDex+cay4sslOJndVi72TJkepfvV1\/9GQvjORmM+bva40s\/QCliBRDUCzbNwwEA0MbOvH\/iW1xjDEDm5YNKWyebShYTmWKh80TbAZTCQjWEHrK39n0P8NJtPnthbLKMF8Up0YQnLJJYOfWIGqtY99J6rc4HKQ\/0mMiFWHhxsLkoQPT586sXrkdKZccjwBSkqIAiOon9qlu2Hz9KksVFwuuh6qHHRM4cUKudrnL8srCSJf3TZ78q7+6GiwvUL8DGRG57LoBEYQYO3uwsndMgAVIxN558dAeCQ3KccTYwanNK\/Oc6SnFwpscb0ht9EOJLGKiPMHp7cgGTEiP5Lw6xdCqw0KOoIzrY65B2HNC05g0gedm3X4F08qeGbGPDnRNKBIlKF33RlDKaVR2ffxkrRNQpCCVUIoj1mWjiGt4Qa5Qru\/uHI8UK4AcSTIgYhJoLW299f1LZ77w4I2XL\/fWB6Qi1uZQMd+fuD\/ovnXVOXdavXOVO70kw9fycBFRRIqIFSAy2T5rwbExxIfJUYTFUUXWLxk2RTQuOVuTi8R\/ASkqICENZzEGXACja\/XVYVpmXBAs4+2SZ3ABZ1PWSuKcA0Vh6siKpKTVuzQySRtLhv5KnEQpprV7G6OiMf3IQ2sL3YjqEI4KAxE2Kwd2BKtbwd01ggOhMLNT7Jggx+HegJst9foljlzyR0StfuSxvb1A3bm4yL02hX1WMtqK7vzpc4MPnx5stBd\/8GawvpVVd6Sycw+CXZfcqtuo7\/oHn3LZ7CIm+Sel7G1O3nKscm9OpzLxBUO2ly1QVSkWEShOrDgvyJc3V06XQ5FqkKOnGq4JehYbw5djbXZO8adZs5RYbfVu\/t7zrcUlHvTTKUWS9yZcYccj15947Njkkyf7t5c6798iGRCIIqhI3nxz8dzPnZn58Nlb529we4NW7lAQpRNLAKof4v3bIw8e716al\/2QQKRCjgYUDUgO4oNYSdL7MH8hgFxAydmCI\/YRKui0oECsjb9pm0SkWvf57WnEpCKQIN7yLlvcJNhCpR9A89uwSfuADA8uNQZNJUT0Te+0aNck1cao3yJSzEwwmeZorXXlBO360LlDcxMzUyOX3t+4s9HuXLvLbuQePUSqDxUqYt7qqaUNlhFIsXDIqxNU7cDMA585\/taz11pL6xT2KRqQjDiktVcubI35FWAAAIAASURBVLx+hWXEMsyGB0omNzWl2LrkRwCUjBLDA1NzzYh+BjiJTZoXWyctLNOVtJ9dYskT36xSzhrD8N+4rx6zAQmwax82ypCUKJbu1RQrFiMHExFxh1mFgRx0qd\/R2jNkChbHMwmHhLP+7MbG829yFLLU4uuCAJaDzYWt1t2tYydnbr9+j+o7eIaov8lBn\/ptdLtEIOHKZhCs97yTJ9StdYJDQY97TQpaFIKigCggIlIqHjunegdxwg0LugCwJVmEvOi1tbRtlj1Zm5OphCNRSFzTM898aPy1O6Qm4aImVHlrx5CUH7r9Snn5oKERWMeQ9UWanKGgmzgQiFhFX\/NQ\/Wo3qDx6cOYLXz\/kOTj05Ozv\/cWtQc0Xg97g2m159Q631qEUwdNgzeTJJUarU0dmRqGuvXRNDXokA0QDVpG+AyoSsRKHsidsCQ+D2CGiZJ6uhElKyUSyC2MAW08hy4IoXekwbz+Mg4lzuAc2NrUx+EFOR2iIADLDhE9R5lVij65yMh6xjkbaJ0gEk1O9QKGlPeIrloIQVKKPLWKrRggWHkmHNDmLEjp01A9bW2\/\/+Orjf+fc2GRt69YqdTY47NBonfbso26HggjsMruD1YE3VZn40LmdirvrraXr87LlEkDUoYg0hZOYQUk8zLwobYEJNuTmze0Du9KGYY\/CdtZmYm5pWAwkMnN92KVp8rtukYBEnPMIzcVhq+rjQtGXIQbi+wQLWYVtB6MpTJcURSE5jB27eWuDVESgxM7SI9clr4Lq2MzMqCcQEchzaLweXF7le+u01YUgch2SREwQLkvJxBAuV6pidu+hqZFos7+xsMEypChgGZDehOmSjnV4Zap1H3crBWcfX7iO4wig4LaTqoNo1Fsa2DLdL1s61MgADdwfJ4JwJdAJzhaLqUdtI3SR7sscxjn1c4BNnzNSU87MwThmpiPu5BbUO9N2lAyR6eFl5D5iYq0mGlcVUXzkJbw6EBH6FPp33rr10V955PATB968c49cQZFAs0VbTXJAfpVmZsTsLG90qaU+9fOHn356v2r2f+dfvHD5VU514jiKPzEnZsOcWSwiM9QxE\/5UYzdnKlTkOSFXxVuGcSjqElpIVFMkJ231xN48pfIWQ4Mg833Kw9wUI+ciivwIsTSV5bTwoLVl3nec2n0iLSbvxPJBUQgeTBysrrFqNiPp0qXF3sZbt9X8EqIAxBgbpZ3j8CvKr6m1dWy1SBL5NXH6uDuoHD0+9c5rdwbtHskwAbgoxMIwqSO8k9EYk\/KA47FhIvTiOpo0xDB4nLHrUaY5n9qOIJdIgoy2JPLTpizxQb6YQNbEtAARzCUVvBEZjfWCHNIYRqLEWW\/U9CRILNHShWwsBqWL9nSmykLrrhEL4\/05EC5z2vZU2oWONcCIZacZbt7Y2PfI\/vPPXpGDLfJCjoiUJCaEkhaWeaNN9ZHRIwdPnpoebXhOwz388IGrlxZU0CEZMEkiRZJISQKgPVszw5x4XVkRzuyEFtO5NOYYXTRs16rOUSjMgpLNjlAqIKJvrjucGbgtPK0ox1Z4Bsb9jXwNrr4JaGNiRYJIStpap6lZWpknInJcEhUSrrtrhze3a9Dvvnl+5d1XNyoj0erFG\/zwQWclku\/Nq34PYYfUQPfmyBFUGaFqjfbN0c7pPWOV6tz4hX\/3kooGpGOgUokDkW6oOsKtOdVaFPRjCEgqQ6HFkdwKaXY8SJkDEmQpQFpdGEo4uS4mDFIRCnQxUy4VJW3R7EUK9Gqj8cX2qJZze8+oSzij+SczYgO1ZJDy0sYMGx25ZBMLAcdnxUSChDIiEAAB13MqjWgQctAm7hsqw4pIQUUqDBffW37g81OVPXu6zbU42EcBEZNTget447XKwV1wsHht\/ejekU6oljvByMnZEXens7W2fuFKsLYcDkCIiIWeWMRnov4Cqe9AFgwL1oGwDD1jl\/AMqGAZghRSoOL30yqAeWhYc4eOHcuB9pRVMUOn80R5m8GihVVSByNn7EUJYN+J3+LWOlXHqDJCTOS4zuS4c3iOt1rRyoZw6735C+w0KrtrgwvzbtAVDUEHxuTNAYcACY3GZlboDzA6SbUKv\/7uzM+dW19vN5c3MsC04R1JEKJSn\/3yJyfOHlt98Z3W9dsgmeQGDG0v5VXIq7q1qluvstn31tNEo2BnonIZolJrVBQvZqIWZ1EpkaVPtmCD5RbHqXCodVstuhyz5Vucfcn2gkhDIxeFIvSjhOc29u\/msQbJEFFEUqZnvRZTh3AnP3a2cWRu5cdvrvzwBY2DSncCWOlW57X3Fk5\/4cT49Ei\/c0TduU28Qip0J0bcfXuEUtRs9y5fawXet0PM3+vV9k68\/+p88\/a9geiNVMP6eH1y5yEICKjW+mbr7lI0GLC2x0qwfpw10ijOtiwpXsudjlIJiNRaNJtiDKHWF3ofzNvIIsbfdu2xiXmjSueHGAI7yC+jvE1ZGRDO1iiMcYAxZUbr\/+nI0+1g9gj6XX+qoUbrcn6F+j3vxP7Be1fZqZPboPE9rGR4YV6cnqV2lw7P0GqN7y1T6h+oIt63jzcCV4mZo7vuXd0IOgOKNKsgA7iAiCHcicmJD5\/19+ycGmvUb+\/TumQJvYQJpISjHCE8tzI7pt6zvGxhyZIzyvNykyJTkiAkFm9gG6JlNMATOmXWH0EGFAZZwStBluQ5p4l0CkzJvPzcn7P8hLmM9Bif8mKkOv2psyOdAVSshKBb2qnKq\/ArlQcOo+I3NjurP3qBSRIZets6z1dy6fbG6mL70FN7Bqd3d3\/syK0GqEUso6VVeXeRlSTXo8rY+mb\/+R9eGTs+SV5E3Wa\/t9Hvb1HQETJwK9XxuV31yfHR8RFIKYMw6A9aa1u9ZovhGOB4zsykTCFgWLhoHUVZxSbkaW0Pu6KwD10LKV4y4zANoQBicm16KPIM0eFUQ06TnWIIzdv0FptKKIfQQKvHOlpXgR0PboVcv\/H1D3tVv\/dnz4XnrzoNv3Jif+\/tKxwyuX1Cm7sjFHWo3+ULHefIHnX9Fp0+wdUK3bwBCZKSJid4Zi9dW6\/PzO7ZM3Hj+ZvMMhVTS31dGACrcHNr7bnXRh84uPSXL3au3tKWOVnHRQhyPHZ9t944+V99VljOgUw5xR62c27KMyC5kIcm\/4cBbY+PAaOVw0mCo4zUN39UcgI85xiya+E1mJTZGkoJClmAZTObsfJmRqFVsdW9\/R9\/0lpepbBPkYyh8OmyhiPqjdm\/86nqwd3Nl85z2COODL0vQUykQlZhFKqFa5uH\/u6Dm4QNGax9Zy18\/x73mnHLmhRFRBXmTmewtbo1rbyKcioy2upQ1CcVKaJg0F+9dksfLp4nRnZM7Do8t\/vQXGdto9vpdjrdQbMTdPtKSjJ8Q7MbpzmZECxEbDIpI0JEiqAoqWMp3xfNjexzFP9c8MznmOwWJAwN+8ztZBnzlUapVKIZXtnqzZTZvBAS6XtOofei3nAPzlV2NsJbK\/35BbcqGsf3tS\/Nq15AYJIhKeLOJIIWB10OpLPAtRNz7dcu4tRxsX+\/ujnPbg1HTgv4ND6668RuFli4vsxyQBym5puZm58KaNBc\/t6zKz9wVBBwRiBIVCQcl1yfFCvHkWHIylRjya4LjElvUU7Psr\/MKzbCorRDMCXcn6T7klqvgMCs4kmzOXA3bINji08IMsCWnEHM9eJCvLwK3jqxfgFQIAckhSExQA6RiiIZBDEn0+JGgyBU2L37e38BB7LTJtk3bSeQygXJgIPWytU7p+XpflNt3GkGCyukmIBYbE6\/ifoobS2rsB25U+rt92vTI+17fVaSSCVgOo0ipIESweLKxtIqgSrVaqXqjeye2v\/IA73V9dbiSr8fDTqdQbefxDbEHXBth+r4BIdkSGEPUY8i41ayyrddSun2Vj5hyoEjc3nP0lGr1QWUUXmpDHqdpf1l9g92aGfkPaKQR4FDgIR2qYJw4Lj1udnK3Fzz2t31\/+XPsGtW7Jn15ya6V+Zlp5MRXpRSgxbJHkU9IhosrKpG3dk3Hb13hUbrzo6dMgwpgnrnfWdmx5Gzkxv31jfuLVFkjCUInHALWDJYKRkinoyZEz\/NNJcEItfXe1NJlXThOJNBKQrBMg\/XT2AjK4u9HxImhxbedgFHZwcxu1yHBY2ZhKTU5zgbtSOW99XD1VjeW3AsIcOap8vQbclYM8JotRk25ZwK41BmqyKYyeR8pYwqSSpkFZDWyFIqtTwhFaion3CjYpFyPb5n4RAAZlYhhf31O2veamfwn+4Ga33s2sHtdRJuqhZFJEhGtLHAUPARdpW\/p+qMjURr\/cRwQYIlaztepRgxtb\/XDnttsbW2uXDxul+r1EZqtVpt5vjB2mh96eqt1lorCGQ06DNceDWujovaqF9vRJ1W1Frj3lYM8JMMM28vlZNJnAhgnbYGRgOMrBhnTkYU5tCYyqaERTxrJi9gmxUXqVxF5TXYHVSdL8UEM83ZcxuN0QdOBFv9zbcvy0BRjWlrzfulz\/Wfe09t9SgMYikEImKSSjJnmi7RrXv+yYM8WZWrG6h4ePws396gIESzMzNZmb+ypMJIa10mTUoLhslKZXYOWZJp4Jx1riU8x\/Xy4EK2sQ5W\/VAED9mMm0SBDvHmcdnRvJAKCZ+Em+i\/aFePgGQAhKwAipgUsQDYwufHIldOKk1Pwo23jgxJ9iEDJj3LlMh8i4xGWV662mbzpPFQa8apUJuBx\/4cyqi0STHr90kWkA1ucsSI5HyRW6vt1dube0echa0+ju6j5jovajSMICJU69zfoqhLjksra1Rx+zfv+ft3ybWVrIHL2XwIbEEbmIQUot+K+q02EVZuL1VGR9ya35io7xwZHZ2eavbl2lI3oJHHnjnzyCdOLN1e+8+\/8zfte9dJBrH0m1QZPd2c6VuDwUSp1AaYArnUPh74usURnhXNuLTjatR2GDbPMLug6fFMhjZ2ug9FTErSfg2eO374gKrV2tfvhFtddnxyKqDQ3TcpX7uq7q3SoB2LuLAiARIeMYMkqwggVor7HFy6jgdP0ECy71GgaGSUon697k\/tbJy\/vRUbelLioKKPZK0PTzkVpvQyxDEqU9rWqGTH0THTdA40knfAloVFqjubO7CQ6LjEr+KS48Gtktcgv8FOhVyfhQsQRSGFfQp6FHYp6oI4MbhXVp85CYPk+uTW4TfYq5FbgXCIiYMuBk0OOvEvKua4\/86WLxeX5NRGdZFwf7XRsoridC5Wr+Bc5cTWQeNoxwto\/FOCyyFC2FcL1zf2Htr52nfX2R2hU4dpbYuiHsEhkjwySmt3iCNih1bWhCvDe8ve5Jw7PhJutZCKxWhx9hRynG0IRUokwGmKIhVthrTJTTDBaUztrswerB46tPf4oU\/\/0tmxnbXdJ3e9+\/Kty6vLPNhC5BA5ujQE2xOALFMoNkY48zjN5ZVJ7uJSHiRnyBrnFgqXSQbYdR3nJDh0MiBsghdMcke8ppkAIWqTY6N7dstIbr53VSmlN5jjUOPAVO\/addkMaGon9TeJQI4Tv6gQUMyQ8TEMYiW5p\/jqLRw\/SV6d7zZJCszM1icdVJzNhY2YKZOi3YUnKlUlFctUx0EmbUND4kJ3ax2P3CoJTwshkjAMjOzWIUqQhGzYitsupYl2TeLH4pDjk1dHY6oyMeM1GlypkFch4SDoc2ezv74Rtdeox4YpJ2eDo9RZSbjkVFCbqO2YcUbHuVKHVyEmbq71l+5FmjqsJEEBzCyLIEMgjzjO+b\/qj+5oU3vhwvGZNdswsxxNCd0xAljoHeg5lerIoT3kuK2bS2rQiw9oxavz6\/sfnvVlr39P4ZE5OnWE3u6RknAc1geQDuerm6hViCRvtCfPnFh54TzLMCU0QqUsahMSrchALhEUBJHw9InQ6cnORggR1fdEoedKgJhUrUFebAfCOk9JscSchy3Z0NAsXTBEJ5N7zlmp6LIlXjPM0BcFJlM5VQIoMPENRyQ24GzGPBAE4deqY\/t2u\/X6+pXrYS\/gGLOiBIWN\/XvDxeVwtUUgahKNjFFrjagSWyZo7jmEJhMxM6CYBbV71O\/T3n10t0cEXlkZf\/zsVjfaXG6yUpmRJdHI8SN7v\/FM5\/27qz97i6WM4b9K5fVb9VtyK+RW2HEdz2EHkVTEhb6WCWQxQ6BpNgKyz8mUqyogHBY+3CpVRsXI9Jd\/+eMPP70\/cBwF4YA8VhyG3\/2DN1\/5z69wgtKEUoRse8QgHjgkPLgVpz7+i3\/\/mRNPHowcxwGIadAb\/Md\/\/teXX3kDKmQZEEtG0pjhHGuNC6055KyYmRV5bmX3ropwKOiTlKQkSZmm8dbIHwJCMFwId+rph3Z\/6SkQ3frTny3+8GWwZGaSwebCunRFdcQfrPT4vWVx8hDPr\/AG0fgIdbYIiKviXgfjDYLbX+s6uwJnclwudxNhRRO4S5lGE4lEdVr32CoMN6FfgKUUvXbFD6SrXnnu9qG5+nJzcPvCbeyYpME6qxAyIkgiQaSYRKzEo+8d5yQGs0EhDGZ0CkcxCCrsmmTDrJkJE6qTnyizBYgrjYqZSDay9oDIaP5x+Sd0460xPbnjyNz6+\/Pda7eVVLGUCxPA9UOzg6Xlwcqm1vCl5hZN76Nuk1jFNmD6LHc9wEmALxRTbKTD61s4NceXFsDR7kl3bb7ZaQUaXKgt2sEYfeT0yJljIycOjD14kFgS2Ca5ctyFcPQ2ESSEckXkCO\/QjvDqbXPolCsPc+rMKB3hEDiWvU5KQXjk+Ow1UB0b3bXr4Y8c2n9oIhGogAt2iT\/8ydNvvXwnCPsc9mNAgtET4jjB1sZvVVEdnZybOnh4Z2plFoZyZHqGKmMctkm4UIEeabBVgWR1jtlB5xSMmnxexRyO1w\/\/0ke7vTAKQ1JMUhl2jHFTQp9CTizFLch1\/L0zTr0Wsaof3YsfuRxFpCIK+73VTccR1dHq5mKLllZpR939+Nnor9+kqUnaWE5yGMWhJL9KJJhVb2HVO3dC\/ngtFoaLg5WWk3LIrZJbJWYKO9qUm1hROKBooAXBSPhwPLde3\/3h48227K+svnF78fmlbuXAjmBjUa0ukpLYMUtBjzYWKOhy0k0wHLZNYf48DpTYZE3kZDLgptIAjKJSVdIRi9s5bJ+Fw+S6zUMztoNn4Wn2AyDiBhMEMblVb+zoAdnuLbx1Jep2OTUL0Dvw+OFgfT1YWo2julIEQZ1NGt1JrVVipvoYEzO55FeZWrHbnu6h+R6vrdL8XX7yURyYdu+t798\/sfD+hookKZWpawux8dJ7RBjcW2tduh0LAXJKX4r7v5xaBepPVGm49caRX3\/aQ4kMpcnz42yCX0TGGA2qbGYt4ozXq1N1fN\/xucnZEUXkkD54iQkKeOjszOGHjlx6YQ2DLZYBdPs+ZV2lBaFwyatRdYRcL6GZapAYtJkHCZ90cojEVpGKQJxS3GT2\/gFEG+2r\/+7H7bUWD7oUasErm7jDRlyFQ44Pv77zyQdnv\/JkNIg2Xr5EGiGoiAj9Zi9SauTQXmwS9Tp8bR5TR0Y\/\/1j7J29wFCXaqg5HgsdHAOZwIFf6TnjQOXxM3pqnaEDRgGNhBEVKUdSjsBsPk9IBQ9w0JmIWQjTmdlf37Vm\/eIP9GsmoeeUuM2RviZwBBT2K+txZhevQyCRVZrG+wIMukUmbEta8Mb1ayPCpyJ3PSZbskgmnQEGT2ZjYMsyhnykSY7OZYLjkasiL45FbI69Ojs\/CISKQQhSM7p9yRuq9u6v9pRVSUaLuGtMHxo4fDpqtYHEl\/kRRQKRIONRZp137qeOQEDh0mPbvx7XLFEVEnNweQXBpZoYWF4hdunyNn\/mYMzo6Otm4un6XErhwKsXfv3174fZtYsl6RKm0zZAyRPuypiULQY5Lfp8GAxGEbmYNXTKNZbNjxjkmTO78Sl\/FYeGRW0Wl4Y+OP\/mxw9Wqow1BdRWhw3JtzHvosT2X3xpT3ZF4+ZLK2rz6XWlnQscjr+oIR6dQmnYEokSVxyE4SUqClDNhrKe0hCEUPRmYiEhAOJKD9a1gdZXDPmnlyBTnlR6rKQNKu9M5lcXvr2+9c4Gl6i2ssiZnkmAg7EeDldbOSe\/65hYHTQq7tDiy47\/+\/GBxdbC2RF1FxPA8JvBoheoeNUNiFTUj\/8h+eeu2thOGCo3boEyQEggsHMAlxyFmr17dcexwwM76W5eIeOLsqebl97nTJxVxl\/zHTgT37nEQkgw4GFBHoT5KI+NiYid129xcixtB4By\/YaiNGkxmG4hYe77CHB6z4QplkAAKOBCgjCBhWucKbTHJbg3VMartQHWMhGAV+VXRmKlzt7l54RoPAo7nsA4JQawAqh\/eF7U7\/TsLWf6mr6liCpnWF6gxTmHkHT\/kfOhMsLFBHJAQsVsKCTQa3Nykfpeq49Tt4+qdyt\/9RHW63mn2mKMEzhbTcJiDWPAvEVnilL6UdZxFUqYKIkXS1Yc9MvSrrYPAFlCGOaMOsXUwGoP1NHbpM6syPrVv9qGz007qW5tcb8UcER15YKq6Y7rb2aCoT2pAKgQUGx0vxGrZbjreSAwRkxaCyLpiyfeQsHHiEIjcYIILzK3UW0pFHA0o6mfikQYehTNVAOi7yXLAodO53iQSRAylGKSHFhxx505zdm7UoTDsNilsR+8Nlr8zrRyHZo9Tp01bdynoUNDhKKB6jTbaREq9fZ4e3C9GPNmN4rOYDTmDrF5OZGmFA+GMzu6qT+\/sLG+0VprkOI0HjrSv3wzXVjRCgImwsemO1cNuMzm4mTtN6jTJr2B8CpUaBX1uabadLSGJAqM29TlMIIf6cHONRZDodqbCRHFhrdLfyMOxUUa8SHOhxDETXo1qE1Mnjh37\/CO9gbr96g14aF28HCwucWToncTkVnj7dslBOJi\/yymsSW+bNDEKApraQRsb0bvvy1bAmx0xOUF+nQZdYgWStHMHLd5L5A99Wu\/X2332R9utAcf60Nq9nY1qh2NpXau6S5E+EhBMikifFExwdHgpWDoYhAkmG+ZFScfYYLWkMZDASeOevCrq40dO7p0Yr4hUbTpJJnUtMndg7OiZA++srdCgxVpwkSVSY3btIB9P6kUqg5P5oIgkH6MUE5d1BMCw51lpuQP7eKF0UoFEcoY4gg4+KYaBDBv5RHw2TghjQztdDwkSYJZKqtU7zQdP7haQpEKSgWoG3b982Xn6NOoeyzHqNbm7QTLERpsadRaCVETBYHDhinP4EFbXOAZ8MnITosSfGHDcamV8357\/H2P\/HSRZkp13oue4XxEqtc6sLK2rq7Xu6elR6JnBDDAASJAAl1wsCWLJJddoNFuzR67xj\/fM+N4aV3C5giRIglyAAAkSA4BDAKMwWrWWpasyq1LrzMgMfZW7n\/eH+1URUQ2O1bR1V1WqiOvux8\/5vt\/HS+X9u6sijADJGStLvxNsbYKU8YFpiZVtd3JEbEWkLyk6\/BwRQk\/trSG3cGyGV05Qq6E6TYh804PtmSgkySlag2+US6RPwpTawIHZgNzcy0jGvOcEEtSTY4DYJyIX42R5tEyr3Smx4ujVLz518dUrIQDa7rX\/8KZsRVpyksKnkQGz+PwcOba\/cD8WVTFDDUXMIeVqOzAwopaX4KDOyw6fHhNSAnKAEEpFEgIiBXYBeAHLZXZ2lt\/dhKvloOWZnZ4x1LpZ5IhIpEAGeqqMOSd+wihJfk6m6zdAjpyxNPa9q9ygPnimnC4wA+czQ0KOqJPDHHBK7uDwM0\/POjaT5uYBrbZyLHBc1EOfSom\/+OLcnbfvi\/YB+A4wKzbLxi9aIlqiDNUw5qbFTKJUp4r9GX1d4sQ8HTm+AbPkjsIYKE5MI0J1N4ZMOx67obuU9jCRkqktECnR2WuUyhbHuGyxXGi31Nv3+BPn5bVVijxETm4J9g6wPJDEB5DHuevgzES0sQWoA72Td42MDBA5Y1ZpbHjg5PHm6mZ7aUtf2O2CPXRmvvr2NRBhSschks0mmxlGRiRiyLKuyPTZJgXtbRC3sDSAUyepsQ+dhgGUIWbjdykVc6h4QAgx3sKUJRZyF+wicBsISEmSIcowlUFkMEGUGWebw51zYExLjdEqYKHCKiPkVpRQFPgkApKR54cCwCaQAxV4\/jy7EcJylfT+wmygCEjxuSkaGhN37hmBWKx4yshj4x\/Db8OxWVAMgAHjaPP4tOQ0Mgn7u8AdsBwcH8OLJ9TqJlejTJwJ215SrZFloe0WJ8YJ0N8\/pLAFyPUPm3QReqZmDLgDvEBWARhX8S26K3EuTfH6M2g7pneYqEMJOXAbeAGd0vGTY489MqL17ApAAvz4\/fpQmX3sySF9oDGAC+eHhibHq7VtsFyIbMAIUKX1cx5kQUmGSlwpmhobkqUKMbiTMnLkDI0ytf5myy1CBIsxsFzkjpFhJRZNosTAmjV7xPdjhqZoVKQxdqbwVe1WR3HkTiyscSvgHdKhhI0NdmxANqvk20BStQlHbNRCIg3tvrtcODUjtvdI6nhICboZa8oNsBxr8vI5ANy7uRD5gdGXcxw5MdO6dVcFXqbJDKAIBImgY89PB\/dXDeU6xlvFZSWCDFXzENo1LJTZ1DyFIdX2QURamp6mbWckfqBkkn5lxeEKFtlFa2h87rMv8oK7+e13woN9iloQgQHg6U0OGVgOK1SgWAFug5AUeSbDRH\/nUpAiajVUq55Oh7hDEm985fUmkdjubFV9qNfo6JCVh6BUwkIRIh8O96xzJ1UQyXsLsX6f5fWlia1Gb8cKtrdh6iTUQnKLUCiZH3NwBLlDioNls9lpnJ9VC1sgyZ4fQqlUGBm+DzK03NnPPD\/3088JRWv\/+bXae7dBBZgjFJnVSFnoLbPBKYJbZq4jCSJjwoDeUEgEoj6O23Q6H2t5WbZMAu6AXUS3fOHSpF22YpQ8+L66cfOgVGLPPTZgc\/PSTIy5jz018\/3VZbILENogLdDB1Dm0GGnZWD5qOr7l5uHo0O9Mz\/NNKdsBSJSjETI+MMg7IYQeSGHoMil3h3paOubr2sNDAxdPtVY2vOUNgmRWqUQYKACr4CB3idnAGIgQyBe3F6znHmXzc7QUUacBjbZlTYa8AMAhkkBKeUGkAOfmaH0dWOwdMSUoVsYGR4\/P1DZ2mntVfeMDAmSqMj1DSnqHtTSkwBz\/CkgGq+vs5HFkFskMyzw7KNU\/kVTUaUi\/jYUyDExAoQz1PfTbhGRuGRBPOJUAwJhgpMtRM1ayhp+8MvfXvuTalqqMrX7rbexUzWuq2WFKkJAoJUhJjSMQkU53IB1YpdXGmMUZADJO3AbmEEL7oHHvrQVxc51kyEZdNjqo1neo2QLWZCWHP3oFnrgiv\/06DA9Dsw1SACpABkog40aThdlBJSMvBIugiMA5lEvgVkAEMDJGOwdgFfHkLNmOurMMvIiOa1uopJSRTCTFaLsDj56FkWFgOPMLL08\/d45r1iVkQihVbJNIdH+IknFlWwqZc2pSLG0YdT88xHbSB\/+BGTV9ehtH08RywCkVR0auPD4h0cTrcoD19fbyg8NyhVdrczPjLtM1nM2ef2H69e8Mec0ScBdYEMujKbOFxcruVLqIeZ4b9gZt5ltwlFV+QA6bCgCoAMKh0om\/+EroRyAilDrdMUPbyQaNxZYFBQDI7MkR+8xs9cP7G\/\/k31PQNk0ckiQFB3LLZbBLiECtvRiuBbSwaD\/3QtgOYKMDxOxCKVKSkINTgaAJMhIrG3j2JGy7GTEd5647fOGkDbi7sOI36iZrABGArFKRD5UOby3EiZQpMNZM6HxFocBSiVrNDOuD8mQ8ikWaEvw2+D6UBrE0AANDEATk+WCXkHEkoUIfhG\/KUlSQ4Y4SEhDjgjGGrHxisjIz7N3dEYc1kBGowNCOdedQ6\/cTgaWpIpKYiYSzwuLihVCGrITkt6i5BzJS9YhNTbFT82r7gPb2yLGU56l\/8x9IKRwcxNFxUGMQhSgFNWsQeqQVRmn4Xjz6392BmVkKQhgoQWEQhytkM2CIp+aAO7S6DbwABQvAdYouECgzoCcAIiFqt1ftkzORUAdfe7t9cwkpSoJZKEEIphG2hptCAGA7vFi6MPAxK4ORpx5CaFY7jD0TVMoIOOLBugN2EYuDlx6ZO3duWF\/wGQAC3VloeS0\/9OTmRuvYmKsVuQpgdn5g6vjU6v428RpwB0hpj2Ea1QCApmqmnHQkIY1h18ghxjWlB18mXhlTp32y2zLGWMvb+Np7ncMWiQCiEESYCbHJwqRSeJTuGznjQ86JCW9tl0Iv\/TskSUkH0SkNQLGtl5+BbRPI\/RpfW7auXIj2d8nvMMbZQEUeHQBIsF2QgtptaLfx2HHarZKKQAl3bKAwMxm2\/KPlTdKXf610AUQE9+Rce31LRpFmN+czm3QHnFMnZKeOq5u3iTDJX0HoxwpO3Gd+h8IAnQKMTOFIwXKLx195vDQ7vvon32\/cvKGDg\/SObJkXS0lSUf39W1v\/4Vv2YFluVMslt\/zkFW91w68ehY0WiZBkgDIkJeJiR2UQYVomK5NJfgwCUKCkNmVZg9xQIpUCBLWzA80mv3CWJoZgwJFvvw1+B5hF+7tAEpBhaRjHpvnwhGodqnYdIo+0GgOMvAsYB1+ARKgMkuViqYSTk7S6jmfmQSEtbQAAoIlTtwtFi9DsILokiLy9b73ZvL+poshfWiEZgJLxVEZlhsuQ9o0Rte8GuG2VysrzeJe2Idd76MvryohF00gTrWewwHLQKfPS0NUnZgoFSz+xEjHw1e17RyrwFMk33q0+fnnEso0KeWDAfuSJmfU7S7JTAuGZizEofd2ih2MoifpRTzDPZeziCGOeP5z2WZkrZLiz7+1XSQQgQpAhajQ9USYfPa+2AkaI\/jbANUVKICZzSxM7yRjykguVQWrsZ0g\/CEqJxWX37Glx7hzdfaAsh08Oy8YhSAEyBLsMUIRayK6cVz6i9IsTA3bFad68p7xAh64Z2iIQIBRPzquWFx4cZeJD8hJ8\/feOGjA5gZZFkSTdRIwT2zPWkHg2jpYZNTllKAwRFNEdGHz58alf+gxnTA5U7v1\/V6TwQZrnwYpx4hEITx7ubv72fyJm2eXK8Ol5b7cqg3ZpfHjq0TNHdx94ewdCGr2CKUgwE9mT1Ubmw+VBCYo8ijy130QRkDaro4RGoNbX2EvPwf0lVETcBeQISJGHaJHXkev3FRIwBKcAg+NsfJIaNWgcUSiAOHAXnCL4wK4eLxQH6NS8IsFOz8rdBu3upbxQUsAsi9vM9Ai0FSgCJZWS7Tt3gRQIHRMrKeeRpywhgvSkXgczAepQeyKl8WNISN1gEMqP5DF7nULAxPxuIqW0baIwMDwzcfHKmALggIQkAT5caCwt7lCngYzfW6jv7PszsyXUXxXh5ZdnX\/\/O2FFzn4KWAe8CmOkfsEwLKHdTxHzKLFKaU5Gnm2J69GnoI3b1loAMfxVAhhB2dOQ4xRQJ6hOwEU849L2UYrMdKQQLuAXcAVaIbEs9ew7ad+FoBVRISr8kAACqEwavvcu\/8Dm5u6faPhuugF0AxkDnnzoVYoOF8eGRv\/6r7e\/d7vzwg87KCgUBKD9efhohS7xSoIFB\/\/Z9REz82VkwZ0o1lEoe1KFShnoEaBtXJ1KOAKq36Vinhwi85LDRAX72ohoalpw1251y0e2s75NSGUw4WfESkqhCiBTJABiPonbt1tHwibmA7PriprdzWB4pjDxyOvT86uKS6Hjx9TTj+knptZjRjjIDFFIRhL7a2clkjDMcKuNwRX7ta7w84Fy+FK3vqWYLwAIlySqA8AEEAQOF4HXA86HVgWIZBkaYxWF4nCIETyIvnpsuP\/+ZcztPHHvnT2\/X3l+gZgjM0iQ1BA4Wh4KjCrbSLs+kVaAPDUM5MDIaTMKxYwQQJV4QRAROuv1IBMiR8RRR0aUTzeyiGfR\/Jikck5hFjcS1gDvgFLFQeeaZubnpUvJpmKJr72z51QPwmoBWY7\/2YKk5O1tKfLhTU8WT56aPNrfQq5Hwgcl41s7MMsVuSkVGSJ79tgl7FPqEXT6QbNgkGvuTkubBJYUaK6qH9eb17O4J5akZsVogawliNjCbR5LW9nHEgVNT4Pq0sQGCkgus2q\/jgyX29IXo7iIbHYTCEERtEKFmdaNtlS6eGLow1\/rTu2GHqDgGjENrFykEAGAO8AI4tnPpdHD7AUVhDlCSUO4x3\/tut\/HMBbx+nYhieaNpyWLmmWcWYqngnDrBLYdankAVLq2yiU5Q4kv\/8F\/ZZbt1b0UFHVQyiVewjJhVAUBCUGYALIq8o\/ve+JmTxWNj+2vbQXW\/bkFlamz8zHFLydbefn2\/FqOs0gCGPJkkpyYlbpFQhFy\/0nxkgM9NRgv3odORfkTo8DOnWaMpNnbBLoIQaLkgA9LZtxrHJwS0W9hBBYQBwMQczo3Pnpn54l94dHJq8PyxgY0Pdw\/Hp3BoCNo19OuIQHaZCmMwMCwdS4JCEwOaaboy28hxSKLSN2NFGaNApt7XC4mRid1jjDNmJGV5nhPm2tcZInb2NmiWB2rjErPAcsEp2wNDjz06adss6SAFHbGydEhBB4I2AVPN4vvX9p95etwtaBIPFlz+5LOzN959EDWLwDugBCmKufjpL8qqN\/tDKLGbBoeYS+9JrsTdKCJUQKaO0NcEAiRJWt6QYoiTmoDFBSlH5hC3gcAEEpu7InJuOYC4ukf3Vqi5i2UHz55FBrR9QPWaXjPy2rL1K18E31cKYGACfAfCNojQnR2DmZn6999vr+8H796lThXCFkgPCIgXkCFwl9yK+\/Fn5V5V+ZmpIOS2gvyupcD30A9pZAY8D6VPwgcZxc4I5OWSPTVOjClE6nSig1ZQa6kgRLfonD8Lqu2\/t0ydpnFjC5\/MPkVA+iTU4mwldUM2HvUy6av9xeX5cyenj43srmyIUNXWN+sky4PFsbmZoenpTsur7+6FHQ8AiGQsqMBUXIoxzNKyCBywinqzxKJjzU+K+6vk+QAMSKlGnZZW3ScuDf3si\/7ybudHN6jThE5gGj9EBvoAAEBsbAzHJ2GwzIcrlcnhgUpRVxnuxBhOdWh3HRo1tb8NioM7BCWB5SiYLQoYA6bbSByYhQBgO5X5eeB2a2OHAkuberKuiJwaU8N\/uA2WHqhyxpAxZuC81EONzV0qMVOtm8tDDKHQ69ACywW3Mj49duzEgEqInIj3Vtt7ey2SAoQAAIq8uwtHGzv+6ZNlFle+Tz458c35yc3DHQpbJiYxJwmI3xXEFG2UX269VP2YcNh1EczMHMEAfxkz2dfmp0AGKEhlX8lsEcziyoIDs+yh4dLMZKfaCKuHIGPEMyAiRAyEkuB7EETUagMRjA+w6REaKigvgGYIkYL3F9wXL8uthtwmaBYwPHKmBhgo\/9YdFVK4ugWWA8KHqKNJUCbiLvL4UAGLVrSxA3YZuGvG4CIyrHdSJHxQgrIDVGZB0yufuRAdHIZH++jXmQV8sMwstIoFkiQjFW5uURABkR75om3b8+MIneCD2xCGoAQqSSqKecc6Qg+s+DWS5oqBSFqegoyIZKDWbi8cv3hm7uz89tJqFAoi1aq12o0Htm0Pz03NXz7v1WrNo2a7VpNCUup1jDEnWglQGQBC4DaoCEsl59yJ8O4itT2DUSEFIqAoAsTRVx9vr9X8W+vSa6LtEBICMcdihQIrFsG1sVyU41OqrdTOodptr9TEG2fHT54cbJWLW0sHdHcdo0O0XTUyDsQBi8RsUFHQ8SRnzHFNoihYwPj4s49c\/NXPWZa1+OXX99+7QyKIu3AGwYbZFClE4By5RdwFu2gVXct1HpYgmAQQYEbGFhcuSMAy7Rn9KtlguVgcePzp+cqwK+MVK6X64Rt7HS8wVkYAAui02otLjXMnyya2jaAyZJ+9NLV5bxC8GggfSI9DWa72w7xSpQtmnxluYgYA0MNoTtnymM214dweHnRCCSIEITEjkc\/HAyZdLk7cYrZ99pc\/PfnMuf2ba3f+76+IhkwXIYOQYejYpiUDBErSXk1uB2ApPD4Hx4+hh7Rbnx9wLn3uSn165PrNLY8Fwd0HYm0NZABE0PBxfJo0PlivIo2WddCaGgv+6OsURTHoTQAioIXcAWcA3ALqhmJMUSG7iG5l4ur5p\/7Wzze2Dq\/99rf8Rp0XbWrVxepy0GmTUnE8uH5hFGPcOTMHNguu3SQVYZJqrqSBoMb9Pysj9U87skaiiaRHZWt3FmfPnjh5+czKjbuRBABGBGEQ7i+tVVc3ysODxy6eCdr+\/uZOp9GWUaSn4bGA2wLLZTMzgBahhSXOH7kQ3rir9CkHhJyDW6TSAIzOhku7h7\/9nXCvWbh0MhofEOsrrgrcyQkYHfIXVuVRXR01KJQEW8As4BxLFTg9+4Pfexc6wvqpi+7ZUX6\/JO4sQ+sAkKFbhHIJBgeAKGQcbJsXisg4ISIydArjH3sMxkeI4alf\/tjsS+eVEqQMe8a0CwzXxXwEY4wYSkTijFmscnK8urhCmRSImBhI0Gs4iOs5ivVkZnSHZkaPTqk0PPL8s1OcM2Wsd+Q1xNq2D66D5Qo4BT0dUZZ9b9X\/aUFoo7ngM\/boE1Ovf3c4bO1D2AaMAGQm6SH+whniPebpi5SMqYi6dNf5GLuU\/BwnTZEiwuHShb\/y6bYXkpCcFIOYeZG\/ZMbHPwJDiUxaTunkbORYpYvHi9OTzVYLSCAiEDKLK2ZFM9M0tg0cIHRNmx0cYAhNBULAxGjlifOvXp66enoILw2O\/WjwP\/3Gm7IF4I5A2AIZQNgAEOA60O4A8nhyw50rF8TeLoUdoz5TKibuCZBEXgQeASUeIA4I6BSs42fnvvgJZ25seHyoMjXWvrckWlWIPJBBGgWHDIAD48zm7rkTikR4fUEfsETS7H9GRaQSkLmVVhppxgAZuaZ+KVEpUpuLy+Mzk+eeuHr\/xt0wMoFhRCCFbBwc3nnt0C2XisMjx5883dyvNnf3g0BSUmU5JWv+uNhpssEh+8xkuLBOAQAvAip0CjQ0DmGASrLaDlp2\/a3beP6UOjwCGeLJeXH7XnRnTYWSRKilbYAckECFoLAwO0OH+\/56HewCfC8ILhxzHpuVG6tkcWjWKQgg2IdmGwZGhB8BAnedGFtGIKW3vkf+mRBg+5vv7v3wGigBUmYi5ql7\/KCho8wCxqyCM\/vfvMJ6oFjY\/ehl\/F8p6Trm+Wo3PbPAKkBhYPbExNRMGZPWFeBRA4aGh93ToIIAlAJEtC1WLIVQ2DkUM5M2xZroK5eHTl2cXKhuQuCCDI1tCVN9QMYVkmjX0n0h4Sn29ytlUV5IuaaObpTUO\/e\/\/EbzoEZhB2VkrEyU5eEmhGdm7sPM5qWBs3\/t1dLZGW\/7MDysJ6AtVKHroBMIcXMHOgSBwNAjikBJ4Ax4mawyWgXyEJfroyVL6jZfESH0QAQQtsFvQtQBGdDOGhQroAiQA2cA6B6bAD8Sm1VjiNE3GYZJ4Ju51ur2WcnBQpGfPUPMoVp74\/u3KrOD7dX92of3VKcBwkfpA6kMEIaQMVYoDjxyztvaCje2SYbGZ6xl7hDnx2ayyq3Y+gQpWR2TxMoEREmk1MH2Lklx9rGLD27eDz2fdHpujM0NWp2gE7YO6+WRwdETx4ojozsrO52GT26Zl4cLE5NBnZynHmvdewC+wMoQjk5Q2AbvyB4Ca2Sa+1J0hOx05MEubW9REEEU4kCZj01DyYKNVVARgIwbfQqUtKbGZOiHy2vAXXDKsE1ytAx7R9bLl6KvvQdD09DYh8gDkqAo6kgAdF3bqCKUoAg2vvZG\/d46SdFcWJGdts6lMD9UL9sCGTCGlgvcIW5bBSdq+2D0yXlVWu4OlA\/FQswotpNiwQa7yMtDjzwxWyhberCg47bn5+y\/96tzUs0KMtNlC9FCBIaWg8konxBKZfvqE9OL7w8qvwGRj9rZHk\/au+AKsTsUCT8i4KTLqJxGxUAXRQeASeXtVTs7u2ZEEfsJ87NIzAF1kKNduvfrf1ScGfW298PDAwOhRAUqKlTsUCjZ6ECkwOtQUAcZAulrp4BAkBdYI5Fz7OTijj8+Ujg46Lz9wY4zU\/KrIWmVDONAFvgeDI7EZ6DNSwU+NOTfXdJCfAO51RG\/yWXYYlgpF06fUIyJo5pqedGdRQoV8OK+Ktb\/3m1ZPxCNGggfTBMh2WwZMOQFt\/ToeX9lNdje1Qo1TGS0qWYo63JO74Rdb1R2WKQQDZuyulcVUp26eHr9\/lqn2TJkpKSHoUD4Xm0nqO8dVqY7zvi0e3LIGhh64qcenXr0xOKN\/Wvfvk9z56yL58BrYuipo7ZStqx15PYhtTpECKSAImPPRaSGEJ0ARydh9hjsbUCnAdwBboGSbKACIyPR4hpEEiwBoKChIJwQu002UGCPn1dv30O3SCC0WzdQFil0S7Y2baCSBFLUD4\/ePwSN65ORviundt7sUsLYoUcSSe8FriSSZjKOfSf0iH1S6DFn5OXJcGJoYuS5ZyZyvmggsNC2GAAmjl2Ghtkg8\/59hXDlkYlvjo21OjUIWqRC1EoZzM67MrAAhr1xWKZxRH0so2nEmsnGyfyBUkoRkACpWyCB8fjnh6WZIDHjYyIlvFW\/s7qSEOkpZhyXx8v7R75IHvEsOwcIQRZPjbHhofrq7n\/+T8H7x0erH64erG6yASyfGuMNq7m8oSIGzAKSUCjDwCj4Hjq2c+VisLCkhAIE4Lae9ZkrXLHozs0oi5NSKgjD7V1RrVEQmSsVAjCkdi042ADlgwhQPzPZ\/YVxPjBQuXiyvfgg2j8AJVBvK2Z8kFt4lHFWWBmzDuZwKNkMbq1jUkgg69UjIDV\/Zn7jwWq7Xov90\/onkaRMoGRrfx\/qHh+eOvvZM1d\/6hGrYBdKxZXVtljfpO0HcmWZDquk9MxUAYmMFy52OzL9R5L21tB2cGIWRyeo44PlsqjpnDsV3FuiSAERyEgLKWhtDafm1Hv3rVefpLUSrazgwCBwm1QUBQIjMTDo6IY76fsxhJg0Qo1vSyYhu4bdBgiEwDDhNZBkYClAzhiPLS1djY5sPkwuSCmj4Qbjo+c2WC46pdNnxqcmCiy2ozFAhqCSyVkuXCmRPSZ5X8QRT85XLj5+7L39Heq4IAMAhZjWo3HjmhAyQW5d33wak9JLv39IphYSIUVKkQnojfkgaV+UEvhCEtgBxIARSQIZ6tQ0Yw9Ajb10RudHDlZqyrEAwQAZFBIwYA4fGbanx0iF7ev34fgx2Wkthe1wcZn8htprdFQ4eGJq8NLp4Kjpb+0RWuAO4fwIba45xybEQVu2BXBbo6iQMxybYY7NChYjIIBofVe1WrFHMubWadJ0eRD2lkF4QAJ0+8DEeGl5JrNHhgqnj7fv3Bf1GiqRaDlS\/W6a5UqZeHSyzG9l0pBTkmkuKFiB3pCB6od1BHby3Mn1+w8aR01KS39NWAIkAYIBC6TXObi32d5rlqeHGrvNaGMPl7eirQPyJDAXmDabKJCmNM83xNFwU5AgIthZg5mT9qdesZ89Q2\/cCN\/4UHnSsJn1nVgGtLHJJsZVx5M\/vMafPCmqO9Sq49QsFCsiCHwvLA+5SdaFJkYTqYyuWudOKMrc4vL4iXjAAISk9IgiAxfpDhxAxK5k7LyW2yAJwSny0uDVx6YLDlPGuYuIYCEggUxN7phqechMy1WcJIFExQJ\/7pnZD18fFM0CCJ9I5JBSqRRNb8AqzZROrLnJdkGpkBSSGMU+kcrG7yKBQIXGysh47D\/NLvJkZceQddN\/SMRi2ugAhNwqlkbmx5a\/vaLCAFwbnCKENjCJHO1jk3xiLFhYVe0OnjhFWzv8zATtrFN9C2QIIlSk6vfXmMVKp+cHL53yGyIKWfHkCTYyShW7\/fZ1sB0sMbCKaHOsVJBbamNLbjUhCglUAm4yMdugSEWADJ0iFStQ30MwYiBzh2PmnlIcH3FnJxvXb6tOh0iPnU3WbLL2kKivxNjKrMgepmieQ53gZYmgVq1GoX\/i0tmNheVGrUHaQWM+lSJCJAkyoqh9uLL2lf\/pD0cvnTjaPGrc3S7ODbtTp737S\/JAqSAEpUCKlGmffh8MGAAxje5Dqwh2kY6aVLLgsTmxsatuVDAQ1I6fL0NqQPLaOF1Wq3v0dtu+fEpeW1KtEAeLcmBkpxaWpoeBW8llwFSeCX3YVA4yBWZ2LUKmKUyO6ZjpEZn+wO5Hs7syTfUzkGN\/oO1CYWDi+NTlR8Zj7icqgHZb1PY9UipSWoFJLAMOUiYMkE9PF12bMSQAlAAnzgwOToweHu5C5KEEo3TNnkd5ll6\/aC\/q0tRgjiOG1C9FymaI3DI8Ie2XVz2HodldGSS9MaVfbcJUBM+QsUK5UB4qdA4adLgPbhGYC7xgVVznzIw4OPI\/vE1SQWWIjo6g3bGiQX95CbwakNEwE4CU0Lz3wBoaL129Mnpi\/uoXrvKC\/f6\/+XZnZAiGBwBDWHtAhzW1uaV9M\/FQSqXOEX08GHARUXkAazukAsoh7RgiQ8YrsxOFqfHDD+9ILYXRfPe8FjxpR6eE33gdWl2g83xuMqaN6cTFp7RjmLUbrQc3Fk5eOGltWUf7NdOhiYmDoG3BfkvRzs611u6dpcL5Y9H+Rri7zmxljVVKj57GMOrcWZJtD9KZiYqrHAkSTHIdEkQt4i4wR77\/oX9UU+\/dBr8JwxN44iTsbVO9joUSACcRqd0mu3ycHqzSTscaLDiPXmjfO6RqQ1F5c827cHHcKbu+rw89A3IlbhempwZPzx7dXpVRJiwt600y+CkdyeSCXWAFlxBENpIJenSSWW8sdXVKWYLAwkLliafmp6dLCpIMKPrR6zt\/9MeLFHgQBiT0JhXDgxgnboFTcIaH\/vIvX3zxiTEjvSMYGneuPjP7o9V1CppAEmOPbgYEj+kuQaq7CZwJw+whN2YlNfnFq5RtWVZliJd8iBwgBM3qT52WWdURAjBeLNgTg97KmvI6qET6FZEDs8rDBRcgaAVIRCChVCqcPM258O8+kLUjIAVuGewiVLeQM\/Q6qnoIFKVjWSPKsWS707y2dPK5y+MnRiNJxz92Zf+tO7RwBzo1Mys3qRhE2VAgw\/sSKSWPMbQdONxEpcxpqVUWjCOzRi+cQMet3liQgYemTE0iTJLCgjJVJSU\/r\/6\/lVlkGc4o5RFbmfwKQGVmYQqCTmflzvKJi2csy93f2VMqBkLqr6EECR9IgQwpKkt\/mI0V5eae8lXYbEbr2874gHNsHPlUtLMnqkdEytx90iDYTMyRinB0GKSU33sNiyUSANtb0Gji8CCeOe389DNwbS34xg+h1VZ7VShw8KW3UnWem+KPnJR3dqDdPFiqPv3iVHmk5B8x0ysnJORoOce+9PHpzz9bu7YUeL7SgXvZFBdM5CegU3u4YzOLuWenopWtxE+Yg7NSt3kindJhirsnbqFTsMtDjzwywZnp\/Sugji+vf7DV3tmkVh0iH6SAbAYbMuAWuGWvOfnOW0MvXh1Bm2l7ScFmLz838\/a3hrzOIckwXv\/6MM1cNTQ\/UqsUIfP8Ze+GCZ+JEuYM9iEeAihSNFQ89Zc+VW8FIopQSEaEipKZWOZcRVKIhNbYAJ+f3Pxnv9d878P4mGBGy8CtgYmhSEDHk8Q4mxjAkzPi3q3g\/gMKOsZVaI\/CwSaQAi5l4MUkZ+3HVaBhaoSgBDjWwYF\/sFIVnO0uH1EgQFLcUY77t6TSmQ1iouNP5Yaj0xAFyTkZk4E4s+yh86eI1NHNeyrUK1Bh0pHCLG+PsqRWzO6IYOC\/1K2dSyCVmLNVZ6HAusANfG\/p9uK5K2dtG7fWdhRxyEZeJzGdBGJtg81Nw7rUjV0KRbBWA1LWyFBpboqPD0bNjndQV5EytzUlEYCY8RBiuYQT42ppGcKQ2ocwOIauRY19ajU4oTM5EJ6YsidGxWGN6m04MQsLG8B4uLhvPX+Vd5TaaTT3G4pBZWr4cHWHGKcYLkFS7vz4Wqdab95aFX6Q2uH1Rs4yGCuM47Kdgu1Yp37pOSup3rAnuUqTVZCynVNKc8Bi6KBTmjk+Nn9qSG90epEs3a8v3Vyj+gG0DkGzC7KnllbYuBUAXFscqdfPDo0XAFEf7qfmK9PHxlaq2xS2EzeD0opYNHxMJCCl4h6moswnR+jJH8kTn7I\/LcUoDdH0N799o1FtUeBR4KEIgCRBPpKFFBAQcATkg0V7asx\/sBonDqB+cTRnfmRutOHa4WPHrbESk75Y2pRrOxB6oCeQAyMQtEF4wC1WdIXXiPdBSkJ5AZA4A86tydLejYUf\/fh9dIAcZ+DMZOvmvgq0u4YylXB8czM9gkSBgQAMLJt2V2LKvWGRWI49cvZYJML6whJpvVuSMgTdQwgTyYp9IlaTzHrM1BoIvaFMaU2fmeXqolmJKISFGwunL5+emZ\/Z3thTxNDcXA0QB5RAEajqEU6Po21R5IEKYlsXieph8\/CIu87g+dPu9FTnoC4O66LdSjQlpBTanJ87LVe2wGubcrG6RuPHoFAEz5O7u53\/7fcpVNDu4PgkyA7MT8HmEUkOoZIfLvPHT0Iz8JpeqyVGj42tvW8bnrfJNwubdxZbd+7Hp4HKSiQzViYExtBywHKBu1GxIL2A5TwBRuGftMJStnkPmdSsOGYxp\/jcC8eHxgoxjo8YwcL1be9gH9pH4NVABEASlaSUg8qAOwgEXqG6XV14UHtyfDqWacPQgH350vjq7SIgkgYoKInpQZgIkkWSq5NPremJg0XsDXQzzyhp4x9nkfQ297zdKgWdWKgp88ionDwAAOA2pH1UM5lAYtxyrJmz49Wiq37uKv3um+F3r4NtGY88SSwPEXLoHAFjQJzPTqmjA1ACuAWK4oQvIqcCtutUOLeVd\/uWkKCv+mxmqHx61rsfCE+fDSK\/2yjoMYhioUhBG\/U0AhEZB2Zx1xk5MyfbnfrSOimRUFEoxSBlMUUpV6B3TSV+M+qm3acknz4dsbjRpilpEpUQUbh0a7FQsudOz3PLAWbpcAhKmDa6img2rNkRJIlJWLxSIAUpIfzg6Obi0Y17IMLRJy+WTszaQ8PolMkqo1NwT82rzT1qtICEGSQQwf46qBArZegcyaUFOtynVkttrFKtAa2Afe4lNjQIQFQ9kNfu8MtTAri\/354\/Nc5sFywb4h4pKAkiJOFD5EHUgciDyAPRAeGB8ED4EHmk\/0X4FHkUdkj4JCMlpVIU2wpSqW\/WcUfdfl7KBcQClsqlq1cnESHuUaDwxeKNTfIa4DchbGPUgbBNUSf+3nwUAQifog75jeho9zvfvtv2BJnWGRDD55+bqVRcUARSao8fk4Ij6CgTw1SVIYjAcJBBkkGA5dcKYpZI2x0Vm6pBkQOCEhS1IWqAaIP0QWoGqWd+SR+l\/s8OiE486RbmPDJlAgPGK2ODM+cm1t86sA582mmAkNBpAAMQAXJGhUFoVGOfqsSxYepIMBm6BMjRKVNlGgDtAiscPx7cvAOtA\/Br4NfBq3WWV6P9\/YnLZ5xSRT\/8qY3SjJvS0E3U8PiZE9hpUNKtYdwqlUYfPd+p1o8erJMZL0tIQ1EhN5PKwPL7CiKSk\/AhUJQssy8L1jQ+TzTpmigBSUS0urg2e\/r4mStnl+48EBHFL4022UtSgrZ33cunBYl4X1SYouAUKKF85W1s+du79vCwOz\/nuKXIE7zoUKuu6prHmi2aCI62YXAcxybpaJ86DeQOSAntCO4u47njMDPCLU73V9T+gVpZxdMX92rw5PkJd2i447cNElfb7c1dLOnam1B4zGHq9d8SiEzn4zKGQIoyEUvGsUDZD8Os7lLvdxhTQkBFc+PW\/FgBIxkCKACb6N7N3ZV76+Q19OCb4oc1rUWJo\/ZbIYM6rH5g7axcOnVmnCEqhIBofr48P1u4vRKayr99KDttjARDFIQhkQgFBS2IOijDFIWspyx9\/PbZ\/m5sI8w\/KAx0anJkKEbZTiP1\/FN3PuJWVZI5p11d43Ojluts\/mDBizpQLGLBpaMq2A5wGybnYW\/T7CREiKDabVXvAOfgOFgcBMGI2RAKq1JxTp1s3b6nggCUAAjiqQPz96q1IBy+eKp+dzFo1AEpqWAN\/NKwK5CQgVuCKIDA1713RHQqxcHLZxsLy0H1ECg5A1V3MFr6w2I3\/rRnOVrdf4R9S5LkXk6GDJvSpLW6DQhQRmJraX325LELV84s3FyMROZuS4QkVKeDBwdO2Q2bUXcr0WDklEa9R0eNqCP4yGjlb\/xiQYjOH\/0gdIrKk7kgKv3It+uIFpueU7sbJAKwHACbmh5tVZUXQr3Bh8o4UFFNiUW2LtxXxivHjg8v7u0Qs4hZGaWocdkk5xmkTIccJJtYPCpEZJyhJrWm5r3MwAcpY3OKe42kQCGiAhlB5Fe3tv7ZP\/kOlQYFoIwCLvyDjcPO7gYEDYg6OpvS0IqSRYgKAEAYEFVrC3\/n\/\/jW8OwMc0sEpIIOdBo7D5Yp7IDwgHHRwT\/+j2++9voGFEqKUIYeefXl6\/chbIPwyVxmFPREfFNP8AhlEn2yMEVJClSApOLQDgSQGQlu1qAYEz10NHxCoNSkcG6NnRqrVzve1paqVXGQ4\/wEVbchjHD2HNT2QATx8SLR5lCvURQAt9hTz9LHPw5f\/gqsLznj45XPvFT\/0zeV34ll3xDn+jAg6R2GMuyMnj5W32DewSEYcLmJB0iDHgigOAD1KukJFmOlocrIufn9O4tBrQEquwIpAbr2DH3oITe7tAFm9d3yqOdjKLMM86epAUPrb0BGsLm0PntCnL1yevneahDoekPf+yUABI22e3IuvLGQExWbJzTVHxBjoCRHqX70\/uHSll0qFC+fitoNsbyqOn4a6a47RJ0GIOHoGB3sgkRwCmBZ6vYSDJRoZ0sUy9iOYHoWAmLnB2pD7uSZ0cV3UfPhdTCTIUAidFXzlEvzRgA08AVuAzJEYIxleUpJaAD2vPqY6fGTxlaoiMLOwerawUED3EEANNWvCCkKIGyDCOKzJUl6MfE8cTNQ6qH70vs34e4GOGUgBUEL\/DppKbMS+kF\/cHPhwf1tsIsABJEHYRuCDkRtkgEqkeTAIebGepiLPEDK5iwkkjQiJOJJ7gizwNI37biySDUAmKoUwGRy5fq9nDOLz56f3FmthfUaeA1qduDMLB6fp1oLuE1BmIlwJeYWMCTgHAtF8CLYrEIQ8sGBgScud4482WyYw9nwaUzqgd5jwnpYvRcNnDvNGWvvHWgzd\/e9zHFgdBJW7mqKwsDk6PCxid0bi2GzlXPWQ+bV6HPW4UMr0fjPrMxUOtE09cIMkihu7IfFQ3MkKkUIEmhzeWMe1dnLp5YXNzttLy62AUCJRrt4rsQKBen7SfMDuwLEkAGzLLcweGy8fv1a2AxDQGTEZ8adM8eV58ujtqq3THa0fhA6TYgCGBwCXwBn4Ldps8GfuiCLBeAOBQoOGsD2lQi2sTJ+cdpy7EhYIDkoDsickYo7MujtHlEuljDF4Zr2HWDsCylw1yHGVCaEnuJhokl\/RIQ+CgkwsS5KAgqUHgQAKqROzZxBmn8jQ6NlNVR5lbkJaKiNzognAoCQSAqIOsBtAAIRogxBhEl0LpAiGUJQNyFEui8qAhCeZu0YIlMK9U0jmLC3LMKuHZ2IJDLGiwNY9JAjKhUPTRPMDCBmpdvMKrgDZ4611vb8g0O9UyCzyXKH58ZGj4\/d\/L0bIAKIfJABLa3jxXNYHKT798EuQ9RMpYFTEzJkODhBIqJb1+DBAybDwcfPte8s+NtViAIEIi3fAdQMobSjgTzqePW7i7NXzjil4tH6rmliZf9XGYH6gd5th+amKlMjO9fvRp6v+R1IyevWter6eKbzlFZ4SDmazfQF6stEp353yjx+RBnAGsLa8vakYKcvnXpw877naSGYAgAVCbG+VRga6gSCEEhjtokom2YBjFv22JUzra2t8KgWQ4xRrKxLRDYyyM+fhXqLqjU4OiKlgFkIDPSOPD5O1S0II+AF7HjWsQmxH+qgeQVh9U9urrbPPHlipDg2LAKf0AIUwNnMn\/\/k5KefbL33QIRh7vwDnSCMyBAIJBERKsaY7ViOVTk\/U1vbybbUHlr5Z0+ChM2uhBkHyQhinL5pFKlEMyBNoZ5CwWNjLdNB2cYUgtIj8xmIDF7WbAagIpRJ7Re\/WYZ2JZJYYiLqm\/zaFcfcc+cBBRAOFCd+4cVSOwARolAcgWvNsdK6XIWAyJm5ZyssDJVGnruw8ZXX1v79Nw1IkttoF449ckIh27y9Q5pFTwAigiCA4TJwhCCKfaoAnLvnT3rX1ynwQUbAGQ\/rw+fmOyub\/u6B3sVICQCGzCJnEPwjEO0MyUIBCBni1u2VyScujRTKteU1pbO9kqStkXHY3UXbHZkddUcHdz64LUIf9fKLbzFZYWdXtUndCfJp17xrTVrdTN10xA\/ddCDsTsxGyn+gbmboF17B3vpWFIanr55fvH4v8INkWiLb\/ujJea9aIyBU6TqM9bucMRg+PR1UDzpbe\/qJjC+jDBDVYU29cw1KBX58Dk\/MycOWaobgBxA0odWgwMOJCTqoAnC1dug8dk7sHQICkMBR17+7tqzk1f\/mqamz0839GkQGeXB4bTnsyMYbdygKcltXon\/HmA2jJ+xuxSpXzo5WEIH6WXfjBIZ+dDPzWqm4AiJQEhiLoVhJFZeE6XUFbpn4W1KEuqmgFDCZFsx6DJ2Zkptc5OybqD+\/0j09hRSvwN6uTPf8s7dbjoQsaHoH3\/6gXfNAhBAFIMNkkm96roowEesBWhWntldtvHMbVGTYZ8xmdnH+ysz+yqHfbseGeoYTw7Sxjq7NZ4bkSgvsEiIHzrFUYkC0vwkCwSpwmw2fngsPqv52FbVVTUWglAZFgH8EMkJmAylKdjcEACUV7d24P37+xPil8wd3l5RSwC1gNo6OwMAg7u0Pnpzjttq9dltFIUihPxwzHe6eNHnqFxWaowvkT0eyEPrl0fftr+ccGKmQP1OyJAEgqHexo92DKIzOPH5x5eZip+0BASEL2hFUKs7AgF9vEKM0RwoR0ALGirPjilR9eV3LtTDWWJNpCUpQEhq+uN3GkXF85nkGIT5YUnsBRARK0d4ujk9DxJRyIreIw0WqtZFbcHDgjBb8VrR+e\/fiJ88uv78qQg9kQCJovnWt+daHwFjcmEg7CpgmN5q8ALRccFpWqRy1PUaQz2XCh3Wa09DMtIRXZlmhRGIZuJDCJM07N\/DN1rSZ6G3tNcmMADNzyqzwJ0MPI9MSxLxgEvq30jGbRNmdxoXIkblKRdXDYK9GUajLSFSyZziGJg4REEi1dN4BcmA2cAu5XRooTpybePubD5RSQAIQcGgYwgj2d4hz6+IJGCzKkBMiRJFlAW0cqlACs5DjyLm5qNlobVdJhtpBi8iIMVISVZCUGGTYdjYg0y5+UlJG0f7C2sCJuYlnHzu4viBZAawSTs3A5vLg2WMkZHVhUUVRolvCTOwk9UlAw36K3J5LSQZ4Z3X\/7d4e6UcCZBHzSqf0RVdavtM6rK3fXpg\/f3p3fa922NBVz9H9dWd0JGi2SLG0X4EckBcnRkrT49VrdykygslE\/Y+pttshtACRGk36\/vfQAhwdss8eZ3Yh2j6Q+1Wqd9jcSVAuVQU7PSuvrUKxYHGLFYvBTmv95vbLf\/Hq4MTgUadJJgBdJjGx6cjeaJcoB0dhUvu7KGJxLDv0psRRl84SUxkTYnaRqFhWozKdD8qz3qjnTTYeKTKdeiTCTAQzZlXAOZBh9pYRJ+lRbN3K32Cz8NiH7CuxBIQhOjpEVYZ6rIIyIiX7fUJm4hIyiWEm5oTzuUszkvH1vZDGRmCvDRRByaW1Va03iJY37JefpaqiB8ukQmtgiDoE9gAyGDk1RaHXXNkAKWKkAKNEvwpK9xo1dIeIkIRW\/JsAabSUhMbqrhBs4Pnngs2jytRkOFTBYTfa2u0sLVMUQRKb16fo6bl3ZHM8CD76f0l3lLp03h\/hIEvSDR6iq8mQukDpSVvrqL5+9\/70hbOS2c1qDQCDVlg4cQw3t0goMIcAAWPuQGno9NzBtbsqjBIZPiaZUowDc4DZBADSN2k7ACSY3I1ktWNNjrOpITZSVj5Thw04NkcB8VJJjYzzs9NciWBxT0Vqf78oXWfqwtTR2lYK54wbaAiZmF4zXNLnsE4QkhBHbZtWZbobImYxa8mEO7sK8m9XmsFJGQMwEfXCMrCr5U2JSz\/RGCZHLULOEkg5HnP85mnBfSwrw4c+LPkbIXbNbIwdyahqY11LP4Zy4sRSiMYUnLaymGUXC8++evFw8bC1tAcooVzAizNWvaEcLr0I3IIqDlNblqeH2geDFPlW0ZHSxsrEwHwZlHd0c1lpPwTjRpGnHaoIQCzRMkHmtQNAJEmEgDZym+xSu4FDbfbpv\/OluSszB9uNH\/3rH9S37xhot9aHxK1QTDxD2KVyR8wfhj2i20SplUhVycr3QjMlTB\/wQdda7Q9FyM6ZSOmkLuk1Wxt37o1duii57VVrSihu8eL0ZHvnIPlsls2HT83X7m8IX3TbargNaBO3NVE\/nhOydLClJMhA7OzAzjYWC+zCRWt+VB36MD02cWp6+Ox8q1jc\/t4dKNo4abeHKqu3D658+uzyG7eCkJPmICgTUkL6TCbSrztlPAWZ\/BbEmNaeycDJzhX1U571UeRU0WlKRy7oIU8Lzl4l0ni7eEWlhzBl57E9TnnKWOoxpaSlBsgupRX0Pdszmy7mJ35IRBERSZG+LywDZDN5jyxhjZNOJtXfhRkP2kPTI1Onx979rfeodQheA2QLOlWw0b1wSh4Oi04kOyJa3Bn41FR4+XT4Tscemwz3guFzg4y3Dt+9F2PdIQ0CMKwunUzIjfLTbK9opBqMmM3BsaBYgYFxHJksnZife\/yYO+BOFyxXz58MGS2zfrt12P3ACtizBKl3EEgxbS2lh2TmE4h9ClrMZfRgP98TplG0RlJD2mSjIGz7+7cWxq5esmze3D9q3l+vHJvu1CNSCpRCkONXTvpHR8FRI2k4oU4atV0CBiKIlx+k6HhkqbVZVwvMJsHlwpYqt\/nU2MTFuU99\/vzEaGF\/1\/va+lHj\/apaOZLr7fud6OrffnryzPR6s4VSmDkhKWSIrkuKSMpY35wxxaHh1QOzdVHIMpAIhFyuX9Yci1lRfbIUMRu7kivmMZe6TZnJuVZBYQaqmHnvMJ+mFH95zDEHM\/GUGb9ptjXalYiW87JgwixO\/CUIyISu\/ZDpfMsYmAD5kxCBceQWMltJAhJAANwC7qJlz1+Z6YTRxt018hogPRibpNXFSEZie9caGy6fnI12a0EAtQ9WrM8+U+4EoydnS4Ujjo2Nt1cIOTCVBC0hA+OEYczIfm2bOzZzCsgRSDCLsUKBDwzhUFkWi5EXRp0AIouCTmd772i3Oeaww5Xd+uoaRR6YxyNvC8xRKDB9m\/u1YjDzvufe7WREkdxeEPK2id6GD\/XmZBNkI4DTKjk26lOSLKRACRH41VuLI5fOYbHQOvCssWmrhpHnoQiGzk+HgV9fPyAdD8ot4CVCjjICKQEi3ZWOPfdoYkNIB2YS2ha4BbAYMAcHBuxjs2x6whkemRkqjBctBChVLD5UYPMzJEBJ6+DAOzzwLrx0YWthX0gZS1LY6FOXjn3xpaM7G1vffhuiMO5eJOlCQPo5swvMdmJpJXbdpikjuomPnu7hBaY5SZTuXJCTHGZL2h40dHIqUZyyRlk5WbLiTbWJveqN7LaQafHlskGxa\/dFyMtiTTwPWoxx17UKRbIYShH3tro2f2SOM\/Xp50qnZtf+4Cf+5iaA0nmMpZHhRz535e3X11oRQqEArAC7e6AIgBGwqBGKO+tW0bKmZ3Fo7Ayoz\/\/9z5U4f+OHGz\/+8o8kFgAD5ICOjYyIBCOBjmWNjvDJUas4iDKUnof1lmo0pJCkUASS2g21c6SEMgMgHTtZHm6PTXz7H399cMBqbGy31lch0DBlhTlMMnXfL9KgtG5\/JmZdNV0jjKQGzMj7Hzqmz3d++q1PyGjZkgCRVHlJBihMUgR+9d7K8JXzxdH50B0qPTLRXFgvjDhUcmpL98kaAAzBAYPWkoKQoWZUAyBjHJFx4BbjAwOFsUFrZAQcLkMhOn4QRFEkpQAACFe34MGmh+6dgbEhFZx++sS9e\/vt9xflQQM4xyKPhq33H9Q+8cLJmz94sHPX13FZVsGe\/YVPDl49W3nkzPgTJ5kMLSNQyRDkESSiQsYsNnputrm5m+2GYLbSSPdAQsyJcLKxf5gRO2F359NUkNnOCvUWnPFf62rQYYIcyWsw8pNgzDb6ssFpGVIbYo7dCNl0NcMdHStf+BuvhmHISTEiJFLKfNn47qmR\/UV+8oRw7PFIbfzL\/wRgoV3EQuXY1ZMDw+UH722pSECxYqCptgUkwS7AzHGqDEVFB0vl8szUx185e3J+kANefGLqvfWLcDhKzSZ4LXW4D74PUQBCkZRRtRnuVCEMSSoiBmFAIBKyY0z4ZIAcGUMFBBbOjYh712u+rBFR2DKGKSUghhtgxuOqdz1zWUHoriby9Sc+VDqTGdYnGo98lBzCwy+GXYdm1x\/n9d7xm0wKSCohjh7sFh+fLh6bvnhprnN1fr0a7L73QA0dA1aE1iEGDQbEygVnoGgPVgpFR1\/RQJJLpJT0QiGEjDqhX9+KvEC02jIQQGRkU4wZEoxd8Dz\/x7\/9vXf+eMD3QjgxSn6NDj1gFtjO6n61cXHozNPzu\/e3yXJBSaXA2zkaOh827m1sfuU1EpHGxqNSZokwrR1lxC2rUDz2i0VSRFmAZ2YFxjTr3IUwOXUI+iCUKONX6I3sjNcWdqWRpkFPfUFMOQ9EZuCSVUdQV1e1qyWTYhoNKzXb+kVQpPyGt\/anH3oND6UxTyWp7qlDiHFnaHj6iyWYGvaXtxGBmA12sTA0\/PynL+7drTY2DqHTgYIDu6sQtkB4UCjgzBRVBiCUIHz0oTBBFcdyAIjIa0Xh6n60tU2He9Q4Aq9hgEOadaRiyzKzwClpmFjmXh2bwvQeVXRgbobWVqDRNLwSFYGIQIaoMg6JfAR9XgSaL0MeLlXL9E3NJ7HS1xv7Gcq6UBfY78Le1c5OTmfzvGB2jqF9k6RUsHrw4l946YVPnvIU\/OEfLx\/4yGoHrOm40YBFIY8CIiWJUIqo0\/ZrjU6tLTqeVggTQjZPNx3CkQAVURInSIKUEFGnVa8CEBxu2RePK4Gy5gOD4NC798ba4y+dvv39e0drDUKgSKz++28d\/PhDb2svOKglDdJEcJgimS3XKlfa1cuUlZXqzniS7Z7epeNJeG6tIPYpa7KoNuy6miHmpEyYs5NkTf2YP5WhRwSFPY9FX9Ma5kWvGGvPUi27thdb3OahaC5sNg8bICIQIUiZweDHjSvGkRfqS1vWUKmzvAXANJ391OXZY2dGf\/N\/\/4lo1cFh0D4E0QEZQrECA6N0UIetI14olOdG+ZAtDne\/8xUpPnfOP2y\/986m0252Dg7Ia4EIYneFSrZ7AwUtDsLwMdq6iUqm9PAUlqDALcKxY7C\/B4cHiMmbTobSQhK7s9Cp\/8QuN1DvevcIMqT2nF6G+gm4H+rufOjMCPt8M9ibcRNbrEkBSUQYqTgSwbFwbMzhXiPc3ZHbG1GrDkGLooCiSO9ACLGqA7KIgH6HNLLUgIscSKFSJHxASx+S4vYyv3QaVYeaAVnuvR8vP\/7CyYsvnXpzbZ2QEUVRrVY7OtSa6QRtHMsJtJuWg3IAOUVB1AncwTLaDkUWMAZSe2Ew\/+ND0jQxG0UfqFYXFyNz2+96xTMhEXo+SDnfbWYfzqZAdck3khgyYpj6RRCzSoCEaZHOSOPlB0igg\/i4brQUhyoWMFJkBJ8iNLH1pmFkNgVCRlwE22GwgwQMuAOM26595aUTD5YPd5c2QQbALWjXgHEYGgdmQ73GSgVndqw0MQKeV792R\/LizY2ZtWqndWtNerWxk0MDU5XWUlWZW71+hbRnwDiMqH0IUqAMUognQmLIQteB+eN6BRqzQTJcTbSvqQ+Leh0MidUEHy4ZpYTvjQa1nVUWWz3D\/ofIB3vmgtnIy7wkADNMDMr3dSgx0apO\/fqPbg9PDahI3v2jd7zbS9SuglfHyKPIBxVhLMOnWNnYtcqzXQvzn2QsTuY\/9HYo0XD4mA1E4s4Sv3BCiZD8llfl139y\/9xLZ67\/6QetPd\/E+iYUYCUxq9s0j5MFyEBJRayx17z88vnC6JAXtE3ODGmfkf4GelKNspqTnNIIs3RO7MdBo65rPuTZ34iZfixmQgXpI3Q8afgBpQHQWYFqSjpK+qExiTzxTCCjkdnhxn4r9EKQkcZvo5SkFKY\/K6KWy+gnm9vAHGAMkZ1+7Nj8lenf\/413ZRCxyQk63IdimYoD2G5a5Nlzo87xGX\/joHbjnooEIALzrMJQZ3stPNyAqH1wbXPwxNTIhfna7QUpM7hxopwBL6YGpy84MgBE28EL52h1gw4P9V6f2LkMDY2IEospdOEgc3znLAYGsJsxh1147VQ9RQTA0Z3L9zp7y87euQV2YzAw+yUQuotbTPbDuJJBUrSzvH\/z9YUPvnPtYHGZmnvgHUHYRuGh0oV4nPYKCkkhEMaDp3gIq2JuHGVYShnzGkFG+xLz56SiWgOPT0AgKVT1vfapF06Xh8qbt7ZAaVmz8dchZamYGRCQZhxw1ykVrn726saNlcZWFZREJZI0sUxqpG4sMZNKi8lYJX6akSX93uSfmHyUhgBnwLgmIBEYMP3XWCz+Tj4biz3xacp3+p9M\/475a2T+AqPkN7H7W8L0G2OUpik6aBfBLlQmR5\/7y5+89u2bW7eXIdSWeQFKolJJ\/h6amJP4xzfkyIJTKv3Ur7x4uO+\/8901QokWACgol61ObfjYwPDZGW+32llYjqqHJExqHZJypobC+8vk1SHySIRB9QhlOHbmWHBUk0LGhXpme0JEu4DCjx9QrWVn6Lhw9hysrlLtUNeu8WMGKf8g08vMNsEzTcf4uO\/xCvZspIm4N1ONIACClZ2uY16XC32UqXlWysOaN\/mrPWEmE8SkZ\/tAJEVQa1URgJSM3TdRYvTW\/aikbqa8CiVRHWTmZbq9xAxhSTML47oNlIngBVLgCbq\/wq6cp13RqXmLP1h8\/meu3vvB4uHaFsgQMAIQmZ0049EFIiVRcZICIn9\/aXO\/3jn9qatb1x5IGcdrSQlKUGqlyyWD0UfW9tnuP\/YMPPKj4O5bet7pmc8+w774xbwy52FlPqYPUGzYNaRGckrolk6\/cMkeKa\/d2TQ6FZl0ZTIaLmO\/Stg0DLiFlnXuhfODZyb\/6J+\/K5HB1ARJHy1ZGEB3bDzY2Kvfvi8D33R19E7EbGY5tgi82oHOI9FforPTUp3W9KXTh8ubrXrTZI0CoRbxEJCUGGtWzc5YKOK5M7S2TvU6xC2cRE\/RrfAkyAKzsZc5kZ1M9GRRPez6lNzTORZm+xvqH4IT6XOf+ajCNdPcTk9DvSAlKF29aBhJiDLKohaywHB4uJI\/31PIlHyZFAaEHl6fAmp08MQ0kNXe65x4ZHby+OjytU0VhSZkM44fzpzjZtysfb1oO3T1HBTsS8+dDRt+dXmXEmp6st+bmi3\/yxwmDE0vN8nfMn8Bufl9NPWepfmWce\/X\/NKzmvQzIEfO0XxU9gvpT24Bt+JPwpKPQmZlP7P+WnGOKgf9nXAr\/k5s4DZwB6wCOCUsVuYeOf3yX\/3U\/Vs79xfr6ugQQtPQz55C8XGqrRIcmYW2C265PDb+6q99bPHO4d2lNoyWaXIUR1weNNXWVufuUnhUoyiAhEWkdYKMl6dHmIqCgwNjtoxRGsIPw1Zn6sy8kirseBkJJyIgWC4ogRrfDAjFIp44STu7+h6oKx3MXsfz3u54VGCeB8j3xvr4aLoa0zltf\/ovcWSzvhP2zhq6gymwfxsGe26nXcjm7sWhNwwJCogUMImxuibXh4QcrLKPKJ2S2GaEZBBHSbpsRqOQbm2xdUj\/hmLQ6dD9ZX7hbLum3v76nc\/+2nOzF2fX3m8Tj3SWlRk\/JFIGjMH1lstKA85zV2TBufeb3x31XnrhL72sovDBD24KzzMIIyVif3DPrZlyBHnqgZRm0rXzQsJsgdE1ssUU1Is5tFl+18KHzapyv530wExv06S4GaMZcActlxUKM1dOfepvvFrfqb\/7G9+QPmGxDJ0GQQCMp99tJuc43hFssIu8NPTE5x9zKsXbd3fKv3DVHinWvnNXfLAiFhfJO4IoQQoYnIwp5JQYPjFVW1jW4mxMnJlAAMxvtTfuLM+cPV5wsLq5K3VnzjgqELhNRIgKbJsdn6eDfaoeIGj+b6+YIm1dZlV+0LUC6b+gp4nd2OReV6YFfRn48dWm58sCfgSxJquf6VqFMco0LhwloEJiqSc9noenVmXK3aMzUI6uyXNSX8U1dCIJ65IJGZwUACDKiIBBq6XuLcOli+trRws3tp\/\/5WcP1g7auxGoiEBhtjrRxw5yYAyL5cqnnwHOm3\/6GqH15r\/7sfLDF3\/t8zMXTtz8+jv1rarw2iQioDiPBXLM8zztP5dXkRFkdlU0WTkbdnVbcnpUo1PL8mfR9I0pl9ubnz\/mPqmJcU7McowB4+bGyCzLLVTGBs+\/eP6JP\/fCzoO97\/+zb7R3qyAC4BYWB1AJkmGco0I6dDXOWLWAOWQV0ClPnpz+2OcvfvOb60dSVUZc6fvq7eu0tgZBG7QGNeuciaEynIPyw85ePD3SJpI4uoVIRp7cvL04c+HE1KWh3cV1KRSRQBkBQ+A2AIBl4ekTan2Vaoc6iQTj5mfXaZPSsjMdeTIZIIB95uaZN5HoI8cLlFe1IeLwM9Btisso5XvOWOqyp2bvL9ini0O5bg0m7fWkeQ7pPh5Pjql76A\/pgsAk0Rl6BQmQfHuYtiOTKTMY4TUwRowDd4C7YJdheJxfvTyI9s\/9rRdvfOPW+195W3XqJupVaSU+A9tBp8BcBwCKn3+JvKjznbcobAMpYNwuFo8\/deGlv\/zx0miltX20sbhb29hnJBljoOPblWIm7Y0kKb2Da04UAJIOw9GBoVqiGkdXKC03yb1hcXiZ6QODIiKlA0Q1\/06BUrprQ7GPH5ElSza+KWnFHyJDZvr6yYFDyfhZaaEStxAZAhZHB4+dmxo9NoKMvf2Vd299+4POwRFEHT2WQLsIg5MAyrIQAKNmC6IQVKTVTsBsslxwy4WxiS\/93VcrM8O\/9xsftqVi\/hHUq3L7EGrboCKQgYFuUDKFIUAE7hRHB0vTM4d3HpAyR2UaOq0ZTciBW8x2huZnhuZm1z+4L0MfRIiOQ8JHp4AXL9DCXaodauYqZuJys1CPRHSZ4OtjeWDXJIC61lbP8RirCnN9Gur6p9UPHJLrx+QWdjp\/oMx3RAj9Insw2wuA3qg+zHeRksEJ9lPKZVQn2Ns6oO49gLKyLOoSn2s3OkQADNCHVl3dX2k8\/fSbP157\/otXdxa2N68FZCiDCEDALVasTH3q2ZEXrgZBdPDOzeaP3ie\/ZTIiESMZLr9+Y29hY\/bK6WOXj42fmznx5KlCwSkMlTr7zUBKAWQX7OLIQLTXFFIqJXXAC0uvrcbNpIAE4uDkoApV1PSVksoIwLTPHLXXQ1DM3Sg4UC5Ghy0TFaRfBGVWFzBmjQ34hy0II33N5pkZSEyzRYtzPjXU2W9CJFhMbdCqX6kAGNoWtyYHg4OG3wqP1vbv\/ujOxq21o8195Xcg8kFf3vRuIsT0S49f+NknZShv\/D9\/Wr+3AoJMZKfloF1Ep3DxhdMzp0b+4B\/\/pH0gyKvK\/U0IGsA5kADRgawRKX1qGaiwND7oV\/dJRQbazWxtR4qdEyaPSElV29wPQyo\/frm9sCq9iCxEZeP8KXqwSq1WWo9QkprU5YWnLFsCU\/wZPbyKT2ZSub4OPtRuRHnuKPbqQrG\/Kzi52mHm6KW+oETKlpI98T7pBBPhYQapzM6U2hep7wUVu41Xugjq8h\/rF16ZIlshYASSQeTBYVXdeXB\/5Mm5hnzsF5463DzwDhSRAuETKUBuDw\/O\/vSLhfFxX4rqN14jr40iIJ1HiwBKkhKt3XDxsL74+i27XHEK9uCZqdnPPnn3X3+foggQhs\/Pnvm55z785z8U7ToEHZBRrB8infdEaGkgJ7OtF3\/tMwcrjYUf3FFhGyLf5PvEu6IWDREi2tbQpfmx564u\/+6PVNAGKdDESykAAsu2BioX\/+rHl7\/8Zmt9z8C2uyQBjKPt2iMjl\/\/WK4u\/\/UZ780CfQiYzQx+knDsD5WO\/9onNf\/eTztZh1GyB3yIZkIx0GjsoCUrHtSuGYv7Fs0OXTyhF40+ea9xbJcYRlA7SwUJ5+uKJ5770+Btfu71dC6hRhcMtiNoQ+eBHUBmDoKmBIwiZnDZkgIxZfOT4zNqP3wUVYIruTtpglqGqI0fOiaCzd8AlFc+dc47NOuODzYWVzvW71G7HeRWUhW72MekhZBGsaThF38tftvykj1S\/UK\/9N\/UTYs+nxT4tgawngzBTafYuYMzpPhLjE3Udj73feuoxwJxqv8u78dABZrYvlauvDQLHMBoBEJQEiFAEFHVgZyt6x3p3wP30J+ce\/Zmn3vny20oRkQIZAoAKQ++oVZwYszxPtTsgIxBRPBg0\/DLSiEvuhFEQcs5G3I7Xae\/vkwKw3EJHyihqH+yLRtxFJMIkx4oxk9NkuaxYQaFku9Pe31WBBh8ap5V5JfQ8kHGwHHduLPL8zv6e8pqgpBlCaoCK5VjBqIgiv17r7O\/p+WcqrzFf1wLbtZWUYRjUa+39PRAhKAkmDpgAECxHiEgK6TU74dERhS2IfJBam5ajBpOSFPmdgxoBUST8g4Zm52h9DDql8vjYi7\/49P5u+8P3tmV9H\/ZWQHogQlN\/ejUoDEL7ADJxsYk4zh2otDd3RKdj+G6ZdFddRqAKARlyV\/eBidsissK2PPEzL7ujg4cz46vvXEfUehroZQNlNdbUw9rRSbm5ZJEufsifoS7D3jB1zJajXTBRwt7xVR+9cELhfogJOIHBm4ZJ11USM2bTrEcm87ew58qXlgapb7ELOpX9KOzC5mBu7gcKTI5iCFEHggasr9XfHbo+7n7sk5cOHtQevH7HjCsAokZ75be+1nnpkdbieuvBOpn8vRg6qIExSoGUxCXwCC2HkXIISCmSEpmFJFEI8BsQtCDyzemReEz1cJxzAAIq24AYBeS3INT83ywdHEyX0nKAMSSiMKSgHS\/sDKhbSdB0MBmB0EWjzGuNkZgFJCAs21Jh6IFZ8xnyHzJQRaCyi8CkgLCDYRtESDKlbppKDQlIURQufeXHou0FTX\/37buEzGgGrSIrFJ\/46Ucqc8N\/\/NsfhJ0m7K5A1ALhmy4oEXgNGJoEuwxRK8GC6a0CmGUPVNrVGpnNKAeX17reGI+giCSijYhYKtoTIyoQTCrmBQikTPBG\/MhhP4Ag9bUtYLfZrNuf23VLJOjmp0HfFWvwFt1sPsLeW1ffWQh2qa96v3NKIlJyiJQu\/37OupMhBHSXoqlQLp389WiQkfIFKuXl6Zid72j2lkIQAYgAmE\/37i0rNle8+tIvP7G3tN3c8IgkyAgUeSvrq0vLQJJEBFK3BLLptrHZXQ9aEEEpTojASEbEQiUCEpGOFtImSTJjjPh7YgzIAi5ARUgKRQAyBClAivgxVYmBj7RKhgikVCICRaCUKQ61a0yXZ3q1KBWLgaJUjG6CZRRwC0iSDq4QEURhTFvU11ALmAVKcSIQAYkAhDBWibiiM2Rr\/fNL4e3sLfzON4FxYhYAQ8sBuwRO4eQL5898\/PxPvrd6tLRJ60sgPJAhmJDteHzUqsLgNBz5QCKm5SMgQ87Y9Hj7ziJlIuAJTFspxYvoUsIp8pFRPjWhRkaD5bW1f\/77hfmJ5od3KN6niJKsqC5MC2HXksmMCh+O8HrICuy1wVD\/VWL1zN\/6fpWHjea7bBXU07ylrKUns2wy\/iZEyBOJKXvaYu\/ph10TesoxF3IflROgGFpM3hita0IlQATAXAg6Ynnp3a9alV++\/NyvvPijX\/9+cIQGFy8iczAqAUqmga3Z+D09AtE8OClVEtAnBWj2kZKgyIy5tGVb31YRgZg5vmSklFQJYocUSAkkkumdueyapB2BiT9eLzNQoPkRSoIUKma8m1BkSsKSEDkH4rqSlHpDUQSkUBoYKSED4DpVkCmJ8ZEVQ8ApA2aPX2wlIQpIa2I4kOWSXWDFobHTUx\/\/lRduLR4tf+tt2lyFoAlREG8KyixpRJAByg6NzkB1C0DGfArk5QKfGJHvBcnENr4rck0fMnI823JGRipXzgf1tr+9Gy0sg1JiS3Vu69RaH2VEht\/Xl5LUXT32mVH3DN8A+yDL+yxXeug5ZRmHTF7e1I2ceWilS93phpmeTX4+0fUj54w+2bUdVyBdXVeMBzSImYsf9TZpMHMjNXUCpglnmJMLmfpfKQBEJUkDbJqivcjf+Kr1mV99+slfePrd339XNIhUBBpHq5SpnbrepKxfSNdg3MY82izl9sYemfiyB8BYnOFO5nqZvAtaVKVUBlzLzNpWAklypttjMgn91FWZPgB1SChmGIfx9s9AMeDm7BakQb3x5dYk\/mVmPECYxqEmOLl83Bsl2XJozFjcRrswODny03\/9xeaRf\/t3fyw318BvQqRbU7EgJo2OIWoewugc2CUQHQAEzgHRrrj+wooyb6pRuiLjpmRFjrZdmZuqHJ\/xdqqND25FjWYK7dHzQKWQJJnhh8qoQQgpJ3noiXtIiE7ULXboZ7CGLhZwcvfp\/SgTa01Wd6HZfx7fg9x6GJQNHy6Xy6\/qLo1GPJ\/OzfcwjXqPsVyZYWPSgKFuPV3mJMQ4aTb30qQlcqw5VZT4JyybartHN+x3fzD96VcvhHX\/wz95V0Y+cGGe5jjtFru3QY0GdsAugFMizpWe2sWMDJ60JnUXXmXKKnO4mPGJQbulTugM9N64us0tFEHpcCggiZBRkMSiGYbxga+PMA0dznbJCUCRkjpKlDKC9VhpiCYnFZkRi+t3Ju439+Q0GXGfA1YR7GJhaOBjf\/Fxe8j54f\/67fbyBghfOy1AGdthBhYQQ1\/bdZiYh90Hpv9EipXccOfQEPf0bwLXyxwtXjhxzB4oYatdfe9m1GyRUaKp9Naj17leh6RSCzw9xJOeYSBkXq6HlKPYNQDsrVO7MrCzvlETEtqDtuz9\/Ji948FD8KYI\/ZuXfdnqaWkYgzep64jDHtlqYheMXyhEfR3PLM6ssy65sHVlQXdPV\/U6NFIPAlDALdU4XHlj5cOK9dQXLzcPG4s\/upXMZ5BUzH9VueoBEdBCu8SHxgYvzFfOTLX36iR9IAXEzEOsL3KZpiJk\/PLJpIszYMgyVW4qo828bAZtpPShqp+teA6TfBRLP223Fw4NwU9X0ZnvitK5PqGpH5AxcEpoF0CEpAQCIah8OmqCouP6AAR3wB4ceubnn5y6MPHNX\/\/hwf0NitompsaIQjXkPwMm0vtO6EGnAeVRCH1gnDvMGhvvLG0DIqCNBt2rrKLtTo\/zSll4fuvGPQp8IH2MK+h9x5PLJOXAu13zCezW21N2++5PqegdrvftpjwEJJpNZaK+q5B6NPZ9vizif4kXOMfgwJyZI+6cYGbqh5TxkuqnABNDTRLeZHw33MCzzbYd80IpqQNjlChBwrrNE7AUKQUgARUAgbBQeGp15f1vkWPD83\/pmaAdrX+wYlKLdFmoRPzKZhhQjKHlHHv12WO\/+HEvlA\/+j\/9AUpq1wOzYyaL61S4EacK7dsLqIlMbmlVX5ZOOeoz8RUHO8ZyehAryAKIMey12JRIQMaScgC472SFVGCkVRwYnrp719lsi9FFGhAqBgWGiIxqbL0PkxCzgLjhlq1x56guPXXr5zPf+9Y83371DQQPCDqg4FY+6aAJEKWROQvsQZi9CswZKOsenoDAEvAQQGUhpueCMDhbGB\/3d\/dbNeyoMTPpSQhw21+nsAkuUMZDP\/KE+sukeYsVHSG372eupe8PvPYkycjer63DIfa6ka0Lw0Wu1z6mI+LAPwT6\/n3HlGO82ZsZ9iXqY5fwBmBgCLF2lpJuxUnFStIrjFvRxQaBUbFPUs3JMEK5maSGADCBsAzKxLt7+TsGx3S\/+rVe+9k\/56rVFUBEoZRpmSmjaZa5BizhweobZjsNV+dRc\/cO7BAjIMcl7oR6ZRU7+brYbTCAM+VZ3vhBJDISpxpx6L6tEvc9P5lpM8ddkuS60kYiQXXSu\/NWfGpqfefRXx6Mg2PjqPhmQh0LgMUhMW42spBpnbuHJn7769Ocvff933nzwxl0KmxA0tNsQlSClEICIIbNIz\/1ylBsCAGjWYOokto7c2WPe5iENzqLftBwxeukEMFZfXD9cWafIo0TqnYa0ZCKHu11IBPleJuZ1Hd1NToKHX71yMtE\/Y0zf52hL3V5Wz8ruHayZoQL1dlER6KG6nC6ffmb0gNmyNjueT3LXMWNDYaTb92hsNWAMNXZq5+E2tx1mcWSxK1opGYYqiuJ7jjTdSBVpv1+Sb9zd6dIwfBHXLMiieu3t+5F92nr1v3vhq\/+nt30zNEe0wK77NgADQIr8nR+9Vzw2FjY6R2\/dJr1iiYCIhAIZGX5pLAPtDSrAuALMtrCo9+03vUFmjllmAUaAKm6LZK3buZFSXhxCMU81NpvHSYXpoNAtFMZHCFDatlUumMEdIgCjrE2WMeAW2AVwB6zS4KOfe\/SJLzzyk\/\/49p0fXFNeDcIWCD\/Oe4sR5gBxSZtAa7i5+FlFQMuenD714qXBycr1\/bvW\/JA7W8C9ncbKZrBfpdAHGVFsQEUigpiBkiJAKF9wUOYOkghGCPHhSwuzML3eg4qw6+aH6RGa32kzG33cC02+iPXRCBmCbAsDu0b92HspTSxF+YWdWclJnkaX87fLpx\/nFSeiJJ6Y2RzkDlqOVS6Nn50dOzM9fHyiPFRhjiWFFJFEzizLYkHYrrWP1vb3HuwerOxKP9DJuHFXwOzHOVuD6YuYCRgyRlYBRMu7OPbaB5vBCLz6N1\/+\/m\/wtetLhAygHeNvMbZIIRKRjA7euta4v0oSwloLRASAwG2pZKQ0wkSfXSw2amDPC4sqMSFnFfNJrUNxA5ZZuoYGywFmAwbUcxXPVFUYd6gQ05aDVqQyru9yestLJzgKSEXN9tJ\/fmPqY1fae4e7r11DreTUZTASmfGAFa\/Ail0Zfuyzjz7\/84+99uV3bnzrXdnSwATfjHaUIspfUDGJqSJgNjCbuAO2y4oDLz498+m\/\/FRENDQ28Mb3FoP7S3J9hcKmTlbErNswvv\/3o1bH5r2cRYmyKbX40Udcn5Mu5yTErPXuITrp\/GmHmVv+R4CeMDca6cZkdLU5u0vLPuqZfj9tTysWk3Z4vAKNCc0BywW7iHaRu4Xx09PHnjg7eHyyUHTb1dbB4s767j2v0QlanowEt1mhUqiMDg7Ojs6cmz39zAXPC3fub6+9\/6C+uq0CT4\/mSXLtcDCILozXkp4KoASlUAo62FV\/8p12I3yrPFz60qUv\/I2X\/\/S3nKV37sTyeIYSiUQqclcCAhlu+5QqyDiQsAoWc13uuNILTGhFHugSk3IQACQRJQkZmN2LKYPG0HU4gsXRconbwDgoFvdvcoSG5DPnYxIwCWnhWvAd73oYO81JCfI6q19\/ff07b1EUKKFAKjPhwFiawyzkDtgFckpOZeCxV69+7M8\/8drvv3\/z2x\/I1hEETYh8UiKOBFbxKIO61VFmOq8QlJannzg3WijbFYDjo8UfPtgRh3sgApAi9u9LNBCG7IWYsoOHPo3KvDQMoW8k2cMFLvgRg4mH\/sHDxvt6rVi9yhvIWwIx\/X4x07aN5dXpYJC66RM5OXU+5Af7NT\/zTBpATnG1CZaLTomXBibOzZ976cr4qZmte1vXvvx6c2NfhBHJCKQgzdsiw9Pa1a4Wp+BUKmPnjp392Pn5\/\/bVjesrq6\/frq\/uqqBjjkRj5weTbJF0dglMPH19n96vg1P2RsLvf7X8yheOf+KvPc9stfTGXcksCD1CBImghLFbpbBbQGDEGDAsDJfnf+5j7tnjkx9\/YvNrP0n7L+mLEvd1TQdB+yrjDrC5epIG1WDcmuJFd\/D07ODUiDtc9tq17LQAs6swZ\/BNrt66+ckRuenJIwLnyK2kVgcgVFKjXKSPueIq3Qs4cgfsIhQGC0NDT37+kSc\/\/8hrX373va+\/Kzv6DAxIRkjm2pbcyjAH7MeUahPnN0ohrr+2NHZyzEW8+fqqCtooA1IRxqqXzNNEsUKf8h68Prhl7Eqk7s+DgS5KWfegLZ\/3mR1V4Z91N8y3UTFdhP0VNRkOXrrTpEq0rMGKsqg9QuoS13QLR\/MXkzgjJ7b766ugOQAdsAvoFEoT44987pnjT5xd+NGdd37vjeCoRpFP2kwUm18yibg6+J4r4fl+a\/OouvXezcrU+OUvPfux\/\/6Ld797c+WH16JmEyIfzBLiwKz4XVPaggxuERp7wDjYRQCAetVjxe\/+fvDsT5\/45K+9XBos3f7ebdGsmxmJZJQYapLATdRtGOUMlgvHptBxh6+c2frGa7pVixl7pFY5YxwbJlWcOaGxTvEYBs3fRH1uj189fvEvfcp2Hf9Lz9\/5F3+gDBwtjVhLQhApn3VHhkDFkXFinAAiAuIcuAMsAIz0CNy0gpUAkPGrylKZBOPALWQ22EVwy8Wx8U\/90jPnXzjx7d9+49a33lN+XcekGddfugIhE19FmSxR1FFN5rlRkoL29e9fe3BtBRlrHbVU5wgiH1SUefX6NBzxYe196IdV\/ujeCXatXugKi8zQRTF7V+hrGvyISfzDylHTNaCHfoeUP5i72zndX64nELjHu5F7PoBZwGywXHBKrFiZOH\/82b\/y6er97T\/9n\/+guVvVhFnSEyeSqFTahTc3YIM2I6Gbflwxq7nWfvtf7g4en7n8516ae+xn3\/u3329t7RGzjIuUmPawgYrAdqlQhtoWaDyJDCFEUAhRGAUTb38fOoAv\/5Xnx6dHfvzlt8I6Qsi1sQCVICW1ntv8qIoAVWtt9\/5vfXPo8unNP\/y2CjxMki0S9o5Zb4ZlJgAlmcDGxG4fG3NjAQNRaXLELbiEOHTxOC8VVKeRy2GLzec95q\/Y3KzHCcxCxiVZUKyAXSQtowXjGI4zqTCjuY2BMeaOUEKnWJoYefXXPj53cvyrv\/7a\/TdvqaCptX7JtQ0z01pKS45sEYSpyJcUyQjCpiLR9BtACmRg9L3aZxhT7BNNfspszBTg0I1jwgQZbYYk1HfI0NVMpi5hZ08oPX3EJ+g7VEz3RCRIQU99z0zMVyDYLUnB7MgPMx30nnkEpWjojNEeYt1zPGUyIkB9BtpFvQLPvvToc7\/48evfuHbnm+94B1UIOiA8MPrmKKb9CEy1XclsTcbpn0L\/k2QU1Fr7d7fsSunKn3uxXe20awEiNz+Akqh8sF1wK9A+ApIpHZAAVAQqABHQi5cOzp9q3K8\/9\/zs6LHRndVa5BtvXmbwS9nBJwnZXto4fPtGuH8AIoyFbxmkBWPIOFo22AUslE8+f6l52N5f2kUpYidHmm1kylTLUYRjl04SyQdf\/nHt1oM4\/Vsll0ZWKI6\/dLV2bSWqNXQvKn5PmElQ4gWrXDnzX3167LHzA9PjtcWtqN4wvg2jGoxDb5J5LLPAcsBy0S6CU8HSyPSF45\/9O5+kkvOtf\/nj9Rsr5DcwbBt7hOZHapt8HtgJGSUhdqMWU3EsqMQCEsTUmZzOIaOgSspN7HLJUdYCkNmKHtaNhI\/Kr4beJYi9RWzfSR51Oc7Nf3MszPakTmtelwAAV\/5JREFU82I6osuWxXHR2PPzYI6PEm+XeeEMYnbp6mFgip\/IQso4cAecArhlVqpc+uwzl155\/O0vv7723oLstCDyQAQo4uWnxbhmycUTgyTpmghNvLiKuegKgEQoj5arIsRHfv6ZwFONnRopQCSUAbglcCrk1YEglmhxQAZWwQxIbBeLZQh49cbe+odrV14+ee6ZU42DoFH1475C79YIWpZNoWZyGrhlTLXPCE0sB5yiPTZ65pOPBQL3bm2o0AMZJr6BjD0EASCstXbfvr35vferH96jwIs5cXHKAndYoTT+wuXajZWo1kDzp+nsB5gFdqE0N3Pmr\/yUWy4VJoeaKzvNxRWzZ6V7teGdGjycVYDCALgVdMq8VL78yuWf\/tXnd4X1gy+\/f\/DebRU0IWhC5KVbJCkEBd0rMJnvYzbfDmNQKiRlqoo302QcRLn6MMt8wVywd\/oYd3NhehZVjmqBea\/8Q\/srfWVm2LUssidoz0De\/AtHd7a\/rbfbzpTPKce+izD3reTNQ5hZjJgKsgEzrFu90dpgu+CUsTh44aeeOfPS1bd\/98fbt+6T34rfWoFKYjY8Nf78lAR3UhePk3K1OhEpqm\/Vgrp\/9rOP+fVWe79BVhFtG6wCeHUEhlYBzK8iAAMZQtiGsA0ygr0aLWxSu90KcfPG5szpsaufuaCAH+60pMxkhkK++0DxXpCJ0shEO6A26bJi+fIvfWr2lavlU1PBYbO+sALCLC3s9ZgpGTVb4VGNQl9DU+JsYwTkYLu8ODD14uXajeXwqGGMsynVgiHjyB1eKk89fdEZGujUWzvfedfb2gEl4m54wg7mwCxiNnIX3ApWxnFoamBi5JkvPfrUF67cv7b9gy9fb1cbtLdmbPIy1OWJAQp2hR8CpiMoyBKHORoson4SspRkhMzdOEYw625WJn0oQ9fM2ta6DDf4EEtQP+98XpP8UbDPPi7gfLxq\/7ZLqh3NOuUf4uzoVuY8XKSGvX+p5+ePg2\/THwwpoXpaLrql2SfOnv\/EY+\/+hzd2765Q0MLQ048RkSSD09bPbnyQ5iqKDMMjG8pIBCRQEoUKSG68fk0xOvczz3U81hg9A0rQ69+EwrDZa8MWRG2QEpT2BzHgDkQ+Uo0iD\/xDiqYO\/PFv\/PpPHvvsped\/4bGp85PvfuXa0dquYjaEHRR6miwA4l2cVPp9UJaclgoVOLdGzswS46zIhi\/N4Z\/kLig5NYxK1OSpTCQWoiEgQ2axQskpFJhjQwx1yvC0AEiBDP396q1\/+dWJx08fLawfXbsLSsUPMcPE18s4MQe4TVYBnQovDx1\/4vQrP3OODznf\/70P7r++KMMQZADIUYQkwsyZnILf48YFppCODI9cU8CJcWCctBwq15GCuEukzGxQKSIBJAFj2wdpR2\/cJU2JcakmJvMKInQjYbJGiq6XvFtl2EeClBG3dLdvHnYCxxkX+TthahTqWz1Tl30B+9nec3l4SYpmho2f3jSSg0uPiw3a2QW3XJ6bfuGvf+HWN26uv3eXgiZEHqrIuHVMTcyQW3pqz2wXbQetAloF5A5YLuMO6tkGMzxcs22ax4ESmmVrt10YGjz\/sy9sNgpKKFhfBL8FYRuCJsggZyBKzliSQAJAQejDQEki276+vr1UvfyxM1c+daHVFM1DXyo9wk664tinqDCLITkJGTKukLtjw5Vj40G9vfLVt5tLGzqdK+nlxPkQ2as1ZnJi4vsbt5A7488\/NvFTz1GpVH\/\/LoUBKJFJ8kheDxlU64c37nsbO6BJjYmuliEgJ70t2iV0SuiWS+NjT3z+0S\/+148eNsQ3\/p\/31j94oNp18JsQeGC72KmDDIEEKBXfBSCNtDCTEdOIwvQCovtwjr5tgu2CXdRdcbSLaLlguWi5aDmo\/47RTlkpbTlTasXVflJmaFksYrYB2NOr6ne09RkS9lefddnFU0UK5ArwfqdVt2IG8\/fKnuES9g+o7PJPUG87FvNyGMzdydPeNwdmg12wK5Wn\/\/JnVt9ZXn3jJmkYRBz+agCYjAOzGGOOU6wMDEzOjM7Ojo6ODFRKBQASgjp+cHBQX1\/bre7XOp4nokAJQVKkAAgTcx9S5C9\/+8OhycHzo4XbX\/8eBV5qXMgE9IJWhwEHgHgUgQAMNpZhZlbZ7ub1ta\/8o\/r5j51++ZeeeOTjZ976yo2dO+uqYxPGvgEUiIyUQCUBMVbLUDakk6SAwLv\/B9\/f\/MkNktTZPSBljpRYWZO4t\/Qi15JUNELZhPyvZ45SWgPFiPPi\/CRzXdVI4FqYggCUNO77rsaEDl1CBsxG7pBdAKdslSonnjn99M89Wjw29rWvLCx8eBjsVMlrg9+CqA1KgjUIrgthU3usUq18aj4EgjRUwzThkBstFHeA22hZwG3mOJbjugPFganh8mjJLlhEFLTD9n6zvVvzWy3p+0oIc\/NMMhT0xNjoCTXYVgExUx9kiQ55\/UpP\/kDfgTv16GLSINcul+x\/6SgkYcxkB9QPqVrxIzXk1KPKpowQpF8qV4YOmqSXEOPAbbScmUfPFoaHH\/z2j6Wnr\/gmI80knluu7ZYuXjrx5DPnr1w+NndsfHCoxAAiLwyCMJQSEQtFt1h0hZD1o\/bW5sG1m2vvvn1vaWFVhEGsNiQgBTKCsB3V4M5X33zk73xpcLJcazvA9QSfAYg0706\/1MTNMJNxkBwgBADY2oSJKXLczu7u9T852ru\/9\/SXnvjS331l4a3VD75+\/XBli0xaWEAyRImk7fPM3A\/TqS8hKAUilO1Ga6mNCKAUyoiUIsq38szjaxl0KjIQmhMRAUkTzASEJA5eey8Skbe2K2p1iuvDbmOlZguketTkmNWFSQEslzul6YvzT\/301akrs\/eubd763upRxNXeNngN8JsQeaYX2vB13GoiV8ipKjMtAGKcjBrRiDHAKqLtMscdOjYxffX45IUZt+RSO1CRFEopUojIbW4BoG1Jm7Wrjf27m9vXlr39KkUh8RCiADEgDA0QBBBAArA0ZML497Af2D3\/m0QPb+J0o+8zFSw9DATz0cNIxKGn8pQWTIvmh4VZ5OCD2PWd5FCHicAfMxK6bMiW3hQZJz0VtMvFyYlP\/L\/+qxtfv7759k3yGvEilACIlmMVKpcfOffzX3r2uRfO79X9B4s7yw92Nreqewf1Zq0V+KEUgiEWSsXh0YGp8aHj82PnzkyfOjvtuvaPf3Trq199d\/HeigraJEMghciIW2AVsVA+9vnnx8\/M3fidH4rGEWjTjVECyNgIk8YAojm3LWI2cAecIszMQcuDkLA04IxNXvn8o4+9MG+R\/OAbN++9ttjaO6TQM8EbMlb9G3YtpfdlRGQs7RtrH5Z2hGRHsloqbRV4ZWj40Yt2pXL4we3w4ACEBzKI3QEsDqvg5oxNGzOYMmaSkCaIhQGMITJiFjAbrQI6xZFjExc\/efHyx8\/XdtvvfWdx9d0l5TVpbgiEhI1tCAIIdax0BDICpwJhB0Q7HsGnxXes\/I7nHDweBdsu2gW7MjDz6MljT512hsrtg0b13nZtabe1dSC8QMUTHURAxpyBYuXY+NiZmdlLc9y169vVtbfu7t9dl74HkR+ja8zsStOBMQWNmpc1USf1eCa6F2GWKJUV41Ifnm\/vbZD6XgWzX4WAEIafwuysM\/EudTOukfr9Zxwlma5MyvZLc9AX6GqKxnIQFm+HRXQrJ15+8uLPvvy9f\/SHYa0KfhOEbx4dbluFyqc+9czf+ztfrLX8P\/z6h9\/97vXDw7qSoZIRaY92XDHo9iAyhpxxyx2fGH31s09+4dVHLc7\/t3\/yx2\/+5H0ZdrShARknqwBupTA19cLf\/8Ubv\/Pawe0H4B9B0DLcsZiul0vqTNxJjBNawGxwXDh+Eg6agBydCkzNVmZnn3x8+MIrp5r7retfv7n6\/nL74IiiwIRVSJFPO8mEqORGUJr9rHnvZnKntUTolMdefPLsf\/8LzLK2vvn22r\/7Jnk1iDwyvJbEfmmE6XE2BsZvWbze4sqQ0OTP6Ekgc4qDU2Onnj712BceiUJx\/TsL915bCtttCloQtEB4cGIaGIOVXYhCiNogI1ARoAWFEWhtmSIi3tu1\/i7+KnH9aRfQKVrlytSF42c\/8UhhpLz84zurr98NG02lP1saNpoIPTX3yQJuoe2WxobOfOLKzOOnDpZ2l757rba6pfy2mWPJgJJ1aKIBYkqiEVJSP+8v5H+z5+7X6w4n6AL+drmiMEe4BspFOCkC4FiYy00He7Fk+LB2bB4umHPkQvcizF0tE3NAqj8EboNdsCqDj\/2FTz74ycLh4hqEHY0GRCBEhpZz\/tLZf\/gP\/uLS2uHf\/4d\/+Obr19u1Qxl2KPJMOaRFFTIEGaIKSQYgQ5KRlKLV7ty4uf7G28tPP336lVcuv\/XmQqPeyEwLEJDLCJ2RgcG5sYNbK+YWF7fX030Lu9R\/8bulx8rtFszOQKsFUQQdL1Swfm1raaMzfHr8qY+dPPvC2TBifluJiAjjMyq5FJk+Icu2i3tkLvGQXcuJuDv23CNDj58nRABefesOeW0z38NML9CATCDORUqu3yYjSUvPyHLAKaFTBqfMiuXhuZlHPvv4y3\/1xdGzEze+t\/iT3\/rJ5vUl0ToCvw5BE8IORAEcHoFr4\/gQVA9BqXgqKAA5gAKKMt97krKou98OWC44RXRLlemJx\/7cC+c\/fmXhh\/eu\/cfX9m8tiVaNAj0Qzr2tKENUIcgIVUQyBBlSFITN1t6t1c33V8aOjT\/5518UAht7LSWy0BroilIi\/AhHLD2kjdkXf\/uQIX7iWqKHDhUzDhdEAI6FmXzHrhveCV2AsoeGh3aBHrKsl4wkLe5tQjzoiUUYLjrFifMnz3\/6qWu\/\/1rUNIUoggQiYhwt5\/NfePHqYyf\/P\/\/L11bXdlXYgqgDSld3ESqBJJEkKqWjxjEJGDUXEtby1cFR8AtfeHxlef\/uwkYm1geRMULLr3vnvvjU\/rWVqNUGyhGBMI7OwswFJ\/lN884qCX4HZqag0QLhQxTC6JB\/0FrdbN\/\/7j0VRc998ZErn7pYnh5u16MwYmRyyOLYs3SFMN2XTFuy8cygq6OoBA6em1Oh2Prj19sLy6CCTCcpSbdOa\/74q1jIbbAc4DZYDloOWS7aRSwMOoOj46dmnvnFZz\/2l54dOzn23tfvvPm7b62\/\/yBq6hK9DWEboo4ZAyoJjSaSwNlJqB6akbp+GIpDEDTjbyIOOdVVtL7HOkXmlsfOH3\/pVz\/TOei89Zs\/2Lu9JDs1iNoQdUD4KAPQeDsdGqHHwsY5IYEEKoHmei+FH+4tbu\/d2zn7+ceHr5yqLe8JP8qrSbNOwuQR71VMY49ZCPu3SfsNxLuWQy55AfNitQyyk9LuaFfaBfWueaI\/y4jU7\/6IfTulkHH4xo8aJ+6MXjq5v3XkH9VBhCgFkUld1s7RYrkYIQoVkvQNZJp6reP5gpkAlAROwDnabqlcKFjMcd00uhkASIIUIEJ\/vy6CYOj0VGdnl4xos\/tNoFxFoWtyCaDMw99pwd4WjI3Dzj40I1ayFbnyCKqre7Wl1YWfLJx49PiFT5699OKZ6srR7deXV96779frFAmUunmbmMRlwubIBifkbE1KtJc3bv+j32U2D\/erJALN0UCGQIxyvRDIDcRZKlJF5gC3LYuXxoYvfOzC2edOVqYHdtZrP\/r965u3t9q7e8pvgQhA6HMpw0eL9cN0cABhACfnYGUFyNIMOJACuIsqMILEbPebu+CUmFs6\/vylCz\/91J1vXl97+55oNyA0qXLJ+w6gNHojw1oyuqs49BcTXI1SUXUxeOP\/PLrws88\/9zc\/\/8G\/\/V59ZTNtapoIXpn4x7JDwjQxHFLyVk7DnQv2i\/uk2Ot8yPVsqLtj+lBbVTInxIfkhGZ4gdB3wgJ9a85cAyDdMmKAWgyPAYZJ8itzyxc\/\/\/z29fXDxRUjjkna7sxCt\/zMs4+89PELY5ODS\/e3m\/U2MQtYfPNhLAu\/MHcGbiO3kFtou3Zx8Mknzv3tX31lZmbohz++e\/vOSnzbpES9CcArJyYL44MH11d0s1vL4ghUToaYF5xjLk6EIAiBMxgbhUYdRIQjo2ADtNvU6QQtb3dpf+nt5epmfXBy5PIrZ0997NzI8QnHLQaRJSUDywVmmwkYj3+lAaNxMnbyi0D5gWy19XwvPv942pLRn8fS3X8XrQLY+lcJ3RJ3KoMzU+deOPfYl5545peeOfbI3N796rt\/9OEHX72292AnrFepUwNdcQg\/o4NJNIDS1OGdNsgQJqchVCBjCJVTAenFb0qS71sAp8QKleMvXj7\/2adv\/P7bG+\/eU55Re+uuFeoRvJF9q6RBHSc3GxoVxSQhAJUckiKIDhb33KHy2VefbGwc+o1OIldMezNZkBNlwjofOlzAHp3ZQzqsGTZCn1iWnHEhd1JZPb\/VNW\/ojmf+CKDTR8w5sqCUnsaq0THalQobKO3cWKaMZZPiaCREbjEetsNjsxP\/8P\/3X3\/7mx9+8N6DldXdZr0OMiTQ8JiEXQY6lAgYHx4pnzpz7PkXH\/mZVx\/dqwe1TiRjspgZ3GsapxKgor0PV0585lHGUTKeihHyfu1cmZEYuBAI42FmdR8cDpPjVG2CjMAZxLFBOjwgRGDMC6z7bzSWbuwNHZs4\/pmLc6dnLjx1Unpyc3FvfWH3cG2\/tnUYNNpAAqQifUqTyvjHVcYoEMdQm9j6ZECUqWMZR8YpzfG1i0Ol4emRydOTx85PTp+dRIdtbDWuPWhv3N88euuBahxC4IHfhKCJUYd0NIXucGg8D0DucAYCRXB0BJLY9DTtt6jTAulBoQJWCVVESUg915aL8twT5x750rNv\/9ZP9m8tU9iKr\/SGgJj+sJlbN2W84XFGfCxUVslQVwIp2cGFr7\/DAJ75lU+\/9k\/\/uLMjKKGZpMok\/ZkUwsNdgPSQZziLG+mbQoFEvSrRrux5yulprL6Z6R9BlSLoGUbkANvUpYbtHhV2R8tg0isvz45z1wmP6sY3nYueA1ISSR3tNP\/x\/\/LNV1459ZnPXP3Fn392aePo1rXlzY3dWr3TbodhKAiAM+Y41kDZHR0pnTgx\/ehjJycnBrYOmr\/3x++\/f2P\/H\/6Dz0nTljRBiGhUnZKUbG3sW65jDZRl6BugWzbCgrrK0pgBj4AkjUNHR3Tt7MDxkzg1Snt7QAwmChC1NCmMlAUAEnntkDWuL9\/8nY2hE1MXPn5xZmrwmUdm7AI\/2m\/v3NmqrVYbe63WYTNotCM\/kFE8qMjgEhMnVOoqMGpMMElqnFuOZRfdwmBpYLw8PDU0enJs5sL04HAx6IS19cN3vnZj+dp6q+GrUoU6dWgcAkkolMFyUNqgbFRC97dAScqkpmlossn3099Dq0lSwtRxtDjVA\/DqUBiEqKXVeMA1DL80dmb+sS89d\/0P3tm\/vUxhGyIPIh9kZFZ4nFWW6xJnpEKUsz4l5QmZ1x8RREcF7N63r1uDlYu\/9Ikbv\/n1sCa0zE2nL8e1C+X5K3+WKRf\/y6Z\/mMVIPOzA6la0WdkvQbmJH\/YVquJHTx+zWPQsXzdTXFO3Sk+3DVh5tEKRlJHMbYSJ+0xDuSRtbOz+0\/\/7xvBg8cojp1555fJLT58sf+qyU3ItzhkQRyDEiDAUMmh6fqNz6+72P\/9X3753d7XpiWPH5+McP8o8UikiUfqhXSoUxoaDajXfHqOsrp6yL2Xsy9VtHiRhRlpbW3DuFLQlbK\/j3CVyLAglaKY9+oAOTLriJx\/g0Mght9\/8vTeZF7guGxovzz1+\/NhTxy++fK7IkSnlNYKD7frO0lF9+8hrelEQhoGMQqkipaSM8+GJMWScc9tyHMt2mO3yQqU4PD8+e250fHrArrgSIGoHtb3m3Z\/c37y+1jhoBh1PRcLgkg6lMeypCOsKlM4gUlAow+AEdhomtExEIKIMNSXZIwmQKIhgZ5NNTQEfp9oRuIOEDFRgbChOsTg89PjPPbv23vLGe\/cp9DKuX90oZIRgBC4aspO5ZVFv\/y8R9yQxs0rH+3iqY9\/7xvvP\/90vzL\/yxPI331TaEqWtGBq1k0M5YVYR+FADU57z3FMtUr+hBnUJXrAXR2MWYR5PneFApr76zL8S9neF5GxdmROwt5tD2Idgj1bJEV6ghIQEBU2U2Ch1JRKClNITUXiw1\/7hd\/df\/8E7xaJbGhislIulou3anDOMJAWR7HSCZrPd6XT8gKTenDgH4YEiRA2MAMzOGEgBKRIRV7JQcuq5QzvbZDPi63S2SpmygBQhoB5shgEtrsCls7BxCF4EVy7AtUUAAhIgBc7M09o2Tk+ACOm9N0mCAiZsuxNUtkP88EcLDlGpwAcGnaGpwYmT4yefmB785ClusZBhBIyMNItUHLjL9C9CjsSAOBEJVT\/0DtaqD968X9+tt+pep9nxm20ZRKAi0rN1lZgtFZBOehFEEhUBSSKJfh1qW+ZuiRaUxqA0CJ0j7ByBIhJSx6QaMr8SEHhqcw2n5nD6BNWa4A5C2ADGwCowy778+SelgNvfvKYCL7326ydNUwUyDGQz7s9QlDDTP8mAC\/WtIlEjChQBQSussmu\/+YPn\/7vP1Jd3qjcXSWrQnkRQ3RAMpB5KIP2ZB95HVKxA\/VxL1N+mAXn4L+aFZ30ibjO3oj6XTchp0jJJND13Tuqm9wEAMJtTKGI7aZpQl+WQS\/3QG2p9GEUy8puN2iEgR8wjP\/R4mpQWQILtIrfMBYolrM401cXIYqREIRhnSf57EhgQB5tSShgxvOuErZP5URUQRhAiPFjDc6ep3sSL83RnUz92bH4GCiVwB2n\/kHa2QUUwMASujcjIa+DCgZBSILYBDgAQGeojzrXsgmuXC9x1LMfiNuOOhZzpzVIpICFlIEUQRUEo\/DDygtAPRRiRlKAnPYlNVndiE9MzmWCcpGzLtkMACFUEERAQeEfQsJBbwBk4FeRO7DhpQxjodQvAaH8XZ07h1Cw1OmCXgDEoDIyenpm9Mv\/Gb\/1E+G2DPyQFCKjja7iFlgtopdU1ZWez+eopvVkRAoESerhvKPcyAkAKrcbq9tpbi+c\/+8xbD7ak1DPGGLEHEg3KOa\/26n6eP2o1IuVaqN3nJvaVv1HP1RCsHBW+e4CC6SFIee1nFh7X3QzKxCCl6zGNScuNQzDzahIxzG1N+vSjxP1DVKq4o+Mj1cMmMAkqNK2LbIeLCLJua\/N1OCBHqzhzbMIuOcrELWR+grTQYIyxbrF8Xi2ISYOaqGdgarrhZhMHBh2ftg7g7Bk6bMBAERoSR0bpiUdg44iWNiH0sFwEXiEiONgh3wPGMoxCA3RSiBJZmAgbUutW4gaixBcDyWzDLDCZJkzoUlwpo0GnLC8QUnmX6T0mHSDKNkdARCT0l28CEVgFKI6AMwBWCZT2lzBQRDsbOHMSxichikBE3B248nPPr9\/eqa7uxXprAUSIDLnN3NL02fnTj58Znx3hnGHKyEmvh9TDINei7NALNu5v3X\/vfnNvn4QPKorLDZ8i+\/63Pnz5f\/jS3BPn19+4RiLQgnhEBcB0RM\/DHEf9opb6jdv6kiywyzCcP3QybZk+LorMKZUO76l3QIiGcYy9y6\/\/9DC7GvP1REatF\/kBc23kLPZ6YgamahBm07PDf\/tvvvrP\/sV3lpfWhS8BAKR+NZPGiTKVBtOmeNTYT8ctXrxy6m\/+9U8OjpSU7rt2v0IIyNCywLGjSOWTGyh7B+oVImV3qLhdI5EAlCAZwMEBFCvwsSd4oYgPtuhzz6nDFuxWcaAAZNPmOvgemvYdoVDU7XzFlFqQM7Yy6t5usvdblVl+SSiAZn9QJiRY5fqcqekhVVqm+QxE+cE3AiCIAFp7KY\/PLmJ5DJhDkujwEE+Nw6ufh44\/uLo6MjN07Q\/eARGiiEAJ02hlllMZfPbzL7z6Kx8PpOzUO5i+1Bl1e1qJxhkG8fbvlJznf+6ZlXvbX\/2\/\/nj73jJFhCQMrFEEUbO5+e7imY9f2Xz\/now8EH4WNA796U8P02B3mw8fut6oTy5vZgbfTTW1ehLRIC6\/MBPb2zUziQ\/x7vzPLqFAHuebr1PzOTUEpLx6Bwsus20V8Nh9n5vTcADRDs8eH\/sX\/\/Mv\/c5X3n3tJx\/s7hy024GSESiVAhGMu5wjd5njVkr2zMzoy594\/Be++Ey9I4JOlOn2QALY1WIUbjuBVJ1aE0GSQWfHL0RS\/GTzIzLjgvTEN7wwBUyAQlA27NWcnaPJv\/ozGEQHC7vB\/V2KOrC7TZ2m0UbqQCUNINPbG2RNmInCIQkIwG5xL6bvGWTSKbJTteygjJJVlyoBKI1AjH\/2ZNH1oXclYuhE1EkIUQfqATEb7DI4A2DZOD0NIpydxZX31hrrO6T5y5pPiQy5\/dgnHv35v\/Gp9390\/09\/76127QhklBRjlMB4MGtSj60QyACZ7RROPnbqs\/\/tKz\/3P\/7iv\/97v1nf2aGIUNfVMiIRrb52Z+6xk5Xp8fpyC5gFjIFKLYeZHgdl8EAPvRkiZtKxMi7l7kEi5SVqlMWgdTO6rT9LAfPwMxm7TlikDJLyoYNH7G0kKZ3H0t49lEpyx5GMU3KIZaaojKi+0\/h\/\/6NvvPjC8S\/93BM\/+\/NP1g7bK8v7t26vLy\/vNmrNMFKgiIGyHV4ZGThzevaxK8fPnZqojJbrgfi3f\/DuvXsH\/9M\/+BxPCRQx2jOe+DtDFemFYbVmOtqUArmSYCPM9IGxqzOcq26UqUhJgpIlbg8XS34R7Ttv+G9+AF4Vwjaq0KQCxjFo2PUmZpPh0mBLTNOMM7PctHmmW0fZ+KFMJl42IDUGj8XoMVN4Eub28+TJ79peifpgFGLhCQkiARur8K3vOKPDs3\/+wvXf+IDC2F2pP5RZlbHRl\/7ci3eurf\/hr3\/L63QobKMMYrsmxrB4hT3dQ\/NNMO5x9+aPm4EI\/uL\/+HOXX3n8rT\/4nhIhEQFJUhHK0K+1DjcPT3386rXVDWKcgHUJTnLnUGI1TGse6uI6YQaTgr0Nz3RKQV2WJepPXSQLs1\/8IXEvmA3RQOzfKO5iiuZdvvlhdxoDGhdOCkgF+0fg+aWZibDRABbXXZSaepRSUqmNzb1\/9W9u\/fEf\/eDMmWNXHz392CPHn3n6FNgWAEghkQgYA86kosAL97eqP3rz3q3bGwv3t\/aPvPn5WUbEkUH6TmAahMDY+MU52QmlH8bfVRIglEkSIurrMOtizZv\/IElKoPD8B6udhRVFFNy6BUGdRBBTYWJxlvkqWYwBdlUhmCZ950AGyaLNrMOu8oag2wWQg3RjOhSnbI8gzw3M1uPZGiWjWMi1DhQFbbh7s3zltFJn6xt7hnxhhFCIyGZPz8ycnPxP3\/i+1zjSED3TOMGUWgKZhInEiWCOemTAI0ly\/dZqY7fx6MuX3v\/q60HYNuAvRA0L3r27ef6zjzPHkQFPsW7pyZcloFJPS\/NhN788pAIePlDPLAXqct5CJp8wvXqlOnPql+P0UVbefkAZSgAjiBlfOMSRGGhiMUFJGcjmQWPmydO1hRU0h6GM73gERJJUoKQQ7dDvrK3W1la2f\/T99wcGiyOjQwNDlUrJKRY4AkgFHV81Wn7j6Kh+WOt4UjEHGAKzlOiIODE39gemlDdkfOLKfH1tnzTxNkn5yaqdiHpegMwAgzCjKwRSBIxAhRQ1g5WFtf\/1XyKSqNfT2HqSoFQ+sgtjtHn8CmGX\/j+9JlDP25mk6vb4brIxCFm9BgGlBOK0GM3w4buSQrD72chszV19RdLNs2BkuhLsNsKmn0xEEBQBB2RuweWI7YZHSmDkg4wAOXIbGQKz8hMLSre\/uPlESoIUxKLIjzqNoFR2GedxLaCITGZ4c6PKi44zUPDaHJBTL27ko+QylGvSdl8d+5rpqe+yoIe4Da2H6rAzM3Xq7rHinxGO1qUqSaYQ+spPGROi6QQY+d\/BvfWzn3n6nltQURsZJ4WZQSpKglCRSTxWEpQQkTrab9YOqjoaIc4iZ4QWAZA212hAk11CtJSIQkXSbKJJSWMCZ9xKcXRudPW712K\/X14zkNmMsfs1yhGek+a0SUqQ2s4XiYOOnumnyPAkyDpeWClpV7e+YkVO\/tKfqV1zTQRzL8wsqD63CcpM19K2Uz9wQ16XQnkKRO+MKvfBSClpsjI1uP3+GgmRxoPqL4mAANKU3VzvfWjhiafOn3j2\/9\/Zl\/Zacl3X7VX33nff0COH7iZFcWzRHERziCSSJiXZim0hUmw6spUJSAzbMAIEQRAHyE9IkA9BYiROgnxwEngI7NixTSuQZQ2WJTu0RHGmJJJqstndHHruft39pjtUrXyoaZ999qm6zwQ\/sJvv3aGqzjl7r7X2WvcKssbSqzkPq3a2YCayc23rtS\/+1eTSevXXSlRXbS5VIvJ86\/z6tfPXlg+sbZ\/NpIkZbuAusmv0nf1+FW30RQyFJtxKQ56Q0TJzY3ctl4hgO\/R\/owzhtUULarqiflbK+fG55LP1Y++uPPX4nsP7r2xdqf2n22VwbWN7Zc\/yDYcPXF5fFw5rUz2SMwo1sQIZNMPpkNJlJMuy0QdvvRnj0dX1K5LPpE1EGWAwlOHo4F0376xvr594n\/lMONdjoOEwGK0IlxoTCw1Lirp7Z+naBgpRVLAkahsIu88xLuebza9QJ5H53Xp\/awea\/HiQClukotu0U1SAlcPXNreMDQPCu6W0qkmFbDxeOXLde8+8wFoTX5lfMKuOS7KtiElIcctDd973kw8XxAyVILya0meLjGUik2tbJ\/\/qu5OLF6sgyqKCk5oPUDKfLObFzs6105dXPnjk8hsnQudCduvTyAbmcM\/KGjSOtdWa7Uws4uYSDhNnmuP+5oE30algXKV07ga1mKYFcSrynbkUk80z58+8\/NZdn\/zwi++eZj6SYgbWmsli\/vILr\/\/s333iF3\/50\/\/pV79w9szFIstkPqh8dfV8jYAoSm5QBmW8QTbIiruO3vTLv\/hj779z\/pUXX5N8CtaxXtmQg6XBeHz0Mx9959k3phsbUszQpi5LEJ9m07aD3Eal3FNkbRnLXhpjN\/uOGDGqc6NUK15o1AAwkesM4kWaYtYsbJ2wRr2GGQrT1Ux2c8eCesyrzGi2qBZGWVpdXrl+72Rro+qB2zTPOlCpkCKv7YYhzOXZ3\/raK3\/8nAzGIhlrfwqGdttSzIvp9vali2Rjss46H4C1+TSlKMqiZrK+efD2I6chAc4rqHBph3EnqOYPVRHhdI\/0hNUpMbbOPEQTEkrPWNR1oFJQAWJNju0Vkpoe7aYoQikKFLkUM86n7zz7+mP\/7Gd+8OXnN96fymBWdk0iheSzN77\/9n\/71T\/6lX\/5uV\/7d7\/wu08\/+\/\/+4tULF65Od3YknxT5VFrqrxSzDGWwJNnSyji78bo9P\/rpR3\/6qUc5nf3af\/j9C+cvsjRmLxXVwyUZjg7efnjPDfvPvvJW7VCSs5la0NPZqkoHxRA87aNYF2x1fViAMCvOJrOya94bQeCOmUxRAx2Nlt7REzIkhlqfFRi9Fc3cTKojattYSPgGCrPNxgPJkE9moTZAdaTlOVcKaEhKMd28Nt3exmCpMsiRQgWJ149ePpV8R4q5YFAKfQpSp4WzdQYppMhnm9s3HD0UnPNtiBOhcSYGY3wW+Q1IPtrGkpGrN0wQY50QyTaodKhYkZDO18atusCUCN1BYpO0idnlY99WqI03I0mUHXY+vXz8vVMvv\/WBTz547A+uFpURSyGSs5gX0+0\/\/\/oLZ89c+dnPf\/yf\/Pwnfv7nHj1x6tKbb519\/djp9947t355YzKd5bmMhoOVleG+A2sf+OCNd995891HD33gluu2JfviF5792p8+e+rk+7WcrfJ3k9HyaO+ee37qseNfeXHr\/AXOJ5LPWeRo1mFVr2nDH5oAV7sg9QwAbVIrXZanRXQa0FzZVDRokphQdOplAsSyDep6EQn9lKNrNA+RAYO9bQNKGlUfGhThbJYX87zprMEakNP4XTlQ1vTeRU7MGoCrERLXoyS55DMppiAlq4OQ85YXRVNjV0wjWRRltnctimxVp00ULsOuWcL9K+l8IcmxJhMXk8odHSI0UKFLFRIUN0upNSALuTI94hQfslamXhpSsJjLfJJvbx7\/0rd\/5Ff+3oWXj196bcJ8KlkhLPGM2Xyy8d1XX3vzrXee\/sPbH3zorvvvv\/VHHj\/6qc88XAyyyWSeT2eSc2k4GC8POcim0\/mV81dOnjz\/tW++9sJzb5x88\/h8Nm1WIJAxG8loGaOVmx+5e++R61\/4718uZo0LU16nyrCRtgUPLmPAgnHSJFqMu+H94QnbHTFfUGcyOZjdRHuHkomY4khMqmr5qw866O40OICBUNMPg+sXpVoV1cRjawrSWCJI7XTSQBPIhoPltdHeNWDAbCSCKsqiRKry2WxrY765wdZ5pCb2Gax8s21kwwELWhLGdgOEbe09ZAWhJsZlMsgwNxjuOEZ5VYedXH0zQ0ICqZ80bx6sQ01vwLT8jQypnK0sUMxZTGW+vfnu2Xe\/8fI9T33suXOXJ+dLbVqp+it9OOdbVycvPX\/lpRdfG42G+6\/bf8Oh6264Ye\/a3pXl8WiQZXmeT7Yn61e2z124cuHMhc2NSS7CMkqN85KaIDIOlmRpGUsrB247cu+n\/8Z3f\/8vty9frpJDqUPtibjDZlvXaaoWYR4xqDsmapNmGpLV8P6dkLMSW9HUhQmInEGVoxR4CAb16Iy+tDsHoxEi1UIawoLt2HsxnUNkOB4Cg6ppM1HwlRdxVr39YHD\/5z5x799+lMS8EtwLUc\/uFjz9+qnnf\/V3puvTanKy5kyKKu+mULqGMlshAzBeXSo2t0PZUMzjhZujfYSdQhQ+tsNYIeMLXiAiGEa3MLkWJSKKwnnnDggHxkgqmHdAbYhQ5MjngimnOz\/40rcfvuvI0c9+7I3f++Z8W2QGmRHFtGLVOC8wFexMZoNz29fOv\/+eoNxSA3FLRbir0c\/6LMtKs1CM18YH9j\/4+Scv\/uC99154jfOdxsKoKY0qQE5Xm9QYqRaJqPXAJvUAWgONdvTf4J\/enWe\/c0G8AzL6bHHlFFaPXr9O1beQDl3cqMnaM7QZem+mU0lyujXZXt8YroxLgYR678oHp6gTSyUbsCiEcu39y5ffPldQ5vNcgCzLKMjL+GIp1k+cyacz5QaTNU1pUWsq2vVdJ14s7Vu7dOq8VSOQ6ETEAqiTthNhE1dt1dvoCNw2l5tKMYM+\/VoAvlCH8hKMiMGI1KBq4DWM0LxyUcWV55DZ9nxz8Oqvf+nRf\/pTg6ce+97T38oFwpyzQjBvm3sUIvOmFmALz6lqpOmYTPTaaFnGa8O9ex\/5hz\/G6eyVP\/iLYrJVzdfkVRozGptK1gxeZxA56pQXzaw32hQ952kOTAefISXdYbQ6VX0YIsAYbBsSD5QFlTURo\/YB9BpmpEhIHurDo5kOKstDFsX2zvb7F9Y+cN36sVPNxGB1Whb5fDqdiGCUiWQyGJWoxYlnXjnxrVer64nKig4k80k5hMXZDMgqRU02wGAJo+XR0rCYl0SF2vyzAbMM49HqTdedfe77Si7byvEkFEkjNWKvk+H17qnma0ADTMcvRcv8VwHF\/UR\/WhbQOhnrHw5djRmlZwuNiUijm5FiLvmEs63tixdf+o2vHr7n5gf+zuOD1TUZrcloRQbjSoNbNqPl+VnkkueSz5HPUTsgSvmXCosDKm9FWVrFyt6l\/fsf\/fkfHw0Hz\/\/mV6dX12W2LXWcEFoYXX28tLtrs6lHwtiAY4RzAQm1ZUA0wqYjMcKrWjY3OihTMdTSDEy0g9HtS2vtT\/Mv3INXK1RSj4NSeAdgbLV\/VZdx++z6Bx++QwaVw2oZCEMRKebn3z138eK1Wx64ORsNZGlVllZlOCpYFPN5ns+LeV7MZ5xNOdvJZzvFbFrMp0WRS5bV0TGrMt4jSysHDl935NaDb796cj7ZqcZHSntbQLJs5bq9+w\/vn1y80qgRm7IoZDndeM+QGLZjSaquplbA0RtKZPgWtUxBxjfZthzxidlm3gQ7HxJxbo3Sv62i9ECAHr6ACfzVe8xkY+fSOxePPvnh\/XfedPHti\/lcqvwdGwUVWpS3gz+VLLvKexqMZLQsSytY2bvnphsf+6WfyOb58\/\/rzzbOnZfZVpN3XcbKNjQ9SBMLbgtIX8zXYNC21lSIMzudaOmWqKm8PIh0EXnmAYJdXXDdTGylFbg7EApiitopCKpQ0cF4sLp6+yfuO\/XMsXxnR4rSN7FCZabb832HDtzzqQeunt+6dGab2bIMRtUQ12BJBktVSCuGyEaVf0DpmzgcY7SM8V4s7d1\/5IZP\/qNPXv+Bg1\/5z3989ewZyadllB2zgQyXZLR8\/T23Xn\/PB49\/6dliZxP5BLUmEYFJghGIR671dgulX0SKSErfEA0ale8+RAyVB\/K\/eJBXBaLVlnEtgNbmwEiizmWo5GA4C1VI0Vjyg3NcPv7Ot379T+7\/Bz\/60C\/95JtffP7yW+9yOqrs98qMCn1qKXhB0JagzAZ17MFytrxy+IePPvDUY1feOffq735969Kl2u2rtD+oqKqawqL3iNPubqqUAT3lvGnyyEDeYLZMJjk5zwda3ZI6lA+R+MXWt7RvSg0K0H0oVKqRo8BRQ+\/NgV5KcPPZtXfPz\/Niz5GDl66sSzaQPBOUdjvzfLr9nf\/zzI23HnnqX3zmtcdPXDx1bjadTWfTKVlwIIXMZ\/PxUFZXhsPKx6BgXZIjG2TZcHnf2p0P37bv0J4\/+x9fPXPsRGkPVyWQZkMZjDAc3XjPrVfePjvf2W7wNm8KUE+vu\/0b01hZePvJxDaGUIDVjL\/sezi9f7qbbJTLi+D4rYWh8I4sRGy9qLzo1nmNVSTQkgzHGK4MVvfc99NP3Pqxe9\/+1psnnvne1pnznE2kqLiEmgVmq5wsg90rl85BafycLS3vvfmGW5+8\/\/BDd5786kvHv\/Fivn1N5jtVFdoUoqJsHcSd8OQC+KWhdBg9sD4dBytjQ8dbUHGtzbVlkq1N4az0hB2Nd4ckZFPKZhZNqnatIMoyYMAybmlpD1YO3vv5T3LC159+hpOrMt2Q+aQyp8mGGK2s3XjkI5978o7HP7R2YHXGLL9u79asuPLelT0H9l5348qgmM4vXFkqOBRBq2OqOI18ll88deGFp7\/95jMv55PqlZENWHf+SwcOPv7Pn\/re733j4qvf52QDZdRPRUHV6XfB2JfbDMcaNBcjiOVKCYRG\/ZxahPExGPJJNoNJorpUe2zHLsA25kmxiNUKzKgDm5oacrAkw2UsrR2845YP\/9zHlw9dd\/zPXz734rHN8+vFdMKikDxHmcxcUEfAVvby2WAwHq8cOnDzI3ff9Yn7L7x1+rU\/\/MuN02c4LZGYeb38KrdvqhlzWBrA1CdwBO+UDoVXwK1jsWXmtBZWZxqmMocLGG7hLvEwt3kA4MNDdHqT+qZX9YsIsqw+iJZktILx\/gM\/dOeDv\/AT3\/r3T++cPSeTJuenAMDBEMMVLO1Z2r9vae\/KnkPXP\/GvnjrxnVPX3j730b\/\/2Ejy5\/7oOye\/8YrMths1L1uOsijy2c7Vzfn2NotpbYIMDIYcjmVpVZbX7vzkg7c\/ce83\/\/VvzDevlmneyGvnNdXzV9suXESK4nuJOoPz0HF3SRgleGaGXlCb9ERi+2OcVvsrfeQhW\/ax6pFaab4UUkBkzsqIISfzy28df+Y\/njt4xwc+9KmHHvzJh69duPaDb37v0rH3J9c25zs7nM9Lf1dggGyQjYajlZXxgdXDP3zHLY\/eVYyXzr14\/Nv\/5Y+vnDqd72xytlOVoI2akU0hqsjXkJJtfat8yaeeDYUFEuEpIQLXK6SLECZP2Y6rHtFOjERzKt+ATlpJMKcc7xntL1JbH1az56Uuv1Qj7lx99+zOZHrko3ef\/JPLHI6FeU3mF8IZSSnynXwy2Rjf8pGja9ftuemOGx944q5jX3vl1S986+rp85xscb5TpwhTKfiaedRciqL6NM0WMBwPl1fueOK+k3\/5ar5TQd9opvUl0gDZoSXquZUItYYLXCkVEGMmEu1UdWB5SO+ZQM+QEtpOpBSiRUA3rXKNekbcyC7CmaBKJZ9LwdoCuFQAzuazyYXvbVw+\/u7ew4duvOumGz90yx2ffoSjbL61IzuT+WTOghgNBuPR0p6V5fHSdGPn0lun3\/zicxePvbt1\/iKnO2Wgj8ynKOYsjJoxnHBVzVvoKMPWQdaI130JCk1VAqVfTzBCqREYJR+F0U7HCSdgSs7LAKC3KV+BGk9SKF\/dgMLExrXVQ2WpPJdiUmxvvvn0M3d+7uNnnn9r50zRTDNXNzefli398v6VO3\/sgfF4MNvY+sq\/+cqZ774x37jMMhymVS\/RXlYqdWYVtjeS4TJG49sfvzefzN955nssA31rKWI140qlUKu9PXTZhwYbF0TgSGdPgpjSh\/gIjwwbuYaZICPTWmIlKPZ6JGqb36j+TPa1Yc1UsPkgRQ3lF7lgznyazyfrW9fW3z6Br4\/GB\/ctH9yzfGB1Zd\/K0toKMhR5MdnamV7b2bm8tXVhfXJlUzhnGWTbhq6Ubn9UMZ2N0UN7RCBmddQIL10Re9vFV\/QgbEVJQ6HXpTp7ekw7c2GsDGI\/rrCEhl8ceTeXCe9b5+dR1zNQJChBNNb05ZjLbOfy90\/sPHn\/HZ\/9yOu\/+XXmpfdp3vZGzFHkRz76Q\/lg+Of\/9g\/ffub7s\/WLrDIqpmAuhZ5\/DyrwejhQRDJkTS+6vHLD\/qOffvi7v\/P16bWrpRYKRc5mcitSz0KX9xCvA+QCWIB5EqIRw5hGrHtCtWaBCDUKc1CgCys3\/RvQ7DlSbaFYSY2xNqqTDMuoejZsOwYqS2wo2QBVDLp+WstSJ0eRlxb3pRYc5X9TxVHULsAa\/HOoWO9USkx7STKvignNXwo+SVon9EJophSNPWkSNEZajWWJa4sRoJofqpvDUh5YxaENV2R5z97bbvnhX\/pbb33h+bPPvV6lUJQLTEjJMBjsuf2DUgw2zpxnPpWKmp+jmEtRGH18jZDWIWM6QnxpRcZ7Rvv2PfqPP7V9deOl3\/pyvnmlRIPKyKeqt1SQDBswPDAXpFG6q2kF9mXxuuMyzg800Wj0FGoIkRmExRR9BJaxNI1BpcRI7R8aLwBWG40ywgxFCUuzDMGrzP8GyDKWI7yN9Shqbr1y+CtqE8667CyKdqhPpfBCHYQI0LD0bkezxdnRZob9JGNpJhrBW\/TirbKGEUbNnhUo3cYo9sBkK0CMPVUCo6n2zCOUsL86RWpsvCnzCilykZkgk+lg49SZU19+7r7PPbp19tLVk\/PqBpdDTEIW843jJ6sJ3jIjuSha6Nt++\/pyNzaQ9UyMjNey1bXbHr9v783Xv\/Q7f5bvbMl8okT5KjS7floQpjWJNyzkFAWRo6ELoNFZjcFtG2B8pHtfrNBnt9BhpERrjMAMVQU4wD0kmtVS52H9EIaIT5ksXYAEi9JxuTZNKEvNGfKZFHOUrEOZlVcVn1otIQYChRmEICXlN+BCpokuOqwTxB8WQtRv63hkBvYu7opazG6kU5SIiIOkUf8Gj2Bjy1vdJ1aBd+0tbInN1nSewMaZK4Lsw59\/8tzr78+2Zw2WDhFUC2+OKgm0qJNegyZHubCijkwtE+BKOHQPVtZuf+y++z\/9yDP\/9f9ee\/e0TDcxrxDRata+pumdGw1fQdYMqwN9V9uXGVHvVeZuDDA+Eu\/PZhHC2QEknL9Wt4WmxIpzDZHQCMUBFghXuTT+R9WAH1leWbRnXQ7WbkIlYlZ6uig\/aakPWNR0PEjnBtjjh76OpXeQOQBv0AnAOJnkVeXlJuIlw8xdzZQvyUopli0z3HGMtjcJaj0jjFGvrQYoG6fXx2vje37miYvHL0w3JsISh6Ow0KNfsa69pOBRZYZnaGMPR6gJiWxl7faPP\/BDf\/PBl377qxfeeLtM3kY+lWJe170SnKtKhht2H7SyGLa0aB2vGQHjpJWnSezJZNdCcxJGz0fQGSJZ+USEYUjjh+ahSOir4CdAtXhSwEmzIakhbcZgCQOgjfIrmqwlkULxB0Sro2W8F3aZyCWfwgXOGwRDSABkV2s43Zb1w6qdhSt288OJisnmoovdHPTBThbFpXcuDlaXj372I5sXNrYvbQQyw8bpsFnfyFgFy2YotRyDOmZ8MKpI+aVVLO8d7tl772c\/dutDd373f3\/9zCuvc3JNZluoLPdzpUPUQEtrLWtNTBi2cDBtBP1W0Ldmc7VK1e8MMD6igxPRnvhJOqr7QIN4Yhp0LDl461M6WEpY9aO2DGSzOI3vLZTMmupOGNp60RVBV2pr\/j7a19onFrt\/SyNBdMVM7HpJxgvQjERAnP6z81PanOYIZEKsamCRF5ffPgvg6Gc+OtyzZ\/PclXwuko2q2d8yOLnhG1BHFGd15ZkNMViS4ZKMVmS0IuMVLK\/uv\/Xmj37+4\/uPHHzxt79y\/rU3Od2U6Rbq2bTIgLyupzpGyYypDLoRUcPmpKNinJ5w6YjToQHSE0iPSMAExFUtwv3SOUDgHNiIlN8S6LKbrQiBOq7+IxpER7R8jiraWoL\/WMQZx1FKLrCEVDQPvPMVMVPogqsUGwmWvk2maNV8A9IHL8VhBI2LqbuaY4zU9rf6FKn3RxYsiisnzl97\/\/KHfvzBmx85OtmcTzbmZFYvtkELg2fDWns4qqK\/h2OMlksUFMtrK4euv\/2J+x\/+2R+5durMd\/7nn15973SlyJ9PUcxaMYaaC4ETKa+HS2rzf1dtFFwseDdVH5vx1haP9u59MLlzq5FUlYWQrEhDftIcC\/CXMeA\/HWod1uhPcGBS\/Y+WlUTQBtPqp1tQNnJcjldatzyUIBwyoJs\/gGfu4apnqMy2tPNnmlQQj0IMoRbobZOLLMLkW3g4oSDWyrElq2p5cHOaDcYYLstodbR3\/x1PPnD3Zx55\/8TlU197+eqJ96YbG5LPWfkjKk+6rDoSkQ0kG2Tj8coNBw\/df9uHPvXAbGPz1d\/+2qVjJ\/PpThW+XczKLDQJrSvrWBGHgVBzeeZ\/wcpk4hBCJhVqAANGI5qxcBahSqyo9opKOYB4CcWFqA7NNntwsFMqvTeikdPovSJjR7abQjwO1EoP4D+GgYpHNVfwyUAX8+CuVqCEoLEmkZQuLNb4iuut0LcIU59HDf22YRax5L\/JZrSdAhPoDyzYAG0H2TY4bPu6AcuTbTCWwTJGqyvXH7jx\/tvv\/omHRytLZ157\/73vHNu6cHWysZlPp8zr1PQsywbD4eryyv7V\/XfddMdjH1o9uPfiD9478c1XLh5\/d75xldVQ6BStHiNXPl1txquVhkoQENY+QaT3WMWbUUwbKhaF9KwxlO8F9j3o+d4nsDV\/HcJ53hi1HGL9cksXepixDONMlphgZDrFm8FTU383iwAzObMitV9AssJbDLLpIe6hFiGNkKKnNGakQ\/ITnukDP0Y1QS6KPFlFMINyxngI6Wqs4a7Kbr5y2SqrzWGl0R8sYTAa799\/4LYjh47ecvi+2264+eDOLL+2ubOzMynmOTPJRkuj5fHa6hKmswtvnr7wg3cuHHtn48z5fGe7UqXldfww5zUhwcYBMTCzMEuC0X\/4tqKJioD0qflerUVlCLLvQV+d69xzPYiExGhvWX0gdLJyhy2kNnhGl3TZbrG6LlCniXM+m0K9zkX3VQ5IhlIxeUYujGHKwiQGFhPHpIGk5FKu40CcJQaSu1n5UX8J225YBjWUQ5U2PwBYRiY3jV82ksEI2VAwGK7u2XfowPjA3tG+1cHaEgYoCuY78+nWZL6+sX1xfeviVeG8XXvFvBEDl4p\/0PJSNqDKXWNqodJu1glxDHSqmrewnQvH8DDa91DcViZ83uIhHQRFDpIrQHSOPQPxUYL\/1PcYafZbL0LYwi+BVsAoIcyvk85Is2XpDIsYV8UMS3J0LjP0IbCdYHH0w9aXNAkiAfUQMK0cAbvgT6DuvuudWE+o6amrZv4QNQTKGIwRhLgEKo\/uJui7SZgp8tLMEnXyaWWDH\/d+seGq7p1JuuPwTsREYqowkOkad16GSdjV3wx74fdAjdO\/WauYvmCZ+DqTSJqB9ONlZs9hQothzzS6e76E6w361RqzdapdIvbjcoggIl7sSDQPkgoBQtT3xdR8ag0HLXBae99sDdBYD+NNExLHATrL0rQnjB7rwClT96NsvfVZlEygMEeRERnKP5YGSNWrBmr0eqqmxDwLFT7DykHTLDa7AlO3ot2QLLiRaDMYNx0wHTgN6U4T+VtrR6E9NugpNqIxOuo0xFDhwBi0IMwWkuKLnVXuOf2JtY6Go02hYVTjukKbYjMx7yeR6Q78yr21oPerRaZm7ROIrFuLdO+CiTG5qHaJJKKMQXggzvLqVM+YfUY37\/RtcNWTmIMgqnlQtjItOMVNE7pUBcuw8SKh8kqHRN1d\/HxGzrENa0V0l+eBuXna\/IIL9PS1gJv2DbSVZCskjqJ\/hQuJRTyuTTwHviZ8D8aTyDDUrgF7+MoM5u669ClcgBw3CuZ4o7GJDj4MEz36hs1FNDfaW1lHhXYwHOhcaUQyWY2KqhzejqvDIN4CXu0aCoQUl60dlUqBSBkxXoXQ0zmBwRiFVodb8yQ21nVRalWUcCj6AbcVpmnt9F2BY3yf9Kf0KcR2QLV6RodpPEFdgop2a6PzLBfZljpIEG9gzz4BD4YyJ7SZNghblxas84yYkqcbEk6PcI45ekcT00w+2o1VoPdLL0TNXPZgmAqdRx9d2E2fhWSX4CPC+MK5CR\/i7QSsaPp188FQZ78qbyRR4y\/xHgajSCnliNBzgGpxRnbmpjRFdMAHwal2D9QrkIE7zG41h7RFLEUgA4wPJ\/CQNFoNq31poBU0PwBzN6ULrGeHrLTj78U4vyRpM8RdCjrwq\/B3UhfDPyKg3wzpAT86Vj6ee14KuHbyJ7xaNPayIYIhcavUhiPqjr4LPYhu0acRqi01WlO9t1O5ubZWBo3WrFls0IedbkAsCcFAMOwCnuFAM+IBlyS\/xQSQEavnQdtfyEDGRzw3NaebkGBAJWIlTOEJCN1K1F3mQHLYtw+ad7gMdMdlSJOikOymujFJjzti2iPG3WT8l0\/Ir8NkPrE+dnAuE1oVcBD2BWP209JNKUi0vTfBsAR7ZKUITw7Yde9Ia2P1vBZOg+pcCurTWpFiXIztmjH+MV0tnIlWhXjimF0qJbyqtPynXISM+Adnc1XzKdrS0JuMAUB0Quvw71lipXlLFOlTSBLwXfq06SLuGAE\/TF5xILW2et7FjcPTXoZ6ZrgNr48vmZqqJp00dmiJr6OFQXdRgbjoQPdXpENdIYBgJVAlajAA3hVsNMMhics6n4Ex1aSuGtOMX7RLx8467GYSErVRh65ELUK4j38UpNRssvCsKVq6iCnGgfAeSziDhS44YT4mE0OyzkdbgGFjjCPBEwwx1UJDXAoBQD\/LVj+GSPw00iUK4NSjaBJpKSkBN\/TmhRY0YXoXM\/mLqeXnVP9GyV2fx4FCvJEIQwTd+yN0LA8Q80juZK37RzbD9VGd7++8uk\/vF214Yw32n3KekJ0sbAzTBzeBkjL1QzuUi9BsVoOcvQWn84kCZTNb8Zu2ycAujqKuy9\/\/i9GRDdspYcE5DSDeDkRciUJYS6oHJdCZMWgKEf+KREG7qYsRzkl5TSx7WsOIY1Have6Lbl1Snd48YALpsJxU3AtCpLPTK8TljUBLF1rmwFEYQcRFIoYBKSndB8uCJ3HoqwJGjFQUBUdX35ymExCGT9jWTMmyXUl0YgXCQTXa5GL3s3SexBDZ1dy9uIMSTZhmV7nnK7GcTDSg+4Awl4z1DEDfrt\/cCPQIgMIVaFBUpk5U2Lz42ISx9i3U2eaGVEfIX\/Q3hw26UTTlKBAF1NMV8cNdvhUlE77tMNxT43VAbWZnUdtWii+BMbO554s8f3ShbxcyRtrmrMm3gES8eW1K67r0uAB++BBHnRIQbrjwwEkm7kXS4jpxhrATAAgdRGmzYHV+L1LQoPrONOOISbyIf21fgESgir2T8SUIfcOCxz\/hSmgVTilSytdCxeVvmhg0miXHe9RtK7M+5qfNcdUHvSlWNfNiH8Xk06P9NKk8ydnoV0wQQMJ+XL9NG+jZbt8tpk3phscS15aphp6pOrPXH7b2cu\/5BJ1VjWj5SzclANvB0Ar8geT3p0vetZGotDRg4tYk1XT6NGMdMEZjOxJdeV340SxKBB9SdCQcrEu628DpqxRbfgUVHEObPKZQH4r7MAuFw2ApdcHkXtHmCR3V5UC65GYIDKR8kPxfh4mcroJUNTkSWbiYOtYf1KrHvyw8wnQjmJzn6p2Wjz5A36mSkjM4OEQPZGeUocoSrb\/w9DZTv1KnQTtgu6gg5cmvi1L\/nTDdMvADPJipbQ6le0dO79lMrZOQA2YS6wiboNptzWZ0BXCwSOwgAwsYoJtbE4ddjG8kNIgWsc+xnUmaeqiG7gkE\/g6w8IFnO4BuszH0EYNRTR+kHGkUBG7fmLJgY2Sd0KnZprllbfctEYCTWAD1LunD5+yGL3sHMWB75yZNwXDmuvVdrIDpWsmqvEVg9G9oRqRLEAuMMYCenD2Z8Y7Z2tAMnV0hfJjVr2nSLNJ9JG1\/vT8C6YsFRYVJlxmE22aoMW7xJCsWZoEL+zC24UwIlKN+AA5eQ92pMUbSe6cVGQ+RVPsJmewnYJlDjau3WjZLe2qQWw\/Ii+fX7KJWjFRmnYdpi+ka0WYoeSMXW3upM1MHqDA4R9ofYXpkKfxjXMHYLm0XE9rDmAaM+vlQYBx9RATWKIsh\/FR7H0D\/dGMoisYCL9iHbsQmdsazpxybcaaxYvDRSE\/KHYDO8coQ3aeLnCF9uPiUF+O9C105lnCffUbRI6EnT2Kah0HOArpJnz6yL2A4UjA7o6uvsnFSRQpjRsH6i3bbJaTHUmjLQURAku9Ra5oqKmAmiUY2BalD6JX8nB3AgdOc0D1iQQkUWFQFcJAFz46SwNvA\/AoxAbUGllmQNDRCDx5oVBuED0uEwqJg2oOqTeVCm2d89DEYCoy9YJTIwJpEKmMjlwrrXkYMqJzeO5J4wuvZI7q7LJWCtEFaoAqdYEbOqFJIC+S0xnspyCdA89LAWPWQo5qZYkps2t7kVEcGlALuI2FlFcUnge7EX9sdho1cm9iu3JngqmFcf5rYnCjuQmnrZdsyxWHAyeNBc2fs6jOT+1T0R8T1I6XzsAsbNYrtArTAGWbWQhIO3Ck9roIAetSAiM5XxMbSsfmBa6oQdGCIAUqXrfefXadni6XCNHohtodJcm+A9JQ\/irhkY4ZXlgt0jSxiYWfcsAHDaqaLZlY1bXAAH0ZC2BgS7VAoCKY5XHjMJwNJUdsvaIeqCNdBWJ+gk31h2O7HVmdmPKojnilZResHgtYTIAKQ4aoFxBm4MDtkBArG8B7dQwzODzjgtuXRApMQOBxF3CPQ7dPswtC9DNWEYzxdyLiIpXdIexoQhGUNwmVNBw2kukO0FrCW+apsdKJm2YeegcqBG7Edg7WR7h4DgKMXbdGLYEeOhKzwI6V1moEG0lBbtJnjFB7vA3huxdJpKpfeKNC59PpbcCRwNnuNdvu6qrZhH0ZNvzjw7GERdbYRTAsP\/Uff5aRRsFhvTKT5Vfg0aNpvvPNkQ7BgJMV3+CAMPF9g9tyiKMmzrGyGbrcZTonHlzz2vkMLVtD2eezpcpL8mUJI6G2zsfYFqR9JAdbUUQRmlRrOhtzFCmTKYybxvOzClM2eutEWiz50vuPhZtCOKSbPK3ijBypAUIgurjPhPwWmBEbJt7bSKPSFkTGJb3XntFqbskYq18+uMsjhtWfnUDzSO6K2vZ49haGrPTRyHbZMWTRExl4mAm30NsVldCxCEBodInH9k5wkA1i4ewXaqh6RZ1t82WgfTexqy2qlBXR7VDJ5jNOhzR3MshpNbB6jRKvC3kNLImFqoutLQQQdBw5Tb8EuOICS9vn3yY4IEKY44zYGhG1wIjp9C1FP1qfE0\/DH9HprI0+Oax7GOBYm9ujvSlSzz3r6I1VgeyTeSs42aBP+wIeeiXkl80xHjzskSnHpHPJAYrSkY6wRSaLAJ2XRF\/cLq3D1sIFEEsNCBLo78N1bg0bjEZFuK9EF0z5sQdQS03iBWnyAnlprEtJ6Nstw72hGfJqfGGDpcHoHCrvK\/r4lNL23NRI8rKRvyAepBzTsIzobtrC37G1awhEu6LkYwkMDo8cynoxViKQ7oUcJNotUUpDz5DFK9UA8DeoJJ3rvI+0UYLLUly5l3i4K4+QHriKc7WXtou8DNSwkHu2P9+\/Aqyb5AaEeqfSgWoTFUkd4tlMIoCBTfk1h6JE5ibGLgZyQfwrHowN4Ah1HaYjbxbcfTQqa1UK7OxPFoVkX6\/7RqrbSK9B+biCEhWifhFoTXxJ9yk8sumyURIazO3oobu0fFALsu4WR5IKSGApjULU4eE2sq+4mjRhovpvzCi5S0tmFkwu1UoGxHGPUjPbGsk7LZOveBgKxfjXgz5CuAeqTEH7H7JWB2M2xJV68bzhVicQrmSESJM0voj\/Sl5aiT8iI5HcM3bTRXwikiKj2IGcaQ+2xJ40XgHvtA7fXRfrMvobU+61FXheL3gN2Xz2v72SHmXLvGRwa3tGFeXSv3NG7gI5eAP3mFyLSKGbQ1SQxhJc7cFgmNExcCPf3NiDTwSB2s9MVANiDnHh+li2ynzwkiLjodS6WVwioHRLQJ6FzUieG2dxHkTHOZ\/wdnAtFJveufsg3PKPgyCwTTw7hXSDv6oVZEZRu8cpCc\/HJTZXiTENTXOtDKzVnVKXTlgGtlDtqIyLQZxg52YKpeVl2DjWqrckZA4WPBtTCRfrNtmNjhA7kPwwYX6BXNoa9iFmVpg6looU7CtokzgbYFSfRe6dO8t1AkEzcO7ZA2+KTStJD8CgL9ggEsMEdEnt+J69b10ekLPYI7frbIZb3W\/9CW5K3eriKp0bX4VdqWJyjK+u8yVGTltIbhjuz8TFJB03We48PBjL9Wz4WEndR4WbPaEwzMkYnnT6LbjQPF392GSc9mCIU\/vAZhLt7ltjR6OlPwt7Do\/dFFchIlHRr7LDiClGZ2ji44I4Wrlftq02fsPK4Rzh9IiTwEmzrILQtPYK3VtcTpFPJ9sFVlJKiiAMtKgcwSJepVuwNZnJGTcy1R3\/oPiwlI3Ud05g8KZCQbMezuvqLJMyXET9EcC5u\/KnUfCaJoB\/0k0C9brPpR3plPbsYn+lbdr5UeAFuo+vRjzph9wN3NtPRh0SvDMTBhxhiEm5fhOCJsSNxTDymbqOCLk69llkPvYvf5mr2TfI1LFpzMoeqpMi5PqhRQjaRrYIPauwIETcKicKVImc926Ex5W7Zc6pFjlLJx5WOh2LUGNAWcf5MU+BIgvg1F0b\/ta5XFsRRJIkGmRCgDlwlFl1wkQ\/M3Xw2plyvo09O46Pl0TX0LFoDZ5kaegEdXCdVArFr92tSwONKYPFczNYP2YOD0QaOeb003GaDUfHGCJdmOA3EFkM3biXBrgnbfDcMh\/a0gXhRkolnJRzUQFy8MT6pGDQTHarFYINWWxwZZc0ml58E3BfSfEBnSnBTdkEnWNHRZjNB7C9URrOfrkjb1CgOBaFJLGvcjc6vhCNdYifb0IzVtS78cCEys+1TmS+axW4WGtlEwCV6+pCOBP3DpoferJE0Eqofg9WVMw06VJFXoLpoLs4ZJz\/STcbR9B3cHZvON3QR0WCot+N\/WqoPKTiRDuRMr2wLa9tgC0gYtaB7XjIemIwpO3oBmi0y0wyqcgGvVUlAh9pZKoUP0+FrIikZ2hfVP886ypTwyiaa9a92V0q\/xX3QKjanqGc0UCvukXVBbozPJHqIjbh9mrI8CyY74Lr90SG5gJTrvfV8g0QqZKTB65BChQXfTclA9mDr6eYgeGEusKc3PEh8QLGrSjRzsaByGgshlOD1QlYgABrYhaSkTNCclI5F0xR9p28GAZNwpj2EZAAWtipp208h\/M7+R6S65U3zgERpQzVXnZTa1KAo49Oj3A5kgPGhJHCHdvg3+cgYdEJH7bhgMqosuirDM4myoAN2QNcygJfsDR9EwQKIBQUgesNPunqehQ8ExBgP\/Y6xuw0CPLsL7ArBYThxSyc9CbsvO5EWTKOrbRJJDEz3OM2YSIOIB0NSA7sQq2EY9u6h8DZBA6HjWtb3UDCMoQnvQTgGFAw1MF1xaKhwocqFgYcGooJBnx9BVkg4CM4FmSiLZDMuZrEbJeaCyw8BfNcHHuo6nG5dF8KtZgWy90Ojs4T4a35Htd78Cirp+wbbH9C5ifAbNtZ2QOjcR5O3Bb0bS7JbSV4IzZRlfmLuQiA4XUczuhU8DdJYG7zGlYuzm4BED0JkHJy6rjOTZZZqPMUJhPO3wuhLu+IrYgFkv2mS2e2a0xJi7DSBoXM12PGCfUAl6Zi7udcluLWscAFqF23XFrdjAtUpYhmp\/8nUU0sxy5YJAKgLMkr8aEfLwC5Ko\/muQzt8ic5GzdYV0Tdv\/fUQhaQ2nr2wIKnrKRhNvUXofqKsJKMkLlBinSG8naxDr8m+fYpdzpzssDpF4F6+oAoA7rOANAq1wPIPenr65q6syziEJg7WFZbOkRQwJ2ahcIFggMAjrydWw\/kzgRTbwy4H196IqI6DBIjuVuO7WP1VBn3k+vF6xmS6d\/go5LVUuUiJhArggjVOVxPkDAcEsIRRNiRukAanGfe+7k1PElOO71p4WgZMAxv3oFAwuXhfSQVTREi4aeyQrjf7QCAyxHl7YxuZ6NNiFa7lw9nxHdOsRjfuGvpEGCSPIr4ZlIQTcIn74tlV18WIX9o33znrW\/NmcWLR1cIoCaO9U7ApNoxXd0uKIaB0AtomWjMMX5SJbiG6+pG6goZpZA+pl8zJ6BB+kCqonRbbjj9Z0hmH7sbZOd4Vi7NM\/RgPf8KmZgZ3NUJ+0wcLabwAF9XQAd3YrPNO0J\/bnKf0ryaSOy0WsCBBZJjTU+tKKVuzo0qIijSyg5hw6hp4WjP4mU2g0rLEbhTpe4Pk5FSHHWzP3Wbci0NcT1obv0O4lmnQfxlZNdcIsZmBr1EEc8W6h2jDAk\/vUnBQFdb3iCEpJM4IEpy\/0BUxomklx7wOpjsLfyFUFCK5\/NyFGe5BOqA3iLFMOosppB+LJOD1FCPO7gMX\/q3pOmSddXRYpgbVKMIK0UAdsHMo0CYtRMj8NEhNoLReAENPmY2APVksCczUgzyJiEBjsG0GFz2MTacSktBK3O0VQ+TGaQaRnTKM7rBqwpaVjsaolXdIqxlq2gQgVmgqg1Qm7wo7ZO7ufEvg+8zEI+k2gQxCmKJiOwwrhPi1cLh44PE9Hm4uydZoV\/9ksdOWLwkAnEYWLsykpqZUkLan3xBGdaN03GO65Z\/TIVDnQdEF1rpelw4oHtrvpj1kFXesjW2iN0K9u8EEfkgCtmN6I2LAQtcQOAI0MkkZwRFz0PniiQ2QnfCdxUuJhFS69EdI+Supcp3+GyA+DZC6XmQHMIzIXTqJxJghNYSqf9hNNl2HZV1DNskTyffwjMZXYIWf7JZK68Q\/1F5+TEfZp8ts3XIgjX+j3lzgFF+SagxMyetK7+q4lgTQFYxLovYMSqPbdDadQBDCtvAE67kNqobTJxzELR1tu+xXikwTHWyvEpgkEGBvWXdf2CnWCh7e3pMorGZEJTInrIIXKUO9aqEXeASkTWUK8nqM3ocWfkU4JdB12ZAgOKjNq6yllEkLoqYn+qFiOj8XCzK9exkGH6WegjZ+I6oaYbwb\/SzheHK0I3dE6f7Brp3QIPxONhMMKIRYjuPEVaXqSTb9q25yo29KpOrKfnNU+shzFPlmHrLIGiVlz9v6btGmG\/tYg008DDFH9252dLPNhRpg+VCaLEr9LpR9W+\/beOpBGAUdEm12tDchzCiFg7sEoyZI5xgaY\/EmX0pBCG2WVpi7HQ86qutQXhNfUENjtRPsSzrkiJLKNqC+hhojEv+7UhD5HJBEmHAUKRZDM30b3cQorsAkdzmtUag6MzsRFzpu4qg8hLseUrF3jLR3lKRbYcS09S8QptpKd4EYcv7\/A5V66wHRWfq9AAAAAElFTkSuQmCC\" alt=\"Shop &amp; Service\" class=\"ti-shop-service-inline-icon\" style=\"width:28px;height:28px;border-radius:8px;object-fit:cover;box-shadow:0 0 0 1px rgba(255,255,255,.08);\"><span>Istruzioni AI configurazione<\/span><\/h4>\n            <div class=\"ti-conf-ai-desc-label\" style=\"font-size:15px;line-height:1.45;color:#cbd5e1;margin-bottom:10px;font-weight:600;\">Fornisci istruzioni di configurazione o ottieni indicazioni tramite AI. Esempio: <i>Aggiungere foto AI a tutti i prodotti<\/i> o <i>fornisci consigli di configurazione<\/i><\/div>\n            <textarea id=\"ti-conf-ai-prompt\" class=\"ti-in\" rows=\"9\" placeholder=\"Scrivi qui la richiesta per la AI di configurazione. La risposta comparira nella stessa area, come unica chat.\" style=\"min-height:210px;line-height:1.45;\"><\/textarea>\n            <div id=\"ti-conf-ai-chat-actions\" style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:10px;margin-bottom:10px;padding:10px;border:1px solid #334155;border-radius:10px;background:#0b1220;\">\n                <button type=\"button\" id=\"ti-conf-ai-send\" class=\"ti-btn\" style=\"background:#10b981;color:#fff;font-weight:800;\" onclick=\"window.runConfigBot()\">Invia<\/button>\n                <button type=\"button\" id=\"ti-conf-ai-copy\" class=\"ti-btn ti-conf-ai-copy-btn\" data-copy-target=\"#ti-conf-ai-prompt\" style=\"background:#334155;color:#fff;font-weight:800;font-size:10px;line-height:1.05;white-space:normal;\" title=\"Copia testo istruzioni AI configurazione\">Copia testo<\/button>\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;\" onclick=\"window.verifyInstructionsArchive()\">\ud83d\udd0e Verifica istruzioni<\/button>\n                <!-- 30.9.1189: pulsante nascosto temporaneamente in attesa di risoluzione lato infrastruttura (GoDaddy). Per riattivare, rimuovere \"display:none;\" dallo style sottostante. -->\n                <!-- Motivo: le richieste da questo pulsante possono restare bloccate per minuti a causa di un problema di rete\/infrastruttura in indagine con il supporto hosting. Il caricamento file dalla chat principale (\"File\") non e' affetto e resta pienamente utilizzabile. -->\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;display:none;\" onclick=\"if(window.pickAiFile1088){window.pickAiFile1088('config');}else if(window.pickConfigBotFile){window.pickConfigBotFile();}\">Carica file per AI<\/button>\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#1d4ed8;color:#fff;\" onclick=\"window.openActivityReport()\">Report Attivit\u00e0<\/button>\n                <button type=\"button\" class=\"ti-btn\" onclick=\"window.clearConfigBot()\">Pulisci<\/button>\n            <\/div>\n            <div id=\"ti-conf-ai-file\" style=\"display:none;margin-top:10px;margin-bottom:10px;font-size:14px;line-height:1.45;color:#bfdbfe;background:#0b1220;padding:10px 12px;border-radius:8px;border:1px solid #334155;\"><\/div>\n            <div id=\"ti-conf-ai-reply\" style=\"display:none;margin-top:10px;background:#000;padding:10px;border-radius:8px;border:1px solid #374151;color:#e5e7eb;white-space:pre-wrap;\"><\/div>\n            <div class=\"ti-conf-ai-desc-label\" style=\"font-size:13px;line-height:1.45;color:#9ca3af;margin-top:8px;margin-bottom:10px;font-weight:500;\">La AI usa il database della ditta corrente ed in genere la sua esperienza Shop &amp; Service.<\/div>\n            <div class=\"ti-conf-ai-desc-label\" style=\"font-size:15px;line-height:1.45;color:#cbd5e1;margin-top:10px;margin-bottom:10px;font-weight:600;\">Per le funzioni <b>Genera immagini AI<\/b> puoi indicare eventuali istruzioni di dettaglio per ottenere immagini piu coerenti con le intenzioni dell utente. Esempio: <i>sfondo chiaro, stile elegante, immagine ravvicinata, ambientazione realistica<\/i>. <span style=\"font-weight:400;color:#94a3b8;\">Nota: per esigenze tecniche della AI, la generazione di piu' immagini puo' avvenire in piu' fasi successive; puoi comunque riavviarla in qualsiasi momento fino al completamento definitivo.<\/span><\/div>\n            <div id=\"ti-conf-ai-image-actions\" style=\"display:flex;gap:4px;flex-wrap:nowrap;align-items:center;margin-top:10px;margin-bottom:10px;overflow-x:auto;overflow-y:hidden;white-space:nowrap;\"><label for=\"ti-conf-ai-image-count-1672\" style=\"display:inline-flex;align-items:center;gap:4px;font-size:11px;white-space:nowrap;flex:0 0 auto;\"><span>N. immagini<\/span><input type=\"number\" id=\"ti-conf-ai-image-count-1672\" min=\"0\" step=\"1\" inputmode=\"numeric\" placeholder=\"Tutte\" title=\"Numero immagini da generare: vuoto o 0 = tutte\" style=\"width:68px;min-width:68px;box-sizing:border-box;padding:6px 5px;border-radius:6px;border:1px solid #64748b;background:#0f172a;color:#fff;font-size:11px;\"><\/label><button type=\"button\" class=\"ti-btn\" style=\"background:#059669;color:#fff;font-size:10px;line-height:1.1;padding:7px 8px;white-space:nowrap;flex:0 0 auto;\" data-ti-batch-ai-btn=\"Prodotti\">Genera immagini AI Prodotti<\/button><span id=\"ti-img-ai-prod-help-1502\" class=\"ti-plugin-button-help ti-plugin-button-help-867\" role=\"button\" tabindex=\"0\" title=\"Aiuto Genera immagini AI Prodotti\" aria-label=\"Aiuto Genera immagini AI Prodotti\" data-ti-help-style=\"text-only-867\">?<\/span>\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#0f766e;color:#fff;font-size:10px;line-height:1.1;padding:7px 8px;white-space:nowrap;flex:0 0 auto;\" data-ti-batch-ai-btn=\"Servizi\">Genera immagini AI Servizi<\/button><span id=\"ti-img-ai-serv-help-1502\" class=\"ti-plugin-button-help ti-plugin-button-help-867\" role=\"button\" tabindex=\"0\" title=\"Aiuto Genera immagini AI Servizi\" aria-label=\"Aiuto Genera immagini AI Servizi\" data-ti-help-style=\"text-only-867\">?<\/span>\n            <\/div>\n            <textarea id=\"ti-conf-ai-photo-detail\" class=\"ti-in\" rows=\"3\" placeholder=\"Istruzioni di dettaglio per la generazione immagini AI (opzionale)\"><\/textarea>\n            <div id=\"ti-configurator-tips-control\" style=\"${(window.isConfiguratorUser && window.isConfiguratorUser()) ? 'display:flex' : 'display:none'};gap:10px;align-items:center;justify-content:space-between;flex-wrap:wrap;margin-top:12px;padding:10px;border:1px solid #334155;border-radius:10px;background:#0f172a;color:#cbd5e1;font-size:12px;\">\n                <label style=\"display:flex;align-items:center;gap:7px;cursor:pointer;\"><input type=\"checkbox\" id=\"ti-cfg-tips-enabled\" onchange=\"window.handleConfiguratorTipsFlagChange(this)\"> Mostra popup <b>Consigli operativi per configuratore\/amministratore<\/b> ai prossimi accessi<\/label>\n                <span id=\"ti-cfg-tips-status\" style=\"color:#93c5fd;\">Popup consigli operativi attivo.<\/span>\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#475569;color:#fff;font-size:12px;padding:7px 10px;\" onclick=\"window.showConfiguratorOperationalTipsPopup(true)\">Apri consigli ora<\/button>\n            <\/div>\n        <\/div>`;\n        const confCnt = gE('ti-conf-cnt'); if (confCnt) { confCnt.innerHTML = html; window.__ensurePluginDateInputs(); window.initPluginDateInputs(confCnt); if (window.ensureAuthorizedConfigInputsEditable512) window.ensureAuthorizedConfigInputsEditable512(confCnt); window.initConfigTopScrollbars(confCnt); window.bindConfigTableUX(confCnt); if (window.ensureAuthorizedConfigInputsEditable512) window.ensureAuthorizedConfigInputsEditable512(confCnt); if (!window.__configRenderedOnce || window.configForceTop) { confCnt.scrollTop = 0; document.querySelectorAll('.ti-cfg-table-container').forEach(el => { el.scrollTop = 0; el.scrollLeft = 0; }); document.querySelectorAll('.ti-cfg-top-scroll, .ti-cfg-bottom-scroll').forEach(el => { el.scrollLeft = 0; }); window.__configRenderedOnce = true; window.configForceTop = false; } else { try { confCnt.scrollTop = cfgScrollState.mainTop || 0; document.querySelectorAll('details.ti-cfg-details').forEach(function(det){ const tbl = det.dataset ? (det.dataset.tbl || '') : ''; const st = cfgScrollState.tables && cfgScrollState.tables[tbl]; const wrap = det.querySelector ? det.querySelector('.ti-cfg-table-container') : null; if (st && wrap) { wrap.scrollLeft = st.left || 0; wrap.scrollTop = st.top || 0; const topBar = wrap.previousElementSibling && wrap.previousElementSibling.classList && wrap.previousElementSibling.classList.contains('ti-sync-hscroll-top') ? wrap.previousElementSibling : null; const bottomBar = wrap.nextElementSibling && wrap.nextElementSibling.classList && wrap.nextElementSibling.classList.contains('ti-sync-hscroll-bottom') ? wrap.nextElementSibling : null; if (topBar) topBar.scrollLeft = wrap.scrollLeft; if (bottomBar) bottomBar.scrollLeft = wrap.scrollLeft; } }); } catch(e) {} } if (window.restoreConfigFilterFocus) setTimeout(window.restoreConfigFilterFocus, 0); if (window.syncConfiguratorOperationalTipsFlagUI) setTimeout(window.syncConfiguratorOperationalTipsFlagUI, 0); }\n        if (window.keepUserCommunicationPopupsInFront) window.keepUserCommunicationPopupsInFront();\n    };\n\n\n    \/\/ 30.9.1590: scheda laterale della singola riga Configurazione.\n    \/\/ Riutilizza esclusivamente i campi gia presenti nella griglia e non introduce alcun campo nel JSON.\n    window.__tiConfigRowDrawerState1590 = null;\n\n    \/\/ 30.9.1595: conserva esattamente il punto della Configurazione quando la scheda laterale viene chiusa\/salvata.\n    window.captureConfigRowDrawerLayout1595 = function(sourceEl) {\n        const st = {mainTop:0, winX:0, winY:0, details:[], sourceEl:sourceEl || null};\n        try { st.winX = window.scrollX || 0; st.winY = window.scrollY || 0; } catch(e) {}\n        try {\n            const cnt = document.getElementById('ti-conf-cnt');\n            if (cnt) st.mainTop = cnt.scrollTop || 0;\n            const root = cnt || document;\n            Array.from(root.querySelectorAll('details.ti-cfg-details')).forEach(function(det){\n                const tbl = det && det.dataset ? String(det.dataset.tbl || '') : '';\n                const wrap = det && det.querySelector ? det.querySelector('.ti-cfg-table-container') : null;\n                st.details.push({tbl:tbl, open:!!det.open, left:wrap ? (wrap.scrollLeft || 0) : 0, top:wrap ? (wrap.scrollTop || 0) : 0});\n            });\n        } catch(e) {}\n        return st;\n    };\n\n    window.restoreConfigRowDrawerLayout1595 = function(st) {\n        if (!st) return;\n        const restore = function(){\n            try {\n                const cnt = document.getElementById('ti-conf-cnt');\n                if (cnt) cnt.scrollTop = st.mainTop || 0;\n                const root = cnt || document;\n                (st.details || []).forEach(function(saved){\n                    let det = null;\n                    try {\n                        det = Array.from(root.querySelectorAll('details.ti-cfg-details')).find(function(d){ return String((d.dataset && d.dataset.tbl) || '') === String(saved.tbl || ''); }) || null;\n                    } catch(e) { det = null; }\n                    if (!det) return;\n                    det.open = !!saved.open;\n                    const wrap = det.querySelector ? det.querySelector('.ti-cfg-table-container') : null;\n                    if (wrap) {\n                        wrap.scrollLeft = saved.left || 0;\n                        wrap.scrollTop = saved.top || 0;\n                        const topBar = wrap.previousElementSibling && wrap.previousElementSibling.classList && wrap.previousElementSibling.classList.contains('ti-sync-hscroll-top') ? wrap.previousElementSibling : null;\n                        const bottomBar = wrap.nextElementSibling && wrap.nextElementSibling.classList && wrap.nextElementSibling.classList.contains('ti-sync-hscroll-bottom') ? wrap.nextElementSibling : null;\n                        if (topBar) topBar.scrollLeft = wrap.scrollLeft;\n                        if (bottomBar) bottomBar.scrollLeft = wrap.scrollLeft;\n                    }\n                });\n                if (st.sourceEl && st.sourceEl.isConnected && typeof st.sourceEl.focus === 'function') {\n                    try { st.sourceEl.focus({preventScroll:true}); } catch(e) { try { st.sourceEl.focus(); } catch(e2){} }\n                }\n                try { window.scrollTo(st.winX || 0, st.winY || 0); } catch(e) {}\n            } catch(e) {}\n        };\n        try { window.requestAnimationFrame(function(){ window.requestAnimationFrame(restore); }); } catch(e) { setTimeout(restore, 0); }\n    };\n\n    window.closeConfigRowDrawer1590 = function() {\n        \/\/ 30.9.1597: chiude SOLO la scheda laterale. La Configurazione resta esattamente com e:\n        \/\/ niente renderConfig(), niente closeModal(), niente ripristino details\/scroll e nessun reset layout.\n        const state1597 = window.__tiConfigRowDrawerState1590;\n        try {\n            const old = document.getElementById('ti-config-row-drawer-1590');\n            if (old && old.parentNode) old.parentNode.removeChild(old);\n        } catch(e) {}\n        window.__tiConfigRowDrawerState1590 = null;\n        try {\n            const confOv1597 = document.getElementById('ti-conf-ov');\n            if (confOv1597 && state1597 && state1597.configOverlayVisible1597) {\n                \/\/ Se la scheda e stata aperta da una Configurazione visibile, un eventuale handler legacy\n                \/\/ non deve poter lasciare nascosto il contenitore padre alla chiusura della scheda.\n                const cs1597 = window.getComputedStyle ? window.getComputedStyle(confOv1597) : null;\n                if ((cs1597 && (cs1597.display === 'none' || cs1597.visibility === 'hidden')) || confOv1597.getAttribute('aria-hidden') === 'true') {\n                    confOv1597.style.display = state1597.configOverlayInlineDisplay1597 || 'flex';\n                    confOv1597.style.visibility = state1597.configOverlayInlineVisibility1597 || '';\n                    confOv1597.setAttribute('aria-hidden','false');\n                }\n            }\n        } catch(e) {}\n        try {\n            if (state1597 && state1597.sourceEl && state1597.sourceEl.isConnected && typeof state1597.sourceEl.focus === 'function') {\n                state1597.sourceEl.focus({preventScroll:true});\n            }\n        } catch(e) {}\n        return false;\n    };\n\n    window.getConfigRowDrawerValue1590 = function(ctrl) {\n        if (!ctrl) return '';\n        if (ctrl.tagName === 'SELECT' && ctrl.multiple) {\n            return Array.from(ctrl.selectedOptions || []).map(function(o){ return String(o.value == null ? '' : o.value).trim(); }).filter(Boolean).join(', ');\n        }\n        if (String(ctrl.type || '').toLowerCase() === 'checkbox') return ctrl.checked ? String(ctrl.value || '1') : '';\n        return String(ctrl.value == null ? '' : ctrl.value);\n    };\n\n    window.getConfigRowDrawerDescription1590 = function(row) {\n        row = row && typeof row === 'object' ? row : {};\n        const wanted = ['Descrizione','Description','Descrizione voce','Voce','Nome','Prodotto','Servizio','Titolo'];\n        const keys = Object.keys(row);\n        for (let i = 0; i < wanted.length; i++) {\n            const target = String(wanted[i]).toLowerCase();\n            const k = keys.find(function(x){ return String(x || '').trim().toLowerCase() === target; });\n            if (k != null) {\n                const v = String(row[k] == null ? '' : row[k]).trim();\n                if (v) return v;\n            }\n        }\n        return '';\n    };\n\n    \/\/ 30.9.1592: gestione media\/file nella scheda laterale riga Configurazione.\n    \/\/ La scheda usa lo stesso campo e lo stesso file manager della riga tabella.\n    window.isConfigRowDrawerFileField1592 = function(key, sourceEl) {\n        const k = String(key || '').trim().toLowerCase();\n        const sid = sourceEl ? String(sourceEl.id || '') : '';\n        if (\/^cfg-img-\/i.test(sid)) return true;\n        return k === 'logo' || k === 'immagine' || k.indexOf('file') >= 0 || k === 'foto' || k === 'doc' || k === 'docs';\n    };\n\n    window.getConfigRowDrawerFileRefs1592 = function(value) {\n        if (window.tiTokenizeFileRefs666) {\n            try { return window.tiTokenizeFileRefs666(value); } catch(e) {}\n        }\n        return String(value == null ? '' : value).split(\/[,;\\r\\n]+\/).map(function(v){ return String(v || '').trim(); }).filter(Boolean);\n    };\n\n    \/\/ 30.9.1960: un solo contatore autorevole File (N), aggiornato anche sulla bozza del file manager.\n    window.tiRefreshFileCount1960 = function(tbl, idx, key, value) {\n        try {\n            tbl = String(tbl == null ? '' : tbl); key = String(key == null ? '' : key); idx = parseInt(idx, 10);\n            if (!tbl || !key || isNaN(idx)) return 0;\n            if (value === undefined || value === null) {\n                try { value = (window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl] && window.currentDbData.Tabelle[tbl][idx]) ? window.currentDbData.Tabelle[tbl][idx][key] : ''; } catch(e0) { value = ''; }\n            }\n            const files1960 = window.getConfigRowDrawerFileRefs1592 ? window.getConfigRowDrawerFileRefs1592(value) : String(value || '').split(\/[,;\\r\\n]+\/).map(function(v){return String(v||'').trim();}).filter(Boolean);\n            const n1960 = files1960.length;\n            document.querySelectorAll('.ti-file-count-btn-1960').forEach(function(btn){\n                if (String(btn.getAttribute('data-ti-file-tbl-1960') || '') === tbl && parseInt(btn.getAttribute('data-ti-file-idx-1960'),10) === idx && String(btn.getAttribute('data-ti-file-key-1960') || '') === key) btn.textContent = 'File (' + n1960 + ')';\n            });\n            document.querySelectorAll('[data-ti-config-row-field-group-1595][data-ti-file-group-1592=\"1\"]').forEach(function(group){\n                if (String(group.getAttribute('data-ti-file-tbl-1592') || '') !== tbl || parseInt(group.getAttribute('data-ti-file-idx-1592'),10) !== idx || String(group.getAttribute('data-ti-file-key-1592') || '') !== key) return;\n                var b = group.querySelector('[data-ti-file-manage-btn-1592]'); if (b) b.textContent = 'File (' + n1960 + ')';\n            });\n            return n1960;\n        } catch(e) { return 0; }\n    };\n\n    window.getConfigRowDrawerFileMeta1592 = function(ref, url) {\n        if (window.tiFileMetaFromRef666) {\n            try { return window.tiFileMetaFromRef666(ref, url); } catch(e) {}\n        }\n        const name = String(ref || '').split(\/[\\\\\/]\/).pop() || String(ref || 'file');\n        const extMatch = name.match(\/\\.([a-z0-9]{1,10})(?:[?#].*)?$\/i);\n        const ext = extMatch ? String(extMatch[1] || '').toLowerCase() : '';\n        return {\n            name: name,\n            ext: ext ? ('.' + ext) : 'n\/d',\n            isImg: \/^(jpg|jpeg|png|webp|gif|bmp|svg)$\/i.test(ext),\n            isPdf: \/^pdf$\/i.test(ext)\n        };\n    };\n\n    window.renderConfigRowDrawerFilePreview1592 = function(group) {\n        if (!group) return;\n        const state = window.__tiConfigRowDrawerState1590;\n        const tbl = String(group.getAttribute('data-ti-file-tbl-1592') || (state && state.table) || '');\n        const idx = parseInt(group.getAttribute('data-ti-file-idx-1592') || (state && state.index), 10);\n        const key = String(group.getAttribute('data-ti-file-key-1592') || '');\n        if (!tbl || isNaN(idx) || !key || !window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tbl] || !window.currentDbData.Tabelle[tbl][idx]) return;\n        const row = window.currentDbData.Tabelle[tbl][idx];\n        const raw = String(row[key] == null ? '' : row[key]);\n        const ctrl = group.querySelector('.ti-config-row-drawer-field-1590[data-key]');\n        if (ctrl && document.activeElement !== ctrl) ctrl.value = raw;\n        const files = window.getConfigRowDrawerFileRefs1592(raw);\n        const btn = group.querySelector('[data-ti-file-manage-btn-1592]');\n        if (btn) btn.textContent = 'File (' + files.length + ')';\n        const previewHost = group.querySelector('[data-ti-file-preview-host-1592]');\n        const nameHost = group.querySelector('[data-ti-file-preview-name-1592]');\n        const openBtn = group.querySelector('[data-ti-file-open-first-1592]');\n        if (!previewHost) return;\n        previewHost.innerHTML = '';\n        if (!files.length) {\n            const empty = document.createElement('div');\n            empty.style.cssText = 'min-height:86px;display:flex;align-items:center;justify-content:center;gap:8px;background:#020617;border:1px dashed #475569;border-radius:8px;color:#94a3b8;font-size:12px;';\n            empty.innerHTML = '<span style=\"font-size:26px;line-height:1;\">\ud83d\udcc1<\/span><span>Nessun file associato<\/span>';\n            previewHost.appendChild(empty);\n            if (nameHost) nameHost.textContent = 'Nessun file disponibile';\n            if (openBtn) { openBtn.disabled = true; openBtn.setAttribute('data-ti-file-url-1592', ''); openBtn.style.opacity = '0.55'; }\n            return;\n        }\n        const ref = files[0];\n        const db = (typeof gE === 'function' && gE('ti-ditta')) ? String(gE('ti-ditta').value || '') : '';\n        let label = tbl;\n        try { label = window.getRecordLabelForUpload ? window.getRecordLabelForUpload(tbl, row, tbl) : tbl; } catch(e) {}\n        let url = '';\n        try { url = window.getSafePreviewUrl ? window.getSafePreviewUrl(ref, db, tbl, key, label) : String(ref || ''); } catch(e) { url = String(ref || ''); }\n        const meta = window.getConfigRowDrawerFileMeta1592(ref, url) || {};\n        const ext = String(meta.ext || '').toLowerCase().replace(\/^\\.\/, '');\n        const box = document.createElement('div');\n        box.style.cssText = 'position:relative;min-height:108px;max-height:180px;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#020617;border:1px solid #475569;border-radius:8px;';\n        const manage = function(ev){ try { if (ev) { ev.preventDefault(); ev.stopPropagation(); } } catch(e){} return window.openConfigRowDrawerFileManager1592(tbl, idx, key, group); };\n        if (meta.isImg || \/^(jpg|jpeg|png|webp|gif|bmp|svg)$\/i.test(ext)) {\n            const img = document.createElement('img');\n            img.src = url;\n            img.alt = 'Anteprima ' + String(meta.name || ref || 'file');\n            img.style.cssText = 'display:block;width:100%;height:132px;object-fit:contain;background:#020617;cursor:pointer;';\n            try {\n                const fb = window.getCompanyFallbackMediaUrl ? window.getCompanyFallbackMediaUrl(db) : '';\n                if (fb) { img.setAttribute('data-fallback', fb); img.onerror = function(){ try { if (window.applyFallbackImage) window.applyFallbackImage(this); } catch(e){} }; }\n            } catch(e) {}\n            img.onclick = manage;\n            box.appendChild(img);\n        } else if (meta.isPdf || ext === 'pdf') {\n            const iframe = document.createElement('iframe');\n            iframe.src = String(url || '') + (String(url || '').indexOf('#') >= 0 ? '' : '#toolbar=0&navpanes=0');\n            iframe.title = 'Anteprima ' + String(meta.name || ref || 'PDF');\n            iframe.loading = 'lazy';\n            iframe.style.cssText = 'display:block;width:100%;height:150px;border:0;background:#fff;';\n            box.appendChild(iframe);\n        } else if (\/^(mp4|webm|ogg|mov|m4v)$\/i.test(ext)) {\n            const video = document.createElement('video');\n            video.src = url; video.controls = true; video.preload = 'metadata'; video.muted = true;\n            video.style.cssText = 'display:block;width:100%;height:150px;object-fit:contain;background:#000;';\n            box.appendChild(video);\n        } else if (\/^(mp3|wav|m4a|aac|flac|oga)$\/i.test(ext)) {\n            const audioWrap = document.createElement('div');\n            audioWrap.style.cssText = 'width:100%;padding:18px;box-sizing:border-box;text-align:center;';\n            audioWrap.innerHTML = '<div style=\"font-size:34px;margin-bottom:10px;\">\ud83c\udfb5<\/div>';\n            const audio = document.createElement('audio'); audio.src = url; audio.controls = true; audio.preload = 'metadata'; audio.style.width = '100%';\n            audioWrap.appendChild(audio); box.appendChild(audioWrap);\n        } else {\n            const generic = document.createElement('button');\n            generic.type = 'button'; generic.style.cssText = 'width:100%;min-height:108px;border:0;background:transparent;color:#e5e7eb;cursor:pointer;padding:12px;';\n            generic.innerHTML = '<div style=\"font-size:38px;line-height:1;margin-bottom:8px;\">\ud83d\udcc4<\/div><div style=\"font-size:11px;color:#94a3b8;\">Anteprima file disponibile<\/div>';\n            generic.onclick = manage;\n            box.appendChild(generic);\n        }\n        previewHost.appendChild(box);\n        if (nameHost) nameHost.textContent = 'Primo file: ' + String(meta.name || ref || 'file') + (files.length > 1 ? ' \u00b7 +' + (files.length - 1) + ' altro\/i' : '');\n        if (openBtn) {\n            openBtn.disabled = !url;\n            openBtn.setAttribute('data-ti-file-url-1592', String(url || ''));\n            openBtn.style.opacity = url ? '1' : '0.55';\n        }\n    };\n\n    window.refreshConfigRowDrawerFiles1592 = function(tbl, idx, key) {\n        const drawer = document.getElementById('ti-config-row-drawer-1590');\n        if (!drawer) return;\n        drawer.querySelectorAll('[data-ti-file-group-1592=\"1\"]').forEach(function(group){\n            const gt = String(group.getAttribute('data-ti-file-tbl-1592') || '');\n            const gi = parseInt(group.getAttribute('data-ti-file-idx-1592') || '-1', 10);\n            const gk = String(group.getAttribute('data-ti-file-key-1592') || '');\n            if (tbl && String(tbl) !== gt) return;\n            if (typeof idx !== 'undefined' && idx !== null && parseInt(idx, 10) !== gi) return;\n            if (key && String(key) !== gk) return;\n            try {\n                const ctrl1602 = group.querySelector('.ti-config-row-drawer-field-1590[data-key]');\n                const row1602 = window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[gt] ? window.currentDbData.Tabelle[gt][gi] : null;\n                if (ctrl1602 && row1602 && Object.prototype.hasOwnProperty.call(row1602, gk)) ctrl1602.value = String(row1602[gk] == null ? '' : row1602[gk]);\n            } catch(e) {}\n            window.renderConfigRowDrawerFilePreview1592(group);\n        });\n    };\n\n    window.syncConfigRowDrawerFileField1592 = function(tbl, idx, key, group) {\n        if (!group || !window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tbl] || !window.currentDbData.Tabelle[tbl][idx]) return;\n        const ctrl = group.querySelector('.ti-config-row-drawer-field-1590[data-key]');\n        if (!ctrl || ctrl.disabled || ctrl.readOnly) return;\n        let val = window.getConfigRowDrawerValue1590 ? window.getConfigRowDrawerValue1590(ctrl) : String(ctrl.value == null ? '' : ctrl.value);\n        if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val);\n        const row = window.currentDbData.Tabelle[tbl][idx];\n        const oldVal = String(row[key] == null ? '' : row[key]);\n        if (oldVal === String(val == null ? '' : val)) return;\n        row[key] = val;\n        if (!window.modifiedFields) window.modifiedFields = new Set();\n        window.modifiedFields.add(tbl + '-' + idx + '-' + key);\n        if (window.currentDbViewData && window.currentDbViewData !== window.currentDbData && window.currentDbViewData.Tabelle && window.currentDbViewData.Tabelle[tbl] && window.currentDbViewData.Tabelle[tbl][idx]) window.currentDbViewData.Tabelle[tbl][idx][key] = val;\n        try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n    };\n\n    window.openConfigRowDrawerFileManager1592 = function(tbl, idx, key, group) {\n        tbl = window.resolveConfigTableName ? window.resolveConfigTableName(tbl) : tbl;\n        idx = parseInt(idx, 10);\n        if (!tbl || isNaN(idx) || !key) return false;\n        try { window.syncConfigRowDrawerFileField1592(tbl, idx, key, group); } catch(e) {}\n        const ov = document.getElementById('ti-file-manager-ov');\n        let observer = null;\n        let seenOpen = false;\n        if (ov && window.MutationObserver) {\n            observer = new MutationObserver(function(){\n                let visible = false;\n                try {\n                    const cs = window.getComputedStyle ? window.getComputedStyle(ov) : null;\n                    visible = ov.getAttribute('aria-hidden') !== 'true' && (!cs || (cs.display !== 'none' && cs.visibility !== 'hidden'));\n                } catch(e) {}\n                if (visible) { seenOpen = true; return; }\n                if (seenOpen) {\n                    try { observer.disconnect(); } catch(e) {}\n                    setTimeout(function(){ try { window.refreshConfigRowDrawerFiles1592(tbl, idx, key); } catch(e){} }, 30);\n                }\n            });\n            try { observer.observe(ov, {attributes:true, attributeFilter:['style','class','aria-hidden']}); } catch(e) { observer = null; }\n            setTimeout(function(){ try { if (observer) observer.disconnect(); } catch(e){} }, 300000);\n        }\n        try { if (window.openFileManager) window.openFileManager(tbl, idx, key); } catch(e) {\n            try { if (observer) observer.disconnect(); } catch(e2) {}\n            if (window.tiAlert) window.tiAlert('Gestione file non disponibile: ' + (e && e.message ? e.message : 'errore')); return false;\n        }\n        return false;\n    };\n\n    window.openConfigRowDrawerFirstFile1592 = function(btn) {\n        if (!btn) return false;\n        const url = String(btn.getAttribute('data-ti-file-url-1592') || '').trim();\n        if (!url) return false;\n        try { window.open(url, '_blank', 'noopener'); } catch(e) { try { window.open(url, '_blank'); } catch(e2){} }\n        return false;\n    };\n\n    window.openConfigRowDrawer1590 = function(tbl, idx, sourceEl) {\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        tbl = window.resolveConfigTableName ? window.resolveConfigTableName(tbl) : tbl;\n        idx = parseInt(idx, 10);\n        if (!tbl || isNaN(idx) || !window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tbl] || !window.currentDbData.Tabelle[tbl][idx]) {\n            if (window.tiAlert) window.tiAlert('Riga non disponibile. Riapri la configurazione e riprova.');\n            return false;\n        }\n        const row = window.currentDbData.Tabelle[tbl][idx];\n        let tr = null;\n        try { tr = sourceEl && sourceEl.closest ? sourceEl.closest('tr[data-row-idx]') : null; } catch(e) { tr = null; }\n        if (!tr) {\n            try {\n                const scope = window.getConfigTableScope ? window.getConfigTableScope(tbl, sourceEl) : document;\n                tr = Array.from(scope.querySelectorAll('tr[data-row-idx]')).find(function(r){ return parseInt(r.getAttribute('data-row-idx') || '', 10) === idx; }) || null;\n            } catch(e) { tr = null; }\n        }\n        if (!tr) {\n            if (window.tiAlert) window.tiAlert('Riga non visibile nella tabella corrente. Rimuovi eventuali filtri e riprova.');\n            return false;\n        }\n\n        const sources = [];\n        const seen = new Set();\n        try {\n            tr.querySelectorAll('input[data-key], textarea[data-key], select[data-key]').forEach(function(src){\n                const key = String(src.getAttribute('data-key') || '');\n                if (!key || seen.has(key)) return;\n                seen.add(key);\n                sources.push(src);\n            });\n        } catch(e) {}\n        if (!sources.length) {\n            if (window.tiAlert) window.tiAlert('Nessun campo di input disponibile per questa riga.');\n            return false;\n        }\n\n        const returnLayout1595 = window.captureConfigRowDrawerLayout1595 ? window.captureConfigRowDrawerLayout1595(sourceEl) : null;\n        const confOv1597 = document.getElementById('ti-conf-ov');\n        let configOverlayVisible1597 = false;\n        let configOverlayInlineDisplay1597 = '';\n        let configOverlayInlineVisibility1597 = '';\n        try {\n            if (confOv1597) {\n                const cs1597 = window.getComputedStyle ? window.getComputedStyle(confOv1597) : null;\n                configOverlayVisible1597 = !cs1597 || (cs1597.display !== 'none' && cs1597.visibility !== 'hidden');\n                configOverlayInlineDisplay1597 = String(confOv1597.style.display || '');\n                configOverlayInlineVisibility1597 = String(confOv1597.style.visibility || '');\n            }\n        } catch(e) {}\n        window.closeConfigRowDrawer1590();\n        \/\/ 30.9.1597: il drawer NON e figlio dell overlay Configurazione. In questo modo i gestori\n        \/\/ generici di Chiudi della Configurazione non ricevono il click della scheda laterale.\n        const host = document.body;\n        const drawer = document.createElement('div');\n        drawer.id = 'ti-config-row-drawer-1590';\n        drawer.setAttribute('role', 'dialog');\n        drawer.setAttribute('aria-modal', 'false');\n        drawer.style.cssText = 'position:fixed;top:0;right:0;bottom:0;width:min(520px,96vw);z-index:2147483200;background:#07111f;color:#fff;border-left:2px solid #2563eb;box-shadow:-12px 0 30px rgba(0,0,0,.55);display:flex;flex-direction:column;text-align:left;font-family:inherit;';\n\n        const desc = window.getConfigRowDrawerDescription1590(row);\n        drawer.innerHTML = '<div style=\"padding:14px 16px 12px;background:#0f172a;border-bottom:1px solid #334155;display:flex;align-items:flex-start;gap:10px;\">'\n            + '<div style=\"min-width:0;flex:1 1 auto;\"><div style=\"font-size:18px;font-weight:800;color:#fff;\">' + window.escapeHtml(String(tbl)) + ' - Riga ' + (idx + 1) + '<\/div>'\n            + (desc ? '<div style=\"margin-top:5px;font-size:12px;line-height:1.35;color:#bfdbfe;white-space:normal;overflow-wrap:anywhere;\">' + window.escapeHtml(desc) + '<\/div>' : '')\n            + '<div style=\"margin-top:6px;font-size:11px;color:#94a3b8;\">Modifica i campi e premi Salva. Per scrivere il database resta necessario Salva Modifiche.<\/div><\/div>'\n            + '<button type=\"button\" class=\"ti-btn\" title=\"Chiudi\" aria-label=\"Chiudi\" style=\"background:#b91c1c;color:#fff;min-width:38px;padding:7px 10px;font-size:18px;line-height:1;\" onclick=\"return window.closeConfigRowDrawer1590()\">\u00d7<\/button><\/div>'\n            + '<div id=\"ti-config-row-drawer-fields-1590\" style=\"padding:14px 16px;overflow:auto;flex:1 1 auto;background:#07111f;\"><\/div>'\n            + '<div style=\"position:sticky;bottom:0;padding:12px 14px;background:#0f172a;border-top:1px solid #334155;display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;\">'\n            + '<button type=\"button\" class=\"ti-btn\" id=\"ti-config-row-copy-1609\" data-ti-config-row-copy-1609=\"1\" style=\"background:#334155;color:#fff;\" onclick=\"return window.copyConfigRowDrawer1590(this)\">Copia testo<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" style=\"background:#b91c1c;color:#fff;\" onclick=\"return window.deleteConfigRowDrawer1590()\">Elimina<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" style=\"background:#475569;color:#fff;\" onclick=\"return window.closeConfigRowDrawer1590()\">Chiudi<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" style=\"background:#059669;color:#fff;font-weight:800;\" onclick=\"return window.saveConfigRowDrawer1590()\">Salva<\/button>'\n            + '<\/div>';\n        host.appendChild(drawer);\n        \/\/ 30.9.1597: blocca la propagazione verso i listener globali\/legacy senza interferire\n        \/\/ con gli handler dei controlli interni (che vengono eseguiti prima, sul target).\n        ['click','dblclick','mousedown','mouseup','pointerdown','pointerup','touchstart','touchend'].forEach(function(evName1597){\n            try { drawer.addEventListener(evName1597, function(ev1597){ try { ev1597.stopPropagation(); } catch(e){} }, false); } catch(e) {}\n        });\n\n        const fieldsHost = drawer.querySelector('#ti-config-row-drawer-fields-1590');\n        sources.forEach(function(src){\n            const key = String(src.getAttribute('data-key') || '');\n            if (!key) return;\n            const group = document.createElement('div');\n            group.style.cssText = 'margin:0 0 12px 0;padding:10px;background:#0b1220;border:1px solid #26354a;border-radius:8px;';\n            group.setAttribute('data-ti-config-row-field-group-1595', '1');\n            const label = document.createElement('label');\n            label.setAttribute('data-ti-config-row-field-label-1595', '1');\n            label.textContent = key;\n            label.style.cssText = 'display:block;margin:0 0 5px 0;font-size:12px;font-weight:800;color:#bfdbfe;white-space:normal;overflow-wrap:anywhere;';\n            const fieldDesc = window.getConfigFieldDescription ? String(window.getConfigFieldDescription(tbl, key) || '') : '';\n            group.appendChild(label);\n            if (fieldDesc) {\n                const help = document.createElement('div');\n                help.textContent = fieldDesc;\n                help.style.cssText = 'margin:0 0 6px 0;font-size:10.5px;line-height:1.3;color:#94a3b8;white-space:normal;overflow-wrap:anywhere;';\n                group.appendChild(help);\n            }\n\n            const ctrl = src.cloneNode(true);\n            try {\n                Array.from(ctrl.attributes || []).forEach(function(a){\n                    const n = String(a.name || '').toLowerCase();\n                    if (n === 'id' || n === 'name' || n === 'data-tbl' || n === 'data-idx' || \/^on\/.test(n)) ctrl.removeAttribute(a.name);\n                });\n            } catch(e) {}\n            ctrl.setAttribute('data-key', key);\n            ctrl.className = 'ti-in ti-config-row-drawer-field-1590';\n            ctrl.style.cssText = 'display:block;width:100%;max-width:100%;box-sizing:border-box;background:#020617;color:#fff;border:1px solid #475569;border-radius:6px;padding:8px;font-size:12px;line-height:1.35;min-height:36px;';\n            if (ctrl.tagName === 'TEXTAREA') ctrl.style.minHeight = '76px';\n            if (ctrl.tagName === 'SELECT' && ctrl.multiple) ctrl.style.minHeight = '92px';\n            try {\n                if (ctrl.tagName === 'SELECT') {\n                    Array.from(ctrl.options || []).forEach(function(opt, i){ opt.selected = !!(src.options && src.options[i] && src.options[i].selected); });\n                } else if (String(ctrl.type || '').toLowerCase() === 'checkbox') {\n                    ctrl.checked = !!src.checked;\n                } else {\n                    ctrl.value = String(src.value == null ? '' : src.value);\n                }\n            } catch(e) {}\n            if (src.disabled) ctrl.disabled = true;\n            if (src.readOnly) ctrl.readOnly = true;\n            if (String(ctrl.type || '').toLowerCase() === 'password') {\n                ctrl.setAttribute('autocomplete', 'new-password');\n                if (String(src.value || '') === '') ctrl.setAttribute('data-ti-password-blank-protected', '1');\n            }\n            if (ctrl.disabled || ctrl.readOnly) {\n                ctrl.style.opacity = '0.72';\n                ctrl.style.cursor = 'not-allowed';\n            }\n\n            const isFileField1592 = window.isConfigRowDrawerFileField1592 ? window.isConfigRowDrawerFileField1592(key, src) : false;\n            if (isFileField1592) {\n                group.setAttribute('data-ti-file-group-1592', '1');\n                group.setAttribute('data-ti-file-tbl-1592', String(tbl));\n                group.setAttribute('data-ti-file-idx-1592', String(idx));\n                group.setAttribute('data-ti-file-key-1592', key);\n                const previewWrap1592 = document.createElement('div');\n                previewWrap1592.style.cssText = 'margin:0 0 8px 0;';\n                previewWrap1592.innerHTML = '<div data-ti-file-preview-host-1592=\"1\"><\/div>'\n                    + '<div data-ti-file-preview-name-1592=\"1\" style=\"margin-top:5px;font-size:10.5px;color:#cbd5e1;white-space:normal;overflow-wrap:anywhere;\"><\/div>';\n                group.appendChild(previewWrap1592);\n            }\n            group.appendChild(ctrl);\n            if (isFileField1592) {\n                const fileActions1592 = document.createElement('div');\n                fileActions1592.style.cssText = 'display:flex;gap:7px;flex-wrap:wrap;align-items:center;margin-top:7px;';\n                const manageBtn1592 = document.createElement('button');\n                manageBtn1592.type = 'button';\n                manageBtn1592.className = 'ti-btn';\n                manageBtn1592.setAttribute('data-ti-file-manage-btn-1592', '1');\n                manageBtn1592.style.cssText = 'background:#4b5563;color:#fff;padding:6px 9px;font-size:11px;';\n                manageBtn1592.textContent = 'File (0)';\n                manageBtn1592.onclick = function(ev){ try { ev.preventDefault(); ev.stopPropagation(); } catch(e){} return window.openConfigRowDrawerFileManager1592(tbl, idx, key, group); };\n                const openFirst1592 = document.createElement('button');\n                openFirst1592.type = 'button';\n                openFirst1592.className = 'ti-btn';\n                openFirst1592.setAttribute('data-ti-file-open-first-1592', '1');\n                openFirst1592.style.cssText = 'background:#1d4ed8;color:#fff;padding:6px 9px;font-size:11px;';\n                openFirst1592.textContent = 'Apri anteprima';\n                openFirst1592.onclick = function(ev){ try { ev.preventDefault(); ev.stopPropagation(); } catch(e){} return window.openConfigRowDrawerFirstFile1592(this); };\n                fileActions1592.appendChild(manageBtn1592);\n                fileActions1592.appendChild(openFirst1592);\n                group.appendChild(fileActions1592);\n            }\n            fieldsHost.appendChild(group);\n            if (isFileField1592) { try { window.renderConfigRowDrawerFilePreview1592(group); } catch(e) {} }\n        });\n\n        window.__tiConfigRowDrawerState1590 = {table: tbl, index: idx, drawer: drawer, sourceEl: sourceEl || null, sourceRow: tr || null, fieldOrder1602: sources.map(function(src){return String(src.getAttribute('data-key')||'');}).filter(Boolean), layout1595: returnLayout1595, configOverlayVisible1597: configOverlayVisible1597, configOverlayInlineDisplay1597: configOverlayInlineDisplay1597, configOverlayInlineVisibility1597: configOverlayInlineVisibility1597};\n        try { if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(drawer); } catch(e) {}\n        try {\n            const first = drawer.querySelector('.ti-config-row-drawer-field-1590:not([disabled]):not([readonly])');\n            if (first && first.focus) first.focus({preventScroll:true});\n        } catch(e) {}\n        return false;\n    };\n\n    window.saveConfigRowDrawer1590 = function() {\n        const state = window.__tiConfigRowDrawerState1590;\n        if (!state || !state.drawer) return false;\n        const tbl = window.resolveConfigTableName ? window.resolveConfigTableName(state.table) : state.table;\n        const idx = parseInt(state.index, 10);\n        const row = window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl] ? window.currentDbData.Tabelle[tbl][idx] : null;\n        if (!row) {\n            if (window.tiAlert) window.tiAlert('Riga non piu disponibile. Riapri la configurazione.');\n            window.closeConfigRowDrawer1590();\n            return false;\n        }\n        let changed = 0;\n        state.drawer.querySelectorAll('.ti-config-row-drawer-field-1590[data-key]').forEach(function(ctrl){\n            const key = String(ctrl.getAttribute('data-key') || '');\n            if (!key || ctrl.disabled || ctrl.readOnly) return;\n            let val = window.getConfigRowDrawerValue1590(ctrl);\n            if (String(ctrl.type || '').toLowerCase() === 'password' && ctrl.getAttribute('data-ti-password-blank-protected') === '1' && String(val).trim() === '') return;\n            if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val);\n            const fieldNorm = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(key) : String(key || '').toLowerCase();\n            if (fieldNorm === 'stato' || fieldNorm === 'status') val = window.normalizeConfigStateValue ? window.normalizeConfigStateValue(val) : val;\n            const oldVal = row[key];\n            if (String(oldVal == null ? '' : oldVal) === String(val == null ? '' : val)) return;\n            row[key] = val;\n            if (!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(tbl + '-' + idx + '-' + key);\n            if (window.currentDbViewData && window.currentDbViewData !== window.currentDbData && window.currentDbViewData.Tabelle && window.currentDbViewData.Tabelle[tbl] && window.currentDbViewData.Tabelle[tbl][idx]) {\n                window.currentDbViewData.Tabelle[tbl][idx][key] = val;\n            }\n            try { if (window.checkConfigUsernameDuplicateInput) window.checkConfigUsernameDuplicateInput(tbl, idx, key, ctrl); } catch(e) {}\n            changed++;\n        });\n        \/\/ 30.9.1595: riallinea la riga visibile senza renderConfig(), cosi Salva non azzera scroll\/aperture\/layout.\n        try {\n            let sourceRow1595 = state.sourceRow && state.sourceRow.isConnected ? state.sourceRow : null;\n            if (!sourceRow1595) {\n                const scope1595 = window.getConfigTableScope ? window.getConfigTableScope(tbl, state.sourceEl || null) : document;\n                sourceRow1595 = Array.from((scope1595 || document).querySelectorAll('tr[data-row-idx]')).find(function(r){\n                    return parseInt(r.getAttribute('data-row-idx') || '-1', 10) === idx && String(r.getAttribute('data-tbl-enc') || '') !== '__never__';\n                }) || null;\n            }\n            if (sourceRow1595) {\n                state.drawer.querySelectorAll('.ti-config-row-drawer-field-1590[data-key]').forEach(function(ctrl){\n                    const key = String(ctrl.getAttribute('data-key') || '');\n                    if (!key) return;\n                    const src = Array.from(sourceRow1595.querySelectorAll('input[data-key],textarea[data-key],select[data-key]')).find(function(el){ return String(el.getAttribute('data-key') || '') === key; }) || null;\n                    if (!src) return;\n                    const val = row[key] == null ? '' : row[key];\n                    try {\n                        if (src.tagName === 'SELECT') {\n                            if (src.multiple) {\n                                const wanted1595 = String(val == null ? '' : val).split(\/[,;\\r\\n]+\/).map(function(v){ return String(v || '').trim(); }).filter(Boolean);\n                                Array.from(src.options || []).forEach(function(o){ o.selected = wanted1595.indexOf(String(o.value == null ? '' : o.value).trim()) >= 0; });\n                            } else src.value = String(val);\n                        } else if (String(src.type || '').toLowerCase() === 'checkbox') {\n                            const sv = String(val == null ? '' : val).trim().toLowerCase();\n                            src.checked = window.tiDbFlagEnabled ? window.tiDbFlagEnabled(val, false) : (!!sv && !['0','false','no','off'].includes(sv));\n                        } else if (String(src.type || '').toLowerCase() !== 'password' || String(val || '') !== '') {\n                            src.value = String(val);\n                        }\n                        if (window.modifiedFields && window.modifiedFields.has(tbl + '-' + idx + '-' + key)) {\n                            src.dataset.dirty = '1';\n                            src.style.setProperty('border-color','#fbbf24','important');\n                        }\n                    } catch(e) {}\n                });\n            }\n        } catch(e) {}\n        try { window.__configRelationSupportCache = null; } catch(e) {}\n        try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        window.closeConfigRowDrawer1590();\n        return false;\n    };\n\n    \/\/ 30.9.1610: copia deterministica dell INTERA riga dati della scheda laterale.\n    \/\/ Fonte autorevole: currentDbData.Tabelle[tabella][riga]. I controlli del drawer sovrascrivono\n    \/\/ i valori della riga per includere anche modifiche appena digitate e non ancora salvate.\n    \/\/ Per i campi file\/media vengono copiati esclusivamente i nomi file.\n    window.copyConfigRowDrawer1590 = function(btn) {\n        const state = window.__tiConfigRowDrawerState1590;\n        if (!state || !state.drawer) return false;\n        const tbl1610 = window.resolveConfigTableName ? window.resolveConfigTableName(state.table) : state.table;\n        const idx1610 = parseInt(state.index, 10);\n        const row1610 = window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl1610]\n            ? window.currentDbData.Tabelle[tbl1610][idx1610] : null;\n        if (!row1610 || typeof row1610 !== 'object') {\n            if (window.tiAlert) window.tiAlert('Riga non disponibile per la copia.');\n            return false;\n        }\n\n        const controls1610 = Array.from(state.drawer.querySelectorAll('.ti-config-row-drawer-field-1590[data-key]'));\n        const ctrlByKey1610 = Object.create(null);\n        controls1610.forEach(function(ctrl){\n            const key = String(ctrl.getAttribute('data-key') || '').trim();\n            if (key && !ctrlByKey1610[key]) ctrlByKey1610[key] = ctrl;\n        });\n\n        \/\/ Prima l ordine visualizzato nella scheda, poi ogni eventuale campo reale rimasto fuori dal rendering.\n        const keys1610 = [];\n        const seen1610 = Object.create(null);\n        function addKey1610(key){\n            key = String(key == null ? '' : key).trim();\n            if (!key || seen1610[key]) return;\n            seen1610[key] = true;\n            keys1610.push(key);\n        }\n        (Array.isArray(state.fieldOrder1602) ? state.fieldOrder1602 : []).forEach(addKey1610);\n        controls1610.forEach(function(ctrl){ addKey1610(ctrl.getAttribute('data-key')); });\n        Object.keys(row1610).forEach(addKey1610);\n\n        function fileNames1610(raw) {\n            let refs = [];\n            try { refs = window.getConfigRowDrawerFileRefs1592 ? window.getConfigRowDrawerFileRefs1592(raw) : []; } catch(e) { refs = []; }\n            if (!refs.length) refs = String(raw == null ? '' : raw).split(\/[,;\\r\\n]+\/).map(function(v){ return String(v || '').trim(); }).filter(Boolean);\n            return refs.map(function(ref){\n                let clean = String(ref || '').trim();\n                try { clean = decodeURIComponent(clean); } catch(e) {}\n                clean = clean.split(\/[?#]\/)[0];\n                const parts = clean.split(\/[\\\\\/]\/).filter(Boolean);\n                return parts.length ? parts[parts.length - 1] : clean;\n            }).filter(Boolean).join(', ');\n        }\n\n        const lines1610 = [\n            'Tabella: ' + String(tbl1610 || state.table || ''),\n            'Riga: ' + String(idx1610 + 1),\n            ''\n        ];\n        let count1610 = 0;\n\n        keys1610.forEach(function(key){\n            const ctrl = ctrlByKey1610[key] || null;\n            let raw = row1610[key] == null ? '' : row1610[key];\n            if (ctrl) {\n                try {\n                    if (!(String(ctrl.type || '').toLowerCase() === 'password' && ctrl.getAttribute('data-ti-password-blank-protected') === '1' && String(ctrl.value || '').trim() === '')) {\n                        raw = window.getConfigRowDrawerValue1590 ? window.getConfigRowDrawerValue1590(ctrl) : (ctrl.value == null ? '' : ctrl.value);\n                    }\n                } catch(e) {}\n            }\n\n            let isFile1610 = false;\n            try {\n                const group = ctrl && ctrl.closest ? ctrl.closest('[data-ti-config-row-field-group-1595=\"1\"]') : null;\n                isFile1610 = !!(group && group.getAttribute('data-ti-file-group-1592') === '1');\n                if (!isFile1610 && window.isConfigRowDrawerFileField1592) isFile1610 = !!window.isConfigRowDrawerFileField1592(key, ctrl);\n            } catch(e) {}\n\n            let value1610 = '';\n            if (isFile1610) {\n                value1610 = fileNames1610(raw);\n            } else if (Array.isArray(raw)) {\n                value1610 = raw.map(function(v){ return String(v == null ? '' : v); }).join(', ');\n            } else if (raw && typeof raw === 'object') {\n                try { value1610 = JSON.stringify(raw); } catch(e) { value1610 = String(raw); }\n            } else {\n                value1610 = String(raw == null ? '' : raw);\n            }\n\n            lines1610.push(String(key) + ': ' + value1610);\n            count1610++;\n        });\n\n        const text1610 = lines1610.join('\\n');\n        window.__tiLastConfigRowCopiedText1609 = text1610;\n        window.__tiLastConfigRowCopiedText1610 = text1610;\n        const oldLabel1610 = btn ? String(btn.textContent || 'Copia testo') : 'Copia testo';\n        function done1610(ok){\n            try {\n                if (btn) {\n                    btn.textContent = ok ? ('Copiati ' + count1610 + ' campi') : 'Copia non riuscita';\n                    setTimeout(function(){ try { btn.textContent = oldLabel1610 || 'Copia testo'; } catch(e){} }, 1800);\n                }\n            } catch(e) {}\n            if (!ok && window.tiAlert) window.tiAlert('Copia non riuscita.');\n        }\n\n        \/\/ Copia sincrona per conservare la user activation del click.\n        try {\n            const ta1610 = document.createElement('textarea');\n            ta1610.value = text1610;\n            ta1610.setAttribute('readonly','readonly');\n            ta1610.style.cssText = 'position:fixed;left:-10000px;top:0;width:2px;height:2px;opacity:0;';\n            document.body.appendChild(ta1610);\n            ta1610.focus(); ta1610.select(); ta1610.setSelectionRange(0, ta1610.value.length);\n            const ok1610 = document.execCommand && document.execCommand('copy');\n            ta1610.remove();\n            if (ok1610) { done1610(true); return false; }\n        } catch(e) {}\n        if (navigator.clipboard && navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(text1610).then(function(){ done1610(true); }).catch(function(){ done1610(false); });\n            return false;\n        }\n        done1610(false);\n        return false;\n    };\n\n    window.deleteConfigRowDrawer1590 = function() {\n        const state = window.__tiConfigRowDrawerState1590;\n        if (!state) return false;\n        const tbl = state.table;\n        const idx = state.index;\n        window.closeConfigRowDrawer1590();\n        setTimeout(function(){ if (window.delTableRow) window.delTableRow(tbl, idx, null); }, 0);\n        return false;\n    };\n\n\n    window.isValidConfigDate = function(v) { const s = String(v == null ? '' : v).trim(); if (!s || \/^DD\\\/MM\\\/YYYY$\/i.test(s) || s === '--\/--\/----') return true; const m = s.match(\/^(\\d{1,2})\\\/(\\d{1,2})\\\/(\\d{4})$\/); if (m) { const d = new Date(Number(m[3]), Number(m[2])-1, Number(m[1])); return d && d.getFullYear()===Number(m[3]) && d.getMonth()===Number(m[2])-1 && d.getDate()===Number(m[1]); } if (\/^\\d{1,2}[\\\/.-]\\d{1,2}[\\\/.-]\\d{2,4}$\/.test(s)) return false; return true; };\n    window.isValidConfigTime = function(v) { const s = String(v == null ? '' : v).trim(); if (!s || \/^HH:MM$\/i.test(s) || s === '--:--') return true; const m = s.match(\/^(\\d{1,2})[:.](\\d{2})$\/); if (m) return Number(m[1]) >= 0 && Number(m[1]) <= 23 && Number(m[2]) >= 0 && Number(m[2]) <= 59; return true; };\n    window.isValidConfigNumber = function(v) { const s = String(v == null ? '' : v).trim().replace(\/[\u20ac\\s]\/g,'').replace(',', '.'); return !s || !isNaN(Number(s)); };\n    window.isEmptyOrStandardDayConfigTime = function(v) { const s = String(v == null ? '' : v).trim(); return !s || \/^HH:MM$\/i.test(s) || s === '--:--'; };\n    window.isEmptyConfigPeriodBoundary = function(v, kind) { const s = String(v == null ? '' : v).trim(); if (!s) return true; if (kind === 'ora' && (\/^HH:MM$\/i.test(s) || s === '--:--')) return true; if (kind === 'data' && (\/^DD\\\/MM\\\/YYYY$\/i.test(s) || s === '--\/--\/----')) return true; return false; };\n    window.getConfigPeriodPairMeta = function(key) {\n        const n = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(key) : String(key || '').toLowerCase();\n        const c = String(n || '').replace(\/[^a-z0-9]+\/g, '');\n        const dateStart = ['dagg','dadata','datada','datainizio','inizioperiodo','iniziovalidita','dal'];\n        const dateEnd = ['agg','adata','dataa','datafine','fineperiodo','finevalidita','al'];\n        const timeStart = ['daora','orainizio','inizioora','orarioda','dalleore','dalle'];\n        const timeEnd = ['aora','orafine','fineora','orarioa','alleore','alle'];\n        if (dateStart.includes(c)) return {kind:'data', side:'start', counter:['agg','a gg','a data','data a','data fine','fine periodo','fine validita','al']};\n        if (dateEnd.includes(c)) return {kind:'data', side:'end', counter:['dagg','da gg','da data','data da','data inizio','inizio periodo','inizio validita','dal']};\n        if (timeStart.includes(c)) return {kind:'ora', side:'start', counter:['aora','a ora','ora fine','fine ora','orario a','alle ore','alle']};\n        if (timeEnd.includes(c)) return {kind:'ora', side:'end', counter:['daora','da ora','ora inizio','inizio ora','orario da','dalle ore','dalle']};\n        return null;\n    };\n    window.getConfigPeriodCounterpartKey = function(row, meta) {\n        if (!row || !meta) return '';\n        const counters = (meta.counter || []).map(x => String(window.normalizeConfigRelationName ? window.normalizeConfigRelationName(x) : x).replace(\/[^a-z0-9]+\/g, ''));\n        for (const k in row) { const c = String(window.normalizeConfigRelationName ? window.normalizeConfigRelationName(k) : k).replace(\/[^a-z0-9]+\/g, ''); if (counters.includes(c)) return k; }\n        return '';\n    };\n    window.getConfigEmptyTimeWarnings = function() {\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return '';\n        const labels = [];\n        for (const tName in window.currentDbData.Tabelle) {\n            const rows = Array.isArray(window.currentDbData.Tabelle[tName]) ? window.currentDbData.Tabelle[tName] : Object.values(window.currentDbData.Tabelle[tName] || {});\n            for (let i = 0; i < rows.length; i++) {\n                const row = rows[i] || {};\n                for (const key in row) {\n                    const val = row[key];\n                    if (val && typeof val === 'object') continue;\n                    const n = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(key) : String(key || '').toLowerCase();\n                    const isHourlyAmount = \/(^| )(costo|prezzo|tariffa|importo) orari[oa]( |$)\/.test(n)\n                        || \/(^| )(costo|prezzo|tariffa|importo) ora( |$)\/.test(n)\n                        || \/(^| )(costo|prezzo|tariffa|importo) per ora( |$)\/.test(n);\n                    const isTime = !isHourlyAmount && (\/(^| )(ora|orario)( |$)\/.test(n) || n.includes('ora appuntamento') || n.includes('ora variazione'));\n                    if (isTime && window.isEmptyOrStandardDayConfigTime(val)) labels.push('tabella ' + tName + ', riga ' + (i + 1) + ', campo ' + key);\n                }\n            }\n        }\n        if (!labels.length) return '';\n        const shown = labels.slice(0, 8).join('\\n- ');\n        const more = labels.length > 8 ? '\\n- ... altri ' + (labels.length - 8) + ' campi orari' : '';\n        return 'Seguono informazioni su campi non necessari, ma che sarebbe utile compilare.\\n\\nAvviso campi orari vuoti o --:--\\n- ' + shown + more + '\\n\\nOrario eventualmente riportato in note config, informazioni o istruzioni. In mancanza viene considerato l orario standard 09:00 - 18:00.\\nVerificare direttamente con la ditta la disponibilita specifica.';\n    };\n    window.extractConfigWarningTarget = function(issueOrMessage) {\n        const issue = (issueOrMessage && typeof issueOrMessage === 'object') ? issueOrMessage : {message:String(issueOrMessage || '')};\n        const msg = String(issue.message || issue.msg || issueOrMessage || '');\n        let table = String(issue.table || '');\n        let row = (typeof issue.row !== 'undefined') ? parseInt(issue.row, 10) : 0;\n        let field = String(issue.field || '');\n        if (!table) {\n            const mt = msg.match(\/tabella\\s+([^,\\.]+)\/i);\n            if (mt && mt[1]) table = mt[1].trim();\n        }\n        if (!row) {\n            const mr = msg.match(\/riga\\s+(\\d+)\/i);\n            if (mr && mr[1]) row = parseInt(mr[1], 10) || 0;\n        }\n        if (!field) {\n            const mf = msg.match(\/campo\\s+([^\\.]+?)(?:\\.|$)\/i);\n            if (mf && mf[1]) field = mf[1].trim();\n        }\n        return {table:table, row:row, field:field, message:msg};\n    };\n\n    window.openConfigTableForWarning = function(tableName, rowNum, fieldName) {\n        const tbl = String(tableName || '').trim();\n        if (!tbl) return false;\n        try { window.closeModal && window.closeModal('ti-alert-ov'); } catch(e) {}\n        if (window.openModal) window.openModal('ti-conf-ov');\n        if (window.renderConfig) window.renderConfig();\n        let det = null;\n        document.querySelectorAll('details.ti-cfg-details').forEach(function(d){\n            if (!det && d.dataset && String(d.dataset.tbl || '') === tbl) det = d;\n        });\n        if (!det) {\n            const nt = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(tbl) : tbl.toLowerCase();\n            document.querySelectorAll('details.ti-cfg-details').forEach(function(d){\n                const dt = d && d.dataset ? String(d.dataset.tbl || '') : '';\n                const nd = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(dt) : dt.toLowerCase();\n                if (!det && nd === nt) det = d;\n            });\n        }\n        if (!det) { window.tiAlert && window.tiAlert('Tabella da modificare non trovata: ' + window.escapeHtml(tbl)); return false; }\n        det.open = true;\n        det.style.boxShadow = '0 0 0 3px rgba(251,191,36,.9)';\n        setTimeout(function(){ det.style.boxShadow = ''; }, 4000);\n        let target = det;\n        const wantedIdx = rowNum ? (parseInt(rowNum, 10) - 1) : -1;\n        const wantedField = String(fieldName || '').trim();\n        if (wantedIdx >= 0) {\n            const inputs = det.querySelectorAll('[data-idx]');\n            inputs.forEach(function(el){\n                if (target !== det) return;\n                const idxOk = parseInt(el.getAttribute('data-idx') || '-1', 10) === wantedIdx;\n                const keyOk = !wantedField || String(el.getAttribute('data-key') || '').toLowerCase() === wantedField.toLowerCase();\n                if (idxOk && keyOk) target = el;\n            });\n            if (target === det) {\n                const rowEl = det.querySelector('tr[data-row-idx=\"' + wantedIdx + '\"]');\n                if (rowEl) target = rowEl;\n            }\n        }\n        setTimeout(function(){\n            try { target.scrollIntoView({behavior:'smooth', block:'center', inline:'center'}); } catch(e) { target.scrollIntoView && target.scrollIntoView(); }\n            if (target && target.focus) target.focus({preventScroll:true});\n            if (target && target.style) {\n                target.style.setProperty('outline', '3px solid #fbbf24', 'important');\n                target.style.setProperty('outline-offset', '2px', 'important');\n                setTimeout(function(){ target.style.removeProperty('outline'); target.style.removeProperty('outline-offset'); }, 5000);\n            }\n        }, 120);\n        return true;\n    };\n\n    window.showConfigValidationWarning = function(issues, partialSaveMode) {\n        const arr = Array.isArray(issues) ? issues : (issues ? [issues] : []);\n        if (!arr.length) return;\n        const first = window.extractConfigWarningTarget(arr[0]);\n        const shown = arr.slice(0, 6).map(function(it){\n            const t = window.extractConfigWarningTarget(it);\n            return '<li style=\"margin-bottom:8px;\">' + window.escapeHtml(t.message || String(it || 'Warning configurazione')) + '<\/li>';\n        }).join('');\n        const more = arr.length > 6 ? '<li style=\"margin-bottom:8px;\">... altri ' + (arr.length - 6) + ' warning<\/li>' : '';\n        const encTable = encodeURIComponent(first.table || '');\n        const encField = encodeURIComponent(first.field || '');\n        const btn = first.table ? '<br><button type=\"button\" class=\"ti-btn\" style=\"margin-top:10px;background:#2563eb;color:#fff;\" onclick=\"window.openConfigTableForWarning(decodeURIComponent(\\'' + encTable + '\\'),' + String(first.row || 0) + ',decodeURIComponent(\\'' + encField + '\\'))\">Apri tabella ' + window.escapeHtml(first.table) + '<\/button>' : '';\n        const intro = partialSaveMode ? 'Le tabelle valide sono state salvate o verranno salvate. La tabella indicata dal warning resta da correggere e non viene sovrascritta.' : 'Correggi il valore indicato prima di salvare quella tabella.';\n        window.tiAlert('<div class=\"ti-config-warning-content-668\" style=\"text-align:left;font-size:12px;line-height:1.25;\"><b style=\"font-size:13px;display:block;margin-bottom:4px;\">Warning configurazione<\/b><div style=\"font-size:12px;line-height:1.25;color:#e5e7eb;margin-bottom:6px;\">' + window.escapeHtml(intro) + '<\/div><ul style=\"margin-top:7px;padding-left:16px;font-size:12px;line-height:1.25;\">' + shown + more + '<\/ul>' + btn + '<\/div>');\n        try { if (window.tiApplyConfigWarningAlertStyle668) window.tiApplyConfigWarningAlertStyle668(); } catch(e) {}\n        setTimeout(function(){ try { if (window.tiApplyConfigWarningAlertStyle668) window.tiApplyConfigWarningAlertStyle668(); } catch(e) {} }, 0);\n    };\n\n    window.collectConfigValidationIssues = function() {\n        const issues = [];\n        if (!window.currentDbData || !window.currentDbData.Tabelle) return issues;\n        const allowedState = \/^(attivo|operativo|demo|configurazione|sospesa|cancellato)?$\/i;\n        const pushIssue = function(tName, rowNumber, key, message) {\n            issues.push({table:String(tName || ''), row:rowNumber || 0, field:String(key || ''), message:String(message || '')});\n        };\n        if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues();\n        window.configTimeFallbackWarning = window.getConfigEmptyTimeWarnings ? window.getConfigEmptyTimeWarnings() : '';\n        for (const tName in window.currentDbData.Tabelle) {\n            const rows = Array.isArray(window.currentDbData.Tabelle[tName]) ? window.currentDbData.Tabelle[tName] : Object.values(window.currentDbData.Tabelle[tName] || {});\n            for (let i = 0; i < rows.length; i++) {\n                const row = rows[i] || {};\n                for (const key in row) {\n                    const val = row[key];\n                    if (val && typeof val === 'object') continue;\n                    const n = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(key) : String(key || '').toLowerCase();\n                    const label = `tabella ${tName}, riga ${i + 1}, campo ${key}`;\n                    const periodMeta = window.getConfigPeriodPairMeta ? window.getConfigPeriodPairMeta(key) : null;\n                    if (periodMeta) {\n                        const counterKey = window.getConfigPeriodCounterpartKey ? window.getConfigPeriodCounterpartKey(row, periodMeta) : '';\n                        if (!counterKey) {\n                            const needed = periodMeta.kind === 'data' ? (periodMeta.side === 'start' ? 'A data \/ A gg' : 'Da data \/ Da gg') : (periodMeta.side === 'start' ? 'A ora' : 'Da ora');\n                            pushIssue(tName, i + 1, key, 'Periodo non completo in ' + label + '. I periodi devono avere due campi: da data a data e\/o da ora ad ora. Campo richiesto: ' + needed + '.');\n                            continue;\n                        }\n                        const thisEmpty = window.isEmptyConfigPeriodBoundary ? window.isEmptyConfigPeriodBoundary(val, periodMeta.kind) : !String(val || '').trim();\n                        const otherEmpty = window.isEmptyConfigPeriodBoundary ? window.isEmptyConfigPeriodBoundary(row[counterKey], periodMeta.kind) : !String(row[counterKey] || '').trim();\n                        if (thisEmpty !== otherEmpty) {\n                            pushIssue(tName, i + 1, key, 'Periodo non completo in tabella ' + tName + ', riga ' + (i + 1) + '. Compila entrambi i campi collegati: ' + key + ' e ' + counterKey + ', oppure lascia entrambi vuoti. Puoi indicare anche testo libero, che verra interpretato successivamente.');\n                            continue;\n                        }\n                    }\n                    const isDate = \/(^| )(data|gg)( |$)\/.test(n) || n.includes('data appuntamento') || n.includes('data variazione');\n                    const isHourlyAmount = \/(^| )(costo|prezzo|tariffa|importo) orari[oa]( |$)\/.test(n)\n                        || \/(^| )(costo|prezzo|tariffa|importo) ora( |$)\/.test(n)\n                        || \/(^| )(costo|prezzo|tariffa|importo) per ora( |$)\/.test(n);\n                    const isTime = !isHourlyAmount && (\/(^| )(ora|orario)( |$)\/.test(n) || n.includes('ora appuntamento') || n.includes('ora variazione'));\n                    if (isDate && !window.isValidConfigDate(val)) { pushIssue(tName, i + 1, key, 'Formato data non valido in ' + label + '. Usa DD\/MM\/YYYY per una data precisa, oppure testo libero descrittivo da interpretare successivamente.'); continue; }\n                    if (isTime && !window.isValidConfigTime(val)) { pushIssue(tName, i + 1, key, 'Formato ora non valido in ' + label + '. Usa HH:MM per un orario preciso, oppure testo libero descrittivo da interpretare successivamente.'); continue; }\n                    const isDocCounter1663 = \/(^| )(num ordine|num fattura|num corrispettivo)( |$)\/.test(n);\n                    if (isHourlyAmount || \/^(prezzo|costo|iva vat|iva|quantita|num ordine|num fattura|num corrispettivo)$\/.test(n) || \/(^| )(prezzo|costo|iva vat|quantita|num ordine|num fattura|num corrispettivo)( |$)\/.test(n)) {\n                        const maskOk1663 = isDocCounter1663 && \/^\\[[^\\[\\]\\r\\n]*#{1,12}\\d+[^\\[\\]\\r\\n]*\\]$\/.test(String(val || '').trim());\n                        if (!maskOk1663 && !window.isValidConfigNumber(val)) { pushIssue(tName, i + 1, key, 'Valore numerico\/formato non valido in ' + label + '. Usa un numero oppure una maschera documento, ad esempio [SS\/AAAA####0].'); continue; }\n                    }\n                    if (n === 'stato' || n === 'status') {\n                        const canonState = window.normalizeConfigStateValue ? window.normalizeConfigStateValue(val) : String(val || '').trim();\n                        if (canonState && ['Attivo','Operativo','Demo','Configurazione','Sospesa','Cancellato'].includes(canonState)) row[key] = canonState;\n                        if (!allowedState.test(String(row[key] || '').trim())) { pushIssue(tName, i + 1, key, 'Stato non valido in ' + label + '. Usa Attivo, Operativo, Demo, Configurazione, Sospesa o Cancellato.'); continue; }\n                    }\n                }\n            }\n        }\n        return issues;\n    };\n\n    window.validateConfigValues = function() {\n        const issues = window.collectConfigValidationIssues ? window.collectConfigValidationIssues() : [];\n        if (issues.length) { window.showConfigValidationWarning && window.showConfigValidationWarning(issues, false); return false; }\n        return true;\n    };\n\n    window.getConfigChangedTables = function() {\n        const map = {};\n        const add = function(t) { t = String(t || '').trim(); if (t) map[t] = true; };\n        try {\n            if (window.modifiedFields && typeof window.modifiedFields.forEach === 'function') {\n                window.modifiedFields.forEach(function(k) {\n                    k = String(k || '');\n                    const p = k.indexOf('-');\n                    if (p > 0) add(k.slice(0, p));\n                });\n            }\n        } catch(e) {}\n        try {\n            (window.tiConfigDeletedRowsManifest || []).forEach(function(it){ if (it && it.table) add(it.table); });\n        } catch(e) {}\n        try {\n            Object.keys(window.tiConfigDeletedTableSnapshots || {}).forEach(add);\n        } catch(e) {}\n        return Object.keys(map);\n    };\n\n    window.saveConfig = function() {\n        const saveNow585 = Date.now ? Date.now() : (new Date()).getTime();\n        if (window.__saveConfigInFlight) {\n            const started585 = parseInt(window.__tiSaveConfigStartedAt585 || window.__tiSaveConfigStartedAt || 0, 10) || 0;\n            if (started585 && (saveNow585 - started585) > 45000) {\n                try { if (window.tiForceUnlockConfigSave585) window.tiForceUnlockConfigSave585('Salvataggio precedente sbloccato automaticamente.'); } catch(e) {}\n            } else {\n                return;\n            }\n        }\n        if(!window.currentDbData) return;\n        if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory();\n        for(let t in window.currentDbData.Tabelle) { if(!Array.isArray(window.currentDbData.Tabelle[t])) window.currentDbData.Tabelle[t] = Object.values(window.currentDbData.Tabelle[t]); }\n        if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues();\n        if (window.validateConfigUniqueUsernames && !window.validateConfigUniqueUsernames()) return;\n        const configValidationIssues = window.collectConfigValidationIssues ? window.collectConfigValidationIssues() : [];\n        if (configValidationIssues.length) {\n            window.tiConfigValidationIssues = configValidationIssues;\n            if (window.showConfigValidationWarning) window.showConfigValidationWarning(configValidationIssues, true);\n        }\n        const btn = gE('lbl-conf-save');\n        let oldText = btn ? String(btn.innerText || '').trim() : 'Salva Modifiche';\n        if (!oldText || \/salvataggio\/i.test(oldText)) oldText = 'Salva Modifiche';\n        let oldBg = btn ? btn.style.background : '';\n        if (\/d97706|217\\s*,\\s*119\\s*,\\s*6\/i.test(String(oldBg || ''))) oldBg = '';\n        const restoreBtn = function(renderAfter){\n            window.__saveConfigInFlight = false;\n            window.__tiSaveConfigStartedAt585 = 0;\n            window.__tiSaveConfigStartedAt = 0;\n            try { if (window.__tiSaveConfigHardTimer585) { clearTimeout(window.__tiSaveConfigHardTimer585); window.__tiSaveConfigHardTimer585 = null; } } catch(e) {}\n            if (btn) {\n                try { btn.disabled = false; btn.removeAttribute('disabled'); } catch(e) { btn.disabled = false; }\n                try { btn.removeAttribute('aria-busy'); btn.removeAttribute('data-ti-saving'); } catch(e) {}\n                btn.style.pointerEvents = '';\n                btn.innerText = oldText;\n                try { btn.style.setProperty('background', '#374151', 'important'); btn.style.setProperty('background-color', '#374151', 'important'); btn.style.setProperty('color', '#fff', 'important'); } catch(e) { btn.style.background = oldBg || '#374151'; }\n            }\n            try { if (window.resetConfigSaveButtonUi668 && !window.__saveConfigInFlight) window.resetConfigSaveButtonUi668(false); } catch(e) {}\n            if (renderAfter) {\n                window.renderConfig();\n                window.keepPluginModalInFront('ti-conf-ov');\n                window.keepUserCommunicationPopupsInFront();\n            }\n        };\n        const hardUnlockSaveUi568 = function(reason){\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, reason || 'Salvataggio interrotto', {notifyUser:false}); } catch(e) {}\n            try {\n                document.querySelectorAll('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(el){\n                    if (el && el.parentNode) el.parentNode.removeChild(el);\n                });\n            } catch(e) {}\n            try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n            restoreBtn(false);\n            try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        };\n        window.tiForceUnlockConfigSave585 = hardUnlockSaveUi568;\n        window.tiForceUnlockConfigSave587 = hardUnlockSaveUi568;\n        window.tiForceUnlockConfigSave588 = hardUnlockSaveUi568;\n        const saveDiag588 = function(msg){\n            try {\n                window.__tiLastConfigSaveDiag588 = '[' + (new Date()).toLocaleTimeString() + '] ' + String(msg || '');\n                if (window.console && console.log) console.log('TI save config 588:', msg);\n            } catch(e) {}\n        };\n        const finishSaveUi588 = function(reason, renderAfter){\n            try { saveDiag588(reason || 'fine salvataggio'); } catch(e) {}\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(true, reason || 'Salvataggio configurazione concluso', {notifyUser:false}); } catch(e) {}\n            try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n            try { restoreBtn(!!renderAfter); } catch(e) { hardUnlockSaveUi568(reason || 'Fine salvataggio configurazione'); }\n            try {\n                const b588 = gE('lbl-conf-save');\n                if (b588) {\n                    try { b588.disabled = false; b588.removeAttribute('disabled'); } catch(e) { b588.disabled = false; }\n                    try { b588.removeAttribute('aria-busy'); b588.removeAttribute('data-ti-saving'); } catch(e) {}\n                    b588.style.pointerEvents = '';\n                    b588.innerText = 'Salva Modifiche';\n                    try { b588.style.setProperty('background', '#374151', 'important'); b588.style.setProperty('background-color', '#374151', 'important'); b588.style.setProperty('color', '#fff', 'important'); } catch(e) { b588.style.background = '#374151'; }\n                }\n                try { if (window.resetConfigSaveButtonUi668 && !window.__saveConfigInFlight) window.resetConfigSaveButtonUi668(false); } catch(e) {}\n            } catch(e) {}\n            try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        };\n        window.__saveConfigInFlight = true;\n        window.__tiSaveConfigStartedAt585 = saveNow585;\n        window.__tiSaveConfigStartedAt = saveNow585;\n        try { if (window.__tiSaveConfigHardTimer585) clearTimeout(window.__tiSaveConfigHardTimer585); } catch(e) {}\n        window.__tiSaveConfigHardTimer585 = setTimeout(function(){\n            if (!window.__saveConfigInFlight) return;\n            hardUnlockSaveUi568('Salvataggio configurazione sbloccato');\n            try { if (window.tiAlert) window.tiAlert('Il salvataggio non ha restituito una chiusura corretta entro il tempo previsto. Il blocco e stato rimosso. Verifica se le modifiche risultano salvate e, se necessario, ripeti Salva Modifiche.'); } catch(e) {}\n        }, 75000);\n        if (btn) {\n            btn.disabled = true;\n            try { btn.setAttribute('aria-busy', 'true'); btn.setAttribute('data-ti-saving', '1'); } catch(e) {}\n            btn.style.pointerEvents = 'none';\n            btn.innerText = 'Salvataggio...';\n            try { btn.style.setProperty('background', '#d97706', 'important'); btn.style.setProperty('background-color', '#d97706', 'important'); btn.style.setProperty('color', '#fff', 'important'); } catch(e) { btn.style.background = '#d97706'; }\n        }\n        if (window.refreshConfigDeletedTableSnapshotsFromCurrentData) window.refreshConfigDeletedTableSnapshotsFromCurrentData();\n        const pendingDeletedManifest = JSON.parse(JSON.stringify(window.tiConfigDeletedRowsManifest || []));\n        const pendingDeletedSnapshots = JSON.parse(JSON.stringify(window.tiConfigDeletedTableSnapshots || {}));\n        const pendingDeletedClientTotal = Math.max(parseInt(window.tiConfigDeletedRowsCountTotal || 0, 10) || 0, pendingDeletedManifest.length || 0);\n        const pendingDefinitiveDelete = pendingDeletedClientTotal > 0 || pendingDeletedManifest.length > 0 || Object.keys(pendingDeletedSnapshots || {}).length > 0;\n        const changedTablesForSave = window.getConfigChangedTables ? window.getConfigChangedTables() : [];\n        const hasRealConfigChanges587 = function(){\n            try {\n                if (!changedTablesForSave || !changedTablesForSave.length) return false;\n                if (!window.configOriginalDbData || !window.configOriginalDbData.Tabelle || !window.currentDbData || !window.currentDbData.Tabelle) return true;\n                for (let i587 = 0; i587 < changedTablesForSave.length; i587++) {\n                    const t587 = changedTablesForSave[i587];\n                    const cur587 = window.currentDbData.Tabelle ? window.currentDbData.Tabelle[t587] : undefined;\n                    const old587 = window.configOriginalDbData.Tabelle ? window.configOriginalDbData.Tabelle[t587] : undefined;\n                    if (JSON.stringify(cur587 === undefined ? null : cur587) !== JSON.stringify(old587 === undefined ? null : old587)) return true;\n                }\n                return false;\n            } catch(e) {\n                return true;\n            }\n        };\n        const realChangesForSave587 = hasRealConfigChanges587();\n        if (!pendingDefinitiveDelete && !realChangesForSave587) {\n            try { if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); } catch(e) {}\n            try { window.configWasSaved = true; } catch(e) {}\n            try { window.__saveConfigInFlight = false; window.__tiSaveConfigStartedAt585 = 0; window.__tiSaveConfigStartedAt = 0; } catch(e) {}\n            try { if (window.__tiSaveConfigHardTimer585) { clearTimeout(window.__tiSaveConfigHardTimer585); window.__tiSaveConfigHardTimer585 = null; } } catch(e) {}\n            try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Nessuna modifica da salvare', {notifyUser:false}); } catch(e) {}\n            try {\n                document.querySelectorAll('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(el){\n                    if (el && el.parentNode) el.parentNode.removeChild(el);\n                });\n            } catch(e) {}\n            try {\n                if (btn) {\n                    btn.disabled = false;\n                    btn.style.pointerEvents = '';\n                    btn.innerText = 'Salva Modifiche';\n                    try { btn.style.removeProperty('background'); btn.style.removeProperty('background-color'); } catch(e) { btn.style.background = ''; }\n                }\n                try { if (window.resetConfigSaveButtonUi668) window.resetConfigSaveButtonUi668(true); } catch(e) {}\n            } catch(e) {}\n            try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n            try { if (window.tiAlert) window.tiAlert('Nessuna modifica da salvare.'); } catch(e) {}\n            return;\n        }\n        const postConfigForm = function(fd, customSignal) {\n            return new Promise(function(resolve, reject){\n                const ctrl = (typeof AbortController !== 'undefined') ? new AbortController() : null;\n                let finished = false;\n                const timeoutMs = 65000;\n                const timer = setTimeout(function(){\n                    if (finished) return;\n                    finished = true;\n                    try { if (ctrl) ctrl.abort(); } catch(e) {}\n                    reject(new Error('Timeout salvataggio configurazione. La richiesta e stata interrotta lato browser: verifica se i dati risultano salvati, poi riapri la Configurazione.'));\n                }, timeoutMs);\n                try { saveDiag588('richiesta server avviata'); } catch(e) {}\n                fetch(window.tiUrl, {method:'POST', body:fd, signal: ctrl ? ctrl.signal : undefined, credentials:'same-origin', cache:'no-store'}).then(function(r){\n                    return r.text().then(function(txt){\n                        try { saveDiag588('risposta server HTTP ' + r.status + ', bytes=' + String(txt || '').length); } catch(e) {}\n                        if (r.status === 413) throw new Error('Errore 413: Limite superato.');\n                        if (!r.ok) throw new Error('Errore Server ' + r.status + (txt ? ': ' + txt.slice(0, 220) : ''));\n                        try { return JSON.parse(txt); }\n                        catch(e) { throw new Error('Risposta salvataggio non valida: ' + String(txt || '').slice(0, 220)); }\n                    });\n                }).then(function(data){\n                    if (finished) return;\n                    finished = true;\n                    clearTimeout(timer);\n                    resolve(data);\n                }).catch(function(err){\n                    if (finished) return;\n                    finished = true;\n                    clearTimeout(timer);\n                    reject(err);\n                });\n            });\n        };\n        const dbName = gE('ti-ditta') ? gE('ti-ditta').value : '';\n        const currentVersion = function(){ return (window.currentDbData && window.currentDbData.__db_version) ? window.currentDbData.__db_version : ''; };\n        const makeSaveForm = function(dbVersion, includeDeleteManifest) {\n            const fdSave = new FormData();\n            fdSave.append('ti_action', 'ti_ai_save_full_db');\n            fdSave.append('db', dbName);\n            const changedForPayload570 = window.getConfigChangedTables ? window.getConfigChangedTables() : [];\n            let savePayload570 = window.currentDbData || {};\n            if (changedForPayload570.length && window.currentDbData && window.currentDbData.Tabelle) {\n                const compactTables570 = {};\n                changedForPayload570.forEach(function(t){ if (window.currentDbData.Tabelle && window.currentDbData.Tabelle[t]) compactTables570[t] = window.currentDbData.Tabelle[t]; });\n                if (Object.keys(compactTables570).length) {\n                    savePayload570 = {Database: window.currentDbData.Database || dbName, __db_version: window.currentDbData.__db_version || '', Tabelle: compactTables570};\n                    fdSave.append('compact_save', '1');\n                }\n            }\n            fdSave.append('payload', utoa(JSON.stringify(savePayload570 || {})));\n            fdSave.append('light_save', '1');\n            fdSave.append('response_light', '1');\n            fdSave.append('save_mode', 'light');\n            fdSave.append('db_version', dbVersion || currentVersion() || '');\n            fdSave.append('changed_tables', utoa(JSON.stringify(changedForPayload570)));\n            if (includeDeleteManifest) {\n                fdSave.append('deleted_rows', utoa(JSON.stringify(pendingDeletedManifest)));\n                fdSave.append('deleted_table_snapshots', utoa(JSON.stringify(pendingDeletedSnapshots)));\n                fdSave.append('deleted_rows_client_total', String(pendingDeletedClientTotal || 0));\n            } else {\n                fdSave.append('deleted_rows', utoa(JSON.stringify([])));\n                fdSave.append('deleted_table_snapshots', utoa(JSON.stringify({})));\n                fdSave.append('deleted_rows_client_total', '0');\n                fdSave.append('delete_already_applied', '1');\n            }\n            return fdSave;\n        };\n        const makeDeleteForm = function() {\n            const fdDelete = new FormData();\n            fdDelete.append('ti_action', 'ti_ai_config_delete_rows_definitive');\n            fdDelete.append('db', dbName);\n            fdDelete.append('db_version', currentVersion() || '');\n            fdDelete.append('deleted_rows', utoa(JSON.stringify(pendingDeletedManifest)));\n            fdDelete.append('deleted_table_snapshots', utoa(JSON.stringify(pendingDeletedSnapshots)));\n            fdDelete.append('deleted_rows_client_total', String(pendingDeletedClientTotal || 0));\n            return fdDelete;\n        };\n\n        if (pendingDefinitiveDelete && window.showProgressPopup) {\n            window.showProgressPopup('Cancellazione definitiva configurazione', 'Clessidra attiva. Avvio la cancellazione definitiva dei record selezionati dal database ditta, poi salvo le modifiche residue. Attendi la fine del processo.', {startPercent: 8, targetPercent: 92, stepMs: 350, cancellable:false});\n        }\n\n        const saveSignal = undefined;\n        const finishSaveOk = function(saveData, definitiveDeletedTotal){\n            saveData = saveData || {};\n            const saveDeletedTotal = (typeof saveData.deleted_rows_total !== 'undefined') ? (parseInt(saveData.deleted_rows_total, 10) || 0) : 0;\n            const deletedTotal = Math.max(0, parseInt(definitiveDeletedTotal || 0, 10) || 0) + Math.max(0, saveDeletedTotal);\n            const saveMsg = deletedTotal > 0 ? ('Configurazione salvata con successo. Cancellazione definitiva completata. Righe cancellate: ' + deletedTotal + '.') : 'Configurazione salvata con successo.';\n            if (pendingDefinitiveDelete && window.hideProgressPopup) window.hideProgressPopup(true, 'Configurazione salvata', {notifyUser:true, remindSave:false, successMessage:saveMsg});\n            const serverWarnings = (saveData && Array.isArray(saveData.value_warnings)) ? saveData.value_warnings : [];\n            setTimeout(function(){ if (serverWarnings.length && window.showConfigValidationWarning) window.showConfigValidationWarning(serverWarnings, true); else if (window.tiAlert) window.tiAlert(deletedTotal > 0 ? ('\u2705 Salvataggio completato. Righe cancellate: ' + deletedTotal + '.') : '\u2705 Salvataggio completato.'); }, 250);\n            const cfgTimeWarn = String(window.configTimeFallbackWarning || '');\n            if (cfgTimeWarn) setTimeout(function(){ window.tiAlert(cfgTimeWarn); }, 1000);\n            window.configWasSaved = true;\n            if (saveData && saveData.db && saveData.db.Tabelle) {\n                window.currentDbData = saveData.db;\n                window.currentDbViewData = null;\n            } else if (window.currentDbData && saveData && saveData.db_version) {\n                window.currentDbData.__db_version = saveData.db_version;\n            }\n            if (window.currentDbData && saveData && saveData.db_version) window.currentDbData.__db_version = saveData.db_version;\n            if (window.currentDbData) window.configOriginalDbData = JSON.parse(JSON.stringify(window.currentDbData || {}));\n            if(window.modifiedFields) window.modifiedFields.clear();\n            try { if (window.resetConfigSaveButtonUi668) window.resetConfigSaveButtonUi668(true); } catch(e) {}\n            window.tiConfigDeletedRowsManifest = [];\n            window.tiConfigDeletedTableSnapshots = {};\n            window.tiConfigDeletedTableSnapshotBeforeCounts = {};\n            window.tiConfigDeletedRowsCountTotal = 0;\n            window.tiLastConfigDeleteCount = 0;\n            const mustRenderAfterSave = !!(serverWarnings.length || deletedTotal > 0 || (saveData && saveData.force_render_after_save));\n            try { finishSaveUi588('Salvataggio configurazione concluso', mustRenderAfterSave); }\n            catch(e) { try { restoreBtn(mustRenderAfterSave); } catch(x) {} }\n        };\n        const runFinalSave = function(versionAfterDelete, definitiveDeletedTotal, includeDeleteManifest) {\n            if (pendingDefinitiveDelete && window.updateProgressPopup) window.updateProgressPopup(78, 'Salvataggio finale configurazione', 'Cancellazione definitiva conclusa. Salvo ora il database aggiornato.', 'Righe cancellate: ' + Math.max(0, definitiveDeletedTotal || 0));\n            return postConfigForm(makeSaveForm(versionAfterDelete || currentVersion(), includeDeleteManifest), saveSignal).then(function(d){\n                if (d && d.success) {\n                    try { saveDiag588('salvataggio confermato dal server'); } catch(e) {}\n                    finishSaveOk((d && d.data) ? d.data : {}, definitiveDeletedTotal || 0);\n                    return d;\n                }\n                try { saveDiag588('salvataggio rifiutato dal server'); } catch(e) {}\n                throw new Error((d && d.data && d.data.message) ? d.data.message : 'salvataggio non riuscito');\n            });\n        };\n\n        const buildDeltaChanges589 = function(){\n            try {\n                if (pendingDefinitiveDelete) return null;\n                if (!window.modifiedFields || typeof window.modifiedFields.forEach !== 'function') return null;\n                if (!window.currentDbData || !window.currentDbData.Tabelle || !window.configOriginalDbData || !window.configOriginalDbData.Tabelle) return null;\n                const tables589 = Object.keys(window.currentDbData.Tabelle || {}).sort(function(a,b){ return String(b).length - String(a).length; });\n                const changes589 = [];\n                const seen589 = {};\n                window.modifiedFields.forEach(function(rawKey){\n                    rawKey = String(rawKey || '');\n                    if (!rawKey) return;\n                    let parsed589 = null;\n                    for (let i589 = 0; i589 < tables589.length; i589++) {\n                        const t589 = tables589[i589];\n                        const prefix589 = String(t589) + '-';\n                        if (rawKey.indexOf(prefix589) !== 0) continue;\n                        const rest589 = rawKey.slice(prefix589.length);\n                        const p589 = rest589.indexOf('-');\n                        if (p589 <= 0) continue;\n                        const idxStr589 = rest589.slice(0, p589);\n                        const key589 = rest589.slice(p589 + 1);\n                        if (!\/^\\d+$\/.test(idxStr589) || !key589 || key589.indexOf('__') === 0) { parsed589 = false; break; }\n                        parsed589 = {table:t589, row:parseInt(idxStr589,10), key:key589};\n                        break;\n                    }\n                    if (parsed589 === false) { changes589.__invalid = true; return; }\n                    if (!parsed589) { changes589.__invalid = true; return; }\n                    const curRows589 = window.currentDbData.Tabelle[parsed589.table];\n                    const oldRows589 = window.configOriginalDbData.Tabelle[parsed589.table];\n                    if (!Array.isArray(curRows589) || !curRows589[parsed589.row] || typeof curRows589[parsed589.row] !== 'object') { changes589.__invalid = true; return; }\n                    if (!Array.isArray(oldRows589) || !oldRows589[parsed589.row] || typeof oldRows589[parsed589.row] !== 'object') { changes589.__invalid = true; return; }\n                    const curVal589 = curRows589[parsed589.row][parsed589.key];\n                    const oldVal589 = oldRows589[parsed589.row][parsed589.key];\n                    if (JSON.stringify(curVal589 == null ? '' : curVal589) === JSON.stringify(oldVal589 == null ? '' : oldVal589)) return;\n                    const sig589 = parsed589.table + '\\u0001' + parsed589.row + '\\u0001' + parsed589.key;\n                    if (seen589[sig589]) return;\n                    seen589[sig589] = true;\n                    changes589.push({table:parsed589.table, row:parsed589.row, key:parsed589.key, value:(curVal589 == null ? '' : curVal589)});\n                });\n                if (changes589.__invalid) return null;\n                if (changes589.length > 300) return null;\n                return changes589;\n            } catch(e) { return null; }\n        };\n        const runDeltaSave589 = function(deltaChanges589){\n            const fdDelta589 = new FormData();\n            fdDelta589.append('ti_action', 'ti_ai_save_config_delta');\n            fdDelta589.append('db', dbName);\n            fdDelta589.append('db_version', currentVersion() || '');\n            fdDelta589.append('changes', utoa(JSON.stringify(deltaChanges589 || [])));\n            try { saveDiag588('salvataggio delta 589 avviato; modifiche=' + String((deltaChanges589 || []).length)); } catch(e) {}\n            return postConfigForm(fdDelta589, saveSignal).then(function(d){\n                if (d && d.success) {\n                    try { saveDiag588('salvataggio delta 589 confermato dal server'); } catch(e) {}\n                    finishSaveOk((d && d.data) ? d.data : {}, 0);\n                    return d;\n                }\n                throw new Error((d && d.data && d.data.message) ? d.data.message : 'salvataggio rapido non riuscito');\n            });\n        };\n        const deltaChanges589 = buildDeltaChanges589();\n        if (deltaChanges589 && deltaChanges589.length > 0) {\n            runDeltaSave589(deltaChanges589).catch(function(e){\n                hardUnlockSaveUi568('Errore salvataggio rapido');\n                const msg589 = (e && e.message) ? e.message : 'Errore durante il salvataggio rapido.';\n                if (window.tiAlert) window.tiAlert(msg589); else alert(msg589);\n            }).finally(function(){\n                setTimeout(function(){\n                    if (window.__saveConfigInFlight) finishSaveUi588('Fine salvataggio rapido configurazione', false);\n                    const b589 = gE('lbl-conf-save');\n                    if (b589 && \/salvataggio\/i.test(String(b589.innerText || ''))) {\n                        b589.disabled = false;\n                        b589.style.pointerEvents = '';\n                        b589.innerText = 'Salva Modifiche';\n                        try { b589.style.removeProperty('background'); b589.style.removeProperty('background-color'); } catch(e) {}\n                    }\n                    try { if (!window.__saveConfigInFlight && window.resetConfigSaveButtonUi668) window.resetConfigSaveButtonUi668(false); } catch(e) {}\n                }, 120);\n            });\n            return;\n        }\n\n        let flowPromise;\n        if (pendingDefinitiveDelete) {\n            if (window.updateProgressPopup) window.updateProgressPopup(20, 'Cancellazione definitiva in corso', 'Il server sta rileggendo il database reale e cancellando i record selezionati.', 'Righe da cancellare: ' + pendingDeletedClientTotal);\n            flowPromise = postConfigForm(makeDeleteForm(), saveSignal).then(function(delRes){\n                if (!(delRes && delRes.success)) throw new Error((delRes && delRes.data && delRes.data.message) ? delRes.data.message : 'cancellazione definitiva non riuscita');\n                const delData = (delRes && delRes.data) ? delRes.data : {};\n                const deletedByEndpoint = (typeof delData.deleted_rows_total !== 'undefined') ? (parseInt(delData.deleted_rows_total, 10) || 0) : 0;\n                const versionAfterDelete = delData.db_version || currentVersion();\n                if (window.updateProgressPopup) window.updateProgressPopup(62, 'Cancellazione definitiva verificata', 'Il processo server di cancellazione definitiva e terminato. Proseguo con il salvataggio finale.', 'Righe cancellate: ' + deletedByEndpoint);\n                return runFinalSave(versionAfterDelete, deletedByEndpoint, false);\n            }).catch(function(firstErr){\n                \/\/ Fallback controllato: se l endpoint separato non riesce a trovare righe ma il payload corrente e gia ridotto,\n                \/\/ il salvataggio finale usa il payload ridotto come fonte autorevole e verifica la scrittura su file.\n                if (window.updateProgressPopup) window.updateProgressPopup(55, 'Cancellazione tramite salvataggio finale', 'Endpoint separato non conclusivo. Applico la tabella ridotta direttamente nel salvataggio finale verificato.', firstErr && firstErr.message ? firstErr.message : 'fallback');\n                return runFinalSave(currentVersion(), 0, true);\n            });\n        } else {\n            flowPromise = runFinalSave(currentVersion(), 0, true);\n        }\n\n        flowPromise.catch(function(e) {\n            const msg = (e && e.message) ? e.message : 'Errore durante il salvataggio.';\n            if (e && (e.name === 'AbortError' || e.userCancelled || (window.isLongAIProcessCancelled && window.isLongAIProcessCancelled()))) {\n                hardUnlockSaveUi568('Salvataggio interrotto');\n                return;\n            }\n            hardUnlockSaveUi568('Errore salvataggio');\n            if (window.tiAlert) window.tiAlert(msg); else alert(msg);\n        }).finally(function(){\n            setTimeout(function(){\n                if (window.__saveConfigInFlight) finishSaveUi588('Fine salvataggio configurazione', false);\n                const b585 = gE('lbl-conf-save');\n                if (b585 && \/salvataggio\/i.test(String(b585.innerText || ''))) {\n                    b585.disabled = false;\n                    b585.style.pointerEvents = '';\n                    b585.innerText = 'Salva Modifiche';\n                    try { b585.style.removeProperty('background'); b585.style.removeProperty('background-color'); } catch(e) {}\n                }\n                try { if (!window.__saveConfigInFlight && window.resetConfigSaveButtonUi668) window.resetConfigSaveButtonUi668(false); } catch(e) {}\n            }, 120);\n        });\n    };\n\n    window.updateMemField = function(tbl, idx, key, el) { \n        const protNorm = v => String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[^a-z0-9]\/g, '');\n        if (!(window.tiAiSsIsDatabaseFullAdmin1562 && window.tiAiSsIsDatabaseFullAdmin1562()) && protNorm(tbl) === 'config' && ['stato','datacreazione','dataattivazione','wcorderid','wcactivateid'].includes(protNorm(key))) {\n            if (el && typeof el.blur === 'function') el.blur();\n            if (window.tiAlert) window.tiAlert('Campo riservato: modificabile solo da sistema, globaladmin o attivazione WooCommerce.');\n            return;\n        }\n        if(window.currentDbData && window.currentDbData.Tabelle[tbl] && window.currentDbData.Tabelle[tbl][idx]) { \n            let normalizedValue = window.normalizeInputValueForKey(key, el.value);\n            const fieldNorm = window.normalizeConfigRelationName ? window.normalizeConfigRelationName(key) : String(key || '').toLowerCase();\n            if (fieldNorm === 'stato' || fieldNorm === 'status') {\n                normalizedValue = window.normalizeConfigStateValue ? window.normalizeConfigStateValue(normalizedValue) : normalizedValue;\n                if (el && ['Attivo','Operativo','Demo','Configurazione','Sospesa','Cancellato'].includes(normalizedValue)) el.value = normalizedValue;\n            }\n            window.currentDbData.Tabelle[tbl][idx][key] = normalizedValue;\n            window.__configRelationSupportCache = null;\n            window.forceWhiteEditStyle && window.forceWhiteEditStyle(el);\n            el.style.setProperty('border-color', '#fbbf24', 'important');\n            if(!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(`${tbl}-${idx}-${key}`);\n            if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            if (window.checkConfigUsernameDuplicateInput) window.checkConfigUsernameDuplicateInput(tbl, idx, key, el);\n        } \n    };\n\n    window.ensureSharedSetupModal = function() {\n        if (gE('ti-shared-setup-ov')) return;\n        const wrap = document.createElement('div');\n        wrap.id = 'ti-shared-setup-ov';\n        wrap.className = 'ti-ov';\n        wrap.innerHTML = `<div class=\"ti-modal\" style=\"width:96%;max-width:760px;text-align:left;\">\n            <h3 style=\"margin-top:0;color:#fff;\">Setup storage centralizzato<\/h3>\n            <div style=\"font-size:12px;color:#9ca3af;margin-bottom:12px;\">Disponibile solo per l amministratore globale. Definisce percorso filesystem condiviso e URL pubblico del repository AI-data usato dal plugin su siti diversi. PATH e URL non devono essere identici come stringa: il PATH e un percorso server, l URL e un indirizzo web pubblico.<\/div>\n            <label style=\"display:block;font-size:12px;color:#bfdbfe;margin-bottom:6px;\">TI_AI_SS_SHARED_BASE_PATH<\/label>\n            <input id=\"ti-shared-base-path\" class=\"ti-in\" placeholder=\"\/percorso\/condiviso\/wp-content\/uploads\/AI-data\/\">\n            <label style=\"display:block;font-size:12px;color:#bfdbfe;margin:12px 0 6px 0;\">TI_AI_SS_SHARED_BASE_URL<\/label>\n            <input id=\"ti-shared-base-url\" class=\"ti-in\" placeholder=\"https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\">\n            <div id=\"ti-shared-setup-info\" style=\"margin-top:12px;font-size:12px;line-height:1.45;color:#cbd5e1;background:#020617;border:1px solid #334155;border-radius:8px;padding:10px;\"><\/div>\n            <div style=\"display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap;margin-top:14px;\">\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#334155;color:#fff;\" onclick=\"window.fillSharedSetupDefaults()\">Usa valori default<\/button>\n                <button type=\"button\" class=\"ti-btn\" onclick=\"window.closeModal('ti-shared-setup-ov')\">Chiudi<\/button>\n                <button type=\"button\" class=\"ti-btn\" style=\"background:#a16207;color:#fff;\" onclick=\"window.saveSharedSetup()\">Salva setup centralizzato<\/button>\n            <\/div>\n        <\/div>`;\n        document.body.appendChild(wrap);\n        if (window.portalizePluginModals) window.portalizePluginModals();\n    };\n\n    window.refreshSharedSetupInfo = function() {\n        const info = gE('ti-shared-setup-info');\n        if (!info) return;\n        const payload = window.tiSharedSetup || {};\n        info.innerHTML = 'Path condiviso salvato:<br><b>' + window.escapeHtml(payload.shared_base_path || '(non impostato)') + '<\/b><br><br>URL condiviso salvato:<br><b>' + window.escapeHtml(payload.shared_base_url || '(non impostato)') + '<\/b><br><br>Percorso effettivo in uso:<br><b>' + window.escapeHtml(payload.effective_base_path || '') + '<\/b><br><br>URL effettivo in uso:<br><b>' + window.escapeHtml(payload.effective_base_url || '') + '<\/b><br><br>Valori default disponibili:<br><b>' + window.escapeHtml(payload.default_base_path || '') + '<\/b><br><b>' + window.escapeHtml(payload.default_base_url || '') + '<\/b><br><br>Esempio URL centralizzato Target Informatica:<br><b>' + window.escapeHtml(payload.target_url_example || '') + '<\/b>';\n    };\n\n    window.fillSharedSetupDefaults = function() {\n        const payload = window.tiSharedSetup || {};\n        const pathInp = gE('ti-shared-base-path');\n        const urlInp = gE('ti-shared-base-url');\n        if (pathInp) pathInp.value = payload.default_base_path || '';\n        if (urlInp) urlInp.value = payload.default_base_url || '';\n    };\n\n    window.openSharedSetupModal = function() {\n        if (window.tiUser !== 'SSGlobalAdmin') { window.tiAlert('Solo l amministratore globale puo usare questo setup.'); return; }\n        window.ensureSharedSetupModal();\n        const payload = window.tiSharedSetup || {};\n        const pathInp = gE('ti-shared-base-path');\n        const urlInp = gE('ti-shared-base-url');\n        if (pathInp) pathInp.value = payload.shared_base_path || payload.default_base_path || '';\n        if (urlInp) urlInp.value = payload.shared_base_url || payload.default_base_url || '';\n        window.refreshSharedSetupInfo();\n        window.openModal('ti-shared-setup-ov');\n    };\n\n    window.saveSharedSetup = function() {\n        if (window.tiUser !== 'SSGlobalAdmin') { window.tiAlert('Solo l amministratore globale puo salvare questo setup.'); return; }\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_config_action');\n        fd.append('mode', 'shared_setup_save');\n        fd.append('shared_base_path', (gE('ti-shared-base-path') && gE('ti-shared-base-path').value) ? gE('ti-shared-base-path').value : '');\n        fd.append('shared_base_url', (gE('ti-shared-base-url') && gE('ti-shared-base-url').value) ? gE('ti-shared-base-url').value : '');\n        window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n            if (!res || !res.success) { window.tiAlert((res && res.data && res.data.message) ? res.data.message : 'Errore salvataggio setup centralizzato.'); return; }\n            window.tiSharedSetup = (res.data && res.data.shared_setup) ? res.data.shared_setup : (window.tiSharedSetup || {});\n            window.tiUploadBase = String((window.tiSharedSetup && window.tiSharedSetup.effective_base_url) || window.tiUploadBase || '').replace(\/\\\/$\/, '');\n            const manualBtn = gE('btn-manual');\n            const sharedManualUrl = String((window.tiSharedSetup && window.tiSharedSetup.manual_url) || '');\n            const sharedDocsBaseUrl = String((window.tiSharedSetup && window.tiSharedSetup.docs_base_url) || 'https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service');\n            if (manualBtn && sharedManualUrl) manualBtn.href = sharedManualUrl;\n            else if (manualBtn && sharedDocsBaseUrl) manualBtn.href = sharedDocsBaseUrl.replace(\/\\\/+$\/, '') + '\/Shop-Service%20Manual.pdf';\n            window.refreshSharedSetupInfo();\n            const replyBox = gE('ti-conf-ai-reply');\n            if (replyBox && res.data && res.data.reply) { replyBox.style.display = 'block'; replyBox.innerHTML = window.escapeHtml(res.data.reply); }\n            window.tiAlert('Setup centralizzato salvato.');\n        }).catch(function(err){\n            window.tiAlert('Errore salvataggio setup centralizzato: ' + ((err && err.message) ? err.message : 'errore sconosciuto'));\n        });\n    };\n\n\n    window.ensureConfigBotLoadingStyle = function() {\n        if (gE('ti-conf-ai-loading-style')) return;\n        const st = document.createElement('style');\n        st.id = 'ti-conf-ai-loading-style';\n        st.innerHTML = '@keyframes tiConfHourglassSpin{0%{transform:rotate(0deg);}50%{transform:rotate(180deg);}100%{transform:rotate(360deg);}}' +\n            '@keyframes tiConfDots{0%,20%{opacity:.2;}50%{opacity:1;}100%{opacity:.2;}}' +\n            '.ti-conf-wait{display:flex;align-items:center;gap:12px;padding:2px 0;}' +\n            '.ti-conf-wait-icon{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:999px;background:#1f2937;border:1px solid #475569;font-size:18px;animation:tiConfHourglassSpin 1.25s ease-in-out infinite;}' +\n            '.ti-conf-wait-text{display:flex;flex-direction:column;gap:2px;line-height:1.35;}' +\n            '.ti-conf-wait-title{font-weight:700;color:#f8fafc;}' +\n            '.ti-conf-wait-sub{font-size:12px;color:#93c5fd;}' +\n            '.ti-conf-wait-dots span{display:inline-block;animation:tiConfDots 1.2s infinite;}' +\n            '.ti-conf-wait-dots span:nth-child(2){animation-delay:.2s;}' +\n            '.ti-conf-wait-dots span:nth-child(3){animation-delay:.4s;}';\n        document.head.appendChild(st);\n    };\n\n    window.getConfigBotWaitingHtml = function(message, detail) {\n        window.ensureConfigBotLoadingStyle();\n        const msg = window.escapeHtml(message || 'Fammi pensare');\n        const sub = window.escapeHtml(detail || 'Sto verificando database, documenti AI e istruzioni disponibili.');\n        return '<div class=\"ti-conf-wait\" aria-live=\"polite\" aria-busy=\"true\">'\n            + '<div class=\"ti-conf-wait-icon\" title=\"Attendere\">\u23f3<\/div>'\n            + '<div class=\"ti-conf-wait-text\">'\n            + '<div class=\"ti-conf-wait-title\">' + msg + ' <span class=\"ti-conf-wait-dots\"><span>.<\/span><span>.<\/span><span>.<\/span><\/span><\/div>'\n            + '<div class=\"ti-conf-wait-sub\">' + sub + '<\/div>'\n            + '<\/div>'\n            + '<\/div>';\n    };\n\n\n    window.getUserWaitingHtml = function(message, detail) {\n        window.ensureConfigBotLoadingStyle();\n        const msg = window.escapeHtml(message || 'Fammi pensare...');\n        const explicitDetail = (arguments.length >= 2);\n        const detailText = explicitDetail ? String(detail == null ? '' : detail) : 'Sto elaborando la richiesta e verifico i dati disponibili.';\n        const sub = window.escapeHtml(detailText);\n        return '<div class=\"ti-conf-wait ti-user-wait\" aria-live=\"polite\" aria-busy=\"true\">'\n            + '<div class=\"ti-conf-wait-icon\" title=\"Attendere\">\u23f3<\/div>'\n            + '<div class=\"ti-conf-wait-text\">'\n            + '<div class=\"ti-conf-wait-title\">' + msg + '<\/div>'\n            + (sub ? '<div class=\"ti-conf-wait-sub\">' + sub + '<\/div>' : '')\n            + '<\/div>'\n            + '<\/div>';\n    };\n\n\n    window.tiIsInfoVerificationRequest = function(text) {\n        const raw = String(text || '').trim();\n        if (!raw) return false;\n        const t = raw.toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '');\n        if (\/\\b(conferma\\s+ordine|conferma\\s+righe|salva\\s+ordine|annulla|login|logout|accedi|importa|carica\\s+file|scatta|foto)\\b\/i.test(t)) return false;\n        if (\/\\b(che\\s+mi\\s+dici|cosa\\s+mi\\s+dici|cosa\\s+sai|dimmi|spiegami|spiega|informazioni?\\s+su|info\\s+su|a\\s+cosa\\s+serve|come\\s+funziona|condizioni|contrattual|commercial|privacy|gdpr|documento|documenti|scheda|bugiardino|foglietto|aspirina|farmaco|farmaci|prodotto|servizio)\\b\/i.test(t)) return true;\n        const wordCount = t.split(\/\\s+\/).filter(Boolean).length;\n        return wordCount >= 2 && wordCount <= 8 && !\/[0-9]+\\s*(pz|pezzi|unita|unit\u00e0|conf|confezioni|kg|g|ml|litri?)\\b\/i.test(t);\n    };\n\n    window.getInfoVerificationWaitingHtml = function(message, detail) {\n        return window.getUserWaitingHtml(\n            message || '\u23f3 Verifica informazioni in corso...',\n            detail || 'Sto cercando informazioni in database ditta, prodotti\/servizi, righe ordine e documenti collegati.'\n        );\n    };\n\n    window.clearConfigBot = function() {\n        const p = gE('ti-conf-ai-prompt'); const r = gE('ti-conf-ai-reply'); const f = gE('ti-conf-ai-file');\n        if (p) p.value = '';\n        if (r) { r.style.display = 'none'; r.innerHTML = ''; }\n        window.configBotFile = null;\n        if (f) { f.style.display = 'none'; f.innerHTML = ''; }\n    };\n\n    window.showConfigImportPreview = function(previewText, importToken) {\n        if (importToken) window.tiConfigImportToken = importToken;\n        const body = gE('ti-conf-import-preview-body');\n        if (body) {\n            body.innerHTML = (previewText || '').replace(\/\\[NO_VOICE\\]\/g, '').trim();\n            if (window.tiConfigImportToken) body.dataset.importToken = window.tiConfigImportToken;\n            if (window.initConfigTopScrollbars) {\n                window.initConfigTopScrollbars(body);\n                setTimeout(function(){ window.initConfigTopScrollbars(body); }, 60);\n                setTimeout(function(){ window.initConfigTopScrollbars(body); }, 250);\n                setTimeout(function(){ window.initConfigTopScrollbars(body); }, 600);\n            }\n        }\n        const refineBox = gE('ti-conf-import-refine-prompt');\n        const refineStatus = gE('ti-conf-import-refine-status');\n        if (refineBox) refineBox.value = '';\n        if (refineStatus) refineStatus.innerHTML = '';\n        window.tiConfigImportRefineRules = [];\n        window.markConfigImportPreviewUpdated('Anteprima pronta. Verifica i dati e conferma solo se corretti.');\n        window.openModal('ti-conf-import-preview-ov');\n    };\n\n    window.hasPendingImportAssociations = function() {\n        const body = gE('ti-conf-import-preview-body');\n        if (!body) return false;\n        if (window.tiConfigImportToken) return true;\n        if (Array.isArray(window.tiConfigImportRefineRules) && window.tiConfigImportRefineRules.length) return true;\n        try {\n            const selects = Array.from(body.querySelectorAll('.ti-import-map-select'));\n            if (selects.some(function(sel){ return String(sel.value || '').trim() !== '' && String(sel.value || '').trim() !== '--'; })) return true;\n            const formulas = Array.from(body.querySelectorAll('.ti-import-price-formula'));\n            if (formulas.some(function(inp){ return String(inp.value || '').trim() !== ''; })) return true;\n            const targets = Array.from(body.querySelectorAll('.ti-import-group-target'));\n            if (targets.some(function(sel){ return String(sel.value || '').trim() !== '' && String(sel.value || '').trim() !== 'Prodotti'; })) return true;\n        } catch(e) {}\n        return false;\n    };\n\n    window.closeConfigImportPreview = function(forceClose) {\n        if (!forceClose && window.hasPendingImportAssociations && window.hasPendingImportAssociations()) {\n            const msg = '<b>Associazioni import non ancora salvate<\/b><br><br>' +\n                'Hai gi\u00e0 fatto associazioni o regole di import nella preview.<br>' +\n                'Vuoi salvarle adesso con la conferma definitiva oppure uscire senza salvarle?<br><br>' +\n                '<span style=\"color:#bbf7d0;font-weight:700;\">SALVA E CONFERMA<\/span> salva l import nel database.<br>' +\n                '<span style=\"color:#fecaca;font-weight:700;\">ESCI SENZA SALVARE<\/span> chiude la finestra e non rende definitive le associazioni.';\n            window.tiConfirmYesNoAction(msg, function(){\n                window.confirmConfigImportPreview(true);\n            }, function(){\n                window.closeConfigImportPreview(true);\n            }, 'SALVA E CONFERMA', 'ESCI SENZA SALVARE');\n            return;\n        }\n        window.closeModal('ti-conf-import-preview-ov');\n    };\n\n    window.markConfigImportPreviewUpdated = function(message) {\n        const note = gE('ti-conf-import-preview-last-update');\n        const body = gE('ti-conf-import-preview-body');\n        const text = message || 'Anteprima modifiche aggiornata. Controlla il risultato e conferma solo se corretto.';\n        if (note) {\n            const now = new Date();\n            let hh = String(now.getHours()).padStart(2, '0');\n            let mm = String(now.getMinutes()).padStart(2, '0');\n            note.style.display = 'block';\n            note.innerHTML = 'Anteprima modifiche aggiornata alle ' + hh + ':' + mm + '. ' + window.escapeHtml(text);\n        }\n        if (body) {\n            try {\n                const active = document.activeElement;\n                const editingImport = !!(active && body.contains(active) && active.matches && active.matches('.ti-import-map-select, .ti-import-group-target, .ti-import-price-formula'));\n                if (!editingImport) body.scrollTop = 0;\n            } catch(e) {}\n            body.setAttribute('data-preview-updated', '1');\n        }\n    };\n\n    window.redisplayConfigImportPreviewForFinalConfirm = function(message) {\n        window.markConfigImportPreviewUpdated(message || 'Rivedi questa anteprima prima della conferma definitiva.');\n        try { window.openModal('ti-conf-import-preview-ov'); } catch(e) {}\n        const body = gE('ti-conf-import-preview-body');\n        if (body && typeof body.focus === 'function') {\n            try { body.setAttribute('tabindex', '-1'); body.focus({preventScroll:true}); } catch(e) {}\n        }\n    };\n\n    window.normalizeImportRefineToken = function(v) {\n        return String(v || '').toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[^a-z0-9]+\/g, ' ').trim();\n    };\n\n    window.tiConfigImportRefineRules = Array.isArray(window.tiConfigImportRefineRules) ? window.tiConfigImportRefineRules : [];\n    window.rememberImportLocalRefineRule = function(dest, src) {\n        const d = String(dest || '').trim();\n        const s = String(src || '').trim();\n        if (!d || !s) return false;\n        window.tiConfigImportRefineRules = Array.isArray(window.tiConfigImportRefineRules) ? window.tiConfigImportRefineRules : [];\n        const nd = window.normalizeImportRefineToken(d);\n        const ns = window.normalizeImportRefineToken(s);\n        const exists = window.tiConfigImportRefineRules.some(function(r){ return window.normalizeImportRefineToken(r.dest) === nd && window.normalizeImportRefineToken(r.src) === ns; });\n        if (!exists) window.tiConfigImportRefineRules.push({dest:d, src:s});\n        return true;\n    };\n\n    window.getImportRefineAssignment = function(prompt) {\n        let txt = String(prompt || '').trim();\n        if (!txt) return null;\n        txt = txt.replace(\/[\\r\\n]+\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n        txt = txt.replace(\/^(?:ut|utente|richiesta|istruzione|comando)\\s*[:\\-]\\s*\/i, '').trim();\n        txt = txt.replace(\/^['\"`]+|['\"`]+$\/g, '').trim();\n        const m = txt.match(\/^(.+?)\\s*(?:=|->|\\u2192|come|\\u00e8| e | in | da )\\s*(.+?)$\/i);\n        if (!m) return null;\n        let leftRaw = String(m[1] || '').replace(\/^campo\\s+\/i, '').trim();\n        let rightRaw = String(m[2] || '').replace(\/^campo\\s+\/i, '').trim();\n        leftRaw = leftRaw.replace(\/^['\"`]+|['\"`]+$\/g, '').trim();\n        rightRaw = rightRaw.replace(\/^['\"`]+|['\"`]+$\/g, '').trim();\n        const left = window.normalizeImportRefineToken ? window.normalizeImportRefineToken(leftRaw) : leftRaw.toLowerCase();\n        const right = window.normalizeImportRefineToken ? window.normalizeImportRefineToken(rightRaw) : rightRaw.toLowerCase();\n        if (!left || !right || left.length > 80 || right.length > 80) return null;\n        return {dest: leftRaw, src: rightRaw, destNorm: left, srcNorm: right, raw: txt};\n    };\n\n    window.isSimpleImportRefineInstruction = function(prompt) {\n        const txt = String(prompt || '').trim();\n        if (!txt) return false;\n        if (window.getImportRefineAssignment && window.getImportRefineAssignment(txt)) return true;\n        return txt.length <= 180 && \/(?:=|->|\\u2192)\/.test(txt);\n    };\n\n    window.getImportTableHeaderTexts = function(table) {\n        const ths = Array.from((table || document).querySelectorAll('thead th'));\n        return ths.map(function(th){\n            let label = '';\n            const span = th.querySelector('span');\n            if (span) label = span.textContent || '';\n            if (!label) label = th.childNodes && th.childNodes.length ? Array.from(th.childNodes).map(function(n){ return n.nodeType === 3 ? n.textContent : ''; }).join(' ') : th.textContent;\n            if (!label) label = th.textContent || '';\n            return String(label || '').replace(\/\\?\/g, '').trim();\n        });\n    };\n\n    window.findImportPreviewRowsTable = function(root, destNorm, srcNorm) {\n        const box = root || gE('ti-conf-import-preview-body') || document;\n        const tables = Array.from(box.querySelectorAll('table'));\n        let best = null;\n        tables.forEach(function(table){\n            if (best) return;\n            if (table.querySelector('.ti-import-map-select, .ti-import-group-target')) return;\n            const headers = window.getImportTableHeaderTexts(table);\n            if (!headers.length) return;\n            const norms = headers.map(function(h){ return window.normalizeImportRefineToken ? window.normalizeImportRefineToken(h) : String(h).toLowerCase(); });\n            const hasSrc = norms.some(function(n){ return n === srcNorm || n.indexOf(srcNorm) !== -1 || srcNorm.indexOf(n) !== -1; });\n            const hasDest = norms.some(function(n){ return n === destNorm || n.indexOf(destNorm) !== -1 || destNorm.indexOf(n) !== -1; });\n            if (hasSrc || hasDest) best = table;\n        });\n        return best;\n    };\n\n    window.ensureImportPreviewLocalRulesNote = function(root) {\n        const box = root || gE('ti-conf-import-preview-body');\n        if (!box) return null;\n        let note = box.querySelector('#ti-import-local-rules-note');\n        if (!note) {\n            note = document.createElement('div');\n            note.id = 'ti-import-local-rules-note';\n            note.style.cssText = 'margin:10px 0;padding:8px 10px;border-radius:8px;border:1px solid #22c55e;background:#052e16;color:#bbf7d0;font-size:12px;font-weight:700;';\n            box.insertBefore(note, box.firstChild);\n        }\n        return note;\n    };\n\n    window.renderImportPreviewLocalRulesNote = function(root) {\n        const note = window.ensureImportPreviewLocalRulesNote(root);\n        if (!note) return;\n        const rules = Array.isArray(window.tiConfigImportRefineRules) ? window.tiConfigImportRefineRules : [];\n        if (!rules.length) { note.style.display = 'none'; return; }\n        note.style.display = 'block';\n        note.innerHTML = 'Regole locali applicate alla preview e al salvataggio: ' + rules.map(function(r){\n            return window.escapeHtml(String(r.dest || '').trim() + ' = ' + String(r.src || '').trim());\n        }).join(' ; ') + '. Controlla l anteprima aggiornata e conferma solo se corretta.';\n    };\n\n    window.findImportColumnIndexByToken = function(headers, tokenNorm) {\n        const norms = headers.map(function(h){ return window.normalizeImportRefineToken ? window.normalizeImportRefineToken(h) : String(h).toLowerCase(); });\n        let idx = norms.findIndex(function(n){ return n === tokenNorm; });\n        if (idx < 0) idx = norms.findIndex(function(n){ return n.indexOf(tokenNorm) !== -1 || tokenNorm.indexOf(n) !== -1; });\n        return idx;\n    };\n\n    window.updateImportPreviewRowsLocal = function(dest, src, root) {\n        const destNorm = window.normalizeImportRefineToken ? window.normalizeImportRefineToken(dest) : String(dest || '').toLowerCase();\n        const srcNorm = window.normalizeImportRefineToken ? window.normalizeImportRefineToken(src) : String(src || '').toLowerCase();\n        const box = root || gE('ti-conf-import-preview-body');\n        if (!box || !destNorm || !srcNorm) return false;\n        const table = window.findImportPreviewRowsTable(box, destNorm, srcNorm);\n        window.renderImportPreviewLocalRulesNote(box);\n        if (!table) return false;\n        let headers = window.getImportTableHeaderTexts(table);\n        let srcIdx = window.findImportColumnIndexByToken(headers, srcNorm);\n        let destIdx = window.findImportColumnIndexByToken(headers, destNorm);\n        if (srcIdx < 0) return false;\n        if (destIdx < 0) {\n            const headRow = table.querySelector('thead tr');\n            if (headRow) {\n                const th = document.createElement('th');\n                th.style.cssText = 'border:1px solid #475569; padding:5px 6px; background:#0f172a; text-align:left; white-space:nowrap;';\n                th.innerHTML = '<div style=\"display:flex;align-items:center;justify-content:space-between;gap:6px;\"><span>' + window.escapeHtml(dest) + '<\/span><\/div>';\n                headRow.appendChild(th);\n                headers.push(dest);\n                destIdx = headers.length - 1;\n                Array.from(table.querySelectorAll('tbody tr')).forEach(function(tr){\n                    const td = document.createElement('td');\n                    td.style.cssText = 'border:1px solid #475569; padding:5px 6px; text-align:left; vertical-align:top; background:#052e16;';\n                    tr.appendChild(td);\n                });\n            }\n        }\n        if (destIdx < 0) return false;\n        let changed = 0;\n        Array.from(table.querySelectorAll('tbody tr')).forEach(function(tr){\n            const cells = Array.from(tr.children || []);\n            if (!cells[srcIdx] || !cells[destIdx]) return;\n            const value = (cells[srcIdx].textContent || '').trim();\n            cells[destIdx].textContent = value;\n            cells[destIdx].style.background = '#052e16';\n            changed++;\n        });\n        return changed > 0;\n    };\n\n    window.tryApplyImportRefineMappingInstruction = function(prompt, root, statusEl) {\n        const parsed = window.getImportRefineAssignment ? window.getImportRefineAssignment(prompt) : null;\n        if (!parsed) {\n            if (window.isSimpleImportRefineInstruction && window.isSimpleImportRefineInstruction(prompt)) {\n                if (statusEl) statusEl.innerHTML = '<span style=\"color:#fbbf24;\">Istruzione breve non chiara. Usa formato: campo destinazione = campo origine. Nessuna chiamata AI eseguita.<\/span>';\n                if (window.redisplayConfigImportPreviewForFinalConfirm) window.redisplayConfigImportPreviewForFinalConfirm('Chiarimento richiesto per il raffinamento. La preview resta invariata fino a istruzione chiara.');\n                return true;\n            }\n            return false;\n        }\n        const box = root || document;\n        const destRaw = parsed.dest;\n        const srcRaw = parsed.src;\n        window.rememberImportLocalRefineRule(destRaw, srcRaw);\n        const updatedRows = window.updateImportPreviewRowsLocal ? window.updateImportPreviewRowsLocal(destRaw, srcRaw, box) : false;\n        const selects = Array.from(box.querySelectorAll('.ti-import-map-select'));\n        if (selects.length) {\n            function optionValueFor(sel, wanted) {\n                const opts = Array.from(sel.options || []);\n                let hit = opts.find(function(o){ return window.normalizeImportRefineToken(o.value) === wanted || window.normalizeImportRefineToken(o.text) === wanted; });\n                if (!hit) hit = opts.find(function(o){ return window.normalizeImportRefineToken(o.value).indexOf(wanted) !== -1 || window.normalizeImportRefineToken(o.text).indexOf(wanted) !== -1; });\n                return hit ? hit.value : '';\n            }\n            selects.forEach(function(sel){\n                const hdr = window.normalizeImportRefineToken(sel.getAttribute('data-source-header') || '');\n                if (hdr === parsed.srcNorm || hdr.indexOf(parsed.srcNorm) !== -1 || parsed.srcNorm.indexOf(hdr) !== -1) {\n                    const val = optionValueFor(sel, parsed.destNorm);\n                    if (val && val !== '--') sel.value = val;\n                }\n            });\n        }\n        if (statusEl) {\n            statusEl.innerHTML = updatedRows\n                ? 'Anteprima aggiornata localmente. Non chiamo il server. Controlla il risultato e conferma per salvare.'\n                : 'Regola locale memorizzata. Non chiamo il server. Verr\u00e0 applicata al salvataggio. Controlla la preview prima di confermare.';\n        }\n        if (window.redisplayConfigImportPreviewForFinalConfirm) window.redisplayConfigImportPreviewForFinalConfirm(updatedRows ? 'Anteprima modifiche aggiornata localmente. Conferma solo se corretta.' : 'Regola locale registrata. Conferma solo se corretta.');\n        return true;\n    };\n\n    window.refineConfigImportPreview = function() {\n        const dbSel = gE('ti-ditta');\n        if (!dbSel || !dbSel.value || dbSel.value === 'NEW_DB') { window.tiAlert('Seleziona una ditta.'); return; }\n        const body = gE('ti-conf-import-preview-body');\n        const promptEl = gE('ti-conf-import-refine-prompt');\n        const statusEl = gE('ti-conf-import-refine-status');\n        const btn = gE('ti-conf-import-refine-btn');\n        const refinePrompt = promptEl ? String(promptEl.value || '').trim() : '';\n        if (!refinePrompt) { window.tiAlert('Scrivi cosa vuoi far raffinare alla AI.'); if (promptEl) promptEl.focus(); return; }\n        const mapping = (window.collectImportMappingFromUI ? window.collectImportMappingFromUI(body || document) : (window.tiConfigImportLastMapping || {}));\n        const fd = new FormData();\n        fd.append('action', 'ti_ai_config_action');\n        fd.append('ti_action', 'ti_ai_config_action');\n        fd.append('db', dbSel.value);\n        fd.append('mode', 'refine_import_preview');\n        fd.append('prompt', 'raffina import preview');\n        fd.append('refine_prompt', refinePrompt);\n        if (window.tiConfigImportToken) fd.append('import_token', window.tiConfigImportToken);\n        fd.append('mapping_json', JSON.stringify(mapping));\n        const oldText = btn ? btn.innerText : '';\n        if (btn) { btn.disabled = true; btn.innerText = 'Raffinamento in corso...'; }\n        \/\/ 30.9.1505: istruzioni naturali come 'Il prezzo \u00e8 Prezzo Mercato' usano direttamente la combo quotazioni, senza chiamata server.\n        try {\n            var rp1505 = window.normalizeImportRefineToken ? window.normalizeImportRefineToken(refinePrompt) : String(refinePrompt||'').toLowerCase();\n            if (\/(^| )prezzo( |$)\/.test(rp1505) && \/prezzo mercato|mercato\/.test(rp1505)) {\n                var changed1505 = 0;\n                Array.from((body || document).querySelectorAll('.ti-import-price-quote-select-1503')).forEach(function(sel){\n                    var opt = Array.from(sel.options || []).find(function(o){return \/prezzo mercato|market price\/i.test(String(o.textContent||o.innerText||''));});\n                    if(opt){sel.value=opt.value;sel.dispatchEvent(new Event('change',{bubbles:true}));changed1505++;}\n                });\n                if(changed1505>0){\n                    if(statusEl)statusEl.innerHTML='Prezzo Mercato applicato localmente a '+changed1505+' righe. Controlla la preview e conferma solo se corretta.';\n                    if(window.redisplayConfigImportPreviewForFinalConfirm)window.redisplayConfigImportPreviewForFinalConfirm('Prezzo Mercato applicato alle righe disponibili.');\n                    if(btn){btn.disabled=false;btn.innerText=oldText||'Raffina anteprima con AI';}\n                    return;\n                }\n            }\n        } catch(e1505) {}\n        if (window.tryApplyImportRefineMappingInstruction && window.tryApplyImportRefineMappingInstruction(refinePrompt, body || document, statusEl)) {\n            if (btn) { btn.disabled = false; btn.innerText = oldText || 'Raffina anteprima con AI'; }\n            return;\n        }\n        if (statusEl) statusEl.innerHTML = 'AI al lavoro sulla prima anteprima...';\n        if (body) body.style.opacity = '0.72';\n        const refineUrl1504 = window.tiAjaxUrl || window.ajaxurl || (typeof window.ajaxUrl1088 === 'function' ? window.ajaxUrl1088() : '') || window.tiUrl;\n        window.postFormDataJsonSafe(refineUrl1504, fd, {tiNoLongProcessSignal:true,tiForceAjaxUrl:true}).then(function(res){\n            if (btn) { btn.disabled = false; btn.innerText = oldText || 'Raffina anteprima con AI'; }\n            if (body) body.style.opacity = '';\n            if (res && res.success) {\n                if (res.data && (res.data.import_token || res.data.preview_token)) window.tiConfigImportToken = res.data.import_token || res.data.preview_token;\n                const rawReply = ((res.data || {}).reply || '').replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                if (rawReply && body) {\n                    body.innerHTML = rawReply;\n                    if (window.tiConfigImportToken) body.dataset.importToken = window.tiConfigImportToken;\n                    if (window.initConfigTopScrollbars) {\n                        window.initConfigTopScrollbars(body);\n                        setTimeout(function(){ window.initConfigTopScrollbars(body); }, 60);\n                        setTimeout(function(){ window.initConfigTopScrollbars(body); }, 250);\n                        setTimeout(function(){ window.initConfigTopScrollbars(body); }, 600);\n                    }\n                }\n                if (window.redisplayConfigImportPreviewForFinalConfirm) window.redisplayConfigImportPreviewForFinalConfirm('Anteprima raffinata. Controlla il risultato prima di confermare.');\n                if (statusEl) statusEl.innerHTML = 'Anteprima raffinata. Controlla il risultato prima di confermare.';\n            } else {\n                const msg = (res && res.data && res.data.message) ? res.data.message : 'Raffinamento non riuscito.';\n                if (statusEl) statusEl.innerHTML = '<span style=\"color:#fca5a5;\">' + window.escapeHtml(msg) + '<\/span>';\n                else window.tiAlert(msg);\n            }\n        }).catch(function(err){\n            if (btn) { btn.disabled = false; btn.innerText = oldText || 'Raffina anteprima con AI'; }\n            if (body) body.style.opacity = '';\n            const msg = 'Errore raffinamento import: ' + ((err && err.message) ? err.message : 'errore sconosciuto');\n            if (statusEl) statusEl.innerHTML = '<span style=\"color:#fca5a5;\">' + window.escapeHtml(msg) + '<\/span>';\n            else window.tiAlert(msg);\n        });\n    };\n\n    window.confirmConfigImportPreview = function(skipClosePrompt) {\n        const dbSel = gE('ti-ditta');\n        if (!dbSel || !dbSel.value || dbSel.value === 'NEW_DB') { window.tiAlert('Seleziona una ditta.'); return; }\n        const body = gE('ti-conf-import-preview-body');\n        const statusEl = gE('ti-conf-import-refine-status');\n        const mapping = (window.collectImportMappingFromUI ? window.collectImportMappingFromUI(body || document) : {});\n        const editedRows = {};\n        (body || document).querySelectorAll('tr[data-row-idx]').forEach(function(tr){\n            if (tr.getAttribute('data-ti-deleted') === '1') return;\n            const gIdx = tr.getAttribute('data-group-idx') || '0';\n            if (!editedRows[gIdx]) editedRows[gIdx] = [];\n            const rowData = {};\n            tr.querySelectorAll('.ti-import-cell-input').forEach(function(input){\n                const field = input.getAttribute('data-field');\n                if (field) rowData[field] = input.value;\n            });\n            editedRows[gIdx].push(rowData);\n        });\n        try {\n            var rowCounts1196 = Object.keys(editedRows).map(function(k){ return k + '=' + editedRows[k].length; }).join(' | ');\n            console.log('[1196] editedRows raccolti prima dell invio:', rowCounts1196, editedRows);\n            if (window.log1088) window.log1088('confirmConfigImportPreview: righe raccolte per gruppo: ' + rowCounts1196);\n        } catch(eLog1196) {}\n\n        const fd = new FormData();\n        fd.append('action', 'ti_ai_config_action');\n        fd.append('ti_action', 'ti_ai_config_action');\n        fd.append('db', dbSel.value);\n        fd.append('mode', 'confirm_import_preview');\n        fd.append('prompt', 'conferma import preview');\n        if (window.tiConfigImportToken) fd.append('import_token', window.tiConfigImportToken);\n        fd.append('mapping_json', JSON.stringify(mapping));\n        fd.append('edited_rows_json', JSON.stringify(editedRows));\n\n        const buttons = Array.from(document.querySelectorAll('#ti-conf-import-preview-ov button'));\n        buttons.forEach(function(btn){ btn.disabled = true; });\n        if (statusEl) statusEl.innerHTML = 'Salvataggio import in corso...';\n        if (body) body.style.opacity = '0.72';\n\n        \/\/ Usare window.tiUrl evita HTTP 400: 0 di admin-ajax.php quando l'accesso e quello interno del plugin.\n        window.postFormDataJsonSafe(window.tiUrl, fd, {tiNoLongProcessSignal:true, cache:'no-store'}).then(function(res){\n            buttons.forEach(function(btn){ btn.disabled = false; });\n            if (body) body.style.opacity = '';\n            if (res && res.success) {\n                const rawReply = ((res.data || {}).reply || '').trim();\n                const cleanReply = rawReply.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                const finalImportMsg = cleanReply || '\u2705 Import completato e salvato nel database.';\n                window.closeConfigImportPreview(true);\n                window.addMsg('ai', window.formatTable(finalImportMsg), finalImportMsg);\n                setTimeout(function(){ if (window.tiAlert) window.tiAlert('\u2705 Salvataggio import completato con successo.'); }, 250);\n                window.tiConfigImportToken = null;\n                \/\/ 30.9.1204: segnale robusto di aggiornamento forzato - garantisce che la prossima apertura di\n                \/\/ Configurazione (in qualsiasi momento avvenga) legga sempre dati freschi dal server, indipendentemente\n                \/\/ da chiavi di cache o stato di visibilita' attuale. Se Configurazione e' gia' aperta, la aggiorna subito.\n                if (res.data && res.data.needs_reload) {\n                    setTimeout(function(){\n                        try {\n                            window.__tiForceDbRefreshNext1204 = true;\n                            window.currentDbData = null;\n                            var dbNameRefresh1198 = (gE('ti-ditta') ? gE('ti-ditta').value : '');\n                            try { if (dbNameRefresh1198) localStorage.removeItem('ti_config_cache_507_' + dbNameRefresh1198); } catch(eLs1198) {}\n                            var confOv1198 = gE('ti-conf-ov');\n                            var confVisible1198 = confOv1198 && getComputedStyle(confOv1198).display !== 'none';\n                            if (confVisible1198 && window.openConfigSafe507) window.openConfigSafe507(null, true, false);\n                        } catch(eRefresh1198) {}\n                    }, 600);\n                }\n            } else {\n                const msg = (res && res.data && res.data.message) ? res.data.message : 'Errore conferma import';\n                if (statusEl) statusEl.innerHTML = '<span style=\"color:#fca5a5;\">' + window.escapeHtml(msg) + '<\/span>';\n                window.tiAlert(msg);\n            }\n        }).catch(function(err){\n            buttons.forEach(function(btn){ btn.disabled = false; });\n            if (body) body.style.opacity = '';\n            const msg = 'Errore conferma import: ' + ((err && err.message) ? err.message : 'errore sconosciuto');\n            if (statusEl) statusEl.innerHTML = '<span style=\"color:#fca5a5;\">' + window.escapeHtml(msg) + '<\/span>';\n            window.tiAlert(msg);\n        });\n    };\n\n    window.cancelConfigImportPreview = function() {\n        const box = gE('ti-conf-ai-prompt');\n        if (box) box.value = 'ANNULLA';\n        window.closeConfigImportPreview(true);\n        window.runConfigBot();\n    };\n\n    window.pickConfigBotFile = function() {\n        window.targetUploadContext = 'config-bot-file';\n        if (window.tiOpenDirectUpload616) return window.tiOpenDirectUpload616('config-bot-file');\n        return false;\n    };\n\n    window.runBatchAIGen = function(tableName) {\n        const dbSel = gE('ti-ditta'); const replyBox = gE('ti-conf-ai-reply');\n        if (!dbSel || !dbSel.value || dbSel.value === 'NEW_DB') { window.tiAlert('Seleziona prima una ditta.'); return; }\n        if (!replyBox) { window.tiAlert('Area risposta configurazione non disponibile.'); return; }\n        const photoDetail = ((gE('ti-conf-ai-photo-detail') && gE('ti-conf-ai-photo-detail').value) ? gE('ti-conf-ai-photo-detail').value : '').trim();\n        replyBox.style.display = 'block';\n        replyBox.innerHTML = 'Preparazione elenco record. Priorit\u00e0 a prodotti e servizi senza associazioni file o immagini.<br>Prompt base: attivit\u00e0 ditta + descrizione prodotto\/servizio.';\n        const initFd = window.buildAjaxFormData('ti_ai_config_action', {\n            db: dbSel.value,\n            mode: 'batch_ai_images',\n            tables: tableName\n        });\n        window.showProgressPopup('Generazione foto AI', 'Sto preparando l elenco dei record. Prompt base: attivit\u00e0 ditta e descrizione prodotto o servizio.', {startPercent: 2, targetPercent: 18, stepMs: 350});\n        window.fetchJsonSafe(window.tiUrl, {method:'POST', body:initFd, tiTimeoutMs: 70000}).then(d => {\n            if (!d.success) {\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                window.hideProgressPopup(false, 'Errore preparazione batch');\n                replyBox.innerHTML = 'Errore: ' + (d.data && d.data.message ? d.data.message : 'Errore sconosciuto');\n                return;\n            }\n            const targets = (d.data && Array.isArray(d.data.targets)) ? d.data.targets : [];\n            if (!targets.length) {\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                window.hideProgressPopup(true, 'Nessun elemento da elaborare', {notifyUser:false, remindSave:false});\n                replyBox.innerHTML = 'Nessun record trovato nella tabella selezionata.';\n                return;\n            }\n            let index = 0;\n            let okCount = 0;\n            const logs = [];\n            const total = targets.length;\n            window.tiBatchAIGenState = {\n                active: true,\n                pendingConfirm: false,\n                generated: [],\n                db: dbSel.value,\n                tableName: tableName,\n                total: total,\n                startedAt: Date.now()\n            };\n            const withoutAssoc = (d.data && typeof d.data.without_associations !== 'undefined') ? parseInt(d.data.without_associations, 10) : targets.filter(function(x){ return !x.has_associations; }).length;\n            const withAssoc = (d.data && typeof d.data.with_associations !== 'undefined') ? parseInt(d.data.with_associations, 10) : Math.max(0, total - withoutAssoc);\n            const detailMode = (d.data && d.data.detail_prompt_mode) ? String(d.data.detail_prompt_mode) : '';\n            const detailInfo = (photoDetail && detailMode === 'leaflet')\n                ? '<br>Istruzione aggiuntiva riconosciuta: <b>foglietto illustrativo \/ materiale informativo<\/b>.'\n                : (photoDetail ? '<br>Istruzione aggiuntiva: <b>' + window.escapeHtml(photoDetail) + '<\/b>.' : '');\n            replyBox.innerHTML = 'Generazione immagini AI pronta.<br>Prompt base: <b>attivit\u00e0 ditta + descrizione prodotto\/servizio<\/b>.<br>Altre fonti informative saranno usate solo successivamente se richieste.' + detailInfo + '<br>Priorit\u00e0: <b>' + withoutAssoc + '<\/b> prodotti\/servizi senza associazioni.<br>Successivi: <b>' + withAssoc + '<\/b> prodotti\/servizi gi\u00e0 con associazioni.';\n            const refreshDb = () => {\n                if (window.refreshCurrentConfigDb) return window.refreshCurrentConfigDb(dbSel.value);\n                const fdDb = window.buildAjaxFormData('ti_ai_get_db_data', {db: dbSel.value});\n                return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fdDb, tiNoLongProcessSignal:true, tiShowTableReadWait:true, tiTableReadTitle:'\u23f3 Lettura tabelle configurazione', tiTableReadDetail:'Sto aggiornando le tabelle dopo l operazione.', tiTableReadItem: dbSel.value}).then(dbRes => {\n                    if (dbRes.success && dbRes.data) { window.currentDbData = dbRes.data; window.renderConfig(); }\n                }).catch(() => {});\n            };\n            const runNext = () => {\n                if (window.isLongAIProcessCancelled()) {\n                    if (window.tiBatchAIGenState && window.tiBatchAIGenState.pendingConfirm) return;\n                    replyBox.innerHTML = 'Operazione interrotta dall utente. Per completarla dovrai ripetere la generazione.';\n                    if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                    window.clearLongAIProcess();\n                    return;\n                }\n                if (index >= total) {\n                    if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                    window.updateProgressPopup(100, 'Generazione foto AI', 'Completamento e verifica salvataggio associazioni.');\n                    Promise.resolve(refreshDb()).finally(function(){\n                        window.hideProgressPopup(true, 'Generazione foto AI completata', {\n                            remindSave: false,\n                            successMessage: 'Attivita AI completata. Immagini associate e verificate: ' + okCount + ' su ' + total + '.'\n                        });\n                        replyBox.innerHTML = '\u2705 Generazione immagini AI completata.<br>Immagini associate e verificate: <b>' + okCount + '<\/b> \/ ' + total + '<br><br>' + logs.slice(0, 40).join('<br>');\n                    });\n                    return;\n                }\n                const item = targets[index];\n                const currentStep = index + 1;\n                const pct = Math.max(5, Math.min(98, Math.round((index \/ total) * 100)));\n                const priorityText = item.has_associations ? 'Elemento gi\u00e0 con associazioni' : 'Priorit\u00e0 senza associazioni';\n                window.updateProgressPopup(pct, 'Generazione foto AI', priorityText + '. Elaborazione ' + currentStep + ' \/ ' + total + ': ' + (item.name || 'Elemento'), (item.name || 'Elemento'));\n                replyBox.innerHTML = 'Generazione immagini AI in corso...<br>' + priorityText + '<br>Elaborazione ' + currentStep + ' \/ ' + total + ': <b>' + (item.name || 'Elemento') + '<\/b>';\n                const fd = window.buildAjaxFormData('ti_ai_config_action', {\n                    db: dbSel.value,\n                    mode: 'batch_ai_image_one',\n                    table: item.table || tableName,\n                    row_index: item.row_index,\n                    detail_prompt: photoDetail\n                });\n                window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(one => {\n                    const data = one && one.data ? one.data : {};\n                    if (one.success && data.generated) {\n                        okCount++;\n                        if (window.tiBatchAIGenState && Array.isArray(window.tiBatchAIGenState.generated) && (data.added_value || data.filename || data.url)) {\n                            window.tiBatchAIGenState.generated.push({\n                                table: data.table || item.table || tableName,\n                                row_index: (typeof data.row_index !== 'undefined') ? data.row_index : item.row_index,\n                                field: data.image_field || 'Immagine',\n                                value: data.added_value || data.filename || data.url,\n                                name: data.name || item.name || 'Elemento'\n                            });\n                        }\n                        if (data.fallback_logo) logs.push('\u2705 ' + (data.name || item.name || 'Elemento') + ': foto non disponibile, usato logo ditta');\n                        else logs.push('\u2705 ' + (data.name || item.name || 'Elemento') + ': immagine generata e associazione salvata');\n                    } else if (one.success && data.skipped) {\n                        logs.push('\u23ed\ufe0f ' + (data.name || item.name || 'Elemento') + ': immagine gia presente');\n                    } else {\n                        logs.push('\u274c ' + (data.name || item.name || 'Elemento') + ': ' + (data.message || 'errore'));\n                    }\n                    index++;\n                    setTimeout(runNext, 350);\n                }).catch(err => {\n                    if (err && (err.userCancelled || window.isLongAIProcessCancelled())) {\n                        if (window.tiBatchAIGenState && window.tiBatchAIGenState.pendingConfirm) return;\n                        replyBox.innerHTML = 'Operazione interrotta dall utente. Per completarla dovrai ripetere la generazione.';\n                        if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                        window.clearLongAIProcess();\n                        return;\n                    }\n                    logs.push('\u274c ' + (item.name || 'Elemento') + ': ' + err.message);\n                    index++;\n                    setTimeout(runNext, 700);\n                });\n            };\n            runNext();\n        }).catch(err => {\n            if (err && (err.userCancelled || window.isLongAIProcessCancelled())) {\n                if (window.tiBatchAIGenState && window.tiBatchAIGenState.pendingConfirm) return;\n                replyBox.innerHTML = 'Operazione interrotta dall utente. Per completarla dovrai ripetere la generazione.';\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                window.clearLongAIProcess();\n                return;\n            }\n            if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n            window.hideProgressPopup(false, 'Errore batch immagini');\n            replyBox.innerHTML = 'Errore di rete: ' + err.message;\n        });\n    };\n\n    window.formatConfigAiErrorMessage = function(payload, fallbackTitle, promptText) {\n        const data = payload && payload.data ? payload.data : {};\n        const rawMsg = String(data.message || (payload && payload.message) || '').trim();\n        const lower = rawMsg.toLowerCase();\n        let reason = rawMsg || 'Errore sconosciuto durante la configurazione AI.';\n        let hint = '';\n        if (!rawMsg) {\n            hint = 'Possibile motivo: errore di interpretazione dei dati o lista troppo complessa.';\n        } else if (lower.includes('nessuna anteprima import')) {\n            hint = 'Possibile motivo: hai confermato con OK ma non esiste piu una anteprima import valida. Rigenera l anteprima dal listino e poi conferma.';\n        } else if (lower.includes('json') || lower.includes('incomplet') || lower.includes('interpretazione') || lower.includes('nessun record') || lower.includes('parser')) {\n            hint = 'Possibile motivo: dati troppo complessi, colonne non chiare, descrizioni con molte virgole\/virgolette o fasce prezzo non omogenee.';\n        } else if (lower.includes('accesso') || lower.includes('ruolo')) {\n            hint = 'Possibile motivo: il ruolo utente non consente questa modifica.';\n        }\n        const simplify = 'Semplifica la lista: usa poche colonne chiare, ad esempio Nome\/Servizio, Prezzo, Descrizione; una sola voce per riga; evita testi troppo lunghi o colonne non necessarie.';\n        let html = '<b>' + window.escapeHtml(fallbackTitle || 'Errore configurazione AI') + '<\/b>';\n        if (String(promptText || '').trim()) html += '<br><br><b>Istruzione inviata alla Configurazione AI:<\/b><br>' + window.escapeHtml(String(promptText || '').trim());\n        html += '<br><br><b>Dettaglio:<\/b><br>' + window.escapeHtml(reason);\n        if (hint) html += '<br><br><b>Possibile motivo:<\/b><br>' + window.escapeHtml(hint);\n        html += '<br><br><b>Come correggere:<\/b><br>' + window.escapeHtml(simplify);\n        return html;\n    };\n\n    window.tiConfigAiHtmlToPlainText482 = function(html) {\n        try {\n            const tmp = document.createElement('div');\n            tmp.innerHTML = String(html || '').replace(\/<br\\s*\\\/?\\s*>\/gi, '\\n');\n            return String(tmp.innerText || tmp.textContent || '').trim();\n        } catch(e) {\n            return String(html || '').replace(\/<br\\s*\\\/?\\s*>\/gi, '\\n').replace(\/<[^>]+>\/g, '').trim();\n        }\n    };\n    window.tiAppendConfigAiToUnifiedChat482 = function(text) {\n        const promptBox = gE('ti-conf-ai-prompt');\n        if (!promptBox) return false;\n        let aiText = String(text || '').replace(\/\\[NO_VOICE\\]\/g, '').trim();\n        if (!aiText) return false;\n        let current = String(promptBox.value || '').trim();\n        current = current.replace(\/\\n+AI:\\s*(Sto elaborando[^\\n]*|Elaborazione in corso[^\\n]*)\\s*$\/i, '').trim();\n        const tail = current.slice(Math.max(0, current.length - aiText.length - 40));\n        if (tail.indexOf(aiText) !== -1) return true;\n        if (current && !\/^Utente:\/i.test(current) && current.indexOf('\\nAI:') === -1) current = 'Utente:\\n' + current;\n        const next = (current ? current + '\\n\\n' : '') + 'AI:\\n' + aiText + '\\n\\nUtente:\\n';\n        promptBox.value = next;\n        try { promptBox.dispatchEvent(new Event('input', {bubbles:true})); } catch(e) {}\n        setTimeout(function(){ try { promptBox.focus({preventScroll:true}); promptBox.selectionStart = promptBox.selectionEnd = promptBox.value.length; } catch(e) {} }, 60);\n        return true;\n    };\n    window.setConfigAiReplyHtml = function(replyBox, html, plainText) {\n        const safeHtml = String(html || '');\n        const rawText = plainText != null ? String(plainText) : window.tiConfigAiHtmlToPlainText482(safeHtml);\n        if (replyBox) {\n            replyBox.style.display = 'block';\n            replyBox.removeAttribute('aria-hidden');\n            replyBox.setAttribute('data-ti-config-ai-persistent-2031','1');\n            replyBox.innerHTML = safeHtml || window.escapeHtml(String(rawText || '')).replace(\/\\n\/g, '<br>');\n        }\n        return true;\n    };\n\n    window.tiConfigAiStateKey330 = function(db) {\n        return 'ti_ai_ss_config_ai_state_330_' + String(db || '').replace(\/[^a-zA-Z0-9_.-]\/g, '_');\n    };\n    \/\/ 30.9.1587: i secret PayPal non devono restare in localStorage, monitor o log browser.\n    window.tiRedactConfigAiSecrets1587 = function(value) {\n        let s = String(value == null ? '' : value);\n        s = s.replace(\/((?:client\\s*secret|client_secret|paypal\\s*secret|secret\\s*paypal)\\s*[:=]\\s*)([^\\s,;]+)\/ig, '$1[PROTETTO]');\n        s = s.replace(\/((?:[\"']client_secret[\"'])\\s*:\\s*[\"'])([^\"']+)([\"'])\/ig, '$1[PROTETTO]$3');\n        return s;\n    };\n    window.tiConfigAiContainsSecret1587 = function(value) {\n        return \/(?:client\\s*secret|client_secret|paypal\\s*secret|secret\\s*paypal)\\s*[:=]\\s*[^\\s,;]\/i.test(String(value == null ? '' : value));\n    };\n    window.saveConfigAiState330 = function(db, prompt, reply, status) {\n        try {\n            if (!db) return;\n            const payload = {\n                db: String(db || ''),\n                prompt: window.tiRedactConfigAiSecrets1587 ? window.tiRedactConfigAiSecrets1587(prompt) : String(prompt || ''),\n                reply: String(reply || ''),\n                status: String(status || ''),\n                ts: Date.now()\n            };\n            localStorage.setItem(window.tiConfigAiStateKey330(db), JSON.stringify(payload));\n            sessionStorage.setItem('ti_ai_ss_last_config_db_330', String(db || ''));\n        } catch(e) {}\n    };\n    window.clearConfigAiState330 = function(db) {\n        try { if (db) localStorage.removeItem(window.tiConfigAiStateKey330(db)); } catch(e) {}\n    };\n    window.getConfigAiState330 = function(db) {\n        try {\n            if (!db) return null;\n            const raw = localStorage.getItem(window.tiConfigAiStateKey330(db));\n            if (!raw) return null;\n            const payload = JSON.parse(raw);\n            if (!payload || payload.db !== String(db || '')) return null;\n            if (payload.ts && (Date.now() - payload.ts) > 86400000) {\n                localStorage.removeItem(window.tiConfigAiStateKey330(db));\n                return null;\n            }\n            if (payload.status === 'running' && payload.ts && (Date.now() - payload.ts) > 180000) {\n                localStorage.removeItem(window.tiConfigAiStateKey330(db));\n                return null;\n            }\n            return payload;\n        } catch(e) { return null; }\n    };\n    window.tiConfigAiPendingShownKey446 = function(db) {\n        return 'ti_ai_ss_config_ai_pending_shown_446_' + String(db || '').replace(\/[^a-zA-Z0-9_.-]\/g, '_');\n    };\n    window.showConfigAiPendingClarification446 = function(db, payload, replyBox, promptBox) {\n        try {\n            if (!payload || payload.status !== 'awaiting_user_details') return false;\n            const reply = String(payload.reply || '').trim();\n            if (!reply) return false;\n            if (window.hideProgressPopup) window.hideProgressPopup(false, 'Chiarimento richiesto', {notifyUser:false});\n            if (replyBox && window.setConfigAiReplyHtml) {\n                const html = '<b>Chiarimento AI richiesto<\/b><br><br>' + window.escapeHtml(reply).replace(\/\\n\/g, '<br>') + '<br><br><span style=\"color:#cbd5e1;font-size:12px;\">Rispondi nel campo Configurazione AI e premi Invia. Non viene avviato nessun nuovo processo finche questa richiesta non viene gestita.<\/span>';\n                replyBox.style.display = 'block';\n                window.setConfigAiReplyHtml(replyBox, html, reply);\n            }\n            if (promptBox) {\n                const draft = String(promptBox.value || '').trim();\n                if (draft && draft !== String(payload.prompt || '').trim()) {\n                    try { sessionStorage.setItem('ti_ai_ss_config_ai_blocked_draft_446_' + String(db || ''), draft); } catch(e) {}\n                }\n                if (!String(promptBox.value || '').trim()) promptBox.value = 'Utente:\\n';\n                promptBox.placeholder = 'Rispondi al chiarimento richiesto dalla AI e premi Invia...';\n                setTimeout(function(){ try { promptBox.focus({preventScroll:true}); promptBox.selectionStart = promptBox.selectionEnd = promptBox.value.length; } catch(e) {} }, 80);\n            }\n            try { sessionStorage.setItem(window.tiConfigAiPendingShownKey446(db), String(Date.now())); } catch(e) {}\n            try { if (window.showPluginModal) window.showPluginModal('ti-conf-ov'); } catch(e) {}\n            return true;\n        } catch(e) { return false; }\n    };\n    window.configAiPendingClarificationNeedsDisplay446 = function(db, payload, prompt) {\n        try {\n            if (!payload || payload.status !== 'awaiting_user_details' || !String(payload.reply || '').trim()) return false;\n            const p = String(prompt || '').trim();\n            const oldPrompt = String(payload.prompt || '').trim();\n            const shownRaw = sessionStorage.getItem(window.tiConfigAiPendingShownKey446(db));\n            const shownAt = shownRaw ? parseInt(shownRaw, 10) : 0;\n            const shownRecently = shownAt && (Date.now() - shownAt) < 3600000;\n            if (!shownRecently) return true;\n            if (!p) return true;\n            if (oldPrompt && p === oldPrompt) return true;\n            return false;\n        } catch(e) { return true; }\n    };\n    window.buildConfigAiPromptWithPendingAnswer446 = function(db, payload, prompt) {\n        try {\n            if (!payload || payload.status !== 'awaiting_user_details') return String(prompt || '');\n            const p = String(prompt || '').trim();\n            if (!p) return p;\n            const oldPrompt = String(payload.prompt || '').trim();\n            const clarification = String(payload.reply || '').replace(\/<[^>]+>\/g, ' ').trim();\n            if (!oldPrompt || p === oldPrompt) return p;\n            try { window.clearConfigAiState330(db); } catch(e) {}\n            try { sessionStorage.removeItem(window.tiConfigAiPendingShownKey446(db)); } catch(e) {}\n            return 'Richiesta precedente: ' + oldPrompt + '\\nChiarimento richiesto dalla AI: ' + clarification + '\\nRisposta utente: ' + p;\n        } catch(e) { return String(prompt || ''); }\n    };\n    window.restoreConfigAiState330 = function(force) {\n        try {\n            const dbSel = gE('ti-ditta');\n            const db = dbSel ? String(dbSel.value || '') : String(sessionStorage.getItem('ti_ai_ss_last_config_db_330') || '');\n            if (!db || db === 'NEW_DB') return false;\n            const payload = window.getConfigAiState330 ? window.getConfigAiState330(db) : null;\n            if (!payload) return false;\n            const replyBox = gE('ti-conf-ai-reply');\n            const promptBox = gE('ti-conf-ai-prompt');\n            if (!replyBox) return false;\n            const currentText = String(replyBox.innerText || replyBox.textContent || '').trim();\n            if (!force && currentText && !\/fammi pensare|elaborando|attendere\/i.test(currentText)) return false;\n            if (promptBox && !String(promptBox.value || '').trim() && payload.prompt) promptBox.value = payload.prompt;\n            let label = '';\n            if (payload.status === 'awaiting_user_details') label = '<b>Richiesta AI in attesa di specifiche utente<\/b><br><br>';\n            else if (payload.status === 'running') label = '<b>Elaborazione precedente non verificata dopo refresh<\/b><br><br>';\n            replyBox.style.display = 'block';\n            window.setConfigAiReplyHtml(replyBox, label + window.escapeHtml(String(payload.reply || '')).replace(\/\\n\/g, '<br>'), String(payload.reply || ''));\n            return true;\n        } catch(e) { return false; }\n    };\n    window.finishConfigAiAwaitingUser330 = function(replyBox, db, prompt, replyText) {\n        if (window.hideProgressPopup) window.hideProgressPopup(false, 'Chiarimento richiesto', {notifyUser:false});\n        if (replyBox) {\n            replyBox.style.display = 'block';\n            window.setConfigAiReplyHtml(replyBox, window.escapeHtml(String(replyText || '')).replace(\/\\n\/g, '<br>'), String(replyText || ''));\n        }\n        window.saveConfigAiState330(db, prompt, replyText, 'awaiting_user_details');\n        try { window.showPluginModal('ti-conf-ov'); } catch(e) {}\n    };\n    (function installConfigAiRestore330(){\n        if (window.__tiConfigAiRestore330Installed) return;\n        window.__tiConfigAiRestore330Installed = true;\n        const prevOpen = window.openModal;\n        if (typeof prevOpen === 'function') {\n            window.openModal = function(id) {\n                const ret = prevOpen.apply(this, arguments);\n                if (id === 'ti-conf-ov') setTimeout(function(){ window.restoreConfigAiState330(false); }, 250);\n                return ret;\n            };\n        }\n        document.addEventListener('DOMContentLoaded', function(){ setTimeout(function(){ window.restoreConfigAiState330(false); }, 700); });\n        setTimeout(function(){ window.restoreConfigAiState330(false); }, 1200);\n    })();\n\n    window.tiActiveConfigAiRequest434 = null;\n    window.isConfigAiFastAdvicePrompt434 = function(prompt) {\n        const rawPrompt434 = String(prompt || '');\n        const p = rawPrompt434.toLowerCase().normalize ? rawPrompt434.toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '') : rawPrompt434.toLowerCase();\n        if (!p.trim()) return false;\n        const hasPaypalConfig1587 = \/\\bpaypal\\b\/.test(p) && \/\\b(configur\\w*|impost\\w*|attiv\\w*|disattiv\\w*|colleg\\w*|credenzial\\w*|client\\s*id|client\\s*secret|webhook|sandbox|live|test\\w*|verific\\w*)\\b\/.test(p);\n        if (hasPaypalConfig1587) return true;\n        const hasBulkContacts1600 = \/\\b(tutti|tutte|ogni)\\b\/.test(p) && \/\\butent[ei]\\b\/.test(p) && \/(operatori|operatore|opertori)\/.test(p) && \/(email|e-mail|gsm|tel|telefono|cellulare|mobile)\/.test(p) && \/(definisc|impost|aggiorn|modific|assegn|compil|valorizz)\/.test(p);\n        if (hasBulkContacts1600) return true;\n        const orderMail1943 = \/\\b(ordine|ordini)\\b\/.test(p) && \/\\b(conferma|confermato|confermata|dopo|seguito)\\b\/.test(p) && \/\\b(email|mail)\\b\/.test(p) && \/\\b(operatori|operatore)\\b\/.test(p);\n        if (orderMail1943) return true;\n        const hasDiscount = \/\\b(sconto|sconti|scontare|scontato|promozione|promozioni|promo|offerta|offerte|coupon|ribasso|riduzione|saldo|saldi)\\b\/.test(p);\n        const hasScope = \/\\b(prodotto|prodotti|articolo|articoli|servizio|servizi|catalogo|listino|prezzo|prezzi|tutti|tutto)\\b\/.test(p);\n        const hasPeriod = \/\\b(fino|fine|mese|scadenza|validita|temporaneo|periodo)\\b\/.test(p);\n        return !!(hasDiscount && (hasScope || hasPeriod));\n    };\n    window.configAiTraceHtml434 = function(prompt, isFast) {\n        const tracePrompt1587 = window.tiRedactConfigAiSecrets1587 ? window.tiRedactConfigAiSecrets1587(prompt) : String(prompt || '');\n        const safe = window.escapeHtml ? window.escapeHtml(tracePrompt1587) : tracePrompt1587.replace(\/[&<>]\/g, function(c){ return ({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]); });\n        const mode = isFast ? 'Percorso veloce: nessun import e nessuna lettura file allegati; se il comando e applicativo puo salvare solo dati esistenti.' : 'Elaborazione Configurazione AI.';\n        return '<div class=\"ti-conf-ai-trace\" style=\"margin-top:10px;padding:8px 10px;border-radius:10px;background:#0f172a;border:1px solid #334155;color:#dbeafe;font-size:12px;line-height:1.35;text-align:left;\">'\n            + '<b>Istruzione ricevuta dalla Configurazione AI<\/b><br>'\n            + '<span style=\"display:block;margin-top:4px;white-space:pre-wrap;\">' + safe + '<\/span>'\n            + '<div style=\"margin-top:6px;color:#bfdbfe;\">' + mode + '<\/div>'\n            + '<\/div>';\n    };\n    window.startConfigAiRequest434 = function(db, prompt, isFast) {\n        const token = 'cfgai-' + Date.now() + '-' + Math.random().toString(36).slice(2, 10);\n        const safePrompt1587 = window.tiRedactConfigAiSecrets1587 ? window.tiRedactConfigAiSecrets1587(prompt) : String(prompt || '');\n        let ctl1600 = null;\n        try { if (typeof AbortController !== 'undefined') ctl1600 = new AbortController(); } catch(e) { ctl1600 = null; }\n        window.tiActiveConfigAiRequest434 = { token: token, db: String(db || ''), prompt: safePrompt1587, fast: !!isFast, cancelled: false, cancelling: false, reconciled: false, startedAt: Date.now(), controller: ctl1600, hardStopTimer: null, pollTimer: null };\n        try {\n            \/\/ 30.9.1745: timeout progressivo. A 120s e 240s non si interrompe piu automaticamente:\n            \/\/ si verifica lo stato server e si estende la finestra. Interruzione solo a 420s.\n            const scheduleTimeout1745 = function(delay1745, stage1745){\n                const st1745 = window.tiActiveConfigAiRequest434;\n                if (!st1745 || st1745.token !== token || st1745.cancelled) return;\n                st1745.hardStopTimer = setTimeout(function(){\n                    const cur1745 = window.tiActiveConfigAiRequest434;\n                    if (!cur1745 || cur1745.token !== token || cur1745.cancelled) return;\n                    if (stage1745 < 3) {\n                        const nextTotal1745 = stage1745 === 1 ? 240 : 420;\n                        try { if (window.tiConfigAiStatus707Step) window.tiConfigAiStatus707Step('Elaborazione ancora attiva: estendo automaticamente il tempo massimo fino a '+nextTotal1745+' secondi. Non riprovare la richiesta.'); } catch(e) {}\n                        try {\n                            if (window.getConfigAiServerStatus1601) window.getConfigAiServerStatus1601(cur1745).then(function(state1745){\n                                if (state1745 && state1745.terminal && window.finishConfigAiRequest434) window.finishConfigAiRequest434(token);\n                            }).catch(function(){});\n                        } catch(e) {}\n                        scheduleTimeout1745(stage1745 === 1 ? 120000 : 180000, stage1745 + 1);\n                        return;\n                    }\n                    try { if (window.tiConfigAiStatus707Step) window.tiConfigAiStatus707Step('Raggiunto il limite finale di 420 secondi: richiedo interruzione e verifico lo stato reale sul server.'); } catch(e) {}\n                    try { if (window.cancelActiveConfigAiRequest434) window.cancelActiveConfigAiRequest434('hard_timeout_1745'); } catch(e) {}\n                }, delay1745);\n            };\n            scheduleTimeout1745(120000, 1);\n        } catch(e) {}\n        return token;\n    };\n    window.isConfigAiRequestActive434 = function(token) {\n        const st = window.tiActiveConfigAiRequest434;\n        return !!(st && st.token === token && !st.cancelled);\n    };\n    window.finishConfigAiRequest434 = function(token) {\n        const st = window.tiActiveConfigAiRequest434;\n        if (st && st.token === token) {\n            try { if (st.hardStopTimer) clearTimeout(st.hardStopTimer); } catch(e) {}\n            try { if (st.pollTimer) clearInterval(st.pollTimer); } catch(e) {}\n            window.tiActiveConfigAiRequest434 = null;\n        }\n    };\n    window.getConfigAiServerStatus1601 = function(st) {\n        if (!st || !st.token || !st.db || !window.buildAjaxFormData || !window.fetchJsonSafe) return Promise.resolve(null);\n        const fd1601 = window.buildAjaxFormData('ti_ai_config_action', {db:st.db, mode:'status_config_ai', request_token:st.token, prompt:''});\n        return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd1601, tiNoLongProcessSignal:true, tiTimeoutMs:5000, credentials:'same-origin'}).then(function(r){ return (r && r.success && r.data) ? (r.data.state || null) : null; }).catch(function(){ return null; });\n    };\n    window.refreshConfigAfterAi1601 = function(dbName) {\n        try {\n            if (!dbName || !window.buildAjaxFormData || !window.fetchJsonSafe) return;\n            const fdDb1601 = window.buildAjaxFormData('ti_ai_get_db_data', {db:dbName});\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fdDb1601, tiNoLongProcessSignal:true, tiTimeoutMs:12000}).then(function(dbRes1601){\n                if (dbRes1601 && dbRes1601.success && dbRes1601.data) { window.currentDbData = dbRes1601.data; if (window.renderConfig) window.renderConfig(); }\n            }).catch(function(){});\n        } catch(e) {}\n    };\n    window.applyConfigAiTerminalState1601 = function(token, state, source) {\n        const st = window.tiActiveConfigAiRequest434;\n        if (!st || st.token !== token || !state || !state.terminal) return false;\n        try { if (st.hardStopTimer) clearTimeout(st.hardStopTimer); } catch(e) {}\n        try { if (st.pollTimer) clearInterval(st.pollTimer); } catch(e) {}\n        try { if (window.tiConfigAiFastAdviceTimeout434) clearTimeout(window.tiConfigAiFastAdviceTimeout434); } catch(e) {}\n        st.reconciled = true; st.cancelled = true;\n        try { if (st.controller) st.controller.abort(); } catch(e) {}\n        const btn1601 = gE('ti-conf-ai-send'); if (btn1601) { btn1601.disabled=false; btn1601.innerText='Invia'; }\n        const rb1601 = gE('ti-conf-ai-reply');\n        const ok1601 = !!state.success;\n        const txt1601 = String(state.reply || (ok1601 ? 'Operazione completata dal server.' : 'Operazione terminata.'));\n        if (rb1601 && window.setConfigAiReplyHtml) { rb1601.style.display='block'; window.setConfigAiReplyHtml(rb1601, txt1601.replace(\/\\[NO_VOICE\\]\/g,'').trim()); }\n        try { if (window.hideProgressPopup) window.hideProgressPopup(ok1601, ok1601?'Configurazione AI completata':'Configurazione AI terminata', {notifyUser:false, remindSave:!!state.needs_reload, successMessage:ok1601?'Configurazione AI completata.':'', errorMessage:ok1601?'':'Configurazione AI terminata.'}); } catch(e) {}\n        try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(ok1601, String(state.process_status || state.status || (ok1601?'completata':'terminata'))); } catch(e) {}\n        if (ok1601 && state.needs_reload) window.refreshConfigAfterAi1601(st.db);\n        window.tiActiveConfigAiRequest434 = null;\n        return true;\n    };\n    window.startConfigAiStatusPoll1601 = function(token) {\n        const st = window.tiActiveConfigAiRequest434;\n        if (!st || st.token !== token || st.pollTimer) return;\n        st.pollTimer = setInterval(function(){\n            const cur = window.tiActiveConfigAiRequest434;\n            if (!cur || cur.token !== token || cur.cancelled || cur.cancelling) { try{clearInterval(st.pollTimer);}catch(e){} return; }\n            window.getConfigAiServerStatus1601(cur).then(function(state){ if (state && state.terminal) window.applyConfigAiTerminalState1601(token, state, 'poll'); });\n        }, 2000);\n    };\n    window.notifyConfigAiCancelServer434 = function(st) {\n        if (!st || !st.token || !st.db || !window.buildAjaxFormData || !window.fetchJsonSafe) return Promise.resolve(null);\n        const fd1601 = window.buildAjaxFormData('ti_ai_config_action', {db:st.db, mode:'cancel_config_ai', request_token:st.token, prompt:''});\n        return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd1601, keepalive:true, credentials:'same-origin', tiNoLongProcessSignal:true, tiTimeoutMs:6000}).catch(function(){ return null; });\n    };\n    window.waitConfigAiCancelResolution1601 = function(st, attempts) {\n        attempts = Math.max(1, Number(attempts||8));\n        return new Promise(function(resolve){\n            function one(left){\n                window.getConfigAiServerStatus1601(st).then(function(state){\n                    if (state && state.terminal) { resolve(state); return; }\n                    if (left <= 1) { resolve(state || null); return; }\n                    setTimeout(function(){ one(left-1); }, 500);\n                });\n            }\n            one(attempts);\n        });\n    };\n    window.cancelActiveConfigAiRequest434 = function(reason) {\n        const st = window.tiActiveConfigAiRequest434;\n        if (!st) return Promise.resolve({status:'none', message:'Nessuna richiesta attiva.'});\n        if (st.cancelling && st.cancelPromise) return st.cancelPromise;\n        st.cancelling = true; st.cancelled = true;\n        try { if (st.hardStopTimer) clearTimeout(st.hardStopTimer); } catch(e) {}\n        try { if (st.pollTimer) clearInterval(st.pollTimer); } catch(e) {}\n        try { if (st.controller) st.controller.abort(); } catch(e) {}\n        try { if (window.tiConfigAiFastAdviceTimeout434) clearTimeout(window.tiConfigAiFastAdviceTimeout434); } catch(e) {}\n        try { if (window.tiLongProcessState && window.tiLongProcessState.controller) window.tiLongProcessState.controller.abort(); } catch(e) {}\n        const sendBtn1601 = gE('ti-conf-ai-send'); if (sendBtn1601) { sendBtn1601.disabled=true; sendBtn1601.innerText='Verifica interruzione...'; }\n        const rb1601 = gE('ti-conf-ai-reply');\n        if (rb1601 && window.setConfigAiReplyHtml) { rb1601.style.display='block'; window.setConfigAiReplyHtml(rb1601, 'Interruzione richiesta. Verifico sul server se l operazione era ancora prima del salvataggio oppure se era gia stata completata. Non riprovare ancora.'); }\n        st.cancelPromise = window.notifyConfigAiCancelServer434(st).then(function(cancelRes){\n            if (cancelRes && cancelRes.success && cancelRes.data && cancelRes.data.already_completed) return cancelRes.data.state || {terminal:true,success:true,needs_reload:!!cancelRes.data.needs_reload,reply:cancelRes.data.reply||'',process_status:'already_completed_1601'};\n            return window.waitConfigAiCancelResolution1601(st, 10);\n        }).then(function(state){\n            let outcome;\n            if (state && state.terminal && state.success) {\n                outcome = {status:'completed', message:'L operazione era gia stata completata dal server prima dell interruzione. Le modifiche gia salvate restano valide.', state:state};\n                if (state.needs_reload) window.refreshConfigAfterAi1601(st.db);\n            } else if (state && state.terminal) {\n                outcome = {status:'cancelled', message:'Interruzione confermata dal server prima del completamento. Nessuna modifica di questa richiesta risulta salvata.', state:state};\n            } else {\n                outcome = {status:'unknown', message:'Interruzione inviata, ma lo stato finale non e ancora verificabile. Non ripetere la richiesta finche non hai riletto il database o ottenuto un esito server.'};\n            }\n            if (sendBtn1601) { sendBtn1601.disabled=false; sendBtn1601.innerText='Invia'; }\n            if (rb1601 && window.setConfigAiReplyHtml) window.setConfigAiReplyHtml(rb1601, outcome.message + '\\n\\nIstruzione ricevuta: ' + String(st.prompt||''));\n            try { if (window.hideProgressPopup) window.hideProgressPopup(false, 'Configurazione AI - verifica interruzione', {notifyUser:false, errorMessage:outcome.message}); } catch(e) {}\n            try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(outcome.status==='completed', outcome.status==='completed'?'completata dopo verifica':(outcome.status==='cancelled'?'interrotta':'interruzione non verificata')); } catch(e) {}\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            window.tiActiveConfigAiRequest434 = null;\n            return outcome;\n        }).catch(function(){\n            if (sendBtn1601) { sendBtn1601.disabled=false; sendBtn1601.innerText='Invia'; }\n            const outcome={status:'unknown',message:'Interruzione inviata, ma non e stato possibile verificare lo stato finale del server. Prima di riprovare rileggi il database.'};\n            if (rb1601 && window.setConfigAiReplyHtml) window.setConfigAiReplyHtml(rb1601, outcome.message);\n            try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(false, 'interruzione non verificata'); } catch(e) {}\n            try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n            window.tiActiveConfigAiRequest434 = null;\n            return outcome;\n        });\n        return st.cancelPromise;\n    };\n\n    \/\/ 30.9.2028 - Configurazione AI: distinguere una risposta\/consiglio da una modifica realmente applicata.\n    \/\/ Il completamento modale non deve coprire la form che contiene la risposta.\n    window.tiConfigAiHasActualChange2028 = function(payload, updatedCount) {\n        try {\n            if (payload && payload.needs_reload) return true;\n            if (updatedCount !== null && typeof updatedCount !== 'undefined' && Number(updatedCount) > 0) return true;\n        } catch(e) {}\n        return false;\n    };\n    window.tiConfigAiHideCompletionNotice2028 = function() {\n        try { const n = gE('ti-conf-ai-completion-notice-2028'); if (n) n.style.display = 'none'; } catch(e) {}\n    };\n    window.tiConfigAiShowCompletionNotice2028 = function(message) {\n        try {\n            const rb = gE('ti-conf-ai-reply');\n            if (!rb) return false;\n            let n = gE('ti-conf-ai-completion-notice-2028');\n            if (!n) {\n                n = document.createElement('div');\n                n.id = 'ti-conf-ai-completion-notice-2028';\n                n.style.cssText = 'display:none;align-items:center;justify-content:space-between;gap:10px;margin-top:8px;padding:8px 10px;border:1px solid #22c55e;border-radius:9px;background:#052e16;color:#dcfce7;font-size:12px;font-weight:700;line-height:1.3;position:relative;z-index:1;';\n                n.innerHTML = '<span data-ti-config-ai-done-text-2028><\/span><button type=\"button\" data-ti-config-ai-done-close-2028 style=\"border:0;border-radius:7px;padding:4px 8px;background:#166534;color:#fff;font-weight:800;cursor:pointer;flex:0 0 auto;\">Chiudi<\/button>';\n                rb.insertAdjacentElement('afterend', n);\n                const c = n.querySelector('[data-ti-config-ai-done-close-2028]');\n                if (c) c.onclick = function(ev){ if(ev){ev.preventDefault();ev.stopPropagation();} n.style.display='none'; return false; };\n            }\n            const t = n.querySelector('[data-ti-config-ai-done-text-2028]');\n            if (t) t.textContent = String(message || 'Attivita AI di configurazione completata.');\n            n.style.display = 'flex';\n            return true;\n        } catch(e) { return false; }\n    };\n\n    window.runConfigBot = function() {\n        const box = gE('ti-conf-ai-prompt'); const replyBox = gE('ti-conf-ai-reply'); const btn = gE('ti-conf-ai-send');\n        try { if (window.tiConfigAiHideCompletionNotice2028) window.tiConfigAiHideCompletionNotice2028(); } catch(e) {}\n        const dbSel = gE('ti-ditta');\n        if (!box || !replyBox || !btn || !dbSel || !dbSel.value || dbSel.value === 'NEW_DB') { window.tiAlert('Seleziona prima una ditta.'); return; }\n        let prompt = (box.value || '').trim();\n        if (!prompt) {\n            const pendingEmpty446 = window.getConfigAiState330 ? window.getConfigAiState330(dbSel.value) : null;\n            if (pendingEmpty446 && pendingEmpty446.status === 'awaiting_user_details') {\n                window.showConfigAiPendingClarification446 && window.showConfigAiPendingClarification446(dbSel.value, pendingEmpty446, replyBox, box);\n                return;\n            }\n            window.tiAlert('Scrivi una istruzione di configurazione.'); return;\n        }\n        const pendingState446 = window.getConfigAiState330 ? window.getConfigAiState330(dbSel.value) : null;\n        if (pendingState446 && pendingState446.status === 'awaiting_user_details') {\n            if (window.configAiPendingClarificationNeedsDisplay446 && window.configAiPendingClarificationNeedsDisplay446(dbSel.value, pendingState446, prompt)) {\n                window.showConfigAiPendingClarification446 && window.showConfigAiPendingClarification446(dbSel.value, pendingState446, replyBox, box);\n                return;\n            }\n            if (window.buildConfigAiPromptWithPendingAnswer446) prompt = window.buildConfigAiPromptWithPendingAnswer446(dbSel.value, pendingState446, prompt);\n        }\n        const roleTxt = String(window.tiRole || '').toLowerCase();\n        const isDbAdmin = roleTxt.includes('amministratore') || window.tiUser === 'SSGlobalAdmin';\n        const wantsStructure = \/struttura\\s+database|adegua\\s+struttura|allinea\\s+struttura|schema\\s+template|aggiungi\\s+campo|rimuovi\\s+campo|nuova\\s+tabella|elimina\\s+tabella\/i.test(prompt);\n        if (wantsStructure && !isDbAdmin) {\n            replyBox.style.display = 'block';\n            replyBox.innerHTML = 'Le modifiche della struttura del database non sono possibili per il tuo ruolo. Richiedi l intervento di un amministratore.';\n            return;\n        }\n        const demoReadonly2031 = !!window.tiDemoReadonly || String(window.tiUser || '').trim().toLowerCase() === 'ssdemo';\n        const infoPrompt2031 = \/^(come|cosa|dove|quando|perch[e\u00e9]|quale|quali|chi|spiega|spiegami|mi spieghi|posso|potrei|vorrei sapere|info|informazioni|aiuto|help|consiglia|consigliami|suggerisci)\\b\/i.test(prompt)\n            || \/\\bcome\\s+(?:posso\\s+|faccio\\s+a\\s+|si\\s+)?(?:modific|configur|impost|gest|attiv|disattiv|us|cambi|ved|tro)\/i.test(prompt)\n            || \/\\?\\s*$\/.test(prompt);\n        const adviceOnly2031 = demoReadonly2031 || infoPrompt2031;\n        btn.disabled = true; const oldText = btn.innerText; btn.innerText = '\u23f3 Elaborazione...';\n        const isFastAdvicePrompt434 = !adviceOnly2031 && !!(window.isConfigAiFastAdvicePrompt434 && window.isConfigAiFastAdvicePrompt434(prompt));\n        const requestToken434 = (window.startConfigAiRequest434 ? window.startConfigAiRequest434(dbSel.value, prompt, isFastAdvicePrompt434) : ('cfgai-' + Date.now()));\n        try { if (window.startConfigAiStatusPoll1601) window.startConfigAiStatusPoll1601(requestToken434); } catch(e) {}\n        replyBox.style.display = 'none';\n        replyBox.innerHTML = '';\n        if (isFastAdvicePrompt434) {\n            try { if (window.clearConfigAiState330) window.clearConfigAiState330(dbSel.value); } catch(e) {}\n        } else {\n            window.saveConfigAiState330(dbSel.value, prompt, 'Elaborazione avviata. Se hai aggiornato la pagina prima della risposta finale, rientra in Configurazione e ripeti o verifica i record: la richiesta resta qui come promemoria.', 'running');\n        }\n        if (window.tiConfigAiUseSimpleWait1943 === true) {\n            try { if (window.tiConfigAiSimpleWait1943Start) window.tiConfigAiSimpleWait1943Start(); } catch(e) {}\n        } else {\n            window.showProgressPopup('Configurazione AI', isFastAdvicePrompt434 ? 'Percorso veloce Configurazione AI: nessuna lettura file non necessaria; eventuale salvataggio solo su campi esistenti.' : 'Sto elaborando le istruzioni e l eventuale file allegato. La percentuale \u00e8 stimata.', {startPercent: 2, targetPercent: isFastAdvicePrompt434 ? 60 : 94, stepMs: isFastAdvicePrompt434 ? 350 : 800, expectedMs: isFastAdvicePrompt434 ? 8000 : 55000});\n        }\n        const fd = window.buildAjaxFormData(adviceOnly2031 ? 'ti_ai_config_advice_2031' : 'ti_ai_config_action', {\n            db: dbSel.value,\n            mode: adviceOnly2031 ? 'advice' : 'ai_ops',\n            prompt: prompt,\n            request_token: requestToken434\n        });\n        \/\/ Il FormData contiene gia il valore necessario al server; da questo punto il secret non resta visibile nella chat.\n        if (window.tiConfigAiContainsSecret1587 && window.tiConfigAiContainsSecret1587(prompt) && box && window.tiRedactConfigAiSecrets1587) {\n            try { box.value = window.tiRedactConfigAiSecrets1587(box.value); } catch(e) {}\n        }\n        if (window.configBotFile) fd.append('file_url', window.configBotFile);\n        if (window.tiConfigImportToken) fd.append('import_token', window.tiConfigImportToken);\n        if (isFastAdvicePrompt434) {\n            try {\n                if (window.tiConfigAiFastAdviceTimeout434) clearTimeout(window.tiConfigAiFastAdviceTimeout434);\n                window.tiConfigAiFastAdviceTimeout434 = setTimeout(function(){\n                    if (!window.isConfigAiRequestActive434 || !window.isConfigAiRequestActive434(requestToken434)) return;\n                    try { if (window.tiLongProcessState && window.tiLongProcessState.controller) window.tiLongProcessState.controller.abort(); } catch(e) {}\n                    if (window.cancelActiveConfigAiRequest434) window.cancelActiveConfigAiRequest434('fast_advice_timeout');\n                }, 20000);\n            } catch(e) {}\n        }\n        const activeReq1600 = window.tiActiveConfigAiRequest434;\n        const fetchOpts1600 = {method:'POST', body:fd};\n        try { if (activeReq1600 && activeReq1600.token === requestToken434 && activeReq1600.controller) fetchOpts1600.signal = activeReq1600.controller.signal; } catch(e) {}\n        window.fetchJsonSafe(window.tiUrl, fetchOpts1600).then(d => {\n            if (window.isConfigAiRequestActive434 && !window.isConfigAiRequestActive434(requestToken434)) {\n                btn.disabled = false; btn.innerText = oldText;\n                try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n                return;\n            }\n            try { if (window.tiConfigAiFastAdviceTimeout434) clearTimeout(window.tiConfigAiFastAdviceTimeout434); } catch(e) {}\n            btn.disabled = false; btn.innerText = oldText;\n            if (!d.success) {\n                const maybeData = d && d.data ? d.data : {};\n                if (maybeData && maybeData.clarify_request && maybeData.reply) {\n                    window.finishConfigAiAwaitingUser330(replyBox, dbSel.value, prompt, String(maybeData.reply));\n                    return;\n                }\n                window.hideProgressPopup(false, 'Errore configurazione AI');\n                try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(false, 'errore configurazione AI'); } catch(e) {}\n                if (window.finishConfigAiRequest434) window.finishConfigAiRequest434(requestToken434);\n                try { if (window.clearConfigAiState330 && isFastAdvicePrompt434) window.clearConfigAiState330(dbSel.value); } catch(e) {}\n                replyBox.style.display = 'block';\n                window.setConfigAiReplyHtml(replyBox, window.formatConfigAiErrorMessage(d, 'Errore configurazione AI', prompt));\n                return;\n            }\n            const replyText = d.data && d.data.reply ? d.data.reply : 'Operazione completata.';\n            if (d.data && d.data.sensitive_input && window.tiRedactConfigAiSecrets1587) {\n                prompt = window.tiRedactConfigAiSecrets1587(prompt);\n                try { if (box) box.value = window.tiRedactConfigAiSecrets1587(box.value); } catch(e) {}\n            }\n            const processStatusEarly434 = d.data && d.data.process_status ? String(d.data.process_status) : '';\n            if (processStatusEarly434 === 'cancelled' || processStatusEarly434 === 'cancelled_before_commit') {\n                try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(false, processStatusEarly434); } catch(e) {}\n                if (window.cancelActiveConfigAiRequest434) window.cancelActiveConfigAiRequest434('server_cancelled');\n                return;\n            }\n            if (d.data && d.data.awaiting_confirm) {\n                window.hideProgressPopup(true, 'Anteprima import pronta', {notifyUser:false, remindSave:false, successMessage:'Anteprima pronta.'});\n                replyBox.style.display = 'none';\n                window.tiConfigImportToken = d.data.import_token || d.data.preview_token || window.tiConfigImportToken || null;\n                if (window.finishConfigAiRequest434) window.finishConfigAiRequest434(requestToken434);\n                try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(true, 'anteprima import pronta'); } catch(e) {}\n                window.showConfigImportPreview(replyText, window.tiConfigImportToken);\n                return;\n            }\n            if (d.data && d.data.needs_reload) window.tiConfigImportToken = null;\n            let cleanReplyText = replyText.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n            if (d.data && d.data.ai_instruction_echo && cleanReplyText.indexOf('Istruzione ricevuta\/inviata alla Configurazione AI') === -1) {\n                cleanReplyText = 'Istruzione ricevuta\/inviata alla Configurazione AI: \"' + String(d.data.ai_instruction_echo) + '\".\\n\\n' + cleanReplyText;\n            }\n            const updatedCount = (d.data && typeof d.data.updated_count !== 'undefined') ? (parseInt(d.data.updated_count, 10) || 0) : null;\n            const processStatus = d.data && d.data.process_status ? String(d.data.process_status) : '';\n            const replyLower330 = cleanReplyText.toLowerCase();\n            const hasActualConfigChange2028 = window.tiConfigAiHasActualChange2028\n                ? window.tiConfigAiHasActualChange2028(d.data || {}, updatedCount)\n                : (!!(d.data && d.data.needs_reload) || (updatedCount !== null && updatedCount > 0));\n            const isAdviceCompleted330 = (processStatus === 'completed_advice' || processStatus === 'completed_operational_advice');\n            const needsUserDetails330 = !isAdviceCompleted330 && (!!(d.data && d.data.clarify_request)\n                || processStatus === 'awaiting_user_details'\n                || (updatedCount === 0 && !d.data.needs_reload && \/(indicami|specific|quali record|quale record|criterio piu preciso|criterio pi\u00f9 preciso|non ho trovato|record aggiornati:\\s*0)\/i.test(replyLower330)));\n            if (needsUserDetails330) {\n                if (window.finishConfigAiRequest434) window.finishConfigAiRequest434(requestToken434);\n                try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(true, 'richiesta dettagli utente'); } catch(e) {}\n                window.finishConfigAiAwaitingUser330(replyBox, dbSel.value, prompt, cleanReplyText);\n                return;\n            }\n\n            \/\/ 30.9.2028: mostra prima e conserva la risposta. Il loader viene chiuso senza generare\n            \/\/ un secondo popup modale che potrebbe coprire\/mascherare la form Configurazione.\n            replyBox.style.display = 'block';\n            window.setConfigAiReplyHtml(replyBox, window.escapeHtml(String(cleanReplyText || '')).replace(\/\\n\/g, '<br>'), cleanReplyText);\n            try { if (window.showPluginModal) window.showPluginModal('ti-conf-ov'); } catch(e) {}\n            try {\n                if (d.data && d.data.support_suggested && window.tiOfferCodeChangeEmail569) {\n                    setTimeout(function(){ window.tiOfferCodeChangeEmail569(prompt, cleanReplyText, {force:true, reason:'support'}); }, 120);\n                }\n            } catch(e) {}\n\n            if (isAdviceCompleted330 || !hasActualConfigChange2028) {\n                window.hideProgressPopup(true, isAdviceCompleted330 ? 'Consiglio operativo AI completato' : 'Risposta AI pronta', {notifyUser:false, remindSave:false});\n            } else {\n                window.hideProgressPopup(true, 'Configurazione AI completata', {notifyUser:false, remindSave:true});\n                try { if (window.tiConfigAiShowCompletionNotice2028) window.tiConfigAiShowCompletionNotice2028('Attivita AI di configurazione completata.'); } catch(e) {}\n            }\n            try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(true, processStatus || (hasActualConfigChange2028 ? 'configurazione completata' : 'risposta pronta')); } catch(e) {}\n            window.saveConfigAiState330(dbSel.value, prompt, cleanReplyText, (isAdviceCompleted330 || !hasActualConfigChange2028) ? 'completed_advice' : ((d.data && d.data.needs_reload) ? 'completed_with_updates' : 'completed'));\n            if (window.finishConfigAiRequest434) window.finishConfigAiRequest434(requestToken434);\n            if (d.data && d.data.needs_reload) {\n                const fdDb = window.buildAjaxFormData('ti_ai_get_db_data', {db: dbSel.value});\n                fetch(window.tiUrl, {method:'POST', body:window.ensureAjaxActionField(fdDb)}).then(r2 => r2.json()).then(dbRes => {\n                    if (dbRes.success && dbRes.data) { window.currentDbData = dbRes.data; window.renderConfig(); }\n                });\n            }\n        }).catch(err => {\n            if (window.isConfigAiRequestActive434 && !window.isConfigAiRequestActive434(requestToken434)) {\n                btn.disabled = false; btn.innerText = oldText;\n                try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n                return;\n            }\n            try { if (window.tiConfigAiFastAdviceTimeout434) clearTimeout(window.tiConfigAiFastAdviceTimeout434); } catch(e) {}\n            btn.disabled = false; btn.innerText = oldText;\n            if (err && (err.userCancelled || window.isLongAIProcessCancelled())) {\n                if (window.cancelActiveConfigAiRequest434) { window.cancelActiveConfigAiRequest434('abort_catch'); return; }\n                replyBox.style.display = 'block'; window.setConfigAiReplyHtml(replyBox, 'Operazione interrotta dall utente. Per completarla dovrai ripetere la richiesta.');\n                try { if (window.clearConfigAiState330) window.clearConfigAiState330(dbSel.value); } catch(e) {}\n                window.clearLongAIProcess(); return;\n            }\n            if (window.finishConfigAiRequest434) window.finishConfigAiRequest434(requestToken434);\n            window.hideProgressPopup(false, 'Errore configurazione AI');\n            try { if (window.tiConfigAiStatus707Finish) window.tiConfigAiStatus707Finish(false, (err && err.message) ? err.message : 'errore comunicazione'); } catch(e) {}\n            replyBox.style.display = 'block';\n            window.setConfigAiReplyHtml(replyBox, window.formatConfigAiErrorMessage({message: 'Errore di comunicazione o risposta server non valida: ' + (err && err.message ? err.message : 'errore sconosciuto')}, 'Errore configurazione AI', prompt));\n        });\n    };\n\n    try { if (typeof window.runConfigBot === 'function' && !window.__tiRunConfigBotCore710) window.__tiRunConfigBotCore710 = window.runConfigBot; } catch(e) {}\n\n    window.openAtecoSearch = function(targetId) {\n        const target = gE('ateco-target-id');\n        const input = gE('ateco-in');\n        const res = gE('ateco-res');\n        const ov = gE('ti-ateco-ov');\n        if (!target || !input || !res || !ov) {\n            if (window.tiAlert) window.tiAlert('Ricerca ATECO non disponibile: ricarica la configurazione e riprova.');\n            return false;\n        }\n        target.value = targetId || '';\n        input.value = '';\n        res.innerHTML = '<i>Scrivi l\\'attivit\u00e0 da cercare...<\/i>';\n        try { window.openModal('ti-ateco-ov'); } catch(e) {}\n        try {\n            ov.setAttribute('data-ti-config-child-modal', '1');\n            if (window.preparePluginModal) window.preparePluginModal(ov);\n            ov.style.setProperty('display', 'flex', 'important');\n            ov.style.setProperty('z-index', '2147483500', 'important');\n            ov.removeAttribute('aria-hidden');\n            ov.setAttribute('data-ti-force-front', '1');\n            if (window.updatePluginScrollLock) window.updatePluginScrollLock();\n            setTimeout(function(){ try { input.focus({preventScroll:true}); } catch(e) {} }, 60);\n        } catch(e) {}\n        return false;\n    };\n    window.searchAteco = function() {\n        const query = gE('ateco-in').value; if (!query) return;\n        const resBox = gE('ateco-res'); resBox.innerHTML = '<i>Ricerca in corso con l\\'IA... \u23f3<\/i>';\n        const fd = new FormData(); fd.append('ti_action', 'ti_ai_chat_start'); fd.append('db', gE('ti-ditta').value || 'NEW_DB'); fd.append('text', \"CERCA ATECO: \" + query);\n        fetch(window.tiUrl, {method: 'POST', body: fd}).then(r=>r.json()).then(res=>{ if (res.success) resBox.innerHTML = res.data.reply; else resBox.innerHTML = \"<span style='color:#ef4444;'>Errore ricerca ATECO.<\/span>\"; });\n    };\n    window.selectAteco = function(codice, desc) { const targetId = gE('ateco-target-id').value; if (targetId) { const inputEl = gE(targetId); if (inputEl) { inputEl.value = desc; inputEl.dispatchEvent(new Event('change')); } } window.closeModal('ti-ateco-ov'); };\n\n    window.showUploadChoice = function(target) { window.targetUploadContext = target || 'chat'; window.openModal('ti-up-choice-ov'); };\n    window.chooseLocal = function() { if (window.tiOpenDirectUpload616) return window.tiOpenDirectUpload616(window.targetUploadContext || 'chat'); return false; };\n    \n    window.chooseAI = function() { \n        window.closeModal('ti-up-choice-ov'); \n        let row = null;\n        if (window.targetUploadContext && typeof window.targetUploadContext === 'object' && window.targetUploadContext.tbl) {\n            row = window.currentDbData.Tabelle[window.targetUploadContext.tbl][window.targetUploadContext.idx] || null;\n        }\n        window.populateAIGenPrompt(row);\n        if (gE('ai-gen-detail')) gE('ai-gen-detail').value = '';\n        gE('ai-gen-res').style.display = 'none'; \n        gE('ai-gen-btn').style.display = 'block'; \n        window.openModal('ti-ai-gen-ov'); \n    };\n    \n    window.doAIGen = function() {\n        let prompt = gE('ai-gen-prompt').value.trim();\n        const detailInstructions = (gE('ai-gen-detail') && gE('ai-gen-detail').value) ? gE('ai-gen-detail').value.trim() : '';\n        if(!prompt && !detailInstructions) { window.tiAlert(\"Inserisci una descrizione!\"); return; }\n        if (!prompt && detailInstructions) prompt = detailInstructions;\n        if (!\/^Attivit\u00e0 ditta:\/i.test(prompt) && !\/^Verifica anzitutto\/i.test(prompt)) { prompt = window.buildAIGenPrompt(prompt); gE('ai-gen-prompt').value = prompt; }\n        if (detailInstructions) {\n            const detailBlock = ' Istruzioni di dettaglio per la generazione foto: ' + detailInstructions + '.';\n            if (prompt.indexOf(detailInstructions) === -1) prompt += detailBlock;\n        }\n        const btn = gE('ai-gen-btn'); btn.innerText = \"\u23f3 Generazione in corso... (10-20 sec)\"; btn.disabled = true;\n        window.showProgressPopup(\"AI Image Generator\", \"Sto generando l'immagine richiesta. La percentuale e stimata fino alla risposta del servizio.\", {startPercent: 6, targetPercent: 93, stepMs: 650});\n        const dbVal = gE('ti-ditta').value || 'Global'; const fd = new FormData(); fd.append('ti_action', 'ti_ai_generate_media'); fd.append('db', dbVal); fd.append('prompt', prompt);\n        window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n            btn.innerText = \"Genera Immagine\"; btn.disabled = false;\n            if(d.success) { window.hideProgressPopup(true, 'Immagine generata', {remindSave:true, notifyUser:false, successMessage:'Attivita AI completata. Immagine generata correttamente.'}); window.currentGenFilename = d.data.filename; gE('ai-gen-img').src = d.data.url; gE('ai-gen-btn').style.display = 'none'; gE('ai-gen-res').style.display = 'block'; } else { window.hideProgressPopup(false, 'Errore generazione immagine'); window.tiAlert((d && d.data && d.data.message) ? d.data.message : 'Errore generazione immagine.'); } \n        }).catch(e => { btn.innerText = \"Genera Immagine\"; btn.disabled = false; if (e && (e.userCancelled || window.isLongAIProcessCancelled())) { window.clearLongAIProcess(); return; } window.hideProgressPopup(false, 'Errore generazione immagine'); const msg = (e && e.message) ? e.message : 'Errore di rete.'; window.tiAlert(msg); });\n    };\n    \n    window.resetAIGen = function() { gE('ai-gen-res').style.display = 'none'; gE('ai-gen-btn').style.display = 'block'; gE('ai-gen-img').src = ''; if (gE('ai-gen-detail')) gE('ai-gen-detail').value = ''; window.currentGenFilename = null; };\n    \n    window.useAIGen = function() {\n        if(!window.currentGenFilename) return; const dbVal = gE('ti-ditta').value || 'Global'; const tgt = window.targetUploadContext; window.closeModal('ti-ai-gen-ov');\n        if(tgt === 'chat') {\n            if(window.addMsg) window.addMsg('ai',\"\u23f3 Elaborazione file AI...\"); \n            const fd = new FormData(); fd.append('ti_action', 'ti_ai_media_upload'); fd.append('db', dbVal); fd.append('tbl', 'Chat'); fd.append('temp_file', window.currentGenFilename);\n            window.fetchJsonSafe(window.tiUrl,{method:'POST',body:fd}).then(d=>{ if(d.success) { window.lastUploadedFile = d.data.url; window.startUserUploadedFileAI(window.lastUploadedFile, d.data.name || window.currentGenFilename || 'immagine-ai.jpg'); } else if(window.addMsg) window.addMsg('ai',`\u26a0\ufe0f Errore salvataggio file AI.`); });\n        } else if (typeof tgt === 'object') {\n            let ctx = tgt;\n            const fd = new FormData(); fd.append('ti_action', 'ti_ai_media_upload'); fd.append('db', dbVal); fd.append('tbl', ctx.tbl); fd.append('temp_file', window.currentGenFilename); fd.append('record_label', window.getRecordLabelForUpload(ctx.tbl, window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[ctx.tbl] ? window.currentDbData.Tabelle[ctx.tbl][ctx.idx] : null, ctx.tbl));\n            window.fetchJsonSafe(window.tiUrl,{method:'POST',body:fd}).then(d=>{ \n                if(d.success) { \n                    let oldVal = window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] || '';\n                    let arr = oldVal.split(',').map(f=>f.trim()).filter(f=>f);\n                    arr.push(d.data.name);\n                    window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] = arr.join(', ');\n                    if(!window.modifiedFields) window.modifiedFields = new Set();\n                    window.modifiedFields.add(`${ctx.tbl}-${ctx.idx}-${ctx.key}`); if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n                    window.renderConfig();\n                    window.openFileManager(ctx.tbl, ctx.idx, ctx.key);\n                } else window.tiAlert(\"Errore: \" + d.data.message); \n            });\n        } else {\n            let tblName = 'Config'; if(tgt.startsWith('cfg-img-')) { const match = tgt.match(\/cfg-img-([^-]+)-\/); if(match) tblName = match[1]; } else if(tgt === 'p-foto') tblName = 'Utenti'; \n            const fd = new FormData(); fd.append('ti_action', 'ti_ai_media_upload'); fd.append('db', dbVal); fd.append('tbl', tblName); fd.append('temp_file', window.currentGenFilename); const recordLabel = (tgt === 'p-foto') ? (gE('p-user').value || gE('p-utente').value || 'utente') : tblName; fd.append('record_label', recordLabel);\n            window.fetchJsonSafe(window.tiUrl,{method:'POST',body:fd}).then(d=>{ if(d.success) { const inp = gE(tgt); if(inp) { inp.value = d.data.name; inp.dispatchEvent(new Event('change')); if(tgt.startsWith('cfg-')) window.renderConfig(); } } else window.tiAlert(\"Errore: \" + d.data.message); });\n        }\n    };\n\n    window.handleFileSelect = function(e) {\n        if(!e.target.files.length) return;\n        const tgt = e.target.dataset.target;\n        const dbVal = gE('ti-ditta').value || 'Global';\n        const fileObj = e.target.files[0];\n\n        if (tgt === 'manager') {\n            let ctx = window.targetUploadContext;\n            const fd = new FormData(); fd.append('ti_action', 'ti_ai_media_upload'); fd.append('db', dbVal); fd.append('file', fileObj); fd.append('tbl', ctx.tbl); fd.append('record_label', window.getRecordLabelForUpload(ctx.tbl, window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[ctx.tbl] ? window.currentDbData.Tabelle[ctx.tbl][ctx.idx] : null, ctx.tbl));\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n                if(d.success) {\n                    let oldVal = window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] || '';\n                    let arr = oldVal.split(',').map(f=>f.trim()).filter(f=>f);\n                    arr.push(d.data.name);\n                    window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] = arr.join(', ');\n                    if(!window.modifiedFields) window.modifiedFields = new Set();\n                    window.modifiedFields.add(`${ctx.tbl}-${ctx.idx}-${ctx.key}`); if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n                    window.renderConfig();\n                    window.openFileManager(ctx.tbl, ctx.idx, ctx.key);\n                } else {\n                    window.tiAlert('Err: ' + (d.data && d.data.message ? d.data.message : 'Errore upload.'));\n                }\n                e.target.dataset.target = ''; e.target.value = '';\n            }).catch(err => {\n                window.tiAlert('Errore di rete: ' + err.message);\n                e.target.dataset.target = ''; e.target.value = '';\n            });\n\n        } else if (tgt === 'config-bot-file') {\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_media_upload');\n            fd.append('db', dbVal);\n            fd.append('file', fileObj);\n            fd.append('tbl', 'Chat');\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n                if (d.success) {\n                    window.configBotFile = d.data.url;\n                    const fileBox = gE('ti-conf-ai-file');\n                    const promptBox = gE('ti-conf-ai-prompt');\n                    const replyBox = gE('ti-conf-ai-reply');\n                    const fileName = d.data.name || fileObj.name || 'file';\n                    if (fileBox) {\n                        fileBox.style.display = 'block';\n                        fileBox.innerHTML = `\ud83d\udcce <b>File caricato per AI:<\/b> ${fileName}<br><span style=\"font-size:13px;color:#cbd5e1;\">Adesso indica cosa deve fare la AI con il contenuto del file.<\/span>`;\n                    }\n                    if (replyBox) {\n                        replyBox.style.display = 'block';\n                        replyBox.innerHTML = '\u2705 File caricato correttamente.';\n                    }\n                    if (promptBox && !promptBox.value.trim()) {\n                        promptBox.value = 'Ho caricato un file per la AI. Analizza il contenuto del file e applica la mia prossima istruzione operativa.';\n                    }\n                    if (promptBox) promptBox.focus();\n                } else {\n                    window.tiAlert('Err: ' + (d.data && d.data.message ? d.data.message : 'Errore upload file.'));\n                }\n                e.target.dataset.target = ''; e.target.value = '';\n            }).catch(err => {\n                window.tiAlert('Errore di rete: ' + err.message);\n                e.target.dataset.target = ''; e.target.value = '';\n            });\n\n        } else if (tgt === 'purchase-import-file') {\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_media_upload');\n            fd.append('db', dbVal);\n            fd.append('file', fileObj);\n            fd.append('tbl', 'Chat');\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n                if (d.success) {\n                    const fileName = d.data.name || fileObj.name || 'file';\n                    if (window.tiAlert) window.tiAlert('File acquisizioni caricato: ' + fileName + '. Preparo import acquisizioni.');\n                    window.startPurchaseFileImport(d.data.url, fileName);\n                } else {\n                    window.tiAlert('Err: ' + (d.data && d.data.message ? d.data.message : 'Errore upload file acquisizioni.'));\n                }\n                e.target.dataset.target = ''; e.target.value = '';\n            }).catch(err => {\n                window.tiAlert('Errore di rete: ' + err.message);\n                e.target.dataset.target = ''; e.target.value = '';\n            });\n\n        } else if (tgt && tgt !== 'chat') {\n            const tblMatch = tgt.match(\/cfg-img-([^-]+)-\/);\n            const tblName = tblMatch ? tblMatch[1] : (tgt === 'p-foto' ? 'Utenti' : 'Config');\n            const fd = new FormData(); fd.append('ti_action', 'ti_ai_media_upload'); fd.append('db', dbVal); fd.append('file', fileObj); fd.append('tbl', tblName); const recordLabel = (tgt === 'p-foto') ? (gE('p-user').value || gE('p-utente').value || 'utente') : tblName; fd.append('record_label', recordLabel);\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n                if(d.success) {\n                    const inp = gE(tgt);\n                    if(inp) {\n                        inp.value = d.data.name;\n                        inp.dispatchEvent(new Event('change'));\n                        if(tgt.startsWith('cfg-')) window.renderConfig();\n                    }\n                    window.tiAlert('Memoria aggiornata!');\n                } else {\n                    window.tiAlert('Err: ' + (d.data && d.data.message ? d.data.message : 'Errore upload.'));\n                }\n                e.target.dataset.target = ''; e.target.value = '';\n            }).catch(err => {\n                window.tiAlert('Errore di rete: ' + err.message);\n                e.target.dataset.target = ''; e.target.value = '';\n            });\n        } else {\n            const runUpload = function(uploadFile){\n                const realFile = (uploadFile instanceof File) ? uploadFile : fileObj;\n                const fd = new FormData(); fd.append('ti_action', 'ti_ai_media_upload'); fd.append('db', dbVal); fd.append('file', realFile, realFile.name || fileObj.name || 'upload'); fd.append('tbl', 'Chat');\n                if(window.addMsg) window.addMsg('ai', '\u23f3 Analisi in corso...');\n                window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(d=>{\n                    if(d.success) {\n                        window.lastUploadedFile = d.data.url;\n                        window.startUserUploadedFileAI(window.lastUploadedFile, realFile.name || fileObj.name || '');\n                    } else {\n                        window.tiAlert('Err: ' + (d.data && d.data.message ? d.data.message : 'Errore upload.'));\n                    }\n                    e.target.dataset.target = ''; e.target.value = '';\n                }).catch(err => {\n                    window.tiAlert('Errore di rete: ' + err.message);\n                    e.target.dataset.target = ''; e.target.value = '';\n                });\n            };\n            if (typeof window.prepareUploadFileForAI === 'function') {\n                window.prepareUploadFileForAI(fileObj).then(runUpload);\n            } else {\n                runUpload(fileObj);\n            }\n        }\n    };\n\n    window.getConfigButtonTableName = function(btn) {\n        let tbl = '';\n        try {\n            const enc = btn && btn.getAttribute ? (btn.getAttribute('data-tbl-enc') || '') : '';\n            if (enc) tbl = decodeURIComponent(enc);\n        } catch(e) { tbl = ''; }\n        try {\n            if (!tbl && btn && btn.closest) {\n                const det = btn.closest('details.ti-cfg-details');\n                if (det && det.dataset) tbl = det.dataset.tbl || '';\n            }\n        } catch(e) {}\n        return window.resolveConfigTableName ? window.resolveConfigTableName(tbl) : tbl;\n    };\n\n    window.handleConfigDeleteRowClick = function(ev, btn) {\n        try { if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } } catch(e) {}\n        const tbl = window.getConfigButtonTableName ? window.getConfigButtonTableName(btn) : '';\n        let idx = NaN;\n        try { idx = parseInt((btn && btn.getAttribute && (btn.getAttribute('data-row-idx') || btn.getAttribute('data-idx'))) || '', 10); } catch(e) { idx = NaN; }\n        if (isNaN(idx) && btn && btn.closest) {\n            try { const tr = btn.closest('tr[data-row-idx]'); if (tr) idx = parseInt(tr.getAttribute('data-row-idx') || '', 10); } catch(e) {}\n        }\n        if (!tbl) { window.tiAlert && window.tiAlert('Tabella non riconosciuta. Riapri la configurazione e riprova.'); return false; }\n        if (isNaN(idx)) { window.tiAlert && window.tiAlert('Riga non riconosciuta. Riapri la configurazione e riprova.'); return false; }\n        \/\/ 30.9.1205: se ci sono altre righe selezionate (checkbox) in questa tabella, la X su una singola riga\n        \/\/ cancella tutte le righe selezionate insieme, con avviso di conferma (non solo quella cliccata).\n        try {\n            const otherSelected = window.getSelectedConfigRowIndexes ? window.getSelectedConfigRowIndexes(tbl, '', btn) : [];\n            if (otherSelected.length > 1 || (otherSelected.length === 1 && otherSelected[0] !== idx)) {\n                try {\n                    const scope = window.getConfigTableScope ? window.getConfigTableScope(tbl, btn) : document;\n                    const ownCheckbox = scope.querySelector('input.ti-config-row-select[data-row-idx=\"' + idx + '\"], input.ti-config-row-select[value=\"' + idx + '\"]');\n                    if (ownCheckbox) ownCheckbox.checked = true;\n                } catch(eCk) {}\n                if (typeof window.delBulk === 'function') { window.delBulk(tbl, '', btn); return false; }\n            }\n        } catch(eSel) {}\n        if (typeof window.delTableRow === 'function') window.delTableRow(tbl, idx, btn);\n        return false;\n    };\n    \/\/ 30.9.1410: gestore del click sul nuovo pulsante toggle attivo\/disattivo - alterna il campo Stato tra\n    \/\/ \"Attivo\" e vuoto, aggiorna i dati sottostanti (marcandoli come modificati per il salvataggio), e\n    \/\/ aggiorna visivamente l'icona\/colore\/titolo del pulsante stesso senza richiedere un ridisegno completo\n    \/\/ della tabella.\n    window.handleConfigToggleStateClick = function(ev, btn) {\n        try { if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } } catch(e) {}\n        const tbl = window.getConfigButtonTableName ? window.getConfigButtonTableName(btn) : '';\n        let idx = NaN;\n        try { idx = parseInt((btn && btn.getAttribute && btn.getAttribute('data-row-idx')) || '', 10); } catch(e) { idx = NaN; }\n        if (!tbl || isNaN(idx)) { window.tiAlert && window.tiAlert('Riga non riconosciuta. Riapri la configurazione e riprova.'); return false; }\n        try {\n            \/\/ 30.9.1422: stessa protezione gia' usata da updateMemField per il campo Stato della tabella Config\n            \/\/ - solo l'amministratore globale puo' modificarlo tramite questo pulsante, dato il significato\n            \/\/ piu' ampio di questo campo specifico (Attivo\/Sospesa\/Demo\/Configurazione), diverso dal semplice\n            \/\/ attivo\/vuoto delle altre tabelle.\n            if (String(tbl).trim().toLowerCase() === 'config' && !(window.tiAiSsIsDatabaseFullAdmin1562 && window.tiAiSsIsDatabaseFullAdmin1562())) {\n                window.tiAlert && window.tiAlert('Campo riservato: lo stato della ditta e\\' modificabile solo da un amministratore.');\n                return false;\n            }\n            const stateKeyEnc = btn.getAttribute('data-state-key-enc') || '';\n            const stateKey = decodeURIComponent(stateKeyEnc);\n            const rowObj = window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl] && window.currentDbData.Tabelle[tbl][idx];\n            if (!rowObj) { window.tiAlert && window.tiAlert('Riga non trovata nei dati correnti.'); return false; }\n            const currentState1569 = String(rowObj[stateKey] || '').trim().replace(\/^[\"']+|[\"']+$\/g,'').trim().toLowerCase();\n            const isConfigState1569 = String(tbl || '').trim().toLowerCase() === 'config';\n            const currentlyActive = isConfigState1569 ? ['attivo','operativo'].includes(currentState1569) : currentState1569 === 'attivo';\n            const newValue = currentlyActive ? '' : 'Attivo';\n            rowObj[stateKey] = newValue;\n            if (!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(`${tbl}-${idx}-${stateKey}`);\n            if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            btn.style.background = '#000';\n            btn.style.color = newValue ? '#22c55e' : '#ffffff';\n            btn.textContent = '\u2713';\n            btn.title = newValue ? 'Attivo - premi per disattivare' : 'Disattivato - premi per attivare';\n            \/\/ 30.9.1424: sincronizza anche il campo di testo\/select regolare per questo stesso campo Stato,\n            \/\/ se presente nella stessa riga - senza questo, il pulsante toggle aggiorna il dato sottostante ma\n            \/\/ il campo separato nella tabella resta visivamente bloccato al valore precedente, dando\n            \/\/ l'impressione che il toggle non abbia avuto effetto.\n            try {\n                var scope1424 = btn.closest ? (btn.closest('tr') || document) : document;\n                var mirrorInput1424 = scope1424.querySelector('[data-tbl=\"' + tbl + '\"][data-idx=\"' + idx + '\"][data-key=\"' + stateKey + '\"]');\n                if (mirrorInput1424) {\n                    mirrorInput1424.value = newValue;\n                    try { mirrorInput1424.dispatchEvent(new Event('input', {bubbles:true})); } catch(eDisp1424) {}\n                }\n            } catch(eMirror1424) {}\n        } catch(eToggle) {}\n        return false;\n    };\n\n    window.handleConfigDeleteSelectedClick = function(ev, btn) {\n        try { if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } } catch(e) {}\n        const tbl = window.getConfigButtonTableName ? window.getConfigButtonTableName(btn) : '';\n        const safeCls = (btn && btn.getAttribute) ? (btn.getAttribute('data-safe-cls') || '') : '';\n        if (!tbl) { window.tiAlert && window.tiAlert('Tabella non riconosciuta. Riapri la configurazione e riprova.'); return false; }\n        if (typeof window.delBulk === 'function') window.delBulk(tbl, safeCls, btn);\n        return false;\n    };\n\n    window.getConfigTableScope = function(tName, sourceEl) {\n        let scope = null;\n        try {\n            if (sourceEl && sourceEl.closest) scope = sourceEl.closest('details.ti-cfg-details');\n            if (scope && scope.dataset && String(scope.dataset.tbl || '') === String(tName || '')) return scope;\n            document.querySelectorAll('details.ti-cfg-details').forEach(function(det){\n                if (!scope && det.dataset && String(det.dataset.tbl || '') === String(tName || '')) scope = det;\n            });\n        } catch(e) {}\n        return scope || document;\n    };\n\n    window.getSelectedConfigRowIndexes = function(tName, sC, sourceEl) {\n        const scope = window.getConfigTableScope ? window.getConfigTableScope(tName, sourceEl) : document;\n        let checks = [];\n        try { checks = Array.from(scope.querySelectorAll('input.ti-config-row-select:checked')); } catch(e) { checks = []; }\n        if (!checks.length && sC) {\n            try { checks = Array.from(scope.querySelectorAll('.ti-cb-' + sC + ':checked')); } catch(e) { checks = []; }\n        }\n        return checks.map(function(x){\n            const raw = (x && x.dataset && x.dataset.rowIdx != null) ? x.dataset.rowIdx : (x ? x.value : '');\n            return parseInt(raw, 10);\n        }).filter(function(n){ return !isNaN(n); });\n    };\n\n    window.toggleAllTI = function(ck, sC, sourceEl) {\n        const tbl = (ck && ck.closest && ck.closest('details.ti-cfg-details') && ck.closest('details.ti-cfg-details').dataset) ? ck.closest('details.ti-cfg-details').dataset.tbl : '';\n        const scope = window.getConfigTableScope ? window.getConfigTableScope(tbl, sourceEl || ck) : document;\n        let boxes = [];\n        try { boxes = Array.from(scope.querySelectorAll('input.ti-config-row-select')); } catch(e) { boxes = []; }\n        if (!boxes.length && sC) {\n            try { boxes = Array.from(scope.querySelectorAll('.ti-cb-' + sC)); } catch(e) { boxes = []; }\n        }\n        boxes.forEach(function(c){ if (c && !c.disabled) c.checked = !!(ck && ck.checked); });\n    };\n    \n    window.delBulk = function(tN, sC, sourceEl) { \n        tN = window.resolveConfigTableName ? window.resolveConfigTableName(tN) : tN;\n        const low = String(tN || '').toLowerCase();\n        if ((low === 'utenti' || low === 'operatori') && !window.canPhysicallyDeleteUserRows()) {\n            window.tiAlert('Solo amministratore o configuratore possono cancellare fisicamente utenti o operatori dal database.');\n            return;\n        }\n        const selectedIndexes = window.getSelectedConfigRowIndexes ? window.getSelectedConfigRowIndexes(tN, sC, sourceEl) : [];\n        if(selectedIndexes.length===0) { window.tiAlert('Seleziona almeno una riga da eliminare nella tabella corrente.'); return; }\n        const doDelete = function(){ \n            if (window.deleteConfigRowsByIndexes) {\n                const ok = window.deleteConfigRowsByIndexes(tN, selectedIndexes, {render:true});\n                if (ok) window.tiAlert('Righe cancellate dalla configurazione corrente: ' + (window.tiLastConfigDeleteCount || selectedIndexes.length) + '. Premi Salva Modifiche per aggiornare il database.');\n                else window.tiAlert('Nessuna riga eliminata. Righe cancellate: 0. Verifica che le righe selezionate siano ancora presenti e che la tabella possa essere svuotata.');\n                return;\n            }\n            if(!Array.isArray(window.currentDbData.Tabelle[tN])) window.currentDbData.Tabelle[tN]=Object.values(window.currentDbData.Tabelle[tN] || {}); \n            if (window.recordConfigDeletedRowsManifest) window.recordConfigDeletedRowsManifest(tN, window.currentDbData.Tabelle[tN], selectedIndexes);\n            selectedIndexes.sort((a,b)=>b-a).forEach(i=>{ window.currentDbData.Tabelle[tN].splice(i,1); }); \n            window.reindexTableRows(tN);\n            window.markTableRowsModified(tN);\n            if (window.syncConfigTableAfterRowMutation) window.syncConfigTableAfterRowMutation(tN);\n            window.renderConfig(); \n        };\n        if (typeof window.tiConfirmYesNoAction === 'function') window.tiConfirmYesNoAction('Eliminare ' + selectedIndexes.length + ' righe selezionate dalla tabella ' + String(tN || '') + '?', doDelete, null, 'ELIMINA', 'ANNULLA');\n        else window.tiConfirm('Eliminare ' + selectedIndexes.length + ' righe?', doDelete);\n    };\n\n    window.bindConfigDeleteActions = function() {\n        if (window.__tiConfigDeleteActionsBound) return;\n        window.__tiConfigDeleteActionsBound = true;\n        document.addEventListener('click', function(ev){\n            const target = ev && ev.target && ev.target.closest ? ev.target : null;\n            if (!target) return;\n            const rowBtn = target.closest('[data-ti-config-delete-row=\"1\"], .ti-config-delete-row-btn');\n            if (rowBtn && rowBtn.closest && rowBtn.closest('details.ti-cfg-details')) {\n                ev.preventDefault();\n                ev.stopPropagation();\n                if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                if (typeof window.handleConfigDeleteRowClick === 'function') window.handleConfigDeleteRowClick(ev, rowBtn);\n                return false;\n            }\n            const bulkBtn = target.closest('[data-ti-config-delete-selected=\"1\"], .ti-config-delete-selected-btn');\n            if (bulkBtn && bulkBtn.closest && bulkBtn.closest('details.ti-cfg-details')) {\n                ev.preventDefault();\n                ev.stopPropagation();\n                if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                if (typeof window.handleConfigDeleteSelectedClick === 'function') window.handleConfigDeleteSelectedClick(ev, bulkBtn);\n                return false;\n            }\n        }, true);\n    };\n    window.bindConfigDeleteActions();\n\n\n\n    window.lastUserPromptText = '';\n    window.restoreLastUserPromptText = function() {\n        const m = gE('ti-msg');\n        if (m && window.lastUserPromptText) {\n            m.value = window.lastUserPromptText;\n            try { m.focus(); } catch(e) {}\n        }\n    };\n\n    window.tiClearUserChatInput = function() {\n        try {\n            const msgInp = gE('ti-msg');\n            if (!msgInp) return;\n            msgInp.value = '';\n            msgInp.removeAttribute('data-ti-pending-text');\n            try { msgInp.dispatchEvent(new Event('input', { bubbles: true })); } catch(_e) {}\n            try { msgInp.dispatchEvent(new Event('change', { bubbles: true })); } catch(_e) {}\n        } catch(_e) {}\n    };\n    window.addMsg = function(r,h,rawSource) {\n        const chat = window.tiEnsureUserChatBelowAiForm717 ? window.tiEnsureUserChatBelowAiForm717() : gE('ti-chat-box');\n        if(!chat) return null;\n        const d = document.createElement('div');\n        d.className = 'ti-bubble ' + r;\n        const baseHtml = String((typeof rawSource === 'string' && rawSource !== '') ? rawSource : (h || ''));\n        d.innerHTML = String(h || '');\n        if(r === 'ai') {\n            d.__tiChatHtmlByLang = d.__tiChatHtmlByLang || {};\n            d.__tiChatHtmlByLang.it = baseHtml;\n            d.setAttribute('data-ti-it-html', baseHtml);\n            if(typeof rawSource === 'string' && rawSource !== '') {\n                d.setAttribute('data-raw-source', rawSource);\n                window.lastAiReplySource = rawSource;\n            }\n        }\n        chat.appendChild(d);\n        try {\n            if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(d);\n            if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(d);\n            if (r === 'ai' && window.tiExtractOrderAiResponseFromBubble637) window.tiExtractOrderAiResponseFromBubble637(d);\n            if (r === 'ai' && d.__tiChatHtmlByLang) {\n                const langNow = String(window.currLang || 'it').toLowerCase() === 'en' ? 'en' : 'it';\n                d.__tiChatHtmlByLang[langNow] = d.innerHTML;\n                if (langNow === 'it') {\n                    d.__tiChatHtmlByLang.it = d.innerHTML;\n                    d.setAttribute('data-ti-it-html', d.innerHTML);\n                }\n            }\n        } catch(e) {}\n        chat.scrollTop = chat.scrollHeight;\n        if (r === 'user' || r === 'ai') { window.tiClearUserChatInput(); }\n        if (r === 'ai') {\n            setTimeout(function(){\n                window.tiClearUserChatInput();\n                const hint = d.querySelector('.ti-order-hint');\n                const toolbar = d.querySelector('.ti-order-toolbar');\n                const target = hint || toolbar;\n                if (target && target.scrollIntoView) {\n                    try { target.scrollIntoView({behavior:'smooth', block:'start'}); } catch(e) { target.scrollIntoView(true); }\n                }\n                if (window.tiExtractOrderAiResponseFromBubble637) window.tiExtractOrderAiResponseFromBubble637(d);\n                window.refreshOrderConfirmPanel();\n                if (window.tiPendingOrderAiResponseHtml637 && window.tiRenderExternalAiResponse637) window.tiRenderExternalAiResponse637(window.tiPendingOrderAiResponseHtml637);\n            }, 80);\n        }\n        const msgInp = gE('ti-msg');\n        if(r === 'ai' && msgInp) { msgInp.value=''; msgInp.focus(); }\n        return d;\n    };\n\n    window.collectImportMappingFromUI = function(root) {\n        const box = root || document;\n        let mapping = {};\n        try {\n            if (window.tiConfigImportLastMapping && typeof window.tiConfigImportLastMapping === 'object') mapping = Object.assign({}, window.tiConfigImportLastMapping);\n            if (box && box.dataset && box.dataset.importMapping) {\n                try { mapping = Object.assign(mapping, JSON.parse(decodeURIComponent(box.dataset.importMapping))); } catch(_e) {}\n            }\n            box.querySelectorAll('.ti-import-group-target').forEach(function(sel){\n                const idx = parseInt(sel.getAttribute('data-group-index') || '0', 10);\n                if (!isNaN(idx)) mapping['__group_target_' + idx] = sel.value || 'Prodotti';\n            });\n            box.querySelectorAll('.ti-import-map-select').forEach(function(sel){\n                const hdr = sel.getAttribute('data-source-header') || '';\n                const idx = parseInt(sel.getAttribute('data-group-index') || '0', 10);\n                if (hdr) {\n                    if (!isNaN(idx)) mapping['__map_' + idx + '__' + hdr] = sel.value || '--';\n                    else mapping[hdr] = sel.value || '--';\n                }\n            });\n            box.querySelectorAll('.ti-import-price-formula').forEach(function(inp){\n                const idx = parseInt(inp.getAttribute('data-group-index') || '0', 10);\n                const val = String(inp.value || '').trim();\n                if (val !== '') {\n                    if (!isNaN(idx)) mapping['__price_formula_' + idx] = val;\n                    else mapping['__price_formula'] = val;\n                }\n            });\n            const pdfImg = box.querySelector('.ti-import-pdf-image-link');\n            if (pdfImg && pdfImg.checked) mapping['__link_pdf_images'] = '1';\n            if (Array.isArray(window.tiConfigImportRefineRules) && window.tiConfigImportRefineRules.length) {\n                mapping['__local_refine_copy_rules'] = JSON.stringify(window.tiConfigImportRefineRules);\n            }\n            try { window.tiConfigImportLastMapping = Object.assign({}, mapping); } catch(_e) {}\n        } catch(e) {}\n        return mapping;\n    };\n\n    window.reapplyImportMappingToUI = function(root, mapping) {\n        const box = root || document;\n        mapping = mapping || {};\n        try {\n            box.querySelectorAll('.ti-import-group-target').forEach(function(sel){\n                const idx = parseInt(sel.getAttribute('data-group-index') || '0', 10);\n                const key = '__group_target_' + idx;\n                if (!isNaN(idx) && Object.prototype.hasOwnProperty.call(mapping, key)) sel.value = mapping[key] || 'Prodotti';\n            });\n            box.querySelectorAll('.ti-import-map-select').forEach(function(sel){\n                const hdr = sel.getAttribute('data-source-header') || '';\n                const idx = parseInt(sel.getAttribute('data-group-index') || '0', 10);\n                const key = '__map_' + idx + '__' + hdr;\n                if (!isNaN(idx) && hdr && Object.prototype.hasOwnProperty.call(mapping, key)) sel.value = mapping[key] || '--';\n            });\n            box.querySelectorAll('.ti-import-price-formula').forEach(function(inp){\n                const idx = parseInt(inp.getAttribute('data-group-index') || '0', 10);\n                const key = '__price_formula_' + idx;\n                if (!isNaN(idx) && Object.prototype.hasOwnProperty.call(mapping, key)) inp.value = mapping[key] || '';\n            });\n            try { window.tiConfigImportLastMapping = Object.assign({}, mapping); } catch(_e) {}\n        } catch(e) {}\n    };\n\n    window.captureImportFocusState = function(sourceEl) {\n        try {\n            const el = sourceEl || document.activeElement;\n            if (!el) return null;\n            const bubble = el.closest ? el.closest('.ti-bubble.ai') : null;\n            const chatBox = gE('ti-chat-box');\n            const state = { bubbleScrollTop: bubble ? bubble.scrollTop : 0 };\n            state.windowScrollX = window.scrollX || window.pageXOffset || 0;\n            state.windowScrollY = window.scrollY || window.pageYOffset || 0;\n            state.chatScrollTop = chatBox ? chatBox.scrollTop : 0;\n            if (chatBox && el.getBoundingClientRect) {\n                try {\n                    const er = el.getBoundingClientRect();\n                    const cr = chatBox.getBoundingClientRect();\n                    state.elementTopInChat = er.top - cr.top;\n                } catch(e) {}\n            }\n            const sc = el.closest ? el.closest('.ti-cfg-table-container, .ti-import-table-container') : null;\n            state.containerScrollLeft = sc ? sc.scrollLeft : 0;\n            state.containerScrollTop = sc ? sc.scrollTop : 0;\n            if (el.classList && el.classList.contains('ti-import-map-select')) {\n                state.kind = 'map';\n                state.groupIndex = el.getAttribute('data-group-index') || '';\n                state.header = el.getAttribute('data-source-header') || '';\n                state.value = el.value || '--';\n                return state;\n            }\n            if (el.classList && el.classList.contains('ti-import-group-target')) {\n                state.kind = 'target';\n                state.groupIndex = el.getAttribute('data-group-index') || '';\n                state.value = el.value || 'Prodotti';\n                return state;\n            }\n            if (el.classList && el.classList.contains('ti-import-price-formula')) {\n                state.kind = 'formula';\n                state.groupIndex = el.getAttribute('data-group-index') || '';\n                state.value = el.value || '';\n                try { state.selStart = el.selectionStart; state.selEnd = el.selectionEnd; } catch(e) {}\n                return state;\n            }\n        } catch(e) {}\n        return null;\n    };\n\n    window.restoreImportFocusState = function(root, state) {\n        if (!state) return;\n        try {\n            const box = root || document;\n            let el = null;\n            if (state.kind === 'map') el = box.querySelector('.ti-import-map-select[data-group-index=\"' + state.groupIndex + '\"][data-source-header=\"' + CSS.escape(state.header || '') + '\"]');\n            else if (state.kind === 'target') el = box.querySelector('.ti-import-group-target[data-group-index=\"' + state.groupIndex + '\"]');\n            else if (state.kind === 'formula') el = box.querySelector('.ti-import-price-formula[data-group-index=\"' + state.groupIndex + '\"]');\n            if (el) {\n                if (typeof el.focus === 'function') el.focus({preventScroll:true});\n                if (state.kind === 'formula') {\n                    try { el.selectionStart = state.selStart || 0; el.selectionEnd = state.selEnd || state.selStart || 0; } catch(e) {}\n                }\n                const sc = el.closest ? el.closest('.ti-cfg-table-container, .ti-import-table-container') : null;\n                if (sc) {\n                    sc.scrollLeft = state.containerScrollLeft || 0;\n                    sc.scrollTop = state.containerScrollTop || 0;\n                }\n                const bubble = el.closest ? el.closest('.ti-bubble.ai') : null;\n                if (bubble) bubble.scrollTop = state.bubbleScrollTop || bubble.scrollTop || 0;\n                const chatBox = gE('ti-chat-box');\n                if (chatBox) {\n                    try {\n                        if (typeof state.elementTopInChat === 'number' && el.getBoundingClientRect) {\n                            const er = el.getBoundingClientRect();\n                            const cr = chatBox.getBoundingClientRect();\n                            chatBox.scrollTop += ((er.top - cr.top) - state.elementTopInChat);\n                        } else if (typeof state.chatScrollTop === 'number') {\n                            chatBox.scrollTop = state.chatScrollTop;\n                        }\n                    } catch(e) {}\n                }\n                try {\n                    if (typeof state.windowScrollY === 'number') window.scrollTo(state.windowScrollX || 0, state.windowScrollY || 0);\n                } catch(e) {}\n            }\n        } catch(e) {}\n    };\n\n    window.refreshImportPreviewFromUI = function(sourceEl) {\n        const previewBody = gE('ti-conf-import-preview-body');\n        const isModalPreview = !!(previewBody && sourceEl && previewBody.contains && previewBody.contains(sourceEl));\n        const bubble = (!isModalPreview && sourceEl && sourceEl.closest) ? sourceEl.closest('.ti-bubble.ai') : null;\n        const targetBox = isModalPreview ? previewBody : bubble;\n        const root = targetBox || document;\n        const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n        if (!dbVal || !targetBox) return;\n        const mapping = window.collectImportMappingFromUI(root);\n        const focusState = window.captureImportFocusState(sourceEl);\n        try { targetBox.dataset.importMapping = encodeURIComponent(JSON.stringify(mapping)); } catch(e) {}\n        const fd = new FormData();\n        fd.append('action', 'ti_ai_config_action');\n        fd.append('ti_action', 'ti_ai_config_action');\n        fd.append('db', dbVal);\n        fd.append('mode', 'refresh_import_preview');\n        fd.append('prompt', 'refresh import preview');\n        if (window.tiConfigImportToken) fd.append('import_token', window.tiConfigImportToken);\n        fd.append('mapping_json', JSON.stringify(mapping));\n        targetBox.style.opacity = '0.75';\n        window.postFormDataJsonSafe(window.tiUrl, fd, {tiNoLongProcessSignal:true}).then(function(res){\n            targetBox.style.opacity = '';\n            if (res && res.success && targetBox) {\n                if (res.data && (res.data.import_token || res.data.preview_token)) window.tiConfigImportToken = res.data.import_token || res.data.preview_token;\n                const rawReply = ((res.data || {}).reply || '').replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                try { window.tiConfigImportLastMapping = Object.assign({}, mapping); } catch(_e) {}\n                if (rawReply) {\n                    targetBox.innerHTML = rawReply;\n                    let applyMap = mapping;\n                    try {\n                        if (targetBox.dataset.importMapping) applyMap = JSON.parse(decodeURIComponent(targetBox.dataset.importMapping));\n                    } catch(e) {}\n                    window.reapplyImportMappingToUI(targetBox, applyMap);\n                    if (window.initConfigTopScrollbars) window.initConfigTopScrollbars(targetBox);\n                    window.restoreImportFocusState(targetBox, focusState);\n                    setTimeout(function(){ window.restoreImportFocusState(targetBox, focusState); }, 0);\n                    if (window.requestAnimationFrame) window.requestAnimationFrame(function(){ window.restoreImportFocusState(targetBox, focusState); });\n                    if (isModalPreview && window.redisplayConfigImportPreviewForFinalConfirm) {\n                        window.redisplayConfigImportPreviewForFinalConfirm('Anteprima modifiche aggiornata dopo la variazione richiesta. Conferma solo se corretta.');\n                    }\n                }\n            }\n        }).catch(function(){\n            targetBox.style.opacity = '';\n            if (isModalPreview && window.markConfigImportPreviewUpdated) {\n                window.markConfigImportPreviewUpdated('Modifica registrata. Se l anteprima non si aggiorna automaticamente, controlla le associazioni visibili prima di confermare.');\n            }\n        });\n    };\n\n    window.scheduleImportPreviewRefresh = function(sourceEl) {\n        clearTimeout(window.importPreviewRefreshTimer);\n        window.importPreviewRefreshTimer = setTimeout(function(){ window.refreshImportPreviewFromUI(sourceEl); }, 180);\n    };\n    window.showFullImg = function(url) { const fullImg = gE('ti-full-img'); if(fullImg) { fullImg.src = url; window.openModal('ti-img-ov'); } };\n    window.getFileNameFromUrlOrValue = function(value) {\n        let raw = String(value || '').trim();\n        raw = raw.replace(\/&amp;\/gi,'&').replace(\/&#38;\/g,'&');\n        if (!raw) return 'file';\n        try {\n            const u = new URL(raw, window.location.origin);\n            const qf = u.searchParams.get('file');\n            if (qf) return decodeURIComponent(qf);\n            const pts = u.pathname.split('\/').filter(Boolean);\n            return decodeURIComponent(pts.pop() || raw);\n        } catch(e) {\n            const clean = raw.split('?')[0].split('#')[0];\n            const pts = clean.split('\/').filter(Boolean);\n            return decodeURIComponent(pts.pop() || raw);\n        }\n    };\n    window.isImageFileName = function(name) {\n        let raw=String(name||'').trim().replace(\/&amp;\/gi,'&').replace(\/&#38;\/g,'&');\n        if(\/^data:image\\\/\/i.test(raw)) return true;\n        try{const u=new URL(raw,window.location.origin);const qf=u.searchParams.get('file');if(qf&&\/\\.(jpg|jpeg|png|webp|gif|bmp|svg)$\/i.test(decodeURIComponent(qf)))return true;}catch(e){}\n        return \/\\.(jpg|jpeg|png|webp|gif|bmp|svg)(?:$|[?#])\/i.test(raw);\n    };\n    window.isPdfFileName = function(name) { return \/\\.pdf$\/i.test(String(name || '')); };\n    window.getFilePreviewIcon = function(name) {\n        const n = String(name || '').toLowerCase();\n        if (\/\\.pdf$\/.test(n)) return '\ud83d\udcd5';\n        if (\/\\.(doc|docx)$\/.test(n)) return '\ud83d\udcd8';\n        if (\/\\.(xls|xlsx|csv)$\/.test(n)) return '\ud83d\udcca';\n        if (\/\\.(txt|json|xml)$\/.test(n)) return '\ud83d\udcc4';\n        if (\/\\.(mp4|mov|avi|webm)$\/.test(n)) return '\ud83c\udfac';\n        return '\ud83d\udcce';\n    };\n    window.ensureFilePreviewModal = function() {\n        let ov = gE('ti-file-preview-ov');\n        if (ov) return ov;\n        ov = document.createElement('div');\n        ov.id = 'ti-file-preview-ov';\n        ov.className = 'ti-ov ti-closable-ov';\n        ov.style.zIndex = '2147483647';\n        ov.innerHTML = '<div class=\"ti-modal\" style=\"width:94vw;max-width:920px;text-align:left;\">'\n            + '<button type=\"button\" class=\"ti-modal-x-red\" onclick=\"window.closeFilePreviewModal()\" title=\"Chiudi\">X<\/button>'\n            + '<h3 id=\"ti-file-preview-title\" style=\"color:#fff;margin-top:0;margin-bottom:12px;padding-right:38px;\">Preview file<\/h3>'\n            + '<div id=\"ti-file-preview-content\" style=\"min-height:120px;color:#e5e7eb;\"><\/div>'\n            + '<div id=\"ti-file-preview-nav-2006\" style=\"display:none;align-items:center;justify-content:center;gap:7px;padding:8px 0 0;\"><\/div>'\n            + '<div class=\"ti-modal-bottom-close-row\"><button type=\"button\" class=\"ti-btn btn-close\" onclick=\"window.closeFilePreviewModal()\">Chiudi<\/button><\/div>'\n            + '<\/div>';\n        document.body.appendChild(ov);\n        return ov;\n    };\n    window.closeFilePreviewModal = function() { window.closeModal('ti-file-preview-ov'); };\n    window.openExternalLinkedFile = function(url) { if (url) window.open(String(url), '_blank', 'noopener'); };\n    window.openFilePreviewModal = function(file, title) {\n        const obj = (typeof file === 'string') ? {url:file, name:window.getFileNameFromUrlOrValue(file)} : (file || {});\n        const url = String(obj.url || obj.raw || '').trim();\n        if (!url) return;\n        const name = String(obj.name || window.getFileNameFromUrlOrValue(url) || 'file');\n        const safeName = window.escapeHtml(name);\n        const safeUrl = window.escapeHtml(url);\n        const ov = window.ensureFilePreviewModal();\n        const titleEl = gE('ti-file-preview-title');\n        const content = gE('ti-file-preview-content');\n        const nav2006 = gE('ti-file-preview-nav-2006');\n        if (nav2006) { nav2006.style.display='none'; nav2006.innerHTML=''; }\n        if (titleEl) titleEl.textContent = title || name;\n        let html = '';\n        if (window.isImageFileName(name) || window.isImageFileName(url)) {\n            const fb = window.getCompanyFallbackMediaUrl(gE('ti-ditta') ? gE('ti-ditta').value : '');\n            html = '<div style=\"text-align:center;\"><img decoding=\"async\" src=\"' + safeUrl + '\" data-fallback=\"' + window.escapeHtml(fb) + '\" onerror=\"window.applyFallbackImage(this)\" alt=\"' + safeName + '\" style=\"max-width:100%;max-height:72vh;object-fit:contain;border-radius:10px;background:#000;border:1px solid #334155;\"><\/div>';\n        } else if (window.isPdfFileName(name) || window.isPdfFileName(url)) {\n            html = '<iframe src=\"' + safeUrl + '#toolbar=1&navpanes=0\" title=\"' + safeName + '\" style=\"width:100%;height:72vh;border:1px solid #334155;border-radius:10px;background:#000;\"><\/iframe>';\n        } else {\n            html = '<div style=\"text-align:center;padding:28px 12px;background:#020617;border:1px solid #334155;border-radius:12px;\">'\n                + '<div style=\"font-size:48px;margin-bottom:10px;\">' + window.getFilePreviewIcon(name) + '<\/div>'\n                + '<div style=\"font-weight:800;margin-bottom:12px;word-break:break-all;\">' + safeName + '<\/div>'\n                + '<button type=\"button\" class=\"ti-btn\" onclick=\"window.openExternalLinkedFile(decodeURIComponent(\\'' + encodeURIComponent(url) + '\\'))\">Apri originale<\/button>'\n                + '<\/div>';\n        }\n        if (content) content.innerHTML = html;\n        window.openModal('ti-file-preview-ov');\n        if (window.keepUserCommunicationPopupsInFront) window.keepUserCommunicationPopupsInFront();\n    };\n    window.openOriginalLinkedFile = function(url) {\n        if (!url) return;\n        window.openFilePreviewModal({url:String(url), name:window.getFileNameFromUrlOrValue(url)});\n    };\n    window.tiOrderMediaNavState2006 = window.tiOrderMediaNavState2006 || {files:[],name:'',index:0};\n    window.renderOrderMediaList2006 = function(){\n        const st=window.tiOrderMediaNavState2006||{files:[],name:''};\n        const files=Array.isArray(st.files)?st.files:[];\n        if(!files.length)return false;\n        const ov=window.ensureFilePreviewModal(),titleEl=gE('ti-file-preview-title'),content=gE('ti-file-preview-content'),nav=gE('ti-file-preview-nav-2006');\n        if(titleEl)titleEl.textContent=(st.name?st.name+' - ':'')+(window.currLang==='en'?'Available files':'File disponibili')+' ('+files.length+')';\n        const cards=files.map(function(f,i){\n            const url=String(f.url||''),name=String(f.name||window.getFileNameFromUrlOrValue(url)||('file '+(i+1))),safeName=window.escapeHtml(name),safeUrl=window.escapeHtml(url);\n            let preview='';\n            if(window.isImageFileName(name)||window.isImageFileName(url)){\n                const fb=window.getCompanyFallbackMediaUrl(gE('ti-ditta')?gE('ti-ditta').value:'');\n                preview='<img decoding=\"async\" src=\"'+safeUrl+'\" data-fallback=\"'+window.escapeHtml(fb)+'\" onerror=\"window.applyFallbackImage(this)\" alt=\"'+safeName+'\">';\n            }else if(window.isPdfFileName(name)||window.isPdfFileName(url)){\n                preview='<iframe src=\"'+safeUrl+'#toolbar=0&navpanes=0\" title=\"'+safeName+'\"><\/iframe>';\n            }else preview='<div class=\"ti-order-file-preview-icon\">'+window.getFilePreviewIcon(name)+'<\/div>';\n            return '<button type=\"button\" class=\"ti-order-file-preview\" data-ti-order-media-index-2006=\"'+i+'\" title=\"Apri: '+safeName+'\">'+preview+'<div class=\"ti-order-file-preview-name\">'+safeName+'<\/div><div class=\"ti-order-file-preview-open\">'+(window.currLang==='en'?'Open file':'Vedi file')+'<\/div><\/button>';\n        }).join('');\n        if(content){content.innerHTML='<div class=\"ti-order-modal-files-grid\">'+cards+'<\/div>';content.querySelectorAll('[data-ti-order-media-index-2006]').forEach(function(btn){btn.onclick=function(){return window.openOrderMediaAt2006(parseInt(btn.getAttribute('data-ti-order-media-index-2006'),10)||0);};});}\n        if(nav){nav.style.display='none';nav.innerHTML='';}\n        window.openModal('ti-file-preview-ov');\n        return false;\n    };\n    window.openOrderMediaAt2006 = function(index){\n        const st=window.tiOrderMediaNavState2006||{files:[],name:''},files=Array.isArray(st.files)?st.files:[];\n        if(!files.length)return false;\n        index=Math.max(0,Math.min(files.length-1,parseInt(index,10)||0));st.index=index;window.tiOrderMediaNavState2006=st;\n        const f=files[index];window.openFilePreviewModal(f,(st.name?st.name+' - ':'')+(f.name||window.getFileNameFromUrlOrValue(f.url||'')));\n        const nav=gE('ti-file-preview-nav-2006');\n        if(nav){nav.style.display='flex';nav.innerHTML='<button type=\"button\" class=\"ti-btn\" '+(index<=0?'disabled':'')+' onclick=\"return window.openOrderMediaAt2006('+(index-1)+');\">&lt;<\/button>'\n            +'<span style=\"font-size:12px;color:#cbd5e1;\">'+(index+1)+' \/ '+files.length+'<\/span>'\n            +(files.length>1?'<button type=\"button\" class=\"ti-btn\" onclick=\"return window.renderOrderMediaList2006();\">'+(window.currLang==='en'?'List':'Elenco')+'<\/button>':'')\n            +'<button type=\"button\" class=\"ti-btn\" '+(index>=files.length-1?'disabled':'')+' onclick=\"return window.openOrderMediaAt2006('+(index+1)+');\">&gt;<\/button>';}\n        return false;\n    };\n    window.openOrderLinkedFilesChoice = function(payload) {\n        const files = Array.isArray(payload && payload.files) ? (window.tiDedupeOrderLinkedFiles483 ? window.tiDedupeOrderLinkedFiles483(payload.files.filter(function(f){ return f && f.url; })) : payload.files.filter(function(f){ return f && f.url; })) : [];\n        if (!files.length) { window.openOrderItemPopup(payload); return false; }\n        window.tiOrderMediaNavState2006={files:files,name:String(payload&&payload.name?payload.name:''),index:0};\n        if (files.length === 1) return window.openOrderMediaAt2006(0);\n        return window.renderOrderMediaList2006();\n    };\n    window.openOrderLinkedFilesFromEl = function(el) {\n        if (!el) return;\n        const raw = el.getAttribute('data-popup') || '';\n        if (!raw) return;\n        try { window.openOrderLinkedFilesChoice(JSON.parse(decodeURIComponent(raw))); }\n        catch(e) { window.openOrderItemPopupFromEl(el); }\n    };\n\n    \/\/ 30.9.2003 - Galleria immagini dedicata alla tabella ordine.\n    \/\/ I documenti restano nel normale elenco File collegati; qui vengono mostrate solo immagini.\n    window.tiOrderImageGalleryState2003 = window.tiOrderImageGalleryState2003 || {files:[], name:'', zoomIndex:-1};\n    window.tiOrderImageFiles2003 = function(files) {\n        const src = Array.isArray(files) ? files : [];\n        const out = [], seen = {};\n        src.forEach(function(f){\n            if (!f) return;\n            const url = String(f.url || f.raw || '').trim();\n            const name = String(f.name || (window.getFileNameFromUrlOrValue ? window.getFileNameFromUrlOrValue(url) : '') || '').trim();\n            const isImg = \/^data:image\\\/\/i.test(url) || (window.isImageFileName && (window.isImageFileName(name) || window.isImageFileName(url)));\n            if (!url || !isImg) return;\n            const key = url.toLowerCase(); if (seen[key]) return; seen[key]=1;\n            out.push({url:url,name:name || ('Immagine '+(out.length+1)),raw:String(f.raw||'')});\n        });\n        return out;\n    };\n    \/\/ 30.9.2006 - Documenti associati navigabili dall utente, separati dal conteggio immagini.\n    window.tiOrderDocumentFiles2006 = function(files) {\n        const src = Array.isArray(files) ? files : [];\n        const out = [], seen = {};\n        src.forEach(function(f){\n            if (!f) return;\n            const url = String(f.url || f.raw || '').trim();\n            const name = String(f.name || (window.getFileNameFromUrlOrValue ? window.getFileNameFromUrlOrValue(url) : '') || '').trim();\n            const isImg = \/^data:image\\\/\/i.test(url) || (window.isImageFileName && (window.isImageFileName(name) || window.isImageFileName(url)));\n            if (!url || isImg) return;\n            const key = (url || name).toLowerCase(); if (seen[key]) return; seen[key]=1;\n            out.push({url:url,name:name || ('Documento '+(out.length+1)),raw:String(f.raw||'')});\n        });\n        return out;\n    };\n    window.openOrderDocumentsFromEl2006 = function(el){\n        if(!el)return false;let raw=el.getAttribute('data-popup')||'';if(!raw)return false;\n        try{const p=JSON.parse(decodeURIComponent(raw));p.files=window.tiOrderDocumentFiles2006(p.files||[]);return window.openOrderLinkedFilesChoice(p);}catch(e){return false;}\n    };\n    window.openOrderDocumentsData2006 = function(el){\n        if(!el)return false;let raw=el.getAttribute('data-ti-order-docs-2006')||'',name=el.getAttribute('data-ti-order-media-name-2006')||'';if(!raw)return false;\n        try{const arr=JSON.parse(decodeURIComponent(raw));const files=(Array.isArray(arr)?arr:[]).map(function(u){return {url:String(u||''),name:window.getFileNameFromUrlOrValue?window.getFileNameFromUrlOrValue(u):''};});return window.openOrderLinkedFilesChoice({name:name,files:files});}catch(e){return false;}\n    };\n    window.ensureOrderImageGallery2003 = function() {\n        let ov = document.getElementById('ti-order-image-gallery-2003');\n        if (ov) return ov;\n        ov = document.createElement('div');\n        ov.id = 'ti-order-image-gallery-2003';\n        ov.style.cssText = 'position:fixed;inset:0;z-index:2147483647;background:rgba(0,0,0,.78);display:none;align-items:center;justify-content:center;padding:14px;';\n        ov.innerHTML = '<div class=\"ti-order-image-gallery-panel-2003\" style=\"width:min(980px,96vw);max-height:92vh;display:flex;flex-direction:column;background:#0b1020;border:1px solid #475569;border-radius:14px;box-shadow:0 20px 60px rgba(0,0,0,.6);color:#fff;overflow:hidden;\">'\n            + '<div style=\"display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid #334155;\"><div id=\"ti-order-image-gallery-title-2003\" style=\"font-weight:900;font-size:16px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\">Immagini<\/div><button type=\"button\" id=\"ti-order-image-gallery-x-2003\" class=\"ti-modal-x-red\" style=\"position:static!important;flex:0 0 auto;\" title=\"Chiudi\">X<\/button><\/div>'\n            + '<div id=\"ti-order-image-gallery-body-2003\" style=\"padding:14px;overflow:auto;min-height:120px;flex:1;\"><\/div>'\n            + '<div id=\"ti-order-image-gallery-actions-2003\" style=\"display:flex;justify-content:center;gap:8px;padding:10px 14px;border-top:1px solid #334155;\"><\/div>'\n            + '<\/div>';\n        document.body.appendChild(ov);\n        const x = document.getElementById('ti-order-image-gallery-x-2003'); if (x) x.onclick=function(){ window.closeOrderImageGallery2003(); };\n        ov.addEventListener('click',function(ev){ if(ev.target===ov) window.closeOrderImageGallery2003(); });\n        document.addEventListener('keydown',function(ev){ if(ev.key==='Escape' && ov.style.display!=='none'){ if((window.tiOrderImageGalleryState2003||{}).zoomIndex>=0) window.renderOrderImageGalleryList2003(); else window.closeOrderImageGallery2003(); } });\n        return ov;\n    };\n    window.closeOrderImageGallery2003 = function(){ const ov=document.getElementById('ti-order-image-gallery-2003'); if(ov)ov.style.display='none'; if(window.tiOrderImageGalleryState2003)window.tiOrderImageGalleryState2003.zoomIndex=-1; return false; };\n    window.renderOrderImageGalleryList2003 = function(){\n        const st=window.tiOrderImageGalleryState2003||{files:[],name:''},files=window.tiOrderImageFiles2003(st.files||[]),ov=window.ensureOrderImageGallery2003();\n        st.files=files;st.zoomIndex=-1;window.tiOrderImageGalleryState2003=st;\n        const title=document.getElementById('ti-order-image-gallery-title-2003'),body=document.getElementById('ti-order-image-gallery-body-2003'),actions=document.getElementById('ti-order-image-gallery-actions-2003');\n        if(title)title.textContent=(st.name?st.name+' - ':'')+(window.currLang==='en'?'Available images':'Immagini disponibili')+' ('+files.length+')';\n        const fb=window.getCompanyFallbackMediaUrl?window.getCompanyFallbackMediaUrl(gE('ti-ditta')?gE('ti-ditta').value:''):'';\n        if(body)body.innerHTML='<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:12px;align-items:start;\">'+files.map(function(f,i){return '<button type=\"button\" data-ti-order-image-index-2003=\"'+i+'\" style=\"background:#111827;border:1px solid #475569;border-radius:10px;padding:7px;color:#fff;cursor:zoom-in;text-align:center;min-width:0;\"><img decoding=\"async\" src=\"'+window.escapeHtml(f.url)+'\" data-fallback=\"'+window.escapeHtml(fb)+'\" onerror=\"window.applyFallbackImage(this)\" alt=\"'+window.escapeHtml(f.name)+'\" style=\"display:block;width:100%;height:118px;object-fit:contain;background:#020617;border-radius:7px;\"><span style=\"display:block;margin-top:5px;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\">'+(i+1)+' \/ '+files.length+'<\/span><\/button>';}).join('')+'<\/div>';\n        if(body)body.querySelectorAll('[data-ti-order-image-index-2003]').forEach(function(btn){btn.addEventListener('click',function(){window.showOrderImageGalleryImage2003(parseInt(btn.getAttribute('data-ti-order-image-index-2003'),10)||0);});});\n        if(actions)actions.innerHTML='<button type=\"button\" class=\"ti-btn btn-close\" onclick=\"return window.closeOrderImageGallery2003();\">'+(window.currLang==='en'?'Close':'Chiudi')+'<\/button>';\n        ov.style.display='flex'; if(window.keepUserCommunicationPopupsInFront)window.keepUserCommunicationPopupsInFront(); return false;\n    };\n    window.showOrderImageGalleryImage2003 = function(index){\n        const st=window.tiOrderImageGalleryState2003||{files:[],name:''},files=window.tiOrderImageFiles2003(st.files||[]); if(!files.length)return false;\n        index=Math.max(0,Math.min(files.length-1,parseInt(index,10)||0));st.files=files;st.zoomIndex=index;window.tiOrderImageGalleryState2003=st;const f=files[index];\n        const ov=window.ensureOrderImageGallery2003(),title=document.getElementById('ti-order-image-gallery-title-2003'),body=document.getElementById('ti-order-image-gallery-body-2003'),actions=document.getElementById('ti-order-image-gallery-actions-2003');\n        if(title)title.textContent=(st.name?st.name+' - ':'')+(window.currLang==='en'?'Image':'Immagine')+' '+(index+1)+' \/ '+files.length;\n        const fb=window.getCompanyFallbackMediaUrl?window.getCompanyFallbackMediaUrl(gE('ti-ditta')?gE('ti-ditta').value:''):'';\n        if(body)body.innerHTML='<div style=\"display:flex;align-items:center;justify-content:center;min-height:55vh;\"><img decoding=\"async\" src=\"'+window.escapeHtml(f.url)+'\" data-fallback=\"'+window.escapeHtml(fb)+'\" onerror=\"window.applyFallbackImage(this)\" alt=\"'+window.escapeHtml(f.name)+'\" style=\"display:block;max-width:100%;max-height:72vh;object-fit:contain;background:#000;border:1px solid #334155;border-radius:10px;\"><\/div>';\n        \/\/ In vista ingrandita Chiudi torna all elenco immagini; 30.9.2006 aggiunge navigazione precedente\/successiva.\n        if(actions)actions.innerHTML='<button type=\"button\" class=\"ti-btn\" '+(index<=0?'disabled':'')+' onclick=\"return window.showOrderImageGalleryImage2003('+Math.max(0,index-1)+');\">&lt;<\/button>'\n            + '<span style=\"display:inline-flex;align-items:center;padding:0 8px;font-size:12px;color:#cbd5e1;\">'+(index+1)+' \/ '+files.length+'<\/span>'\n            + '<button type=\"button\" class=\"ti-btn\" '+(index>=files.length-1?'disabled':'')+' onclick=\"return window.showOrderImageGalleryImage2003('+Math.min(files.length-1,index+1)+');\">&gt;<\/button>'\n            + '<button type=\"button\" class=\"ti-btn btn-close\" onclick=\"return window.renderOrderImageGalleryList2003();\">'+(window.currLang==='en'?'Close':'Chiudi')+'<\/button>';\n        ov.style.display='flex'; return false;\n    };\n    window.openOrderImageGallery2003 = function(payload){\n        payload=payload||{};const files=window.tiOrderImageFiles2003(payload.files||[]);if(!files.length){ if(window.openOrderLinkedFilesChoice)window.openOrderLinkedFilesChoice(payload); return false; }\n        window.tiOrderImageGalleryState2003={files:files,name:String(payload.name||payload.rawName||''),zoomIndex:-1};\n        if(files.length===1)return window.showOrderImageGalleryImage2003(0);return window.renderOrderImageGalleryList2003();\n    };\n    window.openOrderImagesFromEl2003 = function(el){ if(!el)return false;let raw=el.getAttribute('data-popup')||'';if(!raw)return false;try{return window.openOrderImageGallery2003(JSON.parse(decodeURIComponent(raw)));}catch(e){return false;} };\n    window.openOrderImageGalleryData2003 = function(el){\n        if(!el)return false;let raw=el.getAttribute('data-ti-order-images-2003')||'',name=el.getAttribute('data-ti-order-image-name-2003')||'';if(!raw)return false;try{const arr=JSON.parse(decodeURIComponent(raw));const files=(Array.isArray(arr)?arr:[]).map(function(u){return {url:String(u||''),name:window.getFileNameFromUrlOrValue?window.getFileNameFromUrlOrValue(u):''};});return window.openOrderImageGallery2003({name:name,files:files});}catch(e){return false;}\n    };\n    window.renderOrderItemLinkedFiles = function(payload) {\n        const box = gE('ti-order-item-files');\n        if (!box) return;\n        const files = Array.isArray(payload && payload.files) ? payload.files : [];\n        const usable = window.tiDedupeOrderLinkedFiles483 ? window.tiDedupeOrderLinkedFiles483(files.filter(function(f){ return f && f.url; })) : files.filter(function(f){ return f && f.url; });\n        if (!usable.length) { box.style.display = 'none'; box.innerHTML = ''; return; }\n        const title = usable.length === 1 ? 'File collegato' : ('File collegati (' + usable.length + ')');\n        const cards = usable.map(function(f, i){\n            const url = String(f.url || '');\n            const name = String(f.name || window.getFileNameFromUrlOrValue(url) || ('file ' + (i + 1)));\n            const safeName = window.escapeHtml(name);\n            const safeUrl = window.escapeHtml(url);\n            const encUrl = encodeURIComponent(url);\n            let preview = '';\n            if (window.isImageFileName(name) || window.isImageFileName(url)) {\n                const fb = window.getCompanyFallbackMediaUrl(gE('ti-ditta') ? gE('ti-ditta').value : '');\n                preview = `<img decoding=\"async\" src=\"${safeUrl}\" data-fallback=\"${window.escapeHtml(fb)}\" onerror=\"window.applyFallbackImage(this)\" alt=\"${safeName}\">`;\n            } else if (window.isPdfFileName(name) || window.isPdfFileName(url)) {\n                preview = `<iframe src=\"${safeUrl}#toolbar=0&navpanes=0\" title=\"${safeName}\"><\/iframe>`;\n            } else {\n                preview = `<div class=\"ti-order-file-preview-icon\">${window.getFilePreviewIcon(name)}<\/div>`;\n            }\n            return `<button type=\"button\" class=\"ti-order-file-preview\" onclick=\"window.openOriginalLinkedFile(decodeURIComponent('${encUrl}'))\" title=\"Apri versione originale: ${safeName}\">${preview}<div class=\"ti-order-file-preview-name\">${safeName}<\/div><div class=\"ti-order-file-preview-open\">Apri originale<\/div><\/button>`;\n        }).join('');\n        box.innerHTML = `<div class=\"ti-order-modal-files-title\">Seleziona documento da vedere<\/div><div class=\"ti-order-modal-files-grid\">${cards}<\/div>`;\n        box.style.display = '';\n    };\n    window.openOrderPriceCondition1863 = function(el) {\n        if (!el) return;\n        let raw = el.getAttribute('data-price-condition') || '';\n        try { raw = decodeURIComponent(raw); } catch(e) {}\n        if (!raw) raw = (window.currLang === 'en' ? 'Price variation applied.' : 'Variazione di prezzo applicata.');\n        let ov = document.getElementById('ti-price-condition-ov-1863');\n        if (!ov) {\n            ov = document.createElement('div');\n            ov.id = 'ti-price-condition-ov-1863';\n            ov.style.cssText = 'position:fixed;inset:0;z-index:2147483500;background:rgba(0,0,0,.72);display:none;align-items:center;justify-content:center;padding:18px;';\n            ov.innerHTML = '<div style=\"width:min(520px,94vw);max-height:80vh;overflow:auto;background:#0b1020;border:1px solid #ef4444;border-radius:14px;padding:16px;color:#fff;box-shadow:0 18px 50px rgba(0,0,0,.55);\"><div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px;\"><div style=\"font-weight:900;font-size:18px;\"><span style=\"display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background:#dc2626;margin-right:7px;\">!<\/span><span class=\"ti-pc-title-1863\">Condizione prezzo<\/span><\/div><button type=\"button\" class=\"ti-pc-close-1863\" style=\"background:#374151;color:#fff;border:1px solid #64748b;border-radius:8px;padding:5px 10px;cursor:pointer;\">Chiudi<\/button><\/div><div class=\"ti-pc-body-1863\" style=\"white-space:pre-wrap;line-height:1.5;color:#e5e7eb;\"><\/div><\/div>';\n            document.body.appendChild(ov);\n            ov.querySelector('.ti-pc-close-1863').addEventListener('click', function(){ ov.style.display='none'; });\n            ov.addEventListener('click', function(ev){ if(ev.target===ov) ov.style.display='none'; });\n        }\n        const title = ov.querySelector('.ti-pc-title-1863'); if(title) title.textContent = (window.currLang === 'en' ? 'Price condition' : 'Condizione prezzo');\n        const close = ov.querySelector('.ti-pc-close-1863'); if(close) close.textContent = (window.currLang === 'en' ? 'Close' : 'Chiudi');\n        const body = ov.querySelector('.ti-pc-body-1863'); if(body) body.textContent = raw;\n        ov.style.display='flex';\n    };\n    window.orderItemPopupState = null;\n    window.openOrderItemPopup = function(payload) {\n        window.orderItemPopupState = payload || null;\n        if (!payload) return;\n        const qty = window.parseQtyInput(payload.qty);\n        const img = gE('ti-order-item-img'); if (img) { const db1968 = gE('ti-ditta') ? gE('ti-ditta').value : ''; const fb = window.getCompanyOrderLogoUrl1968 ? window.getCompanyOrderLogoUrl1968(db1968) : window.getCompanyFallbackMediaUrl(db1968); img.setAttribute('data-fallback', fb || ''); img.onerror = function(){ window.applyFallbackImage(this); }; img.src = payload.img || fb || ''; img.style.display = (payload.img || fb) ? '' : 'none'; }\n        const titleEl = gE('ti-order-item-title'); if (titleEl) { const tblLow = String(payload.tblName || payload.table || '').toLowerCase(); titleEl.textContent = tblLow.indexOf('serviz') !== -1 ? 'Dettaglio servizio' : (tblLow.indexOf('prodott') !== -1 ? 'Dettaglio articolo' : 'Dettaglio voce'); }\n        const nameEl = gE('ti-order-item-name'); if (nameEl) nameEl.textContent = payload.name || '';\n        const capEl = gE('ti-order-item-caption'); if (capEl) capEl.textContent = payload.desc || payload.name || '';\n        const priceEl = gE('ti-order-item-price'); if (priceEl) priceEl.innerHTML = payload.priceHtml || ('\u20ac ' + window.fmtNum(payload.price || 0));\n        const qtyEl = gE('ti-order-item-qty'); if (qtyEl) qtyEl.value = window.formatQtyInput(qty);\n        const totalEl = gE('ti-order-item-total'); if (totalEl) totalEl.textContent = '\u20ac ' + window.fmtNum((payload.price || 0) * qty);\n        const noteEl = gE('ti-order-item-note'); if (noteEl) noteEl.textContent = payload.note || '';\n        window.renderOrderItemLinkedFiles(payload);\n        if (qtyEl) { qtyEl.oninput = function(){ const q = window.parseQtyInput(this.value); const tot = gE('ti-order-item-total'); if (tot) tot.textContent = '\u20ac ' + window.fmtNum((payload.price || 0) * q); }; }\n        window.openModal('ti-order-item-ov');\n    };\n    window.openOrderItemPopupFromEl = function(el) {\n        if (!el) return;\n        const raw = el.getAttribute('data-popup') || '';\n        if (!raw) return;\n        try {\n            const payload = JSON.parse(decodeURIComponent(raw));\n            window.openOrderItemPopup(payload);\n        } catch(e) {\n            console.error('Popup ordine non valido', e, raw);\n        }\n    };\n    window.confirmOrderItemPopup = function() {\n        const st = window.orderItemPopupState || {};\n        const qtyEl = gE('ti-order-item-qty');\n        const qty = qtyEl ? window.parseQtyInput(qtyEl.value) : 0;\n        if (st.orderId) window.setOrderQty(st.orderId, qty);\n        window.closeOrderItemPopup();\n    };\n    window.closeOrderItemPopup = function() { window.orderItemPopupState = null; window.closeModal('ti-order-item-ov'); };\n    window.setOrderQty = function(orderId, qty) {\n        const val = window.formatQtyInput(qty);\n        document.querySelectorAll('.ti-q[data-order-id=\"' + orderId + '\"]').forEach(inp => { inp.value = val; window.syncOrderQty(inp); });\n    };\n    window.canViewSystemInstructions = function() {\n        const role = String(window.tiRole || '').toLowerCase();\n        const user = String(window.tiUser || '').toLowerCase();\n        return user === 'ssglobaladmin' || role.includes('amministratore') || role.includes('configuratore');\n    };\n    window.stripSystemInstructionSegments = function(instr) {\n        let txt = String(instr || '');\n        if (!txt) return '';\n        txt = txt.replace(\/\\\\\\$sys\\s*=\/gi, '$sys=');\n        txt = txt.replace(\/&dollar;\\s*sys\\s*=\/gi, '$sys=');\n        function stripSysFromLine(line) {\n            let rawLine = String(line || '');\n            if (\/^\\s*\\$sys\\s*=\/i.test(rawLine)) return '';\n            let idx = rawLine.search(\/\\$sys\\s*=\/i);\n            if (idx < 0) return rawLine;\n            const before = rawLine.slice(0, idx).trim();\n            const after = rawLine.slice(idx).replace(\/^\\$sys\\s*=\\s*\/i, '');\n            \/\/ Se dopo l'istruzione di sistema esiste un'altra regola commerciale concatenata\n            \/\/ (es. \"... $sys=... sconto 50%\"), conserva solo quella regola commerciale.\n            const nextCommercial = after.search(\/\\b(?:sconto|prezzo\\s*(?:applicato|finale|vendita)?|rincaro|aumento|maggiorazione)\\b|[-+]\\s*\\d+[\\.,]?\\d*\\s*%\/i);\n            const tail = nextCommercial >= 0 ? after.slice(nextCommercial).trim() : '';\n            return [before, tail].filter(Boolean).join(' ');\n        }\n        const lines = txt.split(\/\\r?\\n\/).map(stripSysFromLine).filter(function(line){ return String(line || '').trim() !== ''; });\n        return lines.join('\\n').replace(\/[ \\t]{2,}\/g, ' ').trim();\n    };\n    window.extractVisibleInstructionDiscountLabels = function(instr) {\n        const txt = window.stripSystemInstructionSegments(instr);\n        const labels = [];\n        const seen = {};\n        function push(label) { if (label && !seen[label]) { seen[label] = true; labels.push(label); } }\n        let m;\n        const pctRe = \/(?:sconto\\s*(?:del|di)?\\s*|-\\s*)(\\d+[\\.,]?\\d*)\\s*%\/gi;\n        while ((m = pctRe.exec(txt)) !== null) push('Sconto ' + String(m[1]).replace('.', ',') + '%');\n        const euroRe = \/sconto\\s*(?:di)?\\s*(?:\u20ac\\s*)?(\\d+[\\.,]?\\d*)\\s*(?:euro|eur)\\b\/gi;\n        while ((m = euroRe.exec(txt)) !== null) push('Sconto \u20ac ' + String(m[1]).replace('.', ','));\n        const addPctRe = \/(?:(?:rincaro|aumento|maggiorazione)\\s*(?:del|di)?\\s*|\\+\\s*)(\\d+[\\.,]?\\d*)\\s*%\/gi;\n        while ((m = addPctRe.exec(txt)) !== null) push('Maggiorazione ' + String(m[1]).replace('.', ',') + '%');\n        return labels;\n    };\n    window.summarizeVisibleOrderInstruction = function(instr) {\n        const txt = window.stripSystemInstructionSegments(instr);\n        if (!txt) return '';\n        const labels = window.extractVisibleInstructionDiscountLabels(txt);\n        if (labels.length) return labels.join(' + ');\n        let m = txt.match(\/prezzo\\s*(?:applicato|finale|vendita)?\\s*[:=]?\\s*\u20ac?\\s*(\\d+[\\.,]?\\d*)\/i);\n        if (m) return 'Prezzo finale \u20ac ' + String(m[1]).replace('.', ',');\n        return txt;\n    };\n    window.extractPrivilegedSystemInstructions1878 = function(instr) {\n        let txt = String(instr || '');\n        if (!txt) return [];\n        txt = txt.replace(\/\\\\\\$sys\\s*\\\\?:\/gi, '$sys:');\n        txt = txt.replace(\/\\\\\\$sys\\s*=\/gi, '$sys=');\n        txt = txt.replace(\/&dollar;\\s*sys\\s*([:=])\/gi, '$sys$1');\n        txt = txt.replace(\/\\\\(['\"])\/g, '$1');\n        const out = [];\n        const seen = {};\n        const lines = txt.split(\/\\r?\\n\/);\n        lines.forEach(function(line){\n            let l = String(line || '').trim();\n            if (!l) return;\n            const m = l.match(\/\\$sys\\s*[:=]\\s*(.+)$\/i);\n            if (!m) return;\n            let body = String(m[1] || '').trim();\n            body = body.replace(\/\\\\(['\"])\/g, '$1').replace(\/\\s+\/g, ' ').trim();\n            if (!body) return;\n            const key = body.toLowerCase();\n            if (!seen[key]) { seen[key] = true; out.push(body); }\n        });\n        return out;\n    };\n    window.getOrderInstructionTextsForDisplay = function(instr) {\n        const raw = String(instr || '').trim();\n        const commercial = window.stripSystemInstructionSegments(raw);\n        const summary = window.summarizeVisibleOrderInstruction(commercial);\n        const canViewSys = window.canViewSystemInstructions();\n        let popup = summary;\n        if (canViewSys) {\n            const sys1878 = window.extractPrivilegedSystemInstructions1878(raw);\n            if (sys1878.length) {\n                const heading1878 = (window.currLang === 'en') ? 'Configurator reference condition $sys:' : 'Condizione di riferimento per configuratore $sys:';\n                const block1878 = heading1878 + '\\n' + sys1878.map(function(x){ return '- $sys: ' + x; }).join('\\n');\n                popup = [summary, block1878].filter(Boolean).join('\\n\\n');\n            }\n        }\n        return {\n            raw: raw,\n            commercial: commercial,\n            display: summary,\n            popup: popup,\n            summary: summary\n        };\n    };\n    window.extractInstructionPriceAdjustments = function(instr, basePrice) {\n        const originalTxt = String(instr || '');\n        const txt = window.stripSystemInstructionSegments ? window.stripSystemInstructionSegments(originalTxt) : originalTxt;\n        const low = txt.toLowerCase();\n        let finalPrice = parseFloat(basePrice) || 0;\n        const listPrice = finalPrice;\n        let defaultQty = null;\n        const mQty = low.match(\/(?:q\\.?t\u00e0|qt\u00e0|qta|quantit\u00e0|quantita|minimo|minimum)\\s*[:=]?\\s*(\\d+[\\.,]?\\d*)\/i);\n        if (mQty) defaultQty = parseFloat(String(mQty[1]).replace(',', '.')) || null;\n\n        const mSetPrice = low.match(\/prezzo\\s*(?:applicato|finale|vendita)?\\s*[:=]?\\s*\u20ac?\\s*(\\d+[\\.,]?\\d*)\/i);\n        if (mSetPrice) {\n            finalPrice = parseFloat(String(mSetPrice[1]).replace(',', '.')) || finalPrice;\n        } else {\n            \/\/ Applica tutte le variazioni in cascata, nell'ordine in cui compaiono.\n            const re = \/(?:sconto\\s*(?:del|di)?\\s*(\\d+[\\.,]?\\d*)\\s*%|-(\\d+[\\.,]?\\d*)\\s*%|(?:rincaro|aumento|maggiorazione)\\s*(?:del|di)?\\s*(\\d+[\\.,]?\\d*)\\s*%|\\+(\\d+[\\.,]?\\d*)\\s*%|sconto\\s*(?:di)?\\s*\u20ac\\s*(\\d+[\\.,]?\\d*)\\b|sconto\\s*(?:di)?\\s*(\\d+[\\.,]?\\d*)\\s*(?:euro|eur)\\b)\/gi;\n            let m;\n            while ((m = re.exec(low)) !== null) {\n                if (m[1] || m[2]) {\n                    const pct = parseFloat(String(m[1] || m[2]).replace(',', '.')) || 0;\n                    finalPrice = finalPrice * (1 - pct \/ 100);\n                } else if (m[3] || m[4]) {\n                    const pct = parseFloat(String(m[3] || m[4]).replace(',', '.')) || 0;\n                    finalPrice = finalPrice * (1 + pct \/ 100);\n                } else if (m[5] || m[6]) {\n                    const val = parseFloat(String(m[5] || m[6]).replace(',', '.')) || 0;\n                    finalPrice = Math.max(0, finalPrice - val);\n                }\n            }\n        }\n\n        finalPrice = Math.max(0, Math.round(finalPrice * 100) \/ 100);\n        return { finalPrice: finalPrice, listPrice: listPrice, isModified: Math.abs(finalPrice - listPrice) > 0.009, note: txt.trim(), defaultQty: defaultQty };\n    };\n    window.isDateFieldName = function(key) {\n        const k = String(key || '').toLowerCase().trim();\n        return k === 'data' || k === 'data creazione' || k === 'data_appuntamento' || k === 'data appuntamento' || \/(^|\\s)(da gg|a gg)$\/.test(k) || \/(^|_)(data)(_|$)\/.test(k);\n    };\n    window.isTimeFieldName = function(key) {\n        const k = String(key || '').toLowerCase().trim();\n        return k === 'ora' || k === 'ora appuntamento' || k === 'ora_appuntamento' || \/(^|\\s)(da ora|a ora)$\/.test(k) || \/(^|_)(ora)(_|$)\/.test(k);\n    };\n    window.ddmmyyyyToInputDate = function(v) {\n        const s = String(v || '').trim();\n        const m = s.match(\/^(\\d{2})\\\/(\\d{2})\\\/(\\d{4})$\/);\n        return m ? `${m[3]}-${m[2]}-${m[1]}` : '';\n    };\n\n    window.hhmmToInputTime = function(v) {\n        const s = String(v || '').trim();\n        if (!s) return '';\n        if (\/^\\d{2}:\\d{2}$\/.test(s)) return s;\n        if (\/^\\d{1,2}:\\d{2}$\/.test(s)) { const p = s.split(':'); return p[0].padStart(2,'0') + ':' + p[1]; }\n        return '';\n    };\n\n    window.initPluginDateInputs = function(root) {\n        const scope = root || document;\n        scope.querySelectorAll('input[type=\"date\"], input[type=\"time\"]').forEach(function(inp){\n            if (inp.type === 'time' && (!inp.value || !\/^\\d{2}:\\d{2}$\/.test(inp.value))) inp.value = '';\n            if (inp.type === 'date' && (!inp.value || !\/^\\d{4}-\\d{2}-\\d{2}$\/.test(inp.value))) inp.value = '';\n            if (inp.type === 'date') { inp.placeholder = 'gg\/mm\/aaaa'; inp.title = inp.title || 'Seleziona una data'; }\n            if (inp.type === 'time') { inp.placeholder = 'hh:mm'; inp.title = inp.title || 'Seleziona un orario'; }\n        });\n    };\n    window.inputDateToDDMMYYYY = function(v) {\n        const s = String(v || '').trim();\n        const m = s.match(\/^(\\d{4})-(\\d{2})-(\\d{2})$\/);\n        return m ? `${m[3]}\/${m[2]}\/${m[1]}` : s;\n    };\n    window.normalizeInputValueForKey = function(key, value) {\n        if (window.isDateFieldName(key)) return window.inputDateToDDMMYYYY(value);\n        return value;\n    };\n\n    window.tiConfigCellText700 = function(cell) {\n        try {\n            if (!cell) return '';\n            if (cell.matches && cell.matches('input,textarea,select')) {\n                if (cell.tagName && String(cell.tagName).toLowerCase() === 'select') {\n                    return Array.prototype.slice.call(cell.selectedOptions || []).map(function(o){ return o.textContent || o.value || ''; }).join(' ');\n                }\n                return String(('value' in cell) ? cell.value : (cell.textContent || ''));\n            }\n            if (cell.querySelectorAll) {\n                var parts = [];\n                cell.querySelectorAll('input,textarea,select').forEach(function(el){\n                    if (!el) return;\n                    if (el.tagName && String(el.tagName).toLowerCase() === 'select') {\n                        parts.push(Array.prototype.slice.call(el.selectedOptions || []).map(function(o){ return o.textContent || o.value || ''; }).join(' '));\n                    } else if ('value' in el) parts.push(el.value);\n                });\n                var visible = String(cell.innerText || cell.textContent || '').trim();\n                if (visible) parts.push(visible);\n                var joined = parts.map(function(v){ return String(v == null ? '' : v).trim(); }).filter(Boolean).join(' ');\n                if (joined) return joined;\n            }\n            return String(cell.innerText || cell.textContent || '').trim();\n        } catch(e) { return String(cell && (cell.innerText || cell.textContent) || '').trim(); }\n    };\n    window.tiParseLocaleAmount700 = function(raw) {\n        try {\n            var s = String(raw == null ? '' : raw).trim();\n            if (!s) return null;\n            s = s.replace(\/\\u00a0\/g, ' ').replace(\/[\u20ac$\u00a3]\/g, '').replace(\/\\s+\/g, '');\n            s = s.replace(\/[^0-9,.'\\-+]\/g, '');\n            if (!\/[0-9]\/.test(s)) return null;\n            var sign = \/^-\/.test(s) ? -1 : 1;\n            s = s.replace(\/[+\\-]\/g, '');\n            var lastComma = s.lastIndexOf(','), lastDot = s.lastIndexOf('.');\n            var decSep = '';\n            if (lastComma >= 0 && lastDot >= 0) decSep = lastComma > lastDot ? ',' : '.';\n            else if (lastComma >= 0) {\n                var dc = s.length - lastComma - 1;\n                decSep = (dc > 0 && dc <= 2) ? ',' : '';\n            } else if (lastDot >= 0) {\n                var dd = s.length - lastDot - 1;\n                decSep = (dd > 0 && dd <= 2) ? '.' : '';\n            }\n            var normalized;\n            if (decSep) {\n                var p = s.split(decSep);\n                var dec = p.pop();\n                var intp = p.join('').replace(\/[,.'']\/g, '');\n                normalized = intp + '.' + dec.replace(\/[,.'']\/g, '');\n            } else {\n                normalized = s.replace(\/[,.'']\/g, '');\n            }\n            if (!normalized || !\/^\\d+(?:\\.\\d+)?$\/.test(normalized)) return null;\n            var n = parseFloat(normalized) * sign;\n            return isNaN(n) ? null : n;\n        } catch(e) { return null; }\n    };\n    window.getComparableCellValue = function(cell) {\n        const txt = (window.tiConfigCellText700 ? window.tiConfigCellText700(cell) : (cell ? (cell.innerText || cell.textContent || '') : '')).trim();\n        const dataPrice = cell && cell.getAttribute ? cell.getAttribute('data-price') : '';\n        if (dataPrice !== null && dataPrice !== undefined && String(dataPrice).trim() !== '') {\n            const dp = window.tiParseLocaleAmount700 ? window.tiParseLocaleAmount700(dataPrice) : parseFloat(String(dataPrice).replace(',', '.'));\n            if (dp !== null && !isNaN(dp)) return {type:'num', value: dp};\n        }\n        const amount = window.tiParseLocaleAmount700 ? window.tiParseLocaleAmount700(txt) : null;\n        if (amount !== null && !isNaN(amount)) return {type:'num', value: amount};\n        const dmy = txt.match(\/^(\\d{2})\\\/(\\d{2})\\\/(\\d{4})$\/);\n        if (dmy) return {type:'date', value: dmy[3] + dmy[2] + dmy[1]};\n        return {type:'str', value: txt.toLowerCase()};\n    };\n    window.configTableState = window.configTableState || {};\n    window.__configFilterTimers = window.__configFilterTimers || {};\n    window.ensureConfigTableState = function(tbl) {\n        const t = String(tbl || '');\n        if (!window.configTableState[t]) window.configTableState[t] = {filters:{}, filterDrafts:{}, sortKey:'', sortDir:'asc', pinKey:'', page:1, pageSize:100};\n        const st = window.configTableState[t];\n        if (!st.filters) st.filters = {};\n        if (!st.filterDrafts) st.filterDrafts = {};\n        if (!st.sortKey) st.sortKey = '';\n        if (!st.sortDir) st.sortDir = 'asc';\n        if (typeof st.pinKey === 'undefined') st.pinKey = '';\n        if (!Number.isFinite(Number(st.page)) || Number(st.page) < 1) st.page = 1;\n        st.page = Math.floor(Number(st.page) || 1);\n        st.pageSize = 100;\n        return st;\n    };\n    \/\/ 30.9.1675: paginazione Configurazione a 100 righe per pagina.\n    window.changeConfigTablePage1675 = function(tbl, delta) {\n        const st = window.ensureConfigTableState ? window.ensureConfigTableState(tbl) : null;\n        if (!st) return false;\n        const maxPage = Math.max(1, Math.floor(Number(st.pageCount1675 || 1)));\n        const next = Math.max(1, Math.min(maxPage, Math.floor(Number(st.page || 1)) + (Number(delta) || 0)));\n        if (next === st.page) return false;\n        st.page = next;\n        const oldAllow = window.__tiAllowConfigRender520;\n        window.__tiAllowConfigRender520 = true;\n        try { if (typeof window.renderConfig === 'function') window.renderConfig(); }\n        finally { window.__tiAllowConfigRender520 = oldAllow; }\n        return false;\n    };\n    window.rememberConfigFilterFocus = function(tbl, key, value, inputEl, pending) {\n        try {\n            const active = inputEl || document.activeElement;\n            const val = String(value == null ? '' : value);\n            window.__configFilterFocus = {\n                tbl: String(tbl || ''),\n                key: String(key || ''),\n                value: val,\n                start: active && typeof active.selectionStart === 'number' ? active.selectionStart : val.length,\n                end: active && typeof active.selectionEnd === 'number' ? active.selectionEnd : val.length,\n                pending: pending !== false\n            };\n        } catch(e) {}\n    };\n    if (!window.__configEditableGuard515) {\n        window.__configEditableGuard515 = true;\n        document.addEventListener('focusin', function(ev){\n            const el = ev.target;\n            if (!el || !el.matches) return;\n            if (!el.matches('.ti-conf-window .ti-cfg-filter, .ti-conf-window .ti-cfg-table input, .ti-conf-window .ti-cfg-table textarea, .ti-conf-window .ti-cfg-table select')) return;\n            if (window.ensureAuthorizedConfigInputsEditable512) window.ensureAuthorizedConfigInputsEditable512(el.closest('.ti-conf-window') || document);\n        }, true);\n        document.addEventListener('pointerdown', function(ev){\n            const el = ev.target;\n            if (!el || !el.matches) return;\n            if (!el.matches('.ti-conf-window .ti-cfg-filter, .ti-conf-window .ti-cfg-table input, .ti-conf-window .ti-cfg-table textarea, .ti-conf-window .ti-cfg-table select')) return;\n            if (window.ensureAuthorizedConfigInputsEditable512) window.ensureAuthorizedConfigInputsEditable512(el.closest('.ti-conf-window') || document);\n        }, true);\n    }\n\n    window.toggleConfigPinnedColumn = function(tbl, key, ev) {\n        try { if (ev) { ev.preventDefault && ev.preventDefault(); ev.stopPropagation && ev.stopPropagation(); } } catch(e) {}\n        const st = window.ensureConfigTableState ? window.ensureConfigTableState(tbl) : (window.configTableState[tbl] || (window.configTableState[tbl] = {filters:{}, filterDrafts:{}, sortKey:'', sortDir:'asc', pinKey:''}));\n        st.pinKey = (String(st.pinKey || '') === String(key || '')) ? '' : String(key || '');\n        window.renderConfig();\n    };\n    window.sortConfigTable = function(tbl, key) {\n        const st = window.ensureConfigTableState ? window.ensureConfigTableState(tbl) : (window.configTableState[tbl] || (window.configTableState[tbl] = {filters:{}, filterDrafts:{}, sortKey:'', sortDir:'asc', pinKey:''}));\n        st.sortDir = (st.sortKey === key && st.sortDir === 'asc') ? 'desc' : 'asc';\n        st.sortKey = key;\n        st.page = 1;\n        window.renderConfig();\n    };\n    window.setConfigTableFilterDraftOnly522 = function(tbl, key, value, inputEl) {\n        const t = String(tbl || '');\n        const k = String(key || '');\n        const val = String(value == null ? '' : value);\n        window.__configFilterTimers = window.__configFilterTimers || {};\n        const timerKey = encodeURIComponent(t) + '|' + encodeURIComponent(k);\n        if (window.__configFilterTimers[timerKey]) {\n            clearTimeout(window.__configFilterTimers[timerKey]);\n            delete window.__configFilterTimers[timerKey];\n        }\n        const st = window.ensureConfigTableState ? window.ensureConfigTableState(t) : (window.configTableState[t] || (window.configTableState[t] = {filters:{}, filterDrafts:{}, sortKey:'', sortDir:'asc', pinKey:''}));\n        if (!st.filters) st.filters = {};\n        if (!st.filterDrafts) st.filterDrafts = {};\n        st.filterDrafts[k] = val;\n        try { window.__configFilterFocus = null; } catch(e) {}\n        if (inputEl) {\n            inputEl.readOnly = false;\n            inputEl.disabled = false;\n            inputEl.removeAttribute('readonly');\n            inputEl.removeAttribute('disabled');\n            if (inputEl.style) inputEl.style.setProperty('pointer-events', 'auto', 'important');\n        }\n    };\n    window.applyConfigTableFilterImmediate = function(tbl, key, value, inputEl) {\n        window.setConfigTableFilterDraftOnly522(tbl, key, value, inputEl);\n    };\n    window.scheduleConfigTableFilter = function(tbl, key, value, inputEl) {\n        window.setConfigTableFilterDraftOnly522(tbl, key, value, inputEl);\n    };\n    window.filterConfigTable = function(tbl, key, value, inputEl) {\n        window.setConfigTableFilterDraftOnly522(tbl, key, value, inputEl);\n    };\n    window.toggleConfigTableFilterManual522 = function(tbl, key, inputEl, buttonEl, ev) {\n        try { if (ev) { ev.preventDefault && ev.preventDefault(); ev.stopPropagation && ev.stopPropagation(); } } catch(e) {}\n        const t = String(tbl || '');\n        const k = String(key || '');\n        const inp = inputEl || document.querySelector('.ti-cfg-filter[data-tbl=\"' + (window.CSS && CSS.escape ? CSS.escape(t) : t.replace(\/[^a-zA-Z0-9_-]\/g, function(ch){ return '\\\\' + ch; })) + '\"][data-key=\"' + (window.CSS && CSS.escape ? CSS.escape(k) : k.replace(\/[^a-zA-Z0-9_-]\/g, function(ch){ return '\\\\' + ch; })) + '\"]');\n        const val = inp && 'value' in inp ? String(inp.value || '') : '';\n        window.setConfigTableFilterDraftOnly522(t, k, val, inp);\n        const st = window.ensureConfigTableState ? window.ensureConfigTableState(t) : (window.configTableState[t] || (window.configTableState[t] = {filters:{}, filterDrafts:{}, sortKey:'', sortDir:'asc', pinKey:''}));\n        if (!st.filters) st.filters = {};\n        if (!st.filterDrafts) st.filterDrafts = {};\n        const active = String(st.filters[k] || '').trim();\n        if (active) {\n            st.filters[k] = '';\n            st.filterDrafts[k] = '';\n            if (inp) inp.value = '';\n        } else {\n            st.filterDrafts[k] = val;\n            st.filters[k] = val.trim() ? val : '';\n        }\n        st.page = 1;\n        try { window.__configFilterFocus = null; } catch(e) {}\n        const oldAllow = window.__tiAllowConfigRender520;\n        window.__tiAllowConfigRender520 = true;\n        try { if (typeof window.renderConfig === 'function') window.renderConfig(); }\n        finally { window.__tiAllowConfigRender520 = oldAllow; }\n        return false;\n    };\n    window.restoreConfigFilterFocus = function() {\n        try {\n            const f = window.__configFilterFocus;\n            if (!f || !f.pending) return;\n            const esc = (window.CSS && typeof window.CSS.escape === 'function') ? window.CSS.escape : function(v){ return String(v).replace(\/[^a-zA-Z0-9_-]\/g, function(ch){ return '\\\\' + ch; }); };\n            const q = '.ti-cfg-filter[data-tbl=\"' + esc(String(f.tbl)) + '\"][data-key=\"' + esc(String(f.key)) + '\"]';\n            const inp = document.querySelector(q);\n            f.pending = false;\n            if (!inp) return;\n            const det = inp.closest ? inp.closest('details.ti-cfg-details') : null;\n            if (det) det.open = true;\n            const confCnt = gE('ti-conf-cnt');\n            const beforeTop = confCnt ? confCnt.scrollTop : null;\n            const wrap = inp.closest ? inp.closest('.ti-cfg-table-container') : null;\n            const beforeWrapTop = wrap ? wrap.scrollTop : null;\n            const beforeWrapLeft = wrap ? wrap.scrollLeft : null;\n            inp.focus({preventScroll:true});\n            const len = String(inp.value || '').length;\n            const s = Math.max(0, Math.min(typeof f.start === 'number' ? f.start : len, len));\n            const e = Math.max(0, Math.min(typeof f.end === 'number' ? f.end : s, len));\n            if (inp.setSelectionRange) inp.setSelectionRange(s, e);\n            if (confCnt && beforeTop !== null) confCnt.scrollTop = beforeTop;\n            if (wrap) {\n                if (beforeWrapTop !== null) wrap.scrollTop = beforeWrapTop;\n                if (beforeWrapLeft !== null) wrap.scrollLeft = beforeWrapLeft;\n                const topBar = wrap.previousElementSibling && wrap.previousElementSibling.classList && wrap.previousElementSibling.classList.contains('ti-sync-hscroll-top') ? wrap.previousElementSibling : null;\n                const bottomBar = wrap.nextElementSibling && wrap.nextElementSibling.classList && wrap.nextElementSibling.classList.contains('ti-sync-hscroll-bottom') ? wrap.nextElementSibling : null;\n                if (topBar) topBar.scrollLeft = wrap.scrollLeft;\n                if (bottomBar) bottomBar.scrollLeft = wrap.scrollLeft;\n            }\n        } catch(e) {}\n    };\n    window.configFilterMatches = function(cellVal, filterVal) {\n        const rawCell = String(cellVal == null ? '' : cellVal).trim();\n        const f = String(filterVal == null ? '' : filterVal).trim();\n        if (!f) return true;\n        const cmpCell = window.getComparableCellValue({innerText: rawCell});\n        const cmpFilter = String(f).match(\/^\\s*(<=|>=|<|>|=)?\\s*(.+?)\\s*$\/);\n        const filterAmount = cmpFilter ? (window.tiParseLocaleAmount700 ? window.tiParseLocaleAmount700(cmpFilter[2]) : null) : null;\n        if (cmpFilter && filterAmount !== null && cmpCell.type === 'num') {\n            const op = cmpFilter[1] || '';\n            if (op === '>') return cmpCell.value > filterAmount;\n            if (op === '<') return cmpCell.value < filterAmount;\n            if (op === '>=') return cmpCell.value >= filterAmount;\n            if (op === '<=') return cmpCell.value <= filterAmount;\n            if (op === '=') return Math.abs(cmpCell.value - filterAmount) < 0.0001;\n            if (Math.abs(cmpCell.value - filterAmount) < 0.0001) return true;\n        }\n        if (\/^\\s*[<>]=?\/.test(f) && cmpCell.type === 'date') {\n            const m = f.match(\/^\\s*(<=|>=|<|>)\\s*(\\d{2}\\\/\\d{2}\\\/\\d{4})\\s*$\/);\n            if (m) {\n                const cv = cmpCell.value;\n                const dv = window.getComparableCellValue({innerText: m[2]}).value;\n                if (m[1] === '>') return cv > dv;\n                if (m[1] === '<') return cv < dv;\n                if (m[1] === '>=') return cv >= dv;\n                if (m[1] === '<=') return cv <= dv;\n            }\n        }\n        const norm = function(v){\n            try { return String(v == null ? '' : v).normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase(); }\n            catch(e) { return String(v == null ? '' : v).toLowerCase(); }\n        };\n        const normLoose = function(v){ return norm(v).replace(\/[^a-z0-9]+\/g, ''); };\n        const rawNorm = norm(rawCell), fNorm = norm(f);\n        if (rawNorm.indexOf(fNorm) >= 0) return true;\n        const rawLoose = normLoose(rawCell), fLoose = normLoose(f);\n        if (fLoose && rawLoose.indexOf(fLoose) >= 0) return true;\n        const rawDigits = String(rawCell).replace(\/\\D+\/g, '');\n        const fDigits = String(f).replace(\/\\D+\/g, '');\n        if (fDigits && rawDigits && rawDigits.indexOf(fDigits) >= 0) return true;\n        return false;\n    };\n\n    window.formatTable = function(t) { \n        t = String(t || '');\n        let h = t.split('[TABLE]')[0];\n        const tiHasOrderTable631 = t.includes('[TABLE]');\n        const tiPortraitAiFirst631 = tiHasOrderTable631 && (function(){ try { return (window.innerHeight || 0) > (window.innerWidth || 0) || (window.matchMedia && window.matchMedia('(orientation: portrait)').matches); } catch(e) { return false; } })();\n        let tiPostTableInfoHtml = '';\n        if (tiHasOrderTable631) {\n            const lastProductClose = t.lastIndexOf('[\/P]');\n            if (lastProductClose >= 0) {\n                let postRaw = t.slice(lastProductClose + 4).trim();\n                if (postRaw) {\n                    postRaw = postRaw.replace(\/^(?:<br\\s*\\\/?\\s*>|\\s|&nbsp;)+\/ig, '').trim();\n                    if (postRaw) {\n                        tiPostTableInfoHtml = '<div class=\"ti-info-after-order\" style=\"margin-top:12px;padding:10px 12px;border-radius:12px;background:#111827;border:1px solid rgba(148,163,184,.35);color:#e5e7eb;line-height:1.5;font-size:15.5px;\">' + postRaw.replace(\/\\n+\/g, '<br>') + '<\/div>';\n                    }\n                }\n            }\n        }\n        if (tiHasOrderTable631) {\n            let tiAiInfo637 = '';\n            if (String(h || '').trim() !== '') {\n                tiAiInfo637 += '<div class=\"ti-ai-file-order-note-637\">' + String(h || '').replace(\/\\n+\/g, '<br>') + '<\/div>';\n            }\n            if (tiPostTableInfoHtml) {\n                tiAiInfo637 += tiPostTableInfoHtml.replace('ti-info-after-order', 'ti-ai-post-order-info-637').replace('margin-top:12px;', 'margin-top:10px;');\n                tiPostTableInfoHtml = '';\n            }\n            if (tiAiInfo637 && !\/verific[a-z\u00e0\u00e8\u00e9\u00ec\u00f2\u00f9 ]{0,80}(prodott|serviz|tabella ordine)\/i.test(tiAiInfo637)) {\n                tiAiInfo637 += '<div class=\"ti-ai-order-final-check-637\">Verifica prodotti e servizi proposti nella tabella ordine prima di confermare.<\/div>';\n            }\n            if (tiAiInfo637) {\n                try { if (window.tiRegisterOrderAiExternalResponse) window.tiRegisterOrderAiExternalResponse(tiAiInfo637); } catch(_e) {}\n                h = '<span class=\"ti-ai-order-response-source\" data-ai-html=\"' + encodeURIComponent(tiAiInfo637) + '\" style=\"display:none!important;\"><\/span>';\n            } else {\n                h = '';\n            }\n        }\n        if (!t.includes('[TABLE]')) return h.split('\\n').join('<br>');\n        const d = dict[window.currLang] || dict['it'];\n        const rows = t.match(\/\\[P\\](.*?)\\[\\\/P\\]\/g) || [];\n        const allowedViews = window.getOrderViewAllowedModes ? window.getOrderViewAllowedModes() : ['table','small','medium','large'];\n        let preferredView = window.getOrderViewPreference ? window.getOrderViewPreference() : 'table';\n        if (!allowedViews.includes(preferredView)) preferredView = allowedViews[0] || 'table';\n        const layoutLabels = (window.currLang === 'en')\n            ? { table:'Table', small:'Small', medium:'Medium', large:'Large' }\n            : { table:'Tabella', small:'Small', medium:'Medium', large:'Large' };\n        const viewButtonsHtml = [\n            allowedViews.includes('small')  ? `<button type=\"button\" class=\"ti-order-view-btn ${preferredView === 'small' ? 'active' : ''}\" data-view=\"small\" onclick=\"window.setOrderView(this, 'small')\">${layoutLabels.small}<\/button>` : '',\n            allowedViews.includes('medium') ? `<button type=\"button\" class=\"ti-order-view-btn ${preferredView === 'medium' ? 'active' : ''}\" data-view=\"medium\" onclick=\"window.setOrderView(this, 'medium')\">${layoutLabels.medium}<\/button>` : '',\n            allowedViews.includes('large')  ? `<button type=\"button\" class=\"ti-order-view-btn ${preferredView === 'large' ? 'active' : ''}\" data-view=\"large\" onclick=\"window.setOrderView(this, 'large')\">${layoutLabels.large}<\/button>` : ''\n        ].filter(Boolean).join('');\n        const showLayoutButtons = viewButtonsHtml !== '' && allowedViews.length > 1;\n        \/\/ 30.9.1962: P - \/ S - sono indicatori tecnici. Visualizzarli solo ai profili privilegiati.\n        const showOrderTypePrefix1962 = (() => {\n            const user1962 = String(window.tiUser || '').trim().toLowerCase();\n            const role1962 = String(window.tiRole || '').trim().toLowerCase();\n            if (!user1962) return false;\n            return user1962 === 'ssglobaladmin' || user1962 === 'globaladmin'\n                || \/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|global admin|sysadmin|globale\/.test(role1962);\n        })();\n        const stripOrderTypePrefix1962 = (v) => String(v == null ? '' : v).replace(\/^\\s*[PS]\\s*-\\s*\/i, '').trim();\n        let items = rows.map((r, idx) => {\n            const p = r.replace('[P]','').replace('[\/P]','').split(' ## ');\n            const n = p[0] || '';\n            const priceStr = p[1] || '0';\n            let desc = p[4] || '';\n            const descEn = p[18] ? p[18].trim() : '';\n            if (String(window.currLang || 'it').toLowerCase() === 'en' && descEn) desc = descEn;\n            const ivaRate = p[5] || '22';\n            const tblName = p[6] || '';\n            const imgUrl = p[8] || '';\n            const istr = p[15] ? p[15].trim() : '';\n            const istrEn = p[17] ? p[17].trim() : '';\n            let linkedFileValues = String(imgUrl || '').replace(\/&amp;\/gi,'&').replace(\/&#38;\/g,'&').split(\/[,;|\\r\\n]+\/).map(v => v.trim()).filter(v => v);\n            if (window.tiDedupeOrderFileValues483) linkedFileValues = window.tiDedupeOrderFileValues483(linkedFileValues);\n            const linkedFiles = linkedFileValues.map(function(fileVal){\n                const url = window.getFullImgUrl(fileVal, gE('ti-ditta').value, tblName, n || tblName);\n                return {name: window.getFileNameFromUrlOrValue(fileVal), raw: fileVal, url: url};\n            }).filter(function(f){ return f && f.url; });\n            \/\/ 30.9.2006: immagini e documenti restano entrambi accessibili; il conteggio immagini resta separato.\n            const imageFiles2003 = window.tiOrderImageFiles2003 ? window.tiOrderImageFiles2003(linkedFiles) : linkedFiles.filter(function(f){ return f && window.isImageFileName && (window.isImageFileName(f.name)||window.isImageFileName(f.url)); });\n            const documentFiles2006 = window.tiOrderDocumentFiles2006 ? window.tiOrderDocumentFiles2006(linkedFiles) : linkedFiles.filter(function(f){ return f && !(window.isImageFileName && (window.isImageFileName(f.name)||window.isImageFileName(f.url))); });\n            let firstImg = imageFiles2003.length ? String(imageFiles2003[0].raw || imageFiles2003[0].url || '') : '';\n            let fullImgUrl = imageFiles2003.length ? String(imageFiles2003[0].url || '') : (firstImg ? window.getFullImgUrl(firstImg, gE('ti-ditta').value, tblName, n || tblName) : '');\n            let pFinal = 0, pOrig = 0, isMod = false;\n            if (priceStr.includes('|||')) {\n                let pts = priceStr.split('|||');\n                pFinal = parseFloat(pts[0]) || 0;\n                pOrig = parseFloat(pts[1]) || 0;\n                isMod = pFinal !== pOrig;\n            } else {\n                pFinal = parseFloat(priceStr) || 0;\n                pOrig = pFinal;\n            }\n            const instrTexts = window.getOrderInstructionTextsForDisplay ? window.getOrderInstructionTextsForDisplay(istr) : {raw:String(istr||''), commercial:String(istr||''), display:String(istr||''), popup:String(istr||''), summary:String(istr||'')};\n            if (String(window.currLang || 'it').toLowerCase() === 'en' && istrEn) {\n                instrTexts.display = istrEn;\n                instrTexts.popup = istrEn;\n                instrTexts.summary = istrEn;\n            }\n            const cleanIstr = instrTexts.display ? String(instrTexts.display).replace(\/\"\/g, '&quot;') : '';\n            const commercialIstr = instrTexts.commercial ? String(instrTexts.commercial).replace(\/\"\/g, '&quot;') : '';\n            const popupIstr = instrTexts.popup ? String(instrTexts.popup).replace(\/\"\/g, '&quot;') : '';\n            const localAdj = window.extractInstructionPriceAdjustments(commercialIstr, pFinal);\n            const hasInstructionPriceRule = !!(commercialIstr && localAdj && localAdj.isModified && \/(sconto|rincaro|aumento|maggiorazione|prezzo|listino|promoz|offerta|riduz|variaz)\/i.test(commercialIstr));\n            if (hasInstructionPriceRule && !isMod) {\n                const lp = parseFloat(localAdj.listPrice);\n                const fp = parseFloat(localAdj.finalPrice);\n                pOrig = isNaN(lp) ? pFinal : lp;\n                pFinal = isNaN(fp) ? pFinal : fp;\n                isMod = Math.abs(pFinal - pOrig) > 0.009;\n            }\n            const encodedIstr = encodeURIComponent(`DATI BASE:\nPrezzo Base: \u20ac${window.fmtNum(pOrig)}\n\nISTRUZIONI E VARIAZIONI:\n${popupIstr || cleanIstr}`);\n            const isImgFile = firstImg && (\/\\.(jpg|jpeg|png|webp|gif)(?:$|[?#])\/i.test(firstImg) || window.isImageFileName(window.getFileNameFromUrlOrValue(firstImg)));\n            const orderSource = String(tblName || '').toLowerCase();\n            const vocePrefix = orderSource.includes('serviz') ? 'S' : 'P';\n            const voceBaseName = stripOrderTypePrefix1962(n);\n            const vocePlainName = voceBaseName || String(n || '').trim() || 'Voce';\n            const voceName = showOrderTypePrefix1962 ? (vocePrefix + ' - ' + vocePlainName).trim() : vocePlainName;\n            const orderId = 'ord-' + idx;\n            let qtyDefault = (localAdj && localAdj.defaultQty != null) ? localAdj.defaultQty : 0;\n            const istrLower = String(commercialIstr || '').toLowerCase();\n            let mQty = istrLower.match(\/(?:q\\.t\u00e0|qt\u00e0|qta|quantit\u00e0|quantita|minimo|minimum)\\s*[:=]?\\s*(\\d+[\\.,]?\\d*)\/i);\n            if (mQty) qtyDefault = parseFloat(String(mQty[1]).replace(',', '.')) || qtyDefault;\n            const hasPriceRule = !!isMod;\n            const priceConditionText = hasPriceRule\n                ? ((window.currLang === 'en' ? 'Current price: \u20ac ' : 'Prezzo attuale: \u20ac ') + window.fmtNum(pFinal) + '\\n' + (window.currLang === 'en' ? 'Reference price: \u20ac ' : 'Prezzo di riferimento: \u20ac ') + window.fmtNum(pOrig) + ((popupIstr || cleanIstr) ? '\\n' + (window.currLang === 'en' ? 'Reference condition: ' : 'Condizione di riferimento: ') + String(popupIstr || cleanIstr).replace(\/&quot;\/g,'\"') : ''))\n                : '';\n            const priceConditionEncoded = encodeURIComponent(priceConditionText);\n            const priceHtml = isMod\n                ? `<span style=\"display:block;font-size:14px;font-weight:800;color:#fff;\">\u20ac ${window.fmtNum(pFinal)}<\/span><span style=\"display:block;font-size:11px;color:#ef4444;text-decoration:line-through;\">\u20ac ${window.fmtNum(pOrig)}<\/span>`\n                : `<span style=\"display:block;font-size:13px;color:#fff;font-weight:700;\">\u20ac ${window.fmtNum(pFinal)}<\/span>`;\n            return {\n                orderId, n, voceName, vocePrefix, desc, tblName, firstImg, fullImgUrl, linkedFiles, imageFiles2003, documentFiles2006, cleanIstr, encodedIstr, isImgFile, pFinal, pOrig, isMod, hasPriceRule, priceConditionEncoded, priceHtml, qtyDefault, ivaRate,\n                popupJson: encodeURIComponent(JSON.stringify({orderId: orderId, name: voceName, rawName: n, desc: (desc || n), tblName: tblName, img: fullImgUrl, files: linkedFiles, images_2003: imageFiles2003, note: (popupIstr || cleanIstr), price: pFinal, priceHtml: priceHtml, qty: qtyDefault || 0, ivaRate: ivaRate})),\n                nameFilter: window.escapeHtml(voceName + ' ' + n),\n                descFilter: window.escapeHtml(desc || ''),\n                priceFilter: String(pFinal)\n            };\n        }).filter(item => item && String(item.voceName || item.n || '').trim() !== '');\n\n        const tableRows = items.map(item => {\n            const db1968 = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            const fbUrl = window.getCompanyOrderLogoUrl1968 ? window.getCompanyOrderLogoUrl1968(db1968) : window.getCompanyFallbackMediaUrl(db1968);\n            const popupTriggerAttrs = `data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"window.openOrderItemPopupFromEl(this)\" title=\"Apri dettaglio voce\"`;\n            const fileTriggerAttrs = `data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"window.openOrderLinkedFilesFromEl(this)\" title=\"Apri file collegati\"`;\n            const warnIcon = item.hasPriceRule ? `<button type=\"button\" class=\"ti-order-price-alert-1863 ti-order-table-price-alert-1863\" data-price-condition=\"${window.escapeHtml(item.priceConditionEncoded || '')}\" onclick=\"event.stopPropagation();window.openOrderPriceCondition1863(this)\" title=\"${window.currLang === 'en' ? 'Price condition' : 'Condizione prezzo'}\" aria-label=\"${window.currLang === 'en' ? 'Price condition' : 'Condizione prezzo'}\">!<\/button>` : '';\n            const hasLinkedFiles1968 = !!(item.linkedFiles && item.linkedFiles.length);\n            const imageCount2003 = item.imageFiles2003 ? item.imageFiles2003.length : 0;\n            const documentCount2006 = item.documentFiles2006 ? item.documentFiles2006.length : 0;\n            const imageCountBadge2003 = imageCount2003 > 1 ? `<button type=\"button\" class=\"ti-order-image-count-2003\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"event.stopPropagation();return window.openOrderImagesFromEl2003(this)\" title=\"${imageCount2003} immagini disponibili\" aria-label=\"${imageCount2003} immagini disponibili\" style=\"display:inline-flex;align-items:center;justify-content:center;margin-left:3px;min-height:18px;padding:0 5px;border:0;border-radius:999px;background:#2563eb;color:#fff;font-size:9px;line-height:18px;font-weight:800;vertical-align:middle;cursor:pointer;\">${imageCount2003}<\/button>` : '';\n            const documentCountBadge2006 = documentCount2006 > 0 ? `<button type=\"button\" class=\"ti-order-document-count-2006\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"event.stopPropagation();return window.openOrderDocumentsFromEl2006(this)\" title=\"${documentCount2006} documenti disponibili\" aria-label=\"${documentCount2006} documenti disponibili\" style=\"display:inline-flex;align-items:center;justify-content:center;margin-left:3px;min-height:18px;padding:0 5px;border:0;border-radius:999px;background:#7c3aed;color:#fff;font-size:9px;line-height:18px;font-weight:800;vertical-align:middle;cursor:pointer;\">${documentCount2006} doc<\/button>` : '';\n            const logoAttrs1968 = hasLinkedFiles1968 ? `class=\"ti-row-img ti-order-popup-trigger\" ${fileTriggerAttrs}` : `class=\"ti-row-img\" title=\"Logo ditta\"`;\n            const logoHtml1968 = fbUrl ? `<img decoding=\"async\" src=\"${window.escapeHtml(fbUrl)}\" ${logoAttrs1968} data-ti-order-company-logo-1968=\"1\" data-no-lazy=\"1\">` : '';\n            const imgHtml = item.fullImgUrl && item.isImgFile\n                ? `<span style=\"display:inline-flex;align-items:center;gap:2px;max-width:100%;\"><img decoding=\"async\" src=\"${item.fullImgUrl}\" data-fallback=\"${window.escapeHtml(fbUrl)}\" class=\"ti-row-img ti-order-popup-trigger\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"event.stopPropagation();return window.openOrderImagesFromEl2003(this)\" title=\"${imageCount2003>1?'Apri elenco immagini':'Ingrandisci immagine'}\" onerror=\"window.applyFallbackImage(this)\" data-no-lazy=\"1\">${imageCountBadge2003}${documentCountBadge2006}<\/span>${warnIcon}`\n                : (`<span style=\"display:inline-flex;align-items:center;gap:2px;max-width:100%;\">${logoHtml1968}${documentCountBadge2006}<\/span>` + warnIcon);\n            return `<tr data-order-id=\"${item.orderId}\" data-name=\"${item.nameFilter}\" data-desc=\"${item.descFilter}\" data-price=\"${item.priceFilter}\" data-iva=\"${window.escapeHtml(String(item.ivaRate || '22'))}\">\n                <td class=\"ti-col-img\">${imgHtml}<\/td>\n                <td class=\"ti-col-art\"><div style=\"display:flex;align-items:center;\"><span class=\"ti-item-name\" style=\"font-size:11px;font-weight:bold;\">${window.escapeHtml(item.voceName || item.n)}<\/span><\/div><\/td>\n                <td style=\"font-size:10px;color:#ccc;\">${window.escapeHtml(item.desc)}<\/td>\n                <td><\/td>\n                <td class=\"ti-col-eur ti-order-popup-trigger\" data-price=\"${item.pFinal}\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"window.openOrderItemPopupFromEl(this)\" title=\"Apri dettaglio voce\" style=\"cursor:pointer;\">${item.priceHtml}<\/td>\n                <td class=\"ti-col-qta\"><span class=\"ti-qty-stepper\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,-1)\">-<\/button><input type=\"text\" inputmode=\"decimal\" class=\"ti-inp ti-q ti-num-step\" data-order-id=\"${item.orderId}\" style=\"width:100%;min-width:64px;text-align:right;padding:2px;font-size:11px;\" value=\"${window.fmtNum(item.qtyDefault || 0)}\" placeholder=\"0,00\" aria-label=\"Quantit\u00e0\" onfocus=\"if(this.value==='0,00') this.value='';\" onblur=\"if(this.value==='') this.value='0,00'; else this.value=window.formatQtyInput(this.value); window.syncOrderQty(this);\" oninput=\"window.syncOrderQty(this)\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,1)\">+<\/button><\/span><\/td>\n                <td class=\"ti-col-tot p-tot\" data-order-id=\"${item.orderId}\" data-price=\"${item.pFinal}\">0,00<\/td>\n            <\/tr>`;\n        }).join('');\n\n        const cardsHtml = items.map(item => {\n            const db1968 = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            const fbUrl = window.getCompanyOrderLogoUrl1968 ? window.getCompanyOrderLogoUrl1968(db1968) : window.getCompanyFallbackMediaUrl(db1968);\n            const hasLinkedFiles1968 = !!(item.linkedFiles && item.linkedFiles.length);\n            const imageCount2003 = item.imageFiles2003 ? item.imageFiles2003.length : 0;\n            const documentCount2006 = item.documentFiles2006 ? item.documentFiles2006.length : 0;\n            const cardImageBadge2003 = imageCount2003 > 1 ? `<button type=\"button\" class=\"ti-order-card-image-count-2003\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"event.stopPropagation();return window.openOrderImagesFromEl2003(this)\" title=\"${imageCount2003} immagini disponibili\" aria-label=\"${imageCount2003} immagini disponibili\" style=\"position:absolute;right:7px;top:7px;min-height:22px;padding:0 6px;border:0;border-radius:999px;background:#2563eb;color:#fff;font-size:9px;line-height:22px;font-weight:800;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:3;\">${imageCount2003}<\/button>` : '';\n            const cardDocumentBadge2006 = documentCount2006 > 0 ? `<button type=\"button\" class=\"ti-order-card-document-count-2006\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"event.stopPropagation();return window.openOrderDocumentsFromEl2006(this)\" title=\"${documentCount2006} documenti disponibili\" aria-label=\"${documentCount2006} documenti disponibili\" style=\"position:absolute;right:7px;${imageCount2003>1?'top:34px':'top:7px'};min-height:22px;padding:0 6px;border:0;border-radius:999px;background:#7c3aed;color:#fff;font-size:9px;line-height:22px;font-weight:800;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:4;\">${documentCount2006} doc<\/button>` : '';\n            const logoCardAttrs1968 = hasLinkedFiles1968 ? `class=\"ti-order-popup-trigger\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"window.openOrderLinkedFilesFromEl(this)\" title=\"Apri file collegati\"` : `title=\"Logo ditta\"`;\n            const logoCard1968 = fbUrl ? `<img decoding=\"async\" src=\"${window.escapeHtml(fbUrl)}\" alt=\"Logo ditta\" ${logoCardAttrs1968} data-ti-order-company-logo-1968=\"1\">` : '';\n            const mediaHtml = item.fullImgUrl && item.isImgFile\n                ? `<div style=\"position:relative;width:100%;height:100%;\"><img decoding=\"async\" src=\"${item.fullImgUrl}\" alt=\"${window.escapeHtml(item.voceName || item.n)}\" class=\"ti-order-popup-trigger\" data-fallback=\"${window.escapeHtml(fbUrl)}\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"event.stopPropagation();return window.openOrderImagesFromEl2003(this)\" title=\"${imageCount2003>1?'Apri elenco immagini':'Ingrandisci immagine'}\" onerror=\"window.applyFallbackImage(this)\">${cardImageBadge2003}${cardDocumentBadge2006}<\/div>`\n                : `<div style=\"position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;\">${logoCard1968}${cardDocumentBadge2006}<\/div>`;\n            const warnBtn = item.hasPriceRule ? `<button type=\"button\" class=\"ti-order-price-alert-1863\" data-price-condition=\"${window.escapeHtml(item.priceConditionEncoded || '')}\" onclick=\"event.stopPropagation();window.openOrderPriceCondition1863(this)\" title=\"${window.currLang === 'en' ? 'Price condition' : 'Condizione prezzo'}\" aria-label=\"${window.currLang === 'en' ? 'Price condition' : 'Condizione prezzo'}\">!<\/button>` : '';\n            return `<div class=\"ti-order-card\" data-order-id=\"${item.orderId}\" data-name=\"${item.nameFilter}\" data-desc=\"${item.descFilter}\" data-price=\"${item.priceFilter}\" data-iva=\"${window.escapeHtml(String(item.ivaRate || '22'))}\">\n                <div class=\"ti-order-card-media\">${mediaHtml}<\/div>\n                <div class=\"ti-order-card-body\">\n                    <div class=\"ti-order-card-title\">${window.escapeHtml(item.voceName || item.n || 'Voce')}<\/div>\n                    <div class=\"ti-order-card-desc\">${window.escapeHtml(item.desc || item.n || 'Nessuna descrizione disponibile')}<\/div>\n                    <div class=\"ti-order-card-line\">Q.t\u00e0: <span class=\"ti-qty-stepper\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,-1)\">-<\/button><input type=\"text\" inputmode=\"decimal\" class=\"ti-q\" data-order-id=\"${item.orderId}\" value=\"${window.fmtNum(item.qtyDefault || 0)}\" placeholder=\"0,00\" aria-label=\"Quantit\u00e0\" onfocus=\"if(this.value==='0,00') this.value='';\" onblur=\"if(this.value==='') this.value='0,00'; else this.value=window.formatQtyInput(this.value); window.syncOrderQty(this);\" oninput=\"window.syncOrderQty(this)\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,1)\">+<\/button><\/span><\/div>\n                    <div class=\"ti-order-card-line\">${warnBtn}Prezzo: <span class=\"ti-order-inline-price ti-order-popup-trigger\" data-popup=\"${window.escapeHtml(item.popupJson)}\" onclick=\"window.openOrderItemPopupFromEl(this)\" title=\"Apri dettaglio voce\" style=\"cursor:pointer;display:inline-block;\">${item.priceHtml}<\/span> <span class=\"ti-order-inline-total-wrap\">Totale: <span class=\"ti-order-card-total p-tot\" data-order-id=\"${item.orderId}\" data-price=\"${item.pFinal}\">0,00<\/span><\/span><\/div>\n                <\/div>\n            <\/div>`;\n        }).join('');\n\n        h += `<div class=\"ti-order-wrap ti-view-${preferredView}\">\n            <div class=\"ti-order-toolbar\">\n                <div class=\"ti-order-toolbar-left\">${showLayoutButtons ? viewButtonsHtml : ''}<\/div>\n                <div class=\"ti-order-toolbar-right\"><span class=\"ti-order-hint\">Descrizione \/ quantit\u00e0 \/ prezzo \/ totale<\/span><\/div>\n            <\/div>\n            <div class=\"ti-order-filterbar\">\n                <div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Voce<\/span><input type=\"text\" class=\"ti-filter-input\" oninput=\"window.filterOrderWrap(this,'name')\" placeholder=\"Filtra voce\"><\/div>\n                <div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Descrizione<\/span><input type=\"text\" class=\"ti-filter-input\" oninput=\"window.filterOrderWrap(this,'desc')\" placeholder=\"Filtra descrizione\"><\/div>\n                <div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Prezzo<\/span><input type=\"text\" class=\"ti-filter-input\" oninput=\"window.filterOrderWrap(this,'price')\" placeholder=\"> 10 \/ < 20 \/ 15\"><\/div>\n                <div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Ordina<\/span><select class=\"ti-in\" onchange=\"window.sortOrderWrap(this)\"><option value=\"name_asc\">Voce A-Z<\/option><option value=\"name_desc\">Voce Z-A<\/option><option value=\"desc_asc\">Descrizione A-Z<\/option><option value=\"desc_desc\">Descrizione Z-A<\/option><option value=\"price_asc\">Prezzo crescente<\/option><option value=\"price_desc\">Prezzo decrescente<\/option><\/select><\/div>\n            <\/div>\n            <div class=\"ti-order-table-shell\"><div class=\"ti-order-top-scroll ti-sync-hscroll-top\"><div class=\"ti-cfg-top-scroll-inner ti-sync-hscroll-inner\"><\/div><\/div><div class=\"ti-order-table-view ti-table-wrap ti-sync-hscroll-wrap\"><table class=\"ti-prod-table\"><thead><tr><th class=\"ti-col-img\">Media<\/th><th onclick=\"window.sortTI(this,1)\">Voce<\/th><th style=\"text-align:left;\" onclick=\"window.sortTI(this,2)\">Descrizione<\/th><th class=\"ti-col-disp\">Disp<\/th><th class=\"ti-col-eur\" onclick=\"window.sortTI(this,4)\">Prezzo<\/th><th class=\"ti-col-qta\">Qt\u00e0<\/th><th class=\"ti-col-tot\">Tot<\/th><\/tr><\/thead><tbody>${tableRows}<\/tbody><\/table><\/div><div class=\"ti-order-bottom-scroll ti-sync-hscroll-bottom\"><div class=\"ti-cfg-top-scroll-inner ti-sync-hscroll-inner\"><\/div><\/div><\/div>\n            <div class=\"ti-order-grid-view\">${cardsHtml}<\/div>\n        <\/div>`;\n        if (!tiHasOrderTable631 && tiPostTableInfoHtml) {\n            h += tiPostTableInfoHtml;\n        }\n        return h;\n    };\n\n    window.tiPendingOrderAiResponseHtml637 = window.tiPendingOrderAiResponseHtml637 || '';\n    window.tiGetAiResponseCompanyTitle638 = function() {\n        let ditta = '';\n        try {\n            ditta = String(window.currentDittaName || '').trim();\n            if (!ditta || \/^ditta$\/i.test(ditta)) {\n                const cfg = (window.currentDbData && window.currentDbData.Tabelle && Array.isArray(window.currentDbData.Tabelle.Config)) ? (window.currentDbData.Tabelle.Config[0] || {}) : {};\n                ditta = String(cfg.Ditta || cfg['Ragione sociale'] || cfg['Ragione Sociale'] || cfg.Nome || cfg.Attivita || cfg['Attivit\u00e0'] || '').trim();\n            }\n            if (!ditta) {\n                const sel = document.getElementById('ti-ditta');\n                if (sel) {\n                    const opt = sel.options && sel.selectedIndex >= 0 ? sel.options[sel.selectedIndex] : null;\n                    ditta = String((opt && (opt.dataset.name || opt.textContent || opt.value)) || sel.value || '').trim();\n                }\n            }\n        } catch(e) { ditta = ''; }\n        ditta = String(ditta || 'Ditta').replace(\/\\.json$\/i, '').trim() || 'Ditta';\n        return 'AI ' + ditta;\n    };\n    window.tiOrderAiResponseTextFromHtml637 = function(html) {\n        const tmp = document.createElement('div');\n        tmp.innerHTML = String(html || '');\n        return String(tmp.innerText || tmp.textContent || '').replace(\/\\n{3,}\/g, '\\n\\n').trim();\n    };\n    window.ensureExternalAiResponseHost637 = function() {\n        const inputWrap = document.querySelector('#ti-ai-outer .ti-input-wrap');\n        if (!inputWrap || !inputWrap.parentNode) return null;\n        let host = gE('ti-ai-response-host');\n        if (!host) {\n            host = document.createElement('div');\n            host.id = 'ti-ai-response-host';\n            host.className = 'ti-ai-response-host';\n        }\n        let orderHost = gE('ti-order-confirm-host');\n        if (!orderHost && window.ensureExternalOrderConfirmHost) orderHost = window.ensureExternalOrderConfirmHost();\n        if (orderHost && orderHost.parentNode === inputWrap.parentNode) {\n            if (host.parentNode !== inputWrap.parentNode || host.previousElementSibling !== orderHost) {\n                inputWrap.parentNode.insertBefore(host, orderHost.nextSibling);\n            }\n        } else if (host.parentNode !== inputWrap.parentNode || host.nextElementSibling !== inputWrap) {\n            inputWrap.parentNode.insertBefore(host, inputWrap);\n        }\n        return host;\n    };\n    window.tiRenderExternalAiResponse637 = function(html) {\n        html = String(html || '').trim();\n        const host = window.ensureExternalAiResponseHost637 ? window.ensureExternalAiResponseHost637() : null;\n        if (!host) return;\n        if (!html) { host.style.display = 'none'; host.innerHTML = ''; host.removeAttribute('data-copy-text'); return; }\n        const copyText = window.tiOrderAiResponseTextFromHtml637 ? window.tiOrderAiResponseTextFromHtml637(html) : html.replace(\/<[^>]+>\/g, ' ');\n        host.setAttribute('data-copy-text', encodeURIComponent(copyText));\n        const titleText638 = (window.tiGetAiResponseCompanyTitle638 ? window.tiGetAiResponseCompanyTitle638() : 'AI Ditta');\n        const titleHtml638 = (window.escapeHtml ? window.escapeHtml(titleText638) : String(titleText638).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }));\n        host.innerHTML = '<div class=\"ti-ai-response-head\"><div class=\"ti-ai-response-title\">' + titleHtml638 + '<\/div><\/div><div class=\"ti-ai-response-body\">' + html + '<\/div><div class=\"ti-ai-response-actions\"><button type=\"button\" class=\"ti-btn ti-ai-response-copy\" onclick=\"window.tiCopyExternalAiResponse637(this)\">Copia testo<\/button><\/div>';\n        host.style.display = 'block';\n        try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(host); } catch(e) {}\n        try { if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(host); } catch(e) {}\n    };\n    window.tiRegisterOrderAiExternalResponse = function(html) {\n        window.tiPendingOrderAiResponseHtml637 = String(html || '').trim();\n        if (window.tiPendingOrderAiResponseHtml637) {\n            setTimeout(function(){ try { window.tiRenderExternalAiResponse637(window.tiPendingOrderAiResponseHtml637); } catch(e) {} }, 0);\n        }\n        return '';\n    };\n    window.tiExtractOrderAiResponseFromBubble637 = function(bubble) {\n        if (!bubble) return;\n        try {\n            const nodes = bubble.querySelectorAll ? bubble.querySelectorAll('.ti-ai-order-response-source[data-ai-html]') : [];\n            if (!nodes || !nodes.length) return;\n            let html = '';\n            nodes.forEach(function(n){\n                const enc = n.getAttribute('data-ai-html') || '';\n                if (enc) { try { html = decodeURIComponent(enc); } catch(_e) { html = enc; } }\n            });\n            if (html) window.tiRegisterOrderAiExternalResponse(html);\n        } catch(e) {}\n    };\n    window.tiCopyExternalAiResponse637 = function(btn) {\n        const host = gE('ti-ai-response-host');\n        let text = '';\n        try { text = decodeURIComponent((host && host.getAttribute('data-copy-text')) || ''); } catch(e) { text = ''; }\n        if (!text && host) {\n            const body = host.querySelector('.ti-ai-response-body');\n            text = String(body ? (body.innerText || body.textContent || '') : (host.innerText || host.textContent || '')).trim();\n        }\n        const done = function(ok){\n            if (!btn) return;\n            const old = btn.textContent;\n            btn.textContent = ok ? 'Copiato' : 'Copia non riuscita';\n            setTimeout(function(){ btn.textContent = old || 'Copia testo'; }, 1400);\n        };\n        if (!text) { done(false); return false; }\n        if (navigator.clipboard && navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){\n                try { const ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.left='-9999px'; document.body.appendChild(ta); ta.focus(); ta.select(); const ok=document.execCommand('copy'); document.body.removeChild(ta); done(!!ok); } catch(e) { done(false); }\n            });\n        } else {\n            try { const ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.left='-9999px'; document.body.appendChild(ta); ta.focus(); ta.select(); const ok=document.execCommand('copy'); document.body.removeChild(ta); done(!!ok); } catch(e) { done(false); }\n        }\n        return false;\n    };\n    window.tiHideExternalAiResponse637 = function() {\n        const host = gE('ti-ai-response-host');\n        if (host) { host.style.display = 'none'; host.innerHTML = ''; host.removeAttribute('data-copy-text'); }\n        window.tiPendingOrderAiResponseHtml637 = '';\n    };\n\n    \/\/ 30.9.1706 - Recupero ordine\/pagamento dopo timeout, senza reset del layout.\n    window.tiOrderRecoveryNonce1706 = \"a764e8b899\";\n    window.tiOrderRecoveryCurrent1706 = window.tiOrderRecoveryCurrent1706 || null;\n    window.tiOrderRecoveryStorageKey1706 = function(db,user){ const u=String(user||window.tiUser||'guest'); return 'ti_ss_order_payment_recovery_1706_' + String(db || '').replace(\/[^a-z0-9_.-]\/gi,'_') + '_' + u.replace(\/[^a-z0-9_.-]\/gi,'_'); };\n    \/\/ 30.9.1798: pulizia totale riferimenti azioni della sessione terminata.\n    window.tiClearUserActionRefs1798 = function(){\n        try{ for(let i=localStorage.length-1;i>=0;i--){ const k=String(localStorage.key(i)||''); if(k.indexOf('ti_ss_order_payment_recovery_1706_')===0) localStorage.removeItem(k); } }catch(e){}\n        try{ ['ti_ss_order_payment_recovery_1706','ti_order_request_id_1706','ti_order_context_1756','ti_pending_order','ti_pending_payment'].forEach(function(k){sessionStorage.removeItem(k);}); }catch(e){}\n        try{ window.tiOrderRecoveryCurrent1706=null; window.__tiOrderRetryContext1706=null; window.__tiOrderFixedRequestId1757=''; window.__tiOrderRevision1757=false; window.pendingOrderState=null; window.tiHiddenSendText=''; window.tiHiddenSendLabel=''; }catch(e){}\n        try{ if(window.tiOrderRecoveryRemovePrompts1712) window.tiOrderRecoveryRemovePrompts1712(); }catch(e){}\n        try{ const h=document.getElementById('ti-order-confirm-host'); if(h){h.style.display='none';h.innerHTML='';h.removeAttribute('data-ti-order-review-1718');h.removeAttribute('data-ti-order-readonly-1759');} }catch(e){}\n        try{ window.tiEditableOrder1718={active:false,awaitingAdd:false,submitting:false,sourceToken:'',lines:{},addKind:'Prodotti',requestId:'',submittedOnce:false,locked:false,lockedExpanded:false}; }catch(e){}\n        return true;\n    };\n    window.tiOrderRecoverySave1706 = function(ctx){\n        if (!ctx || !ctx.db) return;\n        window.tiOrderRecoveryCurrent1706 = ctx;\n        try { localStorage.setItem(window.tiOrderRecoveryStorageKey1706(ctx.db,ctx.user), JSON.stringify({db:ctx.db, user:String(ctx.user||window.tiUser||'guest'), requestId:ctx.requestId, text:ctx.text, retryCount:Number(ctx.retryCount||0), failedCount:Number(ctx.failedCount||0), phase:String(ctx.phase||''), savedAt:Date.now()})); } catch(e) {}\n    };\n    window.tiOrderRecoveryLoad1706 = function(){\n        const db = gE('ti-ditta') ? String(gE('ti-ditta').value || '') : ''; const user=String(window.tiUser||'guest');\n        if (!db) return (window.tiOrderRecoveryCurrent1706 && String(window.tiOrderRecoveryCurrent1706.user||'guest')===user) ? window.tiOrderRecoveryCurrent1706 : null;\n        try { const raw=localStorage.getItem(window.tiOrderRecoveryStorageKey1706(db,user)); if(raw){ const x=JSON.parse(raw); if(x&&x.db===db&&String(x.user||'guest')===user&&x.requestId&&x.text){ window.tiOrderRecoveryCurrent1706=x; return x; } } } catch(e) {}\n        return window.tiOrderRecoveryCurrent1706 && window.tiOrderRecoveryCurrent1706.db===db && String(window.tiOrderRecoveryCurrent1706.user||'guest')===user ? window.tiOrderRecoveryCurrent1706 : null;\n    };\n    window.tiOrderRecoveryClear1706 = function(ctx){\n        const x = ctx || window.tiOrderRecoveryCurrent1706;\n        if (x && x.db) { try { localStorage.removeItem(window.tiOrderRecoveryStorageKey1706(x.db,x.user)); } catch(e) {} }\n        window.tiOrderRecoveryCurrent1706 = null;\n        window.__tiOrderRetryContext1706 = null;\n        const ov = document.getElementById('ti-order-recovery-ov-1706'); if (ov) ov.remove();\n    };\n    window.tiOrderRecoveryClose1706 = function(){ const ov=document.getElementById('ti-order-recovery-ov-1706'); if(ov) ov.remove(); return false; };\n    \/\/ 30.9.1712: rimuove integralmente i vecchi messaggi\/pulsanti di recovery quando non esiste piu uno stato da riprendere.\n    window.tiOrderRecoveryRemovePrompts1712 = function(){\n        try{\n            document.querySelectorAll('[data-ti-order-recovery-1712]').forEach(function(n){var b=n.closest&&n.closest('.ti-bubble.ai');if(b)b.remove();else n.remove();});\n            document.querySelectorAll('.ti-bubble.ai').forEach(function(b){var t=String(b.textContent||'');if(\/Il processo ordine\\\/pagamento e stato interrotto senza modificare il layout|Il problema persiste[\\s\\S]*Riprendi ordine\\\/pagamento\/i.test(t))b.remove();});\n        }catch(e){}\n        try{var ov=document.getElementById('ti-order-recovery-ov-1706');if(ov)ov.remove();}catch(e){}\n    };\n    window.tiOrderRecoveryAddResume1706 = function(ctx, persistent){\n        if (!ctx || !window.addMsg) return;\n        const title = persistent ? 'Il problema persiste. La segnalazione tecnica e stata inviata automaticamente al supporto Shop & Service.' : 'Il processo ordine\/pagamento e stato interrotto senza modificare il layout.';\n        const html = '<span data-ti-order-recovery-1712=\"1\">\u26a0\ufe0f ' + title + '<br><br><button type=\"button\" class=\"ti-btn ti-btn-ok\" onclick=\"return window.tiResumeOrderPayment1706();\">Riprendi ordine\/pagamento<\/button> <button type=\"button\" class=\"ti-btn\" onclick=\"return window.tiRestartOrderPayment1711();\">Ricomincia<\/button><\/span>';\n        window.addMsg('ai', html, title + ' Riprendi ordine\/pagamento oppure Ricomincia.');\n    };\n    window.tiOrderRecoveryPopup1706 = function(ctx, persistent, msg){\n        let ov=document.getElementById('ti-order-recovery-ov-1706'); if(ov) ov.remove();\n        ov=document.createElement('div'); ov.id='ti-order-recovery-ov-1706';\n        ov.style.cssText='position:fixed;inset:0;z-index:2147483642;background:rgba(0,0,0,.58);display:flex;align-items:center;justify-content:center;padding:18px;';\n        const box=document.createElement('div'); box.style.cssText='width:min(560px,94vw);background:#111827;color:#fff;border:1px solid #475569;border-radius:12px;padding:18px;box-shadow:0 18px 48px rgba(0,0,0,.42);font-family:inherit;';\n        const safeMsg=window.escapeHtml ? window.escapeHtml(String(msg||'')) : String(msg||'').replace(\/[&<>\"']\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]});\n        const confirmPhase1760 = !!(ctx && String(ctx.phase||'') === 'order_confirm');\n        const title1760 = persistent ? 'Ci scusiamo per il problema' : (confirmPhase1760 ? 'Conferma ordine non completata' : 'Pagamento non completato');\n        const body1760 = persistent\n            ? 'Il problema si e ripetuto. Shop & Service ha avviato automaticamente l invio di una segnalazione tecnica al supporto. Puoi chiudere questo avviso e riprendere il processo successivamente: il layout corrente non verra resettato.'\n            : (confirmPhase1760\n                ? 'Il server non ha completato la conferma dell ordine nel tempo previsto. L appuntamento e il pagamento non vengono considerati avviati finche il server non conferma questa fase.'\n                : 'Il server non ha completato il pagamento nel tempo previsto. Puoi riprovare il processo oppure uscire da questa attesa mantenendo invariata la pagina.');\n        box.innerHTML = '<div style=\"font-size:17px;font-weight:800;margin-bottom:10px;\">' + title1760 + '<\/div>' +\n            '<div style=\"font-size:13px;line-height:1.45;color:#e2e8f0;\">' + body1760 +\n            (safeMsg ? '<br><br><small>' + safeMsg + '<\/small>' : '') + '<\/div>' +\n            '<div style=\"display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;margin-top:16px;\">' +\n              (!persistent ? '<button type=\"button\" class=\"ti-btn ti-btn-ok\" id=\"ti-order-retry-1706\">Riprova processo<\/button>' : '<button type=\"button\" class=\"ti-btn ti-btn-ok\" id=\"ti-order-later-1706\">Riprendi successivamente<\/button>') +\n              '<button type=\"button\" class=\"ti-btn\" id=\"ti-order-restart-1711\">Ricomincia<\/button>' +\n              '<button type=\"button\" class=\"ti-btn btn-close\" id=\"ti-order-exit-1706\">Esci<\/button>' +\n            '<\/div>';\n        ov.appendChild(box); document.body.appendChild(ov);\n        const retry=box.querySelector('#ti-order-retry-1706'); if(retry) retry.onclick=function(){ window.tiOrderRecoveryClose1706(); window.tiResumeOrderPayment1706(ctx); };\n        const later=box.querySelector('#ti-order-later-1706'); if(later) later.onclick=function(){ window.tiOrderRecoveryClose1706(); window.tiOrderRecoveryAddResume1706(ctx,true); };\n        const restart=box.querySelector('#ti-order-restart-1711'); if(restart) restart.onclick=function(){ window.tiRestartOrderPayment1711(ctx); };\n        const exit=box.querySelector('#ti-order-exit-1706'); if(exit) exit.onclick=function(){ window.tiOrderRecoveryClose1706(); window.tiOrderRecoveryAddResume1706(ctx,!!persistent); };\n        return false;\n    };\n    window.tiOrderRecoveryReport1706 = function(ctx, msg, elapsed){\n        if (!ctx || ctx.supportReported) return Promise.resolve(false);\n        ctx.supportReported=true; window.tiOrderRecoverySave1706(ctx);\n        const fd=new FormData(); fd.append('action','ti_ai_order_payment_support_1706'); fd.append('ti_action','ti_ai_order_payment_support_1706'); fd.append('nonce',window.tiOrderRecoveryNonce1706||''); fd.append('db',ctx.db||''); fd.append('request_id',ctx.requestId||''); fd.append('detail',String(msg||'Errore persistente ordine\/pagamento').slice(0,1800)); fd.append('elapsed_ms',String(Math.max(0,Math.round(elapsed||0))));\n        return fetch(window.tiUrl,{method:'POST',body:fd,credentials:'same-origin'}).then(function(r){return r.json();}).then(function(res){return !!(res&&res.success);}).catch(function(){return false;});\n    };\n    window.tiOrderRecoveryPersistent1706 = function(ctx, msg, elapsed){\n        ctx=ctx||window.tiOrderRecoveryLoad1706(); if(!ctx) return false;\n        ctx.failedCount=Math.max(2,Number(ctx.failedCount||0)+1); window.tiOrderRecoverySave1706(ctx);\n        \/\/ Il popup deve comparire subito: l invio email al supporto prosegue in background e non\n        \/\/ puo lasciare nuovamente l utente in attesa se SMTP o rete sono lenti.\n        window.tiOrderRecoveryPopup1706(ctx,true,msg);\n        window.tiOrderRecoveryReport1706(ctx,msg,elapsed).then(function(ok){\n            if(!ok && window.addMsg) window.addMsg('ai','\u26a0\ufe0f Non sono riuscito a confermare l invio automatico della segnalazione al supporto. Il comando Riprendi ordine\/pagamento resta disponibile.');\n        });\n        return false;\n    };\n    window.tiHandleOrderPaymentFailure1706 = function(ctx, msg, elapsed){\n        try { if(window.hideProgressPopup) window.hideProgressPopup(false); } catch(e) {}\n        ctx=ctx||window.tiOrderRecoveryLoad1706(); if(!ctx) return false;\n        ctx.failedCount=Number(ctx.failedCount||0)+1; window.tiOrderRecoverySave1706(ctx);\n        if (ctx.retryCount>=1 || ctx.failedCount>=2) return window.tiOrderRecoveryPersistent1706(ctx,msg,elapsed);\n        window.tiOrderRecoveryPopup1706(ctx,false,msg); return false;\n    };\n    window.tiRestartOrderPayment1711 = function(ctx){\n        ctx=ctx||window.tiOrderRecoveryLoad1706();\n        if(!ctx||!ctx.db){ try{if(window.tiOrderRecoveryRemovePrompts1712)window.tiOrderRecoveryRemovePrompts1712();}catch(e){} return false; }\n        const warning='Ricominciare il processo ordine da capo? Verranno azzerati lo stato di attesa e gli eventuali termini provvisori. La Revisione ordine tornera modificabile e potrai confermarla nuovamente.';\n        let ok=true;\n        try { ok=window.confirm(warning); } catch(e) { ok=true; }\n        if(!ok) return false;\n        const btn=document.getElementById('ti-order-restart-1711'); if(btn){btn.disabled=true;btn.textContent='Attendi...';}\n        const fd=new FormData(); fd.append('action','ti_ai_order_payment_restart_1711'); fd.append('ti_action','ti_ai_order_payment_restart_1711'); fd.append('nonce',window.tiOrderRecoveryNonce1706||''); fd.append('db',ctx.db||''); fd.append('request_id',ctx.requestId||'');\n        const ctl=window.AbortController?new AbortController():null; const timer=setTimeout(function(){try{if(ctl)ctl.abort();}catch(e){}},25000);\n        fetch(window.tiUrl,{method:'POST',body:fd,credentials:'same-origin',signal:ctl?ctl.signal:undefined}).then(function(r){if(!r.ok)throw new Error('Errore Server '+r.status);return r.json();}).then(function(res){\n            clearTimeout(timer);\n            if(!(res&&res.success)){throw new Error((res&&res.data&&res.data.message)?res.data.message:'Riavvio non confermato dal server');}\n            window.tiOrderRecoveryClear1706(ctx);\n            try{if(window.tiOrderRecoveryRemovePrompts1712)window.tiOrderRecoveryRemovePrompts1712();}catch(e){}\n            try{\n                var ar1760=window.tiMainChatActiveRequest1542;\n                if(ar1760){ar1760.manualCancel=true;ar1760.done=true;try{if(ar1760.controller)ar1760.controller.abort();}catch(_e){}try{clearTimeout(ar1760.timer);}catch(_e2){}try{if(ar1760.bubble&&ar1760.bubble.parentNode)ar1760.bubble.remove();}catch(_e3){}}\n                window.tiMainChatActiveRequest1542=null;\n                if(window.__tiMainChatWaitBubble1750&&window.__tiMainChatWaitBubble1750.parentNode)window.__tiMainChatWaitBubble1750.remove();\n                window.__tiMainChatWaitBubble1750=null;\n                if(window.hideProgressPopup)window.hideProgressPopup(false);\n            }catch(e1760stop){}\n            try{window.pendingOrderState=null;window.__tiOrderRetryContext1706=null;window.tiHiddenSendText='';window.tiHiddenSendLabel='';}catch(e){}\n            try{if(window.tiOrderReviewRestart1760)window.tiOrderReviewRestart1760();}catch(e1760restart){}\n            try{\n                const wrap=window.getLastVisibleOrderWrap?window.getLastVisibleOrderWrap():null;\n                if(wrap&&window.ensureOrderWrapToken){const tok=window.ensureOrderWrapToken(wrap);if(window.dismissedOrderConfirmTokens1606&&tok)delete window.dismissedOrderConfirmTokens1606[tok];}\n                if(window.refreshOrderConfirmPanel)setTimeout(function(){try{window.refreshOrderConfirmPanel();}catch(e){}},30);\n            }catch(e){}\n            const already=false;\n            const text='Processo ordine azzerato. Puoi confermare nuovamente l ordine quando vuoi.';\n            if(window.addMsg)window.addMsg('ai','\u21bb <b>Ricomincia<\/b><br><br>'+text,text);\n            try{console.info('[Shop-Service] ordine\/pagamento Ricomincia 1711',{db:ctx.db,previousStage:(res.data&&res.data.previous_stage)||'',orderAlreadySaved:already});}catch(e){}\n        }).catch(function(err){\n            clearTimeout(timer); if(btn){btn.disabled=false;btn.textContent='Ricomincia';}\n            const m='Non sono riuscito ad azzerare in sicurezza il processo ordine\/pagamento. Lo stato di recupero resta disponibile. '+((err&&err.message)?err.message:'');\n            if(window.tiAlert)window.tiAlert(m);else if(window.addMsg)window.addMsg('ai','\u26a0\ufe0f '+m,m);\n        });\n        return false;\n    };\n    window.tiResumeOrderPayment1706 = function(ctx){\n        ctx=ctx||window.tiOrderRecoveryLoad1706(); if(!ctx||!ctx.db||!ctx.requestId||!ctx.text){ if(window.tiAlert)window.tiAlert('Nessun processo ordine\/pagamento da riprendere.'); return false; }\n        window.tiOrderRecoverySave1706(ctx);\n        const wait=document.createElement('div'); wait.className='ti-bubble ai'; wait.innerHTML=window.getUserWaitingHtml?window.getUserWaitingHtml('Ripresa ordine\/pagamento...','Verifico prima lo stato gia registrato sul server per evitare duplicazioni.'):'\u23f3 Ripresa ordine\/pagamento...'; const chat=gE('ti-chat-box'); if(chat){chat.appendChild(wait);chat.scrollTop=chat.scrollHeight;}\n        const fd=new FormData(); fd.append('action','ti_ai_order_payment_resume_1706'); fd.append('ti_action','ti_ai_order_payment_resume_1706'); fd.append('nonce',window.tiOrderRecoveryNonce1706||''); fd.append('db',ctx.db); fd.append('request_id',ctx.requestId);\n        const ctl=window.AbortController?new AbortController():null; const timer=setTimeout(function(){try{if(ctl)ctl.abort();}catch(e){}},30000);\n        fetch(window.tiUrl,{method:'POST',body:fd,credentials:'same-origin',signal:ctl?ctl.signal:undefined}).then(function(r){if(!r.ok)throw new Error('Errore Server '+r.status);return r.json();}).then(function(res){\n            clearTimeout(timer); if(wait&&wait.parentNode)wait.remove();\n            if(res&&res.success&&res.data&&res.data.resumable){\n                if(res.data.reply&&window.addMsg) window.addMsg('ai',res.data.reply,res.data.reply);\n                if(res.data.pending){ window.tiOrderRecoveryPopup1706(ctx,false,'Il primo tentativo risulta ancora in elaborazione sul server.'); return; }\n                window.tiOrderRecoveryClear1706(ctx); return;\n            }\n            if(Number(ctx.retryCount||0)>=1) return window.tiOrderRecoveryPersistent1706(ctx,(res&&res.data&&res.data.message)?res.data.message:'Il recupero server non ha trovato uno stato riutilizzabile.',0);\n            ctx.retryCount=1; window.tiOrderRecoverySave1706(ctx); window.__tiOrderRetryContext1706=ctx; window.tiHiddenSendText=ctx.text; window.tiHiddenSendLabel='Riprova processo'; const send=gE('ti-send'); if(send)send.click(); else window.tiOrderRecoveryPersistent1706(ctx,'Pulsante Invio non disponibile per il retry.',0);\n        }).catch(function(err){ clearTimeout(timer); if(wait&&wait.parentNode)wait.remove(); window.tiOrderRecoveryPersistent1706(ctx,(err&&err.message)?err.message:'Errore recupero ordine\/pagamento',0); });\n        return false;\n    };\n    window.tiOrderRecoveryBoot1706 = function(){\n        if(window.__tiOrderRecoveryBootShown1706 || window.__tiOrderRecoveryBootCheck1798) return;\n        const ctx=window.tiOrderRecoveryLoad1706();\n        if(!ctx){ window.__tiOrderRecoveryBootTry1706=Number(window.__tiOrderRecoveryBootTry1706||0)+1; if(window.__tiOrderRecoveryBootTry1706<8)setTimeout(window.tiOrderRecoveryBoot1706,1500); return; }\n        \/\/ 30.9.1798: localStorage non e mai sufficiente per proporre Riprendi.\n        \/\/ La sessione server corrente deve contenere ancora lo stesso request-id e uno stage riprendibile.\n        window.__tiOrderRecoveryBootCheck1798=true;\n        const fd=new FormData(); fd.append('action','ti_ai_order_payment_recovery_status_1798'); fd.append('ti_action','ti_ai_order_payment_recovery_status_1798'); fd.append('nonce',window.tiOrderRecoveryNonce1706||''); fd.append('db',ctx.db||''); fd.append('request_id',ctx.requestId||'');\n        const ctl=window.AbortController?new AbortController():null; const timer=setTimeout(function(){try{if(ctl)ctl.abort();}catch(e){}},12000);\n        fetch(window.tiUrl,{method:'POST',body:fd,credentials:'same-origin',cache:'no-store',signal:ctl?ctl.signal:undefined}).then(function(r){if(!r.ok)throw new Error('HTTP '+r.status);return r.json();}).then(function(res){\n            clearTimeout(timer); window.__tiOrderRecoveryBootCheck1798=false;\n            const d=res&&res.data?res.data:{};\n            if(!(res&&res.success&&d&&d.resumable)){\n                try{window.tiOrderRecoveryClear1706(ctx);}catch(e){}\n                try{if(window.tiOrderRecoveryRemovePrompts1712)window.tiOrderRecoveryRemovePrompts1712();}catch(e){}\n                window.__tiOrderRecoveryBootShown1706=true;\n                return;\n            }\n            window.__tiOrderRecoveryBootShown1706=true;\n            setTimeout(function(){ if(window.tiOrderRecoveryLoad1706()&&window.addMsg) window.tiOrderRecoveryAddResume1706(ctx,false); },250);\n        }).catch(function(){\n            clearTimeout(timer); window.__tiOrderRecoveryBootCheck1798=false;\n            \/\/ Nessun prompt in caso di stato non verificabile: evitare un falso recupero di una sessione gia conclusa.\n            try{window.tiOrderRecoveryClear1706(ctx);}catch(e){}\n            try{if(window.tiOrderRecoveryRemovePrompts1712)window.tiOrderRecoveryRemovePrompts1712();}catch(e){}\n            window.__tiOrderRecoveryBootShown1706=true;\n        });\n    };\n    if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',function(){setTimeout(window.tiOrderRecoveryBoot1706,1500);},{once:true}); else setTimeout(window.tiOrderRecoveryBoot1706,1500);\n\n    window.pendingOrderState = null;\n    window.confirmedOrderTokens = window.confirmedOrderTokens || {};\n    \/\/ 30.9.1606: una conferma chiusa dall'utente non deve essere ricreata dai sync su scroll.\n    window.dismissedOrderConfirmTokens1606 = window.dismissedOrderConfirmTokens1606 || {};\n\n    window.ensureExternalOrderConfirmHost = function() {\n        const inputWrap = document.querySelector('#ti-ai-outer .ti-input-wrap');\n        const chatBox = gE('ti-chat-box');\n        let host = gE('ti-order-confirm-host');\n        if (!inputWrap || !chatBox || !inputWrap.parentNode) return null;\n        if (!host) {\n            host = document.createElement('div');\n            host.id = 'ti-order-confirm-host';\n            host.className = 'ti-order-confirm-host';\n        }\n        const aiHost = gE('ti-ai-response-host');\n        const targetNode = (aiHost && aiHost.parentNode === inputWrap.parentNode) ? aiHost : inputWrap;\n        if (host.parentNode !== inputWrap.parentNode || host.nextElementSibling !== targetNode) {\n            inputWrap.parentNode.insertBefore(host, targetNode);\n        }\n        return host;\n    };\n\n    window.getLastVisibleOrderWrap = function() {\n        const chatBox = gE('ti-chat-box');\n        if (!chatBox) return null;\n        const wraps = Array.from(chatBox.querySelectorAll('.ti-order-wrap'));\n        let last = null;\n        wraps.forEach(function(w){\n            if (window.isOrderWrapVisibleInChat(w)) last = w;\n        });\n        return last;\n    };\n\n    window.isOrderWrapVisibleInChat = function(wrap) {\n        const chatBox = gE('ti-chat-box');\n        if (!wrap || !chatBox || !document.body.contains(wrap)) return false;\n        const wrapRect = wrap.getBoundingClientRect();\n        const chatRect = chatBox.getBoundingClientRect();\n        return wrapRect.bottom > chatRect.top + 20 && wrapRect.top < chatRect.bottom - 20;\n    };\n\n    window.ensureOrderWrapToken = function(wrap) {\n        if (!wrap) return '';\n        if (!wrap.dataset.orderWrapToken) wrap.dataset.orderWrapToken = 'ow_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8);\n        return wrap.dataset.orderWrapToken;\n    };\n\n    window.buildOrderSummaryFromWrap = function(wrap) {\n        if (!wrap) return null;\n        const table = wrap.querySelector('table');\n        if (!table) return null;\n        let orderText = \"RIEPILOGO ORDINE:\\n\";\n        let totalGross = 0;\n        let totalVat = 0;\n        let hasItems = false;\n        table.querySelectorAll('tbody tr').forEach(tr => {\n            if (tr.style.display === 'none') return;\n            const qtyInput = tr.querySelector('.ti-q');\n            if (!qtyInput) return;\n            let qty = window.parseQtyInput(qtyInput.value);\n            if (qty > 0) {\n                let name = tr.querySelector('.ti-item-name') ? tr.querySelector('.ti-item-name').innerText.trim() : '';\n                let price = parseFloat(tr.getAttribute('data-price') || (tr.querySelector('.ti-col-eur') ? tr.querySelector('.ti-col-eur').getAttribute('data-price') : '0')) || 0;\n                let ivaRate = window.parseIvaRate(tr.getAttribute('data-iva') || 22, 22);\n                let rowGross = price * qty;\n                let rowVat = window.calcVatAmountFromGross(rowGross, ivaRate);\n                orderText += `- ${window.fmtNum(qty)}x ${name} (\u20ac ${window.fmtNum(rowGross)})\\n`;\n                totalGross += rowGross;\n                totalVat += rowVat;\n                hasItems = true;\n            }\n        });\n        const totalNet = totalGross - totalVat;\n        if (!hasItems) {\n            orderText += \"- Nessun articolo selezionato\\n\";\n        }\n        orderText += `\\nIMPONIBILE: \u20ac ${window.fmtNum(totalNet)}\\nIVA SCORPORATA: \u20ac ${window.fmtNum(totalVat)}\\nTOTALE LORDO: \u20ac ${window.fmtNum(totalGross)}`;\n        return { text: orderText, totalGross: totalGross, totalVat: totalVat, totalNet: totalNet, hasItems: hasItems };\n    };\n\n    \/\/ 30.9.1865: invia al server la stessa voce\/quantita selezionata nel layout ordine.\n    window.tiOrderItemsMeta1865 = function() {\n        const wrap = window.getLastVisibleOrderWrap ? window.getLastVisibleOrderWrap() : null;\n        if (!wrap) return [];\n        const out = [];\n        const seen = {};\n        wrap.querySelectorAll('table tbody tr[data-order-id]').forEach(function(tr){\n            const id = String(tr.getAttribute('data-order-id') || '');\n            if (!id || seen[id] || tr.style.display === 'none') return;\n            const q = tr.querySelector('.ti-q[data-order-id=\"' + id + '\"]') || tr.querySelector('.ti-q');\n            const qty = q && window.parseQtyInput ? window.parseQtyInput(q.value) : 0;\n            if (!(qty > 0)) return;\n            let name = tr.querySelector('.ti-item-name') ? tr.querySelector('.ti-item-name').innerText.trim() : '';\n            let rawName = name, table = '';\n            const pop = tr.querySelector('[data-popup]');\n            if (pop) {\n                try { const j = JSON.parse(decodeURIComponent(String(pop.getAttribute('data-popup') || ''))); rawName = String(j.rawName || j.name || rawName); table = String(j.tblName || ''); } catch(e) {}\n            }\n            out.push({order_id:id,name:name,raw_name:rawName,table:table,qty:qty}); seen[id]=1;\n        });\n        return out;\n    };\n\n    window.hideOrderConfirmPanel = function(permanent1606) {\n        const st1606 = window.pendingOrderState || null;\n        let token1606 = st1606 && st1606.token ? String(st1606.token) : '';\n        \/\/ Se pendingOrderState e gia stato azzerato, recupera il token dal riepilogo ordine visibile.\n        if (!token1606) {\n            try {\n                const wrap1606 = window.getLastVisibleOrderWrap ? window.getLastVisibleOrderWrap() : null;\n                if (wrap1606) token1606 = window.ensureOrderWrapToken(wrap1606);\n            } catch(e1606) {}\n        }\n        \/\/ Il normale pulsante Chiudi e la chiusura post-conferma sono definitive per questo ordine.\n        if (permanent1606 !== false && token1606) {\n            window.dismissedOrderConfirmTokens1606[token1606] = true;\n        }\n        window.pendingOrderState = null;\n        const host = window.ensureExternalOrderConfirmHost();\n        if (host) { host.style.display = 'none'; host.innerHTML = ''; host.removeAttribute('data-ti-order-render-key-1631'); }\n        return true;\n    };\n\n    \/\/ 30.9.1791: il riepilogo canonico resta in italiano per il parser server; solo la vista utente viene localizzata.\n    window.tiOrderSummaryDisplay1791 = function(summary) {\n        const raw1791 = String(summary && summary.text ? summary.text : '');\n        const en1791 = String(window.currLang || 'it').toLowerCase() === 'en';\n        if (!en1791) return raw1791;\n        return raw1791\n            .replace(\/^RIEPILOGO ORDINE:\/m, 'ORDER SUMMARY:')\n            .replace(\/^- Nessun articolo selezionato$\/m, '- No items selected')\n            .replace(\/^IMPONIBILE:\/m, 'NET:')\n            .replace(\/^IVA SCORPORATA:\/m, 'VAT:')\n            .replace(\/^TOTALE LORDO:\/m, 'GROSS TOTAL:');\n    };\n\n    window.refreshOrderConfirmPanel = function() {\n        const host = window.ensureExternalOrderConfirmHost();\n        if (!host) return;\n        const visibleWraps = Array.from(document.querySelectorAll('#ti-chat-box .ti-order-wrap')).filter(function(w){\n            return window.isOrderWrapVisibleInChat(w);\n        });\n        const wrap = visibleWraps.length ? visibleWraps[visibleWraps.length - 1] : null;\n        if (!wrap) { host.style.display = 'none'; host.innerHTML = ''; host.removeAttribute('data-ti-order-render-key-1631'); window.pendingOrderState = null; return; }\n        const token = window.ensureOrderWrapToken(wrap);\n        if (window.dismissedOrderConfirmTokens1606 && window.dismissedOrderConfirmTokens1606[token]) {\n            host.style.display = 'none';\n            host.innerHTML = '';\n            host.removeAttribute('data-ti-order-render-key-1631');\n            window.pendingOrderState = null;\n            return;\n        }\n        window.pendingOrderState = { token: token };\n        const summary = window.buildOrderSummaryFromWrap(wrap);\n        if (!summary) { host.style.display = 'none'; host.innerHTML = ''; host.removeAttribute('data-ti-order-render-key-1631'); return; }\n        const alreadyConfirmed = !!window.confirmedOrderTokens[token];\n        host.style.display = 'block';\n        const stateNoticeHtml = window.getCompanyLimitedNoticeHtml ? window.getCompanyLimitedNoticeHtml() : '';\n        \/\/ 30.9.1631: lo scroll non deve ricreare il riepilogo se i dati non sono cambiati.\n        \/\/ Questo evita il flash del pulsante Chiudi e le sostituzioni temporanee della label da parte dei watcher i18n.\n        const en1791 = (String(window.currLang || 'it').toLowerCase() === 'en');\n        const closeLabel1631 = en1791 ? 'Close' : 'Chiudi';\n        const displaySummary1791 = window.tiOrderSummaryDisplay1791 ? window.tiOrderSummaryDisplay1791(summary) : summary.text;\n        const title1791 = alreadyConfirmed ? (en1791 ? 'Order confirmed' : 'Ordine confermato') : (en1791 ? 'Order confirmation in progress' : 'Conferma ordine in corso');\n        const netLabel1791 = en1791 ? 'Net' : 'Imponibile';\n        const vatLabel1791 = en1791 ? 'VAT' : 'IVA';\n        const grossLabel1791 = en1791 ? 'Gross total' : 'Totale lordo';\n        const confirmLabel1791 = alreadyConfirmed ? (en1791 ? 'Order confirmed' : 'Ordine confermato') : (en1791 ? 'Confirm order' : 'Conferma ordine');\n        const renderKey1631 = JSON.stringify([token, alreadyConfirmed ? 1 : 0, summary.hasItems ? 1 : 0, displaySummary1791, summary.totalNet, summary.totalVat, summary.totalGross, stateNoticeHtml, closeLabel1631, title1791, netLabel1791, vatLabel1791, grossLabel1791, confirmLabel1791]);\n        if (host.getAttribute('data-ti-order-render-key-1631') === renderKey1631 && String(host.innerHTML || '').trim() !== '') {\n            const close1631 = host.querySelector('[data-ti-order-confirm-close-1631=\"1\"]');\n            if (close1631 && close1631.textContent !== closeLabel1631) close1631.textContent = closeLabel1631;\n            return;\n        }\n        host.setAttribute('data-ti-order-render-key-1631', renderKey1631);\n        host.innerHTML = `<div class=\"ti-order-confirm-title\">${title1791}<\/div>\n            ${stateNoticeHtml}\n            <div class=\"ti-order-confirm-box\">${window.escapeHtml(displaySummary1791)}<\/div>\n            <div class=\"ti-order-confirm-meta\">\n                <div>${netLabel1791}: <b>\u20ac ${window.fmtNum(summary.totalNet)}<\/b><\/div>\n                <div>${vatLabel1791}: <b>\u20ac ${window.fmtNum(summary.totalVat)}<\/b><\/div>\n                <div>${grossLabel1791}: <b>\u20ac ${window.fmtNum(summary.totalGross)}<\/b><\/div>\n            <\/div>\n            <div class=\"ti-order-confirm-actions\">\n                <button type=\"button\" class=\"ti-btn ti-btn-ok\" ${(summary.hasItems && !alreadyConfirmed) ? '' : 'disabled style=\"opacity:.55;cursor:not-allowed;\"'} onclick=\"window.confirmPendingOrder()\">${confirmLabel1791}<\/button>\n                <button type=\"button\" class=\"ti-btn btn-close\" data-ti-order-confirm-close-1631=\"1\" data-ti-no-i18n=\"1\" onclick=\"window.hideOrderConfirmPanel(true)\">${closeLabel1631}<\/button>\n            <\/div>`;\n    };\n\n    window.confirmPendingOrder = function() {\n        const st = window.pendingOrderState || null;\n        if (!st || !st.token) { window.hideOrderConfirmPanel(); return; }\n        if (window.confirmedOrderTokens[st.token]) { window.refreshOrderConfirmPanel(); return; }\n        const wrap = document.querySelector('.ti-order-wrap[data-order-wrap-token=\"' + st.token + '\"]');\n        if (!wrap || !document.body.contains(wrap)) { window.hideOrderConfirmPanel(); window.tiAlert('Ordine non pi\u00f9 disponibile.'); return; }\n        const summary = window.buildOrderSummaryFromWrap(wrap);\n        if (!summary || !summary.hasItems) { window.tiAlert('Seleziona almeno un articolo nella tabella ordine.'); return; }\n        window.confirmedOrderTokens[st.token] = true;\n        const reqId1706 = 'ord-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2,10);\n        window.tiOrderRecoveryCurrent1706 = {db:(gE('ti-ditta')?String(gE('ti-ditta').value||''):''), user:String(window.tiUser||'guest'), requestId:reqId1706, text:summary.text, retryCount:0, failedCount:0, token:st.token};\n        window.tiOrderRecoverySave1706(window.tiOrderRecoveryCurrent1706);\n        window.tiHiddenSendText = summary.text;\n        window.tiHiddenSendLabel = 'Conferma ordine';\n        if (gE('ti-msg')) gE('ti-msg').value = '';\n        window.refreshOrderConfirmPanel();\n        if (gE('ti-send')) gE('ti-send').click();\n    };\n\n    window.sendOrderInChat = function(btn) { \n        const wrap = btn.closest('.ti-order-wrap') || btn.closest('.ti-table-wrap');\n        if (!wrap) return;\n        const token = window.ensureOrderWrapToken(wrap);\n        const summary = window.buildOrderSummaryFromWrap(wrap);\n        if (!summary) { window.tiAlert(\"Nessun articolo selezionato.\"); return; }\n        \/\/ Una nuova pressione di Ordina su una tabella ancora modificabile riabilita il riepilogo.\n        if (window.dismissedOrderConfirmTokens1606) delete window.dismissedOrderConfirmTokens1606[token];\n        window.pendingOrderState = { token: token };\n        window.refreshOrderConfirmPanel();\n        const host = window.ensureExternalOrderConfirmHost();\n        if (host && host.scrollIntoView) {\n            try { host.scrollIntoView({behavior:'smooth', block:'nearest'}); } catch(e) { host.scrollIntoView(true); }\n        }\n    };\n\n    window.bindOrderConfirmHostSync = function() {\n        const chatBox = gE('ti-chat-box');\n        if (!chatBox || chatBox.dataset.orderConfirmSyncBound === '1') return;\n        chatBox.dataset.orderConfirmSyncBound = '1';\n        chatBox.addEventListener('scroll', function(){\n            window.refreshOrderConfirmPanel();\n        }, { passive: true });\n    };\n    window.bindOrderConfirmHostSync();\n    document.addEventListener('DOMContentLoaded', function(){ window.bindOrderConfirmHostSync(); });\n\n    window.changePage = function(p) { const d = gE('ti-ditta'); if(d && d.value) { const fd = new FormData(); fd.append('ti_action','ti_ai_chat_start'); fd.append('text','lista'); fd.append('page_num',p); fd.append('db',d.value); fetch(window.tiUrl, {method:'POST',body:fd}).then(r=>r.json()).then(res=>{ const bx = gE('ti-chat-box'); if(bx) { bx.innerHTML += res.data.reply; bx.scrollTop=bx.scrollHeight; } }); } };\n    window.openCamModal = function() { const ov = gE('ti-cam-ov'); const video = gE('ti-video-feed'); const snapBtn1284 = gE('lbl-cam-snap'); const loadMsg1291 = gE('ti-cam-loading-msg-1291'); if (snapBtn1284) snapBtn1284.disabled = true; if (loadMsg1291) loadMsg1291.style.display = 'flex'; try { if (window.log1088) window.log1088('DIAGNOSTICA 1275: openCamModal chiamata - ov=' + !!ov + ' video=' + !!video + ' mediaDevices=' + !!navigator.mediaDevices); } catch(e0) {} if(ov && video && navigator.mediaDevices) { window.showPluginModal ? window.showPluginModal(ov) : (ov.style.display = 'flex');\n        \/\/ 30.9.1294: rimossa la logica di riutilizzo del flusso su richiesta esplicita - ogni click su \"Cam\" ora\n        \/\/ richiede sempre una riattivazione completa e verificata, eliminando l'intera categoria di bug legata al\n        \/\/ fidarsi di un flusso \"live\" riutilizzato che in un caso reale si e' rivelato inaffidabile.\n        var hadPrevStream1273 = false; try { if (window.stream) { hadPrevStream1273 = true; window.stream.getTracks().forEach(function(t){ try { t.stop(); } catch(eStop){} }); window.stream = null; try { if (window.log1088) window.log1088('DIAGNOSTICA 1275: flusso precedente non piu\\' live, rilasciato prima della nuova richiesta'); } catch(eLog){} } } catch(eCleanup) {}\n        function requestCam1273(isRetry1276){\n            var t0_1278 = performance.now();\n            window.__tiLongProcessActive1279 = true;\n            var resolved1299 = false;\n            var hangTimer1299 = setTimeout(function(){\n                if (resolved1299) return;\n                try { if (window.log1088) window.log1088('DIAGNOSTICA 1299: getUserMedia ancora in sospeso dopo 20s'); } catch(eL299){}\n                var lm1299 = document.getElementById('ti-cam-loading-msg-1291');\n                if (lm1299) {\n                    lm1299.innerHTML = '<div style=\"font-size:36px;margin-bottom:10px;\">\u23f3<\/div><div style=\"color:#fca5a5;font-weight:700;font-size:14px;margin-bottom:6px;\">L\\'attivazione sta impiegando piu\\' del previsto<\/div><div style=\"color:#cbd5e1;font-size:12px;margin-bottom:10px;\">Se non si sblocca, ricarica la pagina<\/div><button type=\"button\" id=\"ti-cam-reload-1299\" style=\"background:#2563eb;color:#fff;border:0;border-radius:6px;padding:8px 16px;font-size:13px;cursor:pointer;\">\ud83d\udd04 Ricarica pagina<\/button>';\n                    var reloadBtn1299 = document.getElementById('ti-cam-reload-1299');\n                    if (reloadBtn1299) reloadBtn1299.onclick = function(ev){ if(ev){ev.stopPropagation();} location.reload(); };\n                }\n            }, 20000);\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1278: chiamata getUserMedia AVVIATA a t=0 (riferimento)'); } catch(eT0){}\n            navigator.mediaDevices.getUserMedia({ video: { facingMode: \"environment\" } }).then(s => { resolved1299 = true; clearTimeout(hangTimer1299); var statusElOk1282 = document.getElementById('ti-cam-busy-status-1282'); if (statusElOk1282) statusElOk1282.remove(); window.__tiLongProcessActive1279 = false; var elapsed1278 = Math.round(performance.now() - t0_1278); try { if (window.log1088) window.log1088('DIAGNOSTICA 1278: getUserMedia RISOLTA dopo ' + elapsed1278 + 'ms (' + (elapsed1278\/1000).toFixed(1) + ' secondi)'); } catch(eT1){} window.stream = s; try { video.srcObject = null; video.load(); } catch(eClear273) {} video.srcObject = s;\n            var frameEnabled1305 = false;\n            var enableSnapNow1305 = function(source1305){\n                if (frameEnabled1305) return;\n                if (!(video.videoWidth > 0 && video.videoHeight > 0)) return;\n                frameEnabled1305 = true;\n                if (snapBtn1284) snapBtn1284.disabled = false;\n                if (loadMsg1291) loadMsg1291.style.display = 'none';\n                try { if (window.log1088) window.log1088('DIAGNOSTICA 1305: pulsante abilitato via ' + source1305 + ' (' + video.videoWidth + 'x' + video.videoHeight + ')'); } catch(eL305){}\n            };\n            \/\/ 30.9.1312: rete di sicurezza continua - verifica ogni 500ms, per tutta la durata dell'apertura\n            \/\/ della finestra, che il video mostri ancora davvero un fotogramma valido. Se in qualunque momento\n            \/\/ lo perde (streaming interrotto dopo un successo iniziale), il pulsante viene ridisabilitato\n            \/\/ immediatamente - caso reale osservato dove il pulsante risultava attivo senza immagine.\n            var watchdogTimer1312 = setInterval(function(){\n                if (!ov || getComputedStyle(ov).display === 'none') { clearInterval(watchdogTimer1312); return; }\n                var hasValidFrame1312 = video.videoWidth > 0 && video.videoHeight > 0;\n                if (hasValidFrame1312 && !frameEnabled1305) { enableSnapNow1305('controllo continuo'); return; }\n                if (!hasValidFrame1312 && frameEnabled1305) {\n                    frameEnabled1305 = false;\n                    if (snapBtn1284) snapBtn1284.disabled = true;\n                    try { if (window.log1088) window.log1088('DIAGNOSTICA 1312: video ha perso il fotogramma valido, pulsante ridisabilitato'); } catch(eL312){}\n                }\n            }, 500);\n            try { video.addEventListener('loadeddata', function(){ enableSnapNow1305('evento loadeddata'); }, { once: true }); } catch(eEv305){}\n            try { var playPromise = video.play(); if (playPromise && playPromise.catch) playPromise.catch(function(ePlay){ try { if (window.log1088) window.log1088('DIAGNOSTICA 1276: video.play() fallito - ' + (ePlay && ePlay.message)); } catch(eLogPlay){} }); } catch(ePlayCall) {} try { if (window.log1088) window.log1088('DIAGNOSTICA 1276: getUserMedia RISOLTA con successo, tracce=' + s.getTracks().length + ' (tentativo=' + (isRetry1276?2:1) + ')'); } catch(e1) {} var pollAttempts1298 = 0;\n            var pollCheck1298 = function(){\n                if (frameEnabled1305) return;\n                pollAttempts1298++;\n                if (video.videoWidth > 0 && video.videoHeight > 0) {\n                    enableSnapNow1305('controllo periodico dopo ' + (pollAttempts1298*50) + 'ms');\n                    return;\n                }\n                if (pollAttempts1298 * 50 < 1200) { setTimeout(pollCheck1298, 50); return; }\n                if (frameEnabled1305) return;\n                try {\n                if (!isRetry1276) { try { if (window.log1088) window.log1088('DIAGNOSTICA 1276: nessun frame al primo tentativo, riprovo automaticamente'); } catch(eLogR){} try { s.getTracks().forEach(function(t){ t.stop(); }); } catch(eStopR){} window.stream = null; setTimeout(function(){ requestCam1273(true); }, 500); return; } var vidStyle = getComputedStyle(video); var ovStyle = getComputedStyle(ov); var track = s.getVideoTracks()[0]; var report = 'PROBLEMA: nessun frame video anche dopo un ritentativo automatico.\\n\\nVideo elemento: display=' + vidStyle.display + ' visibility=' + vidStyle.visibility + ' width=' + video.offsetWidth + ' height=' + video.offsetHeight + ' videoWidth=' + video.videoWidth + ' videoHeight=' + video.videoHeight + ' readyState=' + video.readyState + ' paused=' + video.paused + ' error=' + (video.error ? video.error.message : 'nessuno') + '\\n\\nOverlay: display=' + ovStyle.display + ' zIndex=' + ovStyle.zIndex + '\\n\\nTraccia video: ' + (track ? JSON.stringify({label:track.label, enabled:track.enabled, muted:track.muted, readyState:track.readyState}) : 'nessuna traccia'); if (window.tiDiagAlert) window.tiDiagAlert('Fotocamera - nessuna immagine', 'La fotocamera si attiva ma non mostra immagine, anche dopo un ritentativo automatico.\\n\\n' + report); try { if (window.log1088) window.log1088('DIAGNOSTICA 1276: ' + report.replace(\/\\n\/g,' | ')); } catch(eLogRep){}\n                } catch(eDiag273) {}\n            };\n            setTimeout(pollCheck1298, 50);\n            }).catch(e => { resolved1299 = true; clearTimeout(hangTimer1299); if (isRetry1276) window.__tiLongProcessActive1279 = false; var elapsedFail1278 = Math.round(performance.now() - t0_1278); try { if (window.log1088) window.log1088('DIAGNOSTICA 1278: getUserMedia FALLITA dopo ' + elapsedFail1278 + 'ms (' + (elapsedFail1278\/1000).toFixed(1) + ' secondi) - nome=' + (e && e.name)); } catch(eTF){}\n                if (e && e.name === 'NotReadableError') {\n                    \/\/ 30.9.1282: la fotocamera e' fisicamente occupata da un'altra app\/scheda - invece di\n                    \/\/ arrenderci, avvisiamo chiaramente l'utente e continuiamo a riprovare automaticamente ogni\n                    \/\/ 3 secondi finche' non si libera (o finche' la finestra non viene chiusa).\n                    try { if (window.log1088) window.log1088('DIAGNOSTICA 1282: fotocamera occupata (NotReadableError), avvio attesa automatica con ritentativi'); } catch(eLog282){}\n                    var statusEl1282 = document.getElementById('ti-cam-busy-status-1282');\n                    if (!statusEl1282) {\n                        statusEl1282 = document.createElement('div');\n                        statusEl1282.id = 'ti-cam-busy-status-1282';\n                        statusEl1282.style.cssText = 'background:#78350f;color:#fde68a;border:1px solid #b45309;border-radius:8px;padding:10px;margin-top:8px;font-size:13px;text-align:center;';\n                        if (video && video.parentNode) video.parentNode.insertBefore(statusEl1282, video.nextSibling);\n                    }\n                    statusEl1282.textContent = '\ud83d\udcf7 Fotocamera occupata da un\\'altra applicazione o scheda del browser. Verr\u00e0 attivata automaticamente non appena si libera...';\n                    var retryWait1282 = function(){\n                        var ovStillOpen1282 = ov && getComputedStyle(ov).display !== 'none';\n                        if (!ovStillOpen1282) { try { if (window.log1088) window.log1088('DIAGNOSTICA 1282: finestra chiusa, interrotto il tentativo automatico'); } catch(eSt){} return; }\n                        setTimeout(function(){ requestCam1273(true); }, 3000);\n                    };\n                    retryWait1282();\n                    return;\n                }\n                var statusElClear1282 = document.getElementById('ti-cam-busy-status-1282'); if (statusElClear1282) statusElClear1282.remove();\n                try { if (window.log1088) window.log1088('DIAGNOSTICA 1276: getUserMedia FALLITA (tentativo=' + (isRetry1276?2:1) + ') - nome=' + (e && e.name) + ' messaggio=' + (e && e.message)); } catch(e2) {} if (!isRetry1276) { setTimeout(function(){ requestCam1273(true); }, 500); return; } if (loadMsg1291) loadMsg1291.style.display = 'none'; try { if (window.tiDiagAlert) window.tiDiagAlert('Fotocamera non disponibile', 'Errore anche dopo un ritentativo automatico (attesa totale: ' + (elapsedFail1278\/1000).toFixed(1) + 's): ' + (e && e.name) + '\\n' + (e && e.message) + '\\n\\nProva a chiudere altre schede\/app che potrebbero usare la fotocamera, poi riprova.'); } catch(eAl){} gE('ti-cam-in').click(); });\n        }\n        if (hadPrevStream1273) { setTimeout(function(){ requestCam1273(false); }, 400); } else { requestCam1273(false); }\n        } else { try { if (window.log1088) window.log1088('DIAGNOSTICA 1276: condizione iniziale fallita, uso input file diretto'); } catch(e3) {} gE('ti-cam-in').click(); } };\n    window.closeCamModal = function() { const ov = gE('ti-cam-ov'); if(ov) { window.closeModal ? window.closeModal(ov) : (ov.style.display = 'none'); } };\n    window.snapPhoto = function() { const video = gE('ti-video-feed'); const canvas = gE('ti-canvas-snap'); if(video && canvas) { if (!video.videoWidth || !video.videoHeight) { try { if (window.log1088) window.log1088('DIAGNOSTICA 1280: snapPhoto tentata ma video senza dimensioni valide (videoWidth=' + video.videoWidth + ' videoHeight=' + video.videoHeight + ' readyState=' + video.readyState + ')'); } catch(eLog280){} if (window.tiDiagAlert) window.tiDiagAlert('Impossibile scattare la foto', 'Il video non sta ancora mostrando un\\'immagine valida (nessun fotogramma disponibile). Attendi qualche secondo che l\\'immagine appaia prima di scattare.'); else alert('Il video non sta ancora mostrando un\\'immagine valida. Attendi che l\\'immagine appaia prima di scattare.'); return; } canvas.width = video.videoWidth; canvas.height = video.videoHeight; canvas.getContext('2d').drawImage(video, 0, 0);\n        try {\n            var dataUrl1297 = canvas.toDataURL('image\/jpeg', 0.85);\n            var byteString1297 = atob(dataUrl1297.split(',')[1]);\n            var arrBuf1297 = new ArrayBuffer(byteString1297.length);\n            var ia1297 = new Uint8Array(arrBuf1297);\n            for (var i1297 = 0; i1297 < byteString1297.length; i1297++) { ia1297[i1297] = byteString1297.charCodeAt(i1297); }\n            var blob1297 = new Blob([ia1297], { type: 'image\/jpeg' });\n            const file = new File([blob1297], \"snap.jpg\", { type: \"image\/jpeg\" });\n            const dt = new DataTransfer(); dt.items.add(file);\n            const camIn = gE('ti-cam-in');\n            if(camIn) { camIn.files = dt.files; camIn.dispatchEvent(new Event('change')); try { if (window.addMsg) window.addMsg('ai', '<div class=\"ti-camera-photo-msg-1307\" data-ti-photo-ts=\"' + Date.now() + '\">\ud83d\udcf7 Foto scattata e inviata<br><img decoding=\"async\" src=\"' + dataUrl1297 + '\" style=\"max-width:220px;border-radius:8px;margin-top:6px;display:block;\"><\/div>'); } catch(eMsg1303){} }\n            window.closeCamModal();\n        } catch(eSync1297) {\n            try { if (window.tiDiagAlert) window.tiDiagAlert('Errore scatto foto', 'Conversione immagine fallita: ' + eSync1297.message); } catch(eB){}\n        } } else { try { if (window.tiDiagAlert) window.tiDiagAlert('Errore', 'Elemento video o canvas non trovato (video=' + !!video + ' canvas=' + !!canvas + ')'); } catch(eNF){} } };\n\n\n    window.tiSpeechPrimed = false;\n    window.primeSpeech = function() {\n        if (!('speechSynthesis' in window) || window.tiSpeechPrimed) return;\n        try {\n            const u = new SpeechSynthesisUtterance(' ');\n            u.volume = 0;\n            window.speechSynthesis.cancel();\n            window.speechSynthesis.speak(u);\n            window.tiSpeechPrimed = true;\n        } catch(e) {}\n    };\n    ['click','touchstart','keydown'].forEach(function(evt){\n        document.addEventListener(evt, function(){ window.primeSpeech(); }, { once:true, passive:true });\n    });\n\n    window.tiIsNoPopupVoiceRole = function() {\n        const role = String(window.tiRole || window.tiUserRole || window.currentUserRole || '').toLowerCase();\n        const user = String(window.tiUser || window.tiUsername || '').toLowerCase();\n        return user === 'ssglobaladmin' || \/amministratore|configuratore|responsabile\/.test(role);\n    };\n    window.tiHasVisiblePopupOrAlert = function() {\n        try {\n            return !!Array.from(document.querySelectorAll('.ti-ov, #ti-alert-ov, #ti-ai-loader-ov')).find(function(el){\n                if (!el) return false;\n                const cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n                const disp = cs ? cs.display : el.style.display;\n                const vis = cs ? cs.visibility : el.style.visibility;\n                return disp !== 'none' && vis !== 'hidden' && el.offsetParent !== null;\n            });\n        } catch(e) { return false; }\n    };\n    window.tiShouldSuppressPopupSpeech = function(text) {\n        if (!window.tiIsNoPopupVoiceRole || !window.tiIsNoPopupVoiceRole()) return false;\n        const raw = String(text || '');\n        const clean = raw.replace(\/<[^>]+>\/g, ' ').replace(\/\\s+\/g, ' ').trim().toLowerCase();\n        if (!clean) return false;\n        if (window.tiHasVisiblePopupOrAlert && window.tiHasVisiblePopupOrAlert()) return true;\n        return \/^(\u26a0|\u2757|attenzione|avviso|errore|conferma|operazione|seleziona|inserisci|nessun|solo|sessione|elaborazione|processo|salvataggio|login|accesso|richiesta)\/i.test(clean);\n    };\n\n    window.tiPrepareSpeechPunctuation = function(text) {\n        let s = String(text || '');\n        if (!s.trim()) return s;\n\n        \/\/ Protegge l'articolo eliso prima della pulizia della punteggiatura.\n        \/\/ Senza questa normalizzazione \"l'AI\" diventava \"l AI\" e alcune voci leggevano \"elle AI\".\n        s = s\n            .replace(\/\\b([Ll])[\\u2019']\\s*(AI|A\\.?I\\.?|IA)\\b\/g, function(m, art, acr) { return (art === 'L' ? 'La ' : 'la ') + acr.replace(\/\\.\/g, ''); })\n            .replace(\/\\b([Ll])[\\u2019']\\s*([A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff])\/g, function(m, art, chr) { return (art === 'L' ? 'L' : 'l') + chr; });\n\n        \/\/ Non trasformare mai i segni in parole (niente \"punto\", \"virgola\", \"segno di spunta\").\n        \/\/ I segni di fine frase diventano a-capo per ottenere una pausa vocale senza pronunciare il carattere.\n        s = s\n            .replace(\/\\.\\.\\.\/g, '\\n')\n            .replace(\/[.!?\u00bf\u00a1]+\/g, '\\n')\n            .replace(\/[,;:]+\/g, ' ')\n            .replace(\/[()\\[\\]{}<>]\/g, ' ')\n            .replace(\/[\"\u201c\u201d\u2018\u2019'`\u00b4]\/g, ' ')\n            .replace(\/[\\\/\\\\|]\/g, ' ')\n            .replace(\/\\s+[\u2013\u2014-]\\s+\/g, ' ')\n            .replace(\/[\u2013\u2014]\/g, ' ');\n\n        \/\/ Rimuove caratteri grafici\/simboli che alcune voci leggono letteralmente,\n        \/\/ ad esempio \"segno di spunta\", \"croce\", \"triangolo di attenzione\".\n        s = s\n            .replace(\/[\u2713\u2714\u2611\u2705\u2717\u2718\u274c\u2b55\u26d4\u26a0\u2757\u2753\u2b50\u2605\u2606\u25c6\u25c7\u25a0\u25a1\u25b2\u25b3\u25bc\u25bd\u25cf\u25cb\u2022\u00b7]\/g, ' ')\n            .replace(\/[\\u2600-\\u27BF\\u2B00-\\u2BFF]\/g, ' ')\n            .replace(\/[\\uFE0E\\uFE0F\\u200D]\/g, ' ')\n            .replace(\/[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]\/g, ' ')\n            .replace(\/[ \\t]+\/g, ' ')\n            .replace(\/\\n\\s+\/g, '\\n')\n            .replace(\/\\n{2,}\/g, '\\n')\n            .trim();\n\n        return s;\n    };\n\n\n    window.tiItalianNumberToWords498 = function(n){\n        n = Math.max(0, Math.floor(Number(n) || 0));\n        var ones = ['zero','uno','due','tre','quattro','cinque','sei','sette','otto','nove','dieci','undici','dodici','tredici','quattordici','quindici','sedici','diciassette','diciotto','diciannove'];\n        var tens = ['', '', 'venti','trenta','quaranta','cinquanta','sessanta','settanta','ottanta','novanta'];\n        function under100(x){\n            if (x < 20) return ones[x];\n            var t = Math.floor(x\/10), u = x % 10;\n            var w = tens[t];\n            if (u === 1 || u === 8) w = w.slice(0, -1);\n            return w + (u ? ones[u] : '');\n        }\n        function under1000(x){\n            if (x < 100) return under100(x);\n            var h = Math.floor(x\/100), r = x % 100;\n            var w = (h === 1 ? 'cento' : ones[h] + 'cento');\n            if (r >= 80 && r < 90) w = w.slice(0, -1);\n            return w + (r ? under100(r) : '');\n        }\n        function words(x){\n            if (x < 1000) return under1000(x);\n            if (x < 1000000) {\n                var k = Math.floor(x\/1000), r = x % 1000;\n                var wk = (k === 1 ? 'mille' : words(k) + 'mila');\n                return wk + (r ? under1000(r) : '');\n            }\n            if (x < 1000000000) {\n                var m = Math.floor(x\/1000000), r2 = x % 1000000;\n                var wm = (m === 1 ? 'un milione' : words(m) + ' milioni');\n                return wm + (r2 ? ' ' + words(r2) : '');\n            }\n            return String(x);\n        }\n        return words(n);\n    };\n\n    window.tiPrepareEuroSpeech498 = function(text){\n        var s = String(text || '');\n        function normalizeNum(num){\n            num = String(num || '').replace(\/\\s\/g, '');\n            var parts = num.split(',');\n            var intPart = parts[0].replace(\/\\.\/g, '');\n            var cents = parts.length > 1 ? (parts[1] || '').replace(\/\\D\/g, '').slice(0,2) : '';\n            var value = parseInt(intPart, 10);\n            if (!isFinite(value) || isNaN(value)) return '';\n            \/\/ Per importi con migliaia, la voce deve evidenziare le migliaia e non leggere il punto come decimale.\n            \/\/ Esempio richiesto: \u20ac 46.800,00 -> quarantaseimila euro.\n            if (value >= 1000 && \/\\.\/.test(num)) {\n                var thousandsOnly = Math.floor(value \/ 1000) * 1000;\n                return window.tiItalianNumberToWords498(thousandsOnly) + ' euro';\n            }\n            var out = window.tiItalianNumberToWords498(value) + (value === 1 ? ' euro' : ' euro');\n            var c = cents ? parseInt(cents.padEnd(2, '0'), 10) : 0;\n            if (c > 0) out += ' e ' + window.tiItalianNumberToWords498(c) + ' centesimi';\n            return out;\n        }\n        s = s.replace(\/\u20ac\\s*([0-9]{1,3}(?:\\.[0-9]{3})+(?:,[0-9]{1,2})?|[0-9]+(?:,[0-9]{1,2})?)\/g, function(m, n){ return normalizeNum(n) || m; });\n        s = s.replace(\/([0-9]{1,3}(?:\\.[0-9]{3})+(?:,[0-9]{1,2})?|[0-9]+(?:,[0-9]{1,2})?)\\s*\u20ac\/g, function(m, n){ return normalizeNum(n) || m; });\n        return s;\n    };\n\n    \/\/ 30.9.1901 - Audio liste numerate: oltre 3 voci non leggere l elenco completo.\n    \/\/ La UI\/testo resta invariata; la voce annuncia soltanto la presenza della tabella per scelte rapide.\n    window.tiNumberedListCount1901 = function(rawText) {\n        var raw1901 = String(rawText == null ? '' : rawText);\n        if (!raw1901) return 0;\n        var plain1901 = raw1901\n            .replace(\/<\\s*br\\s*\\\/?\\s*>\/gi, '\\n')\n            .replace(\/<\\\/\\s*(?:p|div|li|tr|h[1-6])\\s*>\/gi, '\\n')\n            .replace(\/<[^>]+>\/g, ' ');\n        var md1901 = plain1901.match(\/(?:^|\\n)\\s*(?:[-*]\\s*)?\\d{1,3}\\s*[\\.\\)]\\s+\/gm) || [];\n        if (md1901.length > 0) return md1901.length;\n        var ol1901 = raw1901.match(\/<li(?:\\s[^>]*)?>\/gi) || [];\n        var hasOl1901 = \/<ol(?:\\s[^>]*)?>\/i.test(raw1901);\n        return hasOl1901 ? ol1901.length : 0;\n    };\n    window.tiStopCurrentChatSpeech1901 = function(reason1901) {\n        try {\n            if (window.speechSynthesis) {\n                window.speechSynthesis.cancel();\n                try { console.info('[Shop-Service] audio 1901: lettura corrente interrotta', {reason:String(reason1901||'prosecuzione processo')}); } catch(eLog1901) {}\n            }\n        } catch(e1901) {}\n    };\n\n    \/\/ 30.9.1902 - Se un ordine appena confermato contiene piu di una voce,\n    \/\/ non leggere il corpo della risposta: conferma soltanto l ordine e le eventuali note esplicite.\n    window.tiCompactConfirmedOrderSpeech1902 = function(rawText1902) {\n        var raw1902 = String(rawText1902 == null ? '' : rawText1902);\n        if (!raw1902 || !\/(?:ordine\\s+(?:definitivamente\\s+)?confermat|ordine\\s+salvato|order\\s+confirmed)\/i.test(raw1902)) return '';\n\n        var count1902 = 0;\n        try {\n            var st1902 = window.tiEditableOrder1718;\n            if (st1902 && st1902.lines && typeof st1902.lines === 'object') {\n                count1902 = Object.keys(st1902.lines).filter(function(k1902){\n                    var x1902 = st1902.lines[k1902];\n                    return x1902 && Number(x1902.qty || 0) > 0;\n                }).length;\n            }\n        } catch(eState1902) {}\n        if (count1902 < 2) {\n            try {\n                var rows1902 = document.querySelectorAll('#ti-order-confirm-host .ti-order-review-table-1718 tbody tr[data-key], #ti-ai-outer .ti-order-review-table-1718 tbody tr[data-key]');\n                if (rows1902 && rows1902.length) count1902 = rows1902.length;\n            } catch(eDom1902) {}\n        }\n        if (count1902 < 2) {\n            var p1902 = raw1902.match(\/\\[P\\][\\s\\S]*?\\[\\\/P\\]\/g) || [];\n            if (p1902.length) count1902 = p1902.length;\n        }\n        if (count1902 < 2) return '';\n\n        var plain1902 = raw1902\n            .replace(\/<!--NOAUDIO_START-->[\\s\\S]*?<!--NOAUDIO_END-->\/g, '')\n            .replace(\/<\\s*br\\s*\\\/?\\s*>\/gi, '\\n')\n            .replace(\/<\\\/\\s*(?:p|div|li|tr|h[1-6])\\s*>\/gi, '\\n')\n            .replace(\/<[^>]+>\/g, ' ');\n        try {\n            var ta1902 = document.createElement('textarea');\n            ta1902.innerHTML = plain1902;\n            plain1902 = ta1902.value;\n        } catch(eDecode1902) {}\n        plain1902 = plain1902.replace(\/[*_#~`]\/g, '').replace(\/\\r\/g, '');\n\n        var notes1902 = [];\n        plain1902.split(\/\\n+\/).forEach(function(line1902){\n            var l1902 = String(line1902 || '').replace(\/\\s+\/g, ' ').trim();\n            if (!l1902) return;\n            var m1902 = l1902.match(\/^(?:nota(?:\\s+dell[\u2019']?ordine|\\s+ordine)?|note(?:\\s+dell[\u2019']?ordine|\\s+ordine)?|indicazioni\\s+ordine)\\s*[:\\-]\\s*(.+)$\/i);\n            if (!m1902 || !m1902[1]) return;\n            var n1902 = String(m1902[1]).trim();\n            if (!n1902 || \/\\$sys\\s*[:=]\/i.test(n1902) || \/\\[percorso riservato\\]\/i.test(n1902)) return;\n            if (notes1902.indexOf(n1902) < 0) notes1902.push(n1902);\n        });\n\n        var en1902 = String(window.currLang || 'it').toLowerCase() === 'en';\n        var out1902 = en1902 ? 'Order confirmed.' : 'Ordine confermato.';\n        if (notes1902.length) out1902 += (en1902 ? ' Order notes: ' : ' Note ordine: ') + notes1902.join('. ');\n        try { console.info('[Shop-Service] audio 1902: conferma ordine multi-voce sintetica', {voci:count1902,note:notes1902.length}); } catch(eLog1902) {}\n        return out1902;\n    };\n\n    window.speakText = function(text) {\n        if (!('speechSynthesis' in window) || window.isMuted) return; \n        let raw = String(text || '');\n        var compactOrder1902 = window.tiCompactConfirmedOrderSpeech1902 ? window.tiCompactConfirmedOrderSpeech1902(raw) : '';\n        if (compactOrder1902) raw = compactOrder1902;\n        var numberedCount1901 = compactOrder1902 ? 0 : (window.tiNumberedListCount1901 ? window.tiNumberedListCount1901(raw) : 0);\n        if (numberedCount1901 > 3) {\n            raw = (String(window.currLang || 'it').toLowerCase() === 'en')\n                ? 'A table with the available items is shown for quick choices.'\n                : 'E disponibile la tabella con le voci per eventuali scelte rapide.';\n            try { console.info('[Shop-Service] audio 1901: elenco numerato non letto', {voci:numberedCount1901}); } catch(eList1901) {}\n        }\n        if (window.tiShouldSuppressPopupSpeech && window.tiShouldSuppressPopupSpeech(raw)) return;\n        window.primeSpeech();\n        window.speechSynthesis.cancel();\n\n        raw = raw.replace(\/<!--NOAUDIO_START-->[\\s\\S]*?<!--NOAUDIO_END-->\/g, '');\n        raw = raw.replace(\/<div[^>]*class=[\"'][^\"']*ti-company-state-warning[^\"']*[\"'][^>]*>[\\s\\S]*?<\\\/div>\/gi, '');\n        raw = raw.replace(\/<div[^>]*>\\s*\u26a0\ufe0f\\s*Stato ditta:[\\s\\S]*?<\\\/div>\/gi, '');\n        raw = raw.replace(\/\u26a0\ufe0f\\s*Stato ditta:\\s*(Configurazione|Sospesa)[\\s\\S]*?(?=(Sono l'assistente|Come posso|$))\/gi, '');\n        raw = raw.replace(\/Attenzione\\.\\s*La ditta risulta (sospesa|in configurazione)\\.[\\s\\S]*?(?=(Sono l'assistente|Come posso|$))\/gi, '');\n        raw = raw.replace(\/<div[^>]*>\\s*<b>\\s*\u2139\ufe0f\\s*Report esecuzione istruzioni AI<\\\/b>[\\s\\S]*?<\\\/div>\/gi, '');\n        let clean = raw.replace(\/\\[TABLE\\][\\s\\S]*?\\[\\\/TABLE\\]\/g, '').replace(\/\\[P\\][\\s\\S]*?\\[\\\/P\\]\/g, '').replace(\/<\\s*br\\s*\\\/?\\s*>\/gi, '\\n').replace(\/<\\\/(p|div|li|tr|h[1-6])>\/gi, '\\n').replace(\/<[^>]+>\/g, ' ').trim();\n        clean = clean.replace(\/[*_#~`]\/g, ''); \n        clean = clean.replace(\/(\\d{1,2})\\\/(\\d{1,2})\\\/(\\d{4})\/g, \"$1 del $2 $3\");\n        clean = clean.replace(\/(\\d{1,2})\\\/(\\d{1,2})\/g, \"$1 del $2\");\n        clean = clean.replace(\/(\\d{1,2}):(\\d{2})\/g, \"$1 e $2 minuti\");\n        clean = clean.replace(\/tasto\\s+X\\b\/gi, \"tasto ixs\");\n        clean = clean.replace(\/\\bX\\b(?=\\s*per\\s+annullare)\/gi, \"ixs\");\n        if (window.tiPrepareEuroSpeech498) clean = window.tiPrepareEuroSpeech498(clean);\n        if (window.tiPrepareSpeechPunctuation) clean = window.tiPrepareSpeechPunctuation(clean);\n\n        if (clean) { \n            let u = new SpeechSynthesisUtterance(clean); \n            u.lang = window.currLang === 'en' ? 'en-US' : 'it-IT'; u.rate = 1.0; u.pitch = 1.2; \n            let voices = window.speechSynthesis.getVoices();\n            if(voices.length > 0) {\n                let femaleVoice = voices.find(v => v.lang.includes(u.lang) && (v.name.includes('Google') || v.name.includes('Elsa') || v.name.includes('Bianca') || v.name.includes('Female') || v.name.includes('Samantha') || v.name.includes('Victoria') || v.name.includes('Jenny') || v.name.includes('Zira') || v.name.includes('Hazel')));\n                if(femaleVoice) { u.voice = femaleVoice; } else { let langVoice = voices.find(v => v.lang.includes(u.lang)); if(langVoice) u.voice = langVoice; }\n            }\n            setTimeout(() => { window.speechSynthesis.speak(u); }, 150);\n        }\n    };\n    if ('speechSynthesis' in window) { window.speechSynthesis.onvoiceschanged = function() { window.speechSynthesis.getVoices(); }; }\n\n    window.extractCurrentUserEmailFromData = function(data) {\n        try {\n            if (!data || !data.Tabelle || !window.tiUser || window.tiUser === 'SSGlobalAdmin') return '';\n            const tables = ['Utenti', 'Operatori'];\n            for (const tbl of tables) {\n                const rows = Array.isArray(data.Tabelle[tbl]) ? data.Tabelle[tbl] : Object.values((data.Tabelle && data.Tabelle[tbl]) || {});\n                for (const row of rows) {\n                    if (!row || typeof row !== 'object') continue;\n                    const userKey = Object.keys(row).find(k => String(k).toLowerCase() === 'username' || String(k).toLowerCase() === 'user');\n                    if (!userKey) continue;\n                    if (String(row[userKey] || '').trim().toLowerCase() !== String(window.tiUser || '').trim().toLowerCase()) continue;\n                    const emailKey = Object.keys(row).find(k => String(k).toLowerCase() === 'email');\n                    const email = emailKey ? String(row[emailKey] || '').trim() : '';\n                    if (email) return email;\n                }\n            }\n        } catch(e) {}\n        return '';\n    };\n\n    window.prefillSupportFeedbackForm = function(forceRefresh) {\n        const emailInput = gE('ti-support-email');\n        const infoBox = gE('help-email');\n        if (!emailInput) return Promise.resolve('');\n        if (!forceRefresh && String(emailInput.value || '').trim() !== '') {\n            const keepVal = String(emailInput.value || '').trim();\n            if (infoBox) infoBox.innerHTML = keepVal ? '<div style=\"font-size:12px;color:#93c5fd;\">Email utente proposta: <b>' + window.escapeHtml(keepVal) + '<\/b><\/div>' : '';\n            return Promise.resolve(keepVal);\n        }\n        const localEmail = window.extractCurrentUserEmailFromData(window.currentDbData);\n        if (localEmail) {\n            emailInput.value = localEmail;\n            if (infoBox) infoBox.innerHTML = '<div style=\"font-size:12px;color:#93c5fd;\">Email utente proposta: <b>' + window.escapeHtml(localEmail) + '<\/b><\/div>';\n            return Promise.resolve(localEmail);\n        }\n        const dbSel = gE('ti-ditta');\n        if (!dbSel || !dbSel.value || dbSel.value === 'NEW_DB' || !window.tiUser || window.tiUser === 'SSGlobalAdmin') {\n            if (infoBox) infoBox.innerHTML = '';\n            return Promise.resolve('');\n        }\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_get_db_data');\n        fd.append('db', dbSel.value);\n        return window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n            const email = (res && res.success && res.data) ? window.extractCurrentUserEmailFromData(res.data) : '';\n            if (email) {\n                window.currentDbData = res.data;\n                emailInput.value = email;\n                if (infoBox) infoBox.innerHTML = '<div style=\"font-size:12px;color:#93c5fd;\">Email utente proposta: <b>' + window.escapeHtml(email) + '<\/b><\/div>';\n            } else if (infoBox) {\n                infoBox.innerHTML = '';\n            }\n            return email;\n        }).catch(function(){ if (infoBox) infoBox.innerHTML = ''; return ''; });\n    };\n\n    window.toggleSupportFeedbackBox = function(forceOpen) {\n        const box = gE('ti-help-support-box');\n        const toggleBtn = gE('ti-help-support-toggle');\n        if (!box) return;\n        const shouldOpen = (typeof forceOpen === 'boolean') ? forceOpen : (box.style.display === 'none' || box.style.display === '');\n        box.style.display = shouldOpen ? 'block' : 'none';\n        if (toggleBtn) toggleBtn.innerText = shouldOpen ? '\u2716\ufe0f Chiudi segnalazione assistenza' : '\ud83d\udee0\ufe0f Segnalazione assistenza tecnica';\n        if (shouldOpen) {\n            window.prefillSupportFeedbackForm(true).then(function(){ const sbj = gE('ti-support-subject'); if (sbj && !sbj.value) sbj.focus(); });\n        }\n    };\n\n    window.getSupportFeedbackChatHistory = function() {\n        const chat = gE('ti-chat-box');\n        if (!chat) return '';\n        const lines = [];\n        const bubbles = Array.from(chat.querySelectorAll('.ti-bubble')).slice(-30);\n        bubbles.forEach(function(b){\n            const clone = b.cloneNode(true);\n            clone.querySelectorAll('table, .ti-order-grid-view, .ti-order-toolbar, .ti-order-filterbar, .ti-cfg-top-scroll, .ti-cfg-bottom-scroll, .ti-order-top-scroll, .ti-order-bottom-scroll').forEach(function(n){ n.remove(); });\n            const txt = String(clone.innerText || '').trim();\n            if (!txt || txt.indexOf('Fammi pensare') !== -1) return;\n            lines.push((b.classList.contains('user') ? 'Utente' : 'Assistente') + ': ' + txt);\n        });\n        let out = lines.join('\\n\\n').trim();\n        if (out.length > 15000) out = out.slice(out.length - 15000);\n        return out;\n    };\n\n    window.sendSupportFeedback = function() {\n        const dbSel = gE('ti-ditta');\n        const email = (gE('ti-support-email') ? gE('ti-support-email').value : '').trim();\n        const subject = (gE('ti-support-subject') ? gE('ti-support-subject').value : '').trim();\n        const message = (gE('ti-support-message') ? gE('ti-support-message').value : '').trim();\n        const sendBtn = gE('ti-support-send');\n        if (!subject) { window.tiAlert('Oggetto obbligatorio.'); return; }\n        if (!message) { window.tiAlert('Inserisci il testo della segnalazione.'); return; }\n        if (email && !\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(email)) { window.tiAlert('Email mittente non valida.'); return; }\n        const fd = new FormData();\n        fd.append('ti_action', 'ti_ai_send_email');\n        fd.append('mode', 'support_feedback');\n        fd.append('db', dbSel && dbSel.value ? dbSel.value : 'NEW_DB');\n        fd.append('sender_email', email);\n        fd.append('feedback_subject', subject);\n        fd.append('feedback_message', message);\n        fd.append('chat_history', window.getSupportFeedbackChatHistory());\n        if (sendBtn) { sendBtn.disabled = true; sendBtn.innerText = 'Invio in corso...'; }\n        window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n            if (sendBtn) { sendBtn.disabled = false; sendBtn.innerText = 'Invia segnalazione'; }\n            if (res && res.success) {\n                if (gE('ti-support-subject')) gE('ti-support-subject').value = '';\n                if (gE('ti-support-message')) gE('ti-support-message').value = '';\n                window.toggleSupportFeedbackBox(false);\n                window.tiAlert((res.data && res.data.reply) ? res.data.reply : 'La segnalazione sar\u00e0 analizzata per eventualmente rispondere.<br><br>Grazie per la collaborazione.');\n            } else {\n                window.tiAlert((res && res.data && res.data.message) ? res.data.message : 'Errore invio segnalazione.');\n            }\n        }).catch(function(err){ if (sendBtn) { sendBtn.disabled = false; sendBtn.innerText = 'Invia segnalazione'; } window.tiAlert('Errore invio segnalazione: ' + ((err && err.message) ? err.message : 'errore sconosciuto')); });\n    };\n\n    window.openHelpModal = function() {\n        window.prefillSupportFeedbackForm(true);\n        window.openModal('ti-help-ov');\n    };\n\n    window.sendHelpChat = () => {\n        const msg = gE('help-bot-in').value; if(!msg) return;\n        const replyBox = gE('help-bot-reply');\n        replyBox.innerHTML = \"<i>Analizzo il manuale... \u23f3<\/i>\";\n        gE('help-bot-in').value = '';\n        \n        const fd = new FormData(); fd.append('ti_action','ti_ai_chat_start'); fd.append('db', gE('ti-ditta').value || 'NEW_DB');\n        fd.append('text', \"DOMANDA SUL MANUALE CONFIGURAZIONE: Rispondi solo con informazioni operative chiare ed esempi di compilazione basati su manuale, schema standard e dati disponibili. Non riportare frasi su campi vuoti, colonne senza nome o valori \\\"\\\". Domanda: \" + msg);\n        \n        fetch(window.tiUrl,{method:'POST',body:fd}).then(r=>r.json()).then(res=>{\n            if(res.success) { replyBox.innerHTML = res.data.reply.replace(\/\\n\/g, '<br>'); } \n            else { replyBox.innerHTML = \"<span style='color:#ef4444;'>Errore AI. Controlla la connessione.<\/span>\"; }\n        });\n    };\n\n    window.applyMuteState = function() {\n        const muteBtn = gE('ti-mute-btn'); if(!muteBtn) return;\n        const d = dict[window.currLang] || dict['it'];\n        if(window.muteState === 0) {\n            window.isMuted = false;\n            muteBtn.innerText = d.muteOn;\n            muteBtn.style.background = '#222';\n            muteBtn.style.borderColor = '#444';\n        } else if (window.muteState === 1) {\n            window.isMuted = true;\n            muteBtn.innerText = d.muteOff;\n            muteBtn.style.background = '#b91c1c';\n            muteBtn.style.borderColor = '#991b1b';\n        } else if (window.muteState === 2) {\n            window.isMuted = true;\n            muteBtn.innerText = d.muteOff;\n            muteBtn.style.background = '#b91c1c';\n            muteBtn.style.borderColor = '#991b1b';\n        }\n    };\n\n    window.tiTranslateHtmlLocallyToCurrentLanguage = function(html) {\n        html = String(html || '');\n        if (!html.trim() || String(window.currLang || 'it').toLowerCase() !== 'en') return html;\n        const box = document.createElement('div');\n        box.innerHTML = html;\n        try {\n            if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(box);\n            if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(box);\n        } catch(e) {}\n        return box.innerHTML || html;\n    };\n    window.tiRemoteTranslateHtmlForCurrentLanguage = function(html, dbValue) {\n        return Promise.resolve(window.tiTranslateHtmlLocallyToCurrentLanguage ? window.tiTranslateHtmlLocallyToCurrentLanguage(html) : String(html || ''));\n    };\n    window.tiAddAiMessageTranslatedIfNeeded = function(html, voice, dbValue) {\n        const originalHtml = String(html || '');\n        const originalVoice = String(voice || originalHtml || '');\n        const bubble = window.addMsg ? window.addMsg('ai', originalHtml, originalHtml) : null;\n        let voiceSource = originalVoice;\n        if (String(window.currLang || 'it').toLowerCase() === 'en') {\n            voiceSource = bubble ? String(bubble.innerText || bubble.textContent || '') : (window.tiTranslateHtmlLocallyToCurrentLanguage ? window.tiTranslateHtmlLocallyToCurrentLanguage(originalVoice) : originalVoice);\n            voiceSource = String(voiceSource || '').replace(\/<[^>]+>\/g, ' ').replace(\/\\s+\/g, ' ').trim();\n            if (window.tiQueueRemoteEnglishChatTranslation && bubble) window.tiQueueRemoteEnglishChatTranslation(bubble, originalHtml, dbValue);\n        }\n        if (voiceSource && window.speakText) window.speakText(voiceSource);\n        return bubble;\n    };\n\n\n    window.tiChatTranslationCache = window.tiChatTranslationCache || Object.create(null);\n    window.tiChatTranslationPending = window.tiChatTranslationPending || Object.create(null);\n    window.tiHashString = function(str) {\n        str = String(str == null ? '' : str);\n        let h = 0;\n        for (let i = 0; i < str.length; i++) { h = ((h << 5) - h + str.charCodeAt(i)) | 0; }\n        return String(h >>> 0) + '_' + String(str.length);\n    };\n    window.tiRememberVisibleChatLanguage = function(lang) {\n        lang = String(lang || window.currLang || 'it').toLowerCase();\n        document.querySelectorAll('.ti-bubble.ai').forEach(function(b){\n            if (!b.__tiChatHtmlByLang) b.__tiChatHtmlByLang = {};\n            if (!b.__tiChatHtmlByLang[lang]) b.__tiChatHtmlByLang[lang] = b.innerHTML;\n        });\n    };\n    window.tiRemoteTranslateHtmlToLanguage = function(html, targetLang, dbValue, fallback) {\n        targetLang = String(targetLang || 'it').toLowerCase() === 'en' ? 'en' : 'it';\n        html = String(html || '');\n        const localFallback = (fallback !== undefined) ? fallback : html;\n        if (!html.trim()) return Promise.resolve(html);\n        const cacheKey = targetLang + ':' + window.tiHashString(html);\n        if (window.tiChatTranslationCache && Object.prototype.hasOwnProperty.call(window.tiChatTranslationCache, cacheKey)) {\n            return Promise.resolve(window.tiChatTranslationCache[cacheKey]);\n        }\n        if (window.tiChatTranslationPending && window.tiChatTranslationPending[cacheKey]) return window.tiChatTranslationPending[cacheKey];\n        try {\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_chat_start');\n            fd.append('db', dbValue || (gE('ti-ditta') ? gE('ti-ditta').value : '') || '');\n            fd.append('text', 'TRADUCI_ESATTAMENTE_QUESTO_HTML_IN_' + targetLang.toUpperCase() + ': ' + html);\n            if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd);\n            const pending = fetch(window.tiUrl, {method:'POST', body:fd})\n                .then(function(r){ return r.json(); })\n                .then(function(res){\n                    const out = (res && res.success && res.data && res.data.reply) ? String(res.data.reply || '') : localFallback;\n                    window.tiChatTranslationCache[cacheKey] = out;\n                    delete window.tiChatTranslationPending[cacheKey];\n                    return out;\n                })\n                .catch(function(){ delete window.tiChatTranslationPending[cacheKey]; return localFallback; });\n            window.tiChatTranslationPending[cacheKey] = pending;\n            return pending;\n        } catch(e) { return Promise.resolve(localFallback); }\n    };\n    window.tiQueueRemoteEnglishChatTranslation = function(bubble, sourceHtml, dbValue) {\n        if (!bubble || !sourceHtml || String(window.currLang || 'it').toLowerCase() !== 'en') return;\n        sourceHtml = String(sourceHtml || '');\n        if (!sourceHtml.trim() || sourceHtml.length > 24000) return;\n        if (!window.tiRemoteTranslateHtmlToLanguage) return;\n        const sourceKey = window.tiHashString ? window.tiHashString(sourceHtml) : String(sourceHtml.length);\n        if (bubble.__tiRemoteEnSourceKey === sourceKey) return;\n        bubble.__tiRemoteEnSourceKey = sourceKey;\n        const timeout = new Promise(function(resolve){ setTimeout(function(){ resolve(null); }, 6500); });\n        Promise.race([window.tiRemoteTranslateHtmlToLanguage(sourceHtml, 'en', dbValue || (gE('ti-ditta') ? gE('ti-ditta').value : ''), null), timeout]).then(function(outHtml){\n            if (!outHtml || String(window.currLang || 'it').toLowerCase() !== 'en') return;\n            const currentIt = bubble.getAttribute('data-ti-it-html') || (bubble.__tiChatHtmlByLang && bubble.__tiChatHtmlByLang.it) || '';\n            if (currentIt && currentIt !== sourceHtml) return;\n            bubble.innerHTML = String(outHtml || '');\n            bubble.__tiChatHtmlByLang = bubble.__tiChatHtmlByLang || {};\n            bubble.__tiChatHtmlByLang.en = bubble.innerHTML;\n            try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(bubble); } catch(e) {}\n        }).catch(function(){});\n    };\n    window.tiTranslateChatBubblesForLanguage = function(targetLang, force) {\n        targetLang = String(targetLang || window.currLang || 'it').toLowerCase() === 'en' ? 'en' : 'it';\n        const bubbles = Array.from(document.querySelectorAll('.ti-bubble.ai')).slice(-80);\n        bubbles.forEach(function(bubble){\n            if (!bubble) return;\n            if (!bubble.__tiChatHtmlByLang) bubble.__tiChatHtmlByLang = {};\n            const rawSource = bubble.getAttribute('data-raw-source') || '';\n            const storedIt = bubble.getAttribute('data-ti-it-html') || bubble.__tiChatHtmlByLang.it || rawSource || bubble.innerHTML;\n            if (targetLang === 'it') {\n                bubble.innerHTML = storedIt;\n                bubble.__tiChatHtmlByLang.it = storedIt;\n                bubble.setAttribute('data-ti-it-html', storedIt);\n                try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(bubble); } catch(e) {}\n                return;\n            }\n            if (!force && bubble.__tiChatHtmlByLang.en) {\n                bubble.innerHTML = bubble.__tiChatHtmlByLang.en;\n                try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(bubble); } catch(e) {}\n                return;\n            }\n            if (rawSource && \/\\[TABLE\\]|\\[P\\]\/.test(rawSource) && window.formatTable) {\n                bubble.innerHTML = window.formatTable(rawSource);\n                try {\n                    if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(bubble);\n                    if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(bubble);\n                    if (window.tiExtractOrderAiResponseFromBubble637) window.tiExtractOrderAiResponseFromBubble637(bubble);\n                } catch(e) {}\n                bubble.__tiChatHtmlByLang.en = bubble.innerHTML;\n                return;\n            }\n            bubble.innerHTML = storedIt;\n            try {\n                if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(bubble);\n                if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(bubble);\n            } catch(e) {}\n            bubble.__tiChatHtmlByLang.en = bubble.innerHTML;\n            if (window.tiQueueRemoteEnglishChatTranslation) window.tiQueueRemoteEnglishChatTranslation(bubble, storedIt, (gE('ti-ditta') ? gE('ti-ditta').value : ''));\n        });\n    };\n    window.forceApplyCurrentLanguageEverywhere = function(reason) {\n        try {\n            if (!['it','en'].includes(String(window.currLang || '').toLowerCase())) window.currLang = 'it';\n            if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(document.body || document.documentElement);\n            if (window.applyLayoutLanguage) window.applyLayoutLanguage(true);\n            if (window.tiTranslateChatBubblesForLanguage) window.tiTranslateChatBubblesForLanguage(window.currLang, true);\n            [60, 180, 420, 900].forEach(function(ms){\n                setTimeout(function(){\n                    try {\n                        if (window.applyLayoutLanguage) window.applyLayoutLanguage(true);\n                        if (window.tiTranslateChatBubblesForLanguage) window.tiTranslateChatBubblesForLanguage(window.currLang, true);\n                    } catch(e) {}\n                }, ms);\n            });\n        } catch(e) { try { console.warn('Shop & Service forced language apply error', e); } catch(ignore) {} }\n    };\n    window.setShopServiceLanguage = function(lang) {\n        const dittaSel = gE('ti-ditta');\n        const selectedDbBefore = dittaSel && dittaSel.value ? dittaSel.value : (window.tiCurrentSelectedDb || localStorage.getItem('ti_saved_db') || '');\n        const previousLang = String(window.currLang || 'it').toLowerCase() === 'en' ? 'en' : 'it';\n        if (window.tiRememberVisibleChatLanguage) window.tiRememberVisibleChatLanguage(previousLang);\n        window.currLang = String(lang || 'it').toLowerCase() === 'en' ? 'en' : 'it';\n        if (window.tiI18nClearCache) window.tiI18nClearCache();\n        localStorage.setItem('ti_lang_' + window.tiUser, window.currLang);\n        if (selectedDbBefore) window.tiCurrentSelectedDb = selectedDbBefore;\n        try { document.querySelectorAll('.ti-lang-opt').forEach(function(e){ e.classList.toggle('active', String(e.dataset.lang || '') === window.currLang); }); } catch(e) {}\n        try {\n            if (dittaSel && selectedDbBefore && Array.from(dittaSel.options || []).some(function(o){ return o.value === selectedDbBefore; })) {\n                dittaSel.value = selectedDbBefore;\n                if (selectedDbBefore !== 'NEW_DB') localStorage.setItem('ti_saved_db', selectedDbBefore);\n            }\n            if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n            if (window.syncDittaTrigger) window.syncDittaTrigger();\n            if (window.applyCompanyLimitedNotice) window.applyCompanyLimitedNotice();\n        } catch(e) {}\n        try {\n            const d = dict[window.currLang] || dict['it'];\n            if(gE('ti-msg')) gE('ti-msg').placeholder = d.ph;\n            if(gE('ti-send')) gE('ti-send').innerText = d.send;\n            if(gE('ti-new')) gE('ti-new').innerText = d.new;\n            if(gE('ti-copy')) { gE('ti-copy').innerText = d.copy; }\n            if(gE('ti-file')) gE('ti-file').innerText = d.file;\n            if(gE('ti-products-btn')) gE('ti-products-btn').innerText = d.products || 'Prodotti';\n            if(gE('ti-services-btn')) gE('ti-services-btn').innerText = d.services || 'Servizi';\n            if(gE('ti-activities-btn')) gE('ti-activities-btn').innerText = d.activities || (window.currLang === 'en' ? 'Activities' : 'Attivit\u00e0');\n            if(gE('ti-kbd-btn')) gE('ti-kbd-btn').innerText = d.kbd;\n            if(gE('ti-mic')) gE('ti-mic').innerText = d.mic;\n            if(gE('ti-cam')) gE('ti-cam').innerText = d.cam;\n            if(gE('ti-login-btn') && gE('ti-login-btn').style.display !== 'none') gE('ti-login-btn').innerText = d.login || (window.currLang === 'en' ? 'Login' : 'Accedi');\n        } catch(e) {}\n        try { if (window.applyMuteState) window.applyMuteState(); } catch(e) {}\n        window.forceApplyCurrentLanguageEverywhere('language-switch');\n        if (window.currLang === 'en' && typeof window.fetchDitteList === 'function') {\n            try {\n                window.fetchDitteList({silent:true}).then(function(){\n                    try {\n                        const dsNow = gE('ti-ditta');\n                        if (dsNow && selectedDbBefore && Array.from(dsNow.options || []).some(function(o){ return o.value === selectedDbBefore; })) {\n                            dsNow.value = selectedDbBefore;\n                            window.tiCurrentSelectedDb = selectedDbBefore;\n                            if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n                        }\n                        if (window.forceApplyCurrentLanguageEverywhere) window.forceApplyCurrentLanguageEverywhere('language-switch-ditta-refresh');\n                    } catch(e) {}\n                }).catch(function(){});\n            } catch(e) {}\n        }\n        setTimeout(function(){\n            try {\n                const ds = gE('ti-ditta');\n                if (ds && selectedDbBefore && Array.from(ds.options || []).some(function(o){ return o.value === selectedDbBefore; })) {\n                    ds.value = selectedDbBefore;\n                    window.tiCurrentSelectedDb = selectedDbBefore;\n                    if (selectedDbBefore !== 'NEW_DB') localStorage.setItem('ti_saved_db', selectedDbBefore);\n                    if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n                }\n            } catch(e) {}\n        }, 250);\n    };\n\n    if (!window.__tiLangSwitchDelegatedBound) {\n        window.__tiLangSwitchDelegatedBound = true;\n        document.addEventListener('click', function(ev) {\n            const target = ev.target && ev.target.closest ? ev.target.closest('.ti-lang-opt') : null;\n            if (!target) return;\n            ev.preventDefault();\n            ev.stopPropagation();\n            window.setShopServiceLanguage(target.dataset.lang || 'it');\n        }, true);\n    }\n    document.querySelectorAll('.ti-lang-opt').forEach(function(el) {\n        el.onclick = function(ev) {\n            if (ev) { ev.preventDefault(); ev.stopPropagation(); }\n            window.setShopServiceLanguage(this.dataset.lang || 'it');\n        };\n    });\n\n    document.addEventListener(\"DOMContentLoaded\", function() {\n        const confAiBtn = gE('ti-conf-ai-send');\n        if (confAiBtn) confAiBtn.onclick = window.runConfigBot;\n        const dom = { chat: gE('ti-chat-box'), ditta: gE('ti-ditta'), msg: gE('ti-msg'), send: gE('ti-send'), btnNew: gE('ti-new') };\n\n        \/\/ 30.9.1903: conserva il testo usato per cercare una ditta e lo riporta nella\n        \/\/ chatbot della ditta scelta. sessionStorage consente di superare anche un eventuale\n        \/\/ reload\/logout tecnico durante il cambio ditta senza scrivere nulla nel database.\n        window.tiStoreCompanySearchCarry1903 = function(text, dbValue) {\n            const q = String(text || '').replace(\/\\u00a0\/g, ' ').trim();\n            const db1903 = String(dbValue || '').trim();\n            if (!q || !db1903 || db1903 === 'NEW_DB') return false;\n            const payload1903 = { text:q, db:db1903, ts:Date.now() };\n            window.__tiCompanySearchCarry1903 = payload1903;\n            try { sessionStorage.setItem('ti_company_search_carry_1903', JSON.stringify(payload1903)); } catch(e) {}\n            return true;\n        };\n        window.tiReadCompanySearchCarry1903 = function(dbValue) {\n            const db1903 = String(dbValue || '').trim();\n            let p1903 = window.__tiCompanySearchCarry1903 || null;\n            if (!p1903) {\n                try { const raw1903 = sessionStorage.getItem('ti_company_search_carry_1903'); if (raw1903) p1903 = JSON.parse(raw1903); } catch(e) { p1903 = null; }\n            }\n            if (!p1903 || !String(p1903.text || '').trim() || String(p1903.db || '') !== db1903) return null;\n            if (!Number(p1903.ts || 0) || (Date.now() - Number(p1903.ts || 0)) > 10 * 60 * 1000) {\n                try { sessionStorage.removeItem('ti_company_search_carry_1903'); } catch(e) {}\n                window.__tiCompanySearchCarry1903 = null;\n                return null;\n            }\n            return p1903;\n        };\n        window.tiConsumeCompanySearchCarry1903 = function(dbValue) {\n            const p1903 = window.tiReadCompanySearchCarry1903 ? window.tiReadCompanySearchCarry1903(dbValue) : null;\n            if (!p1903) return false;\n            const q1903 = String(p1903.text || '').trim();\n            try { sessionStorage.removeItem('ti_company_search_carry_1903'); } catch(e) {}\n            window.__tiCompanySearchCarry1903 = null;\n            if (!q1903) return false;\n            setTimeout(function(){\n                try {\n                    const d1903 = document.getElementById('ti-ditta');\n                    const m1903 = document.getElementById('ti-msg');\n                    const b1903 = document.getElementById('ti-send');\n                    if (!d1903 || String(d1903.value || '') !== String(dbValue || '') || !m1903 || !b1903) return;\n                    m1903.value = q1903;\n                    m1903.dispatchEvent(new Event('input',{bubbles:true}));\n                    try { b1903.dispatchEvent(new MouseEvent('click',{bubbles:true,cancelable:true,view:window})); }\n                    catch(eClick1903) { try { b1903.click(); } catch(_e1903) {} }\n                    try { console.info('[Shop-Service] ricerca ditta 1903: testo riportato nella chatbot',{db:String(dbValue||''),text:q1903}); } catch(eLog1903) {}\n                } catch(e1903) {}\n            }, 450);\n            return true;\n        };\n\n        window.tiEnsureUserChatBelowAiForm717 = function() {\n            try {\n                const chat = gE('ti-chat-box');\n                const form = document.querySelector('#ti-ai-outer .ti-input-wrap');\n                if (!chat || !form || !form.parentNode) return chat || null;\n                if (form.previousElementSibling !== chat) form.parentNode.insertBefore(chat, form);\n                if (chat.classList) chat.classList.add('ti-chat-after-ai-form-717');\n                chat.setAttribute('data-ti-placement', 'after-ai-form');\n                return chat;\n            } catch(e) { return gE('ti-chat-box'); }\n        };\n        if (window.tiEnsureUserChatBelowAiForm717) {\n            window.tiEnsureUserChatBelowAiForm717();\n            setTimeout(window.tiEnsureUserChatBelowAiForm717, 0);\n            setTimeout(window.tiEnsureUserChatBelowAiForm717, 500);\n        }\n\n        document.addEventListener('change', function(ev){\n            const t = ev.target;\n            if (t && (t.classList.contains('ti-import-map-select') || t.classList.contains('ti-import-group-target'))) window.scheduleImportPreviewRefresh(t);\n        });\n        document.addEventListener('input', function(ev){\n            const t = ev.target;\n            if (t && t.classList && t.classList.contains('ti-import-price-formula')) window.scheduleImportPreviewRefresh(t);\n        });\n        \n        if (gE('help-ver')) gE('help-ver').innerText = window.tiVersion + (window.tiVersionDateTime ? ' - ' + window.tiVersionDateTime : '');\n        window.tiAudioKey = window.tiAudioStorageKey716 ? window.tiAudioStorageKey716() : ('ti_mute_state_' + location.host + '_' + (window.tiUser || 'guest'));\n        const tiAudioPersistent716 = !!(window.tiAudioPersistentAllowed716 && window.tiAudioPersistentAllowed716());\n        let tiStoredMute716 = null;\n        try {\n            if (tiAudioPersistent716) tiStoredMute716 = localStorage.getItem(window.tiAudioKey);\n            else localStorage.removeItem(window.tiAudioKey);\n        } catch(e) {}\n        window.muteState = tiStoredMute716 ? parseInt(tiStoredMute716, 10) : 0;\n        if (isNaN(window.muteState) || window.muteState < 0 || (!tiAudioPersistent716 && window.muteState !== 1)) window.muteState = 0;\n        window.applyMuteState();\n        \n        const muteBtn = gE('ti-mute-btn');\n        if(muteBtn) {\n            muteBtn.onclick = () => {\n                const canPersistMute716 = !!(window.tiAudioPersistentAllowed716 && window.tiAudioPersistentAllowed716());\n                if (canPersistMute716) window.muteState = (window.muteState + 1) % 3;\n                else window.muteState = (window.muteState === 1 ? 0 : 1);\n                try {\n                    if(canPersistMute716 && window.muteState === 2) { localStorage.setItem(window.tiAudioKey, '2'); }\n                    else { localStorage.removeItem(window.tiAudioKey); }\n                } catch(e) {}\n                window.applyMuteState();\n                if(window.isMuted && window.speechSynthesis) window.speechSynthesis.cancel();\n            };\n        }\n        \n        \/\/ 30.9.1933: la prima vista deve essere sempre realmente TUTTE per ogni utente.\n        \/\/ Un filtro persistito su Demo in localStorage faceva richiedere al server soltanto le ditte Demo\n        \/\/ (nel caso reale: Catering, Ferramenta Terni, Ristorante e Termoidraulica Italiana) anche dopo login diversi.\n        window.ditteStateFilter = 'all';\n        try {\n            localStorage.setItem('ti_ditte_state_filter', 'all');\n            localStorage.setItem('ti_show_suspended_ditte', '1');\n        } catch(e1933filter) {}\n        window.showSuspendedDitte = true;\n        window.showDemoDitteOnly = false;\n        window.showActiveDitteOnly = false;\n        window.renderSuspendedToggle = function() {\n            const b = gE('ti-show-sospese-btn'); if(!b) return;\n            if (window.ditteStateFilter === 'active') {\n                b.textContent = 'Attive';\n                b.style.background = '#059669';\n                b.title = 'Attive: mostra solo le ditte con Stato Attivo\/Operativo. Clic successivo: solo sospese.';\n            } else if (window.ditteStateFilter === 'demo') {\n                b.textContent = 'Demo';\n                b.style.background = '#0369a1';\n                b.title = 'Demo: mostra solo le ditte demo. Clic successivo: Tutte.';\n            } else if (window.ditteStateFilter === 'suspended') {\n                b.textContent = 'Sosp';\n                b.style.background = '#b91c1c';\n                b.title = 'Sosp: mostra solo le ditte sospese. Clic successivo: Demo.';\n            } else {\n                b.textContent = 'Tutte';\n                b.style.background = '#374151';\n                b.title = 'Tutte: mostra tutte le ditte, incluse sospese e demo. Clic successivo: solo attive.';\n            }\n            window.showSuspendedDitte = true;\n            window.showDemoDitteOnly = (window.ditteStateFilter === 'demo');\n            window.showActiveDitteOnly = (window.ditteStateFilter === 'active');\n        };\n        window.normalizeSearchText = function(str) {\n            return String(str || '')\n                .toLowerCase()\n                .normalize('NFD')\n                .replace(\/[\u0300-\u036f]\/g, '')\n                .replace(\/[^a-z0-9\\s]\/g, ' ')\n                .replace(\/\\s+\/g, ' ')\n                .trim();\n        };\n        window.filterDitteData = function(list, query) {\n            list = Array.isArray(list) ? list : [];\n            const q = window.normalizeSearchText(query || '');\n            if (!q) return list;\n            const tokens = q.split(\/\\s+\/).filter(Boolean);\n            const synonyms = {\n                farmacia: ['farmacia', 'parafarmacia', 'sanitario', 'farmaci', 'salute'],\n                ferramenta: ['ferramenta', 'bricolage', 'utensili', 'viti', 'fissaggi'],\n                fiori: ['fiori', 'fioraio', 'bouquet', 'piante', 'floreale'],\n                auto: ['auto', 'autofficina', 'carrozzeria', 'gomme', 'ricambi'],\n                capelli: ['capelli', 'hairstyle', 'parrucchiere', 'barbiere', 'acconciature'],\n                estetica: ['estetica', 'beauty', 'benessere', 'trattamenti', 'viso'],\n                ristorante: ['ristorante', 'pizzeria', 'cucina', 'menu', 'piatti'],\n                medico: ['medico', 'sanitario', 'visite', 'esami', 'specialistica']\n            };\n            const expandToken = function(tok) {\n                let out = [tok];\n                Object.keys(synonyms).forEach(key => {\n                    const vals = synonyms[key];\n                    if (key === tok || vals.includes(tok)) out = out.concat(vals);\n                });\n                return Array.from(new Set(out));\n            };\n            const scored = list.map(d => {\n                const nome = window.normalizeSearchText(d.nome_pura || d.label || '');\n                const settore = window.normalizeSearchText(d.settore || '');\n                const accoglienza = window.normalizeSearchText(d.accoglienza || '');\n                const db = window.normalizeSearchText(d.db || '');\n                const hay = [nome, settore, accoglienza, db].join(' | ');\n                let score = 0;\n                let matchedAll = true;\n                tokens.forEach(tok => {\n                    const expanded = expandToken(tok);\n                    let tokenMatched = false;\n                    expanded.forEach(v => {\n                        if (!v) return;\n                        if (nome === v) { score += 120; tokenMatched = true; }\n                        else if (nome.startsWith(v)) { score += 90; tokenMatched = true; }\n                        else if (nome.includes(v)) { score += 60; tokenMatched = true; }\n                        if (settore === v) { score += 110; tokenMatched = true; }\n                        else if (settore.startsWith(v)) { score += 85; tokenMatched = true; }\n                        else if (settore.includes(v)) { score += 55; tokenMatched = true; }\n                        if (db === v) { score += 80; tokenMatched = true; }\n                        else if (db.includes(v)) { score += 45; tokenMatched = true; }\n                        if (accoglienza.includes(v)) { score += 20; tokenMatched = true; }\n                        if (!tokenMatched && v.length >= 3) {\n                            const prefix = v.slice(0, 4);\n                            if (nome.includes(prefix) || settore.includes(prefix) || db.includes(prefix)) {\n                                score += 18; tokenMatched = true;\n                            }\n                        }\n                    });\n                    if (!tokenMatched) matchedAll = false;\n                });\n                if (nome.includes(q)) score += 100;\n                if (settore.includes(q)) score += 90;\n                if (db.includes(q)) score += 70;\n                return { item: d, score, matchedAll };\n            }).filter(x => x.score > 0 || x.matchedAll);\n            scored.sort((a,b) => {\n                if ((b.score||0) !== (a.score||0)) return (b.score||0) - (a.score||0);\n                return String(a.item.nome_pura || '').localeCompare(String(b.item.nome_pura || ''));\n            });\n            return scored.map(x => x.item);\n        };\n\n        window.closeDittaPopup = function() {\n            const pop = gE('ti-ditta-popup');\n            if (pop) pop.style.display = 'none';\n        };\n\n        window.syncDittaTrigger = function() {\n            const sel = gE('ti-ditta');\n            const btn = gE('ti-ditta-trigger');\n            if (!sel || !btn) return;\n            const opt = sel.options && sel.selectedIndex >= 0 ? sel.options[sel.selectedIndex] : null;\n            let label = '-- Scegli una ditta --';\n            let color = '#ffffff';\n            let borderColor = '#444';\n            if (opt) {\n                label = String(opt.text || label);\n                \/\/ 30.9.1588: nella riga della ditta scelta mostra solo nome ditta e attivita.\n                \/\/ Lo stato resta nei data-* e nel popup elenco, ma non viene ripetuto nel testo selezionato.\n                if (opt.value && opt.value !== 'NEW_DB') {\n                    const selectedState1588 = String(opt.getAttribute('data-company-state') || opt.getAttribute('data-stato') || '').trim();\n                    if (selectedState1588) {\n                        const statePrefix1588 = '[' + selectedState1588 + '] ';\n                        if (label.toLowerCase().startsWith(statePrefix1588.toLowerCase())) {\n                            label = label.slice(statePrefix1588.length);\n                        }\n                    } else {\n                        label = label.replace(\/^\\[[^\\]]+\\]\\s*\/, '');\n                    }\n                }\n                const status = String(opt.getAttribute('data-status') || '').toLowerCase();\n                if (status === 'sospesa' || status === 'sviluppo') { color = '#ef4444'; borderColor = '#7f1d1d'; }\n                else if (status === 'demo') { color = '#38bdf8'; borderColor = '#0e7490'; }\n                else if (status === 'configurazione') { color = '#facc15'; borderColor = '#a16207'; }\n                else if (opt.value === 'NEW_DB') { color = '#10b981'; borderColor = '#065f46'; }\n            }\n            btn.textContent = label;\n            btn.style.color = color;\n            btn.style.borderColor = borderColor;\n            btn.style.background = '#000000';\n        };\n\n        window.renderDittePopup = function() {\n            const sel = gE('ti-ditta');\n            const pop = gE('ti-ditta-popup');\n            if (!sel || !pop) return;\n            const options = Array.from(sel.options || []);\n            pop.innerHTML = '';\n            options.forEach(function(opt){\n                const status = String(opt.getAttribute('data-status') || '').toLowerCase() || 'attivo';\n                const effectiveStatus = (opt.value === 'NEW_DB') ? 'nuova' : status;\n                const fullText = String(opt.text || '').trim();\n                let badgeText = '';\n                let baseText = fullText;\n                if (opt.value === 'NEW_DB') {\n                    badgeText = 'Nuova';\n                } else if (opt.value) {\n                    badgeText = String(opt.getAttribute('data-company-state') || '').trim();\n                    if (!badgeText) {\n                        badgeText = effectiveStatus === 'sospesa' ? 'Sospesa'\n                            : (effectiveStatus === 'configurazione' ? 'Configurazione'\n                            : (effectiveStatus === 'demo' ? 'Demo'\n                            : (effectiveStatus === 'sviluppo' ? 'Sviluppo' : 'Attivo')));\n                    }\n                    const statePrefix1577 = '[' + badgeText + '] ';\n                    const stateSuffix1576 = ' - ' + badgeText;\n                    if (fullText.toLowerCase().startsWith(statePrefix1577.toLowerCase())) {\n                        baseText = fullText.slice(statePrefix1577.length);\n                    } else if (fullText.toLowerCase().endsWith(stateSuffix1576.toLowerCase())) {\n                        \/\/ Compatibilita con opzioni gia renderizzate dalla release precedente.\n                        baseText = fullText.slice(0, fullText.length - stateSuffix1576.length);\n                    }\n                }\n\n                const row = document.createElement('div');\n                row.className = 'ti-ditta-row ' + effectiveStatus + (sel.value === opt.value ? ' active' : '');\n                row.setAttribute('role', 'button');\n                row.tabIndex = opt.disabled ? -1 : 0;\n                if (!opt.value) row.classList.add('empty');\n                if (opt.disabled) row.classList.add('none');\n\n                const main = document.createElement('span');\n                main.className = 'ti-ditta-row-main';\n                main.textContent = baseText || fullText || '--';\n                if (row.classList.contains('empty') || row.classList.contains('none')) {\n                    main.style.setProperty('color', '#cbd5e1', 'important');\n                } else {\n                    main.style.setProperty('color', '#ffffff', 'important');\n                }\n                row.appendChild(main);\n\n                if (badgeText) {\n                    const badge = document.createElement('span');\n                    badge.className = 'ti-ditta-row-badge ' + effectiveStatus;\n                    badge.textContent = badgeText;\n                    row.appendChild(badge);\n                }\n\n                const pickRow = function(ev){\n                    if (ev) ev.preventDefault();\n                    if (opt.disabled) return;\n                    sel.value = opt.value;\n                    if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n                    window.closeDittaPopup();\n                    sel.dispatchEvent(new Event('change', {bubbles:true}));\n                };\n                row.onclick = pickRow;\n                row.onkeydown = function(ev){\n                    if (ev.key === 'Enter' || ev.key === ' ') pickRow(ev);\n                };\n                pop.appendChild(row);\n            });\n        };\n\n        window.toggleDittaPopup = function() {\n            const pop = gE('ti-ditta-popup');\n            if (!pop) return;\n            const willOpen = pop.style.display === 'none' || !pop.style.display;\n            if (willOpen) {\n                if (window.renderDittePopup) window.renderDittePopup();\n            if (window.syncLoginDbSelect) window.syncLoginDbSelect();\n                pop.style.display = 'block';\n            } else {\n                pop.style.display = 'none';\n            }\n        };\n\nwindow.forceWhiteEditStyle = function(el) {\n            if (!el) return;\n            try {\n                const inConf = !!(el.closest && (el.closest('.ti-conf-window') || el.closest('.ti-conf-body') || el.closest('.ti-cfg-table') || el.closest('.ti-import-map-table') || el.closest('#ti-profile-ov') || el.closest('#ti-newdb-ov') || el.closest('#ti-new-db-ov')));\n                if (!inConf) return;\n                el.style.setProperty('color', '#ffffff', 'important');\n                el.style.setProperty('-webkit-text-fill-color', '#ffffff', 'important');\n                el.style.setProperty('caret-color', '#ffffff', 'important');\n                el.style.setProperty('background', '#000000', 'important');\n                el.style.setProperty('background-color', '#000000', 'important');\n                el.style.setProperty('background-image', 'none', 'important');\n                el.style.setProperty('text-shadow', 'none', 'important');\n                el.style.setProperty('color-scheme', 'dark', 'important');\n                if (el.tagName === 'SELECT' && el.options) {\n                    Array.from(el.options).forEach(function(opt){\n                        opt.style.setProperty('color', '#ffffff', 'important');\n                        opt.style.setProperty('-webkit-text-fill-color', '#ffffff', 'important');\n                        opt.style.setProperty('background', '#000000', 'important');\n                        opt.style.setProperty('background-color', '#000000', 'important');\n                    });\n                }\n            } catch(e) {}\n        };\n\n        window.bindConfigWhiteEditHandlers = function() {\n            if (window.__tiConfigWhiteEditBound) return;\n            window.__tiConfigWhiteEditBound = true;\n\n            document.addEventListener('focusin', function(ev) {\n                const el = ev.target;\n                if (!el) return;\n                window.forceWhiteEditStyle(el);\n            }, true);\n\n            document.addEventListener('input', function(ev) {\n                const el = ev.target;\n                if (!el) return;\n                window.forceWhiteEditStyle(el);\n            }, true);\n\n            document.addEventListener('change', function(ev) {\n                const el = ev.target;\n                if (!el) return;\n                window.forceWhiteEditStyle(el);\n            }, true);\n\n            document.addEventListener('click', function(ev) {\n                const el = ev.target;\n                if (!el) return;\n                if (el.matches && (el.matches('.ti-conf-window input, .ti-conf-window textarea, .ti-conf-window select, .ti-cfg-table input, .ti-cfg-table textarea, .ti-cfg-table select, .ti-import-map-table input, .ti-import-map-table textarea, .ti-import-map-table select, #ti-profile-ov input, #ti-profile-ov textarea, #ti-profile-ov select, #ti-newdb-ov input, #ti-newdb-ov textarea, #ti-newdb-ov select, #ti-new-db-ov input, #ti-new-db-ov textarea, #ti-new-db-ov select, .ti-conf-window [contenteditable=\"true\"], .ti-cfg-table [contenteditable=\"true\"], .ti-import-map-table [contenteditable=\"true\"]'))) {\n                    window.forceWhiteEditStyle(el);\n                }\n            }, true);\n        };\n\n        window.bindConfigWhiteEditHandlers();\n\nwindow.applyDittaSelectVisual = function() {\n            const sel = gE('ti-ditta');\n            if (!sel) return;\n            const opt = sel.options && sel.selectedIndex >= 0 ? sel.options[sel.selectedIndex] : null;\n            let color = '#ffffff', weight = '400';\n            if (opt) {\n                const status = String(opt.getAttribute('data-status') || '').toLowerCase();\n                if (status === 'sospesa' || status === 'sviluppo') { color = '#ef4444'; weight = '700'; }\n                else if (status === 'demo') { color = '#38bdf8'; weight = '700'; }\n                else if (status === 'configurazione') { color = '#facc15'; weight = '700'; }\n                else if (opt.value === 'NEW_DB') { color = '#10b981'; weight = '700'; }\n            }\n            sel.style.color = color;\n            sel.style.fontWeight = weight;\n            sel.style.background = '#000000';\n            if (window.syncDittaTrigger) window.syncDittaTrigger();\n            if (window.updateCompanyReferenceDateTime) window.updateCompanyReferenceDateTime();\n        };\n\n        window.renderDitteDropdown = function() {\n            const dittaInput = gE('ti-ditta'); if(!dittaInput) return;\n            const prevSelectedDb = dittaInput.value || ((String(window.tiUser || '').trim() && String(window.tiSessionDb || '').trim()) ? window.tiSessionDb : '') || window.tiCurrentSelectedDb || localStorage.getItem('ti_saved_db') || '';\n            if (prevSelectedDb) window.tiCurrentSelectedDb = prevSelectedDb;\n            const filterInp = gE('ti-filter-ditte');\n            const q = filterInp ? filterInp.value : '';\n            if(!window.ditteData || !Array.isArray(window.ditteData)) window.ditteData = [];\n            let sorted = window.filterDitteData([...window.ditteData], q);\n            if(window.sortMode === 'AZ') { sorted.sort((a,b) => (a.nome_pura||'').localeCompare(b.nome_pura||'')); } else { sorted.sort((a,b) => (a.settore || '').localeCompare(b.settore || '')); }\n\n            dittaInput.innerHTML = '';\n\n            const optEmpty = document.createElement('option');\n            optEmpty.value = '';\n            optEmpty.textContent = '-- Scegli una ditta --';\n            optEmpty.setAttribute('data-status', 'attivo');\n            optEmpty.style.color = '#ffffff';\n            optEmpty.style.background = '#000000';\n            dittaInput.appendChild(optEmpty);\n\n            const optNew = document.createElement('option');\n            optNew.value = 'NEW_DB';\n            optNew.textContent = '+ Nuova ditta ...';\n            optNew.setAttribute('data-status', 'nuova');\n            optNew.style.color = '#10b981';\n            optNew.style.fontWeight = '700';\n            optNew.style.background = '#000000';\n            dittaInput.appendChild(optNew);\n\n            sorted.forEach(function(d){\n                const opt = document.createElement('option');\n                const safeName = String(d.nome_pura || '');\n                const safeSettore = String(d.settore || '');\n                let statusCode = 'attivo';\n                let displayState1576 = String(d.company_state || d.stato || '').trim();\n                let color = '#ffffff';\n                if (d.is_dev) {\n                    statusCode = 'sviluppo';\n                    displayState1576 = 'Sviluppo';\n                    color = '#ef4444';\n                } else if (d.is_sosp) {\n                    statusCode = 'sospesa';\n                    displayState1576 = 'Sospesa';\n                    color = '#ef4444';\n                } else if (d.is_demo) {\n                    statusCode = 'demo';\n                    displayState1576 = 'Demo';\n                    color = '#38bdf8';\n                } else if (d.is_conf) {\n                    statusCode = 'configurazione';\n                    displayState1576 = 'Configurazione';\n                    color = '#facc15';\n                } else {\n                    if (!\/^(attivo|operativo)$\/i.test(displayState1576)) displayState1576 = 'Attivo';\n                    displayState1576 = \/^operativo$\/i.test(displayState1576) ? 'Operativo' : 'Attivo';\n                }\n                const statePrefix1577 = '[' + displayState1576 + '] ';\n                opt.value = d.db;\n                \/\/ 30.9.1577: stato davanti al nome: resta sempre visibile anche quando settore\/attivita sono lunghi.\n                opt.textContent = statePrefix1577 + safeName + (safeSettore ? ' - ' + safeSettore : '');\n                opt.setAttribute('data-status', statusCode);\n                opt.setAttribute('data-stato', displayState1576);\n                opt.setAttribute('data-company-state', displayState1576);\n                opt.setAttribute('data-acc', String(d.accoglienza || ''));\n                opt.setAttribute('data-acc-en', String(d.accoglienza_en || ''));\n                opt.setAttribute('data-ref-datetime', String(d.ref_datetime || ''));\n                opt.setAttribute('data-ref-tz', String(d.ref_timezone || ''));\n                opt.setAttribute('data-logo', String(d.logo || ''));\n                opt.setAttribute('data-qr', String(d.qr || ''));\n                opt.setAttribute('data-demo-login-available', d.demo_login_available ? '1' : '0');\n                opt.setAttribute('data-demo-login-user', String(d.demo_login_user || ''));\n                opt.setAttribute('data-demo-login-pass', String(d.demo_login_pass || ''));\n                opt.setAttribute('data-demo-login-notice', String(d.demo_login_notice || ''));\n                opt.setAttribute('data-name', safeName);\n                opt.setAttribute('data-tab-tab', String(d.tab_tab || ''));\n                opt.setAttribute('data-tab-sma', String(d.tab_sma || ''));\n                opt.setAttribute('data-tab-med', String(d.tab_med || ''));\n                opt.setAttribute('data-tab-lar', String(d.tab_lar || ''));\n                opt.style.color = color;\n                opt.style.background = '#000000';\n                if (statusCode !== 'attivo') opt.style.fontWeight = '700';\n                dittaInput.appendChild(opt);\n            });\n\n            if (!sorted.length && q) {\n                const optNone = document.createElement('option');\n                optNone.value = '';\n                optNone.disabled = true;\n                optNone.textContent = 'Nessuna ditta trovata';\n                optNone.style.color = '#9ca3af';\n                optNone.style.background = '#000000';\n                dittaInput.appendChild(optNone);\n            }\n\n            if (prevSelectedDb && !Array.from(dittaInput.options || []).some(function(o){ return o.value === prevSelectedDb; })) {\n                const savedRecord = (window.ditteData || []).find(function(d){ return String(d && d.db || '') === String(prevSelectedDb); });\n                if (savedRecord) {\n                    const opt = document.createElement('option');\n                    const safeName = String(savedRecord.nome_pura || '');\n                    const safeSettore = String(savedRecord.settore || '');\n                    let statusCode = 'attivo', color = '#ffffff';\n                    let displayState1576 = String(savedRecord.company_state || savedRecord.stato || '').trim();\n                    if (savedRecord.is_dev) { statusCode = 'sviluppo'; displayState1576 = 'Sviluppo'; color = '#ef4444'; }\n                    else if (savedRecord.is_sosp) { statusCode = 'sospesa'; displayState1576 = 'Sospesa'; color = '#ef4444'; }\n                    else if (savedRecord.is_demo) { statusCode = 'demo'; displayState1576 = 'Demo'; color = '#38bdf8'; }\n                    else if (savedRecord.is_conf) { statusCode = 'configurazione'; displayState1576 = 'Configurazione'; color = '#facc15'; }\n                    else { if (!\/^(attivo|operativo)$\/i.test(displayState1576)) displayState1576 = 'Attivo'; displayState1576 = \/^operativo$\/i.test(displayState1576) ? 'Operativo' : 'Attivo'; }\n                    const statePrefix1577 = '[' + displayState1576 + '] ';\n                    opt.value = savedRecord.db;\n                    opt.textContent = statePrefix1577 + safeName + (safeSettore ? ' - ' + safeSettore : '');\n                    opt.setAttribute('data-status', statusCode);\n                    opt.setAttribute('data-stato', displayState1576);\n                    opt.setAttribute('data-company-state', displayState1576);\n                    opt.setAttribute('data-acc', String(savedRecord.accoglienza || ''));\n                    opt.setAttribute('data-acc-en', String(savedRecord.accoglienza_en || ''));\n                    opt.setAttribute('data-ref-datetime', String(savedRecord.ref_datetime || ''));\n                    opt.setAttribute('data-ref-tz', String(savedRecord.ref_timezone || ''));\n                    opt.setAttribute('data-logo', String(savedRecord.logo || ''));\n                    opt.setAttribute('data-qr', String(savedRecord.qr || ''));\n                    opt.setAttribute('data-name', safeName);\n                    opt.setAttribute('data-tab-tab', String(savedRecord.tab_tab || ''));\n                    opt.setAttribute('data-tab-sma', String(savedRecord.tab_sma || ''));\n                    opt.setAttribute('data-tab-med', String(savedRecord.tab_med || ''));\n                    opt.setAttribute('data-tab-lar', String(savedRecord.tab_lar || ''));\n                    opt.style.color = color;\n                    opt.style.background = '#000000';\n                    if (statusCode !== 'attivo') opt.style.fontWeight = '700';\n                    dittaInput.appendChild(opt);\n                }\n            }\n            if (prevSelectedDb) {\n                const hasPrev = Array.from(dittaInput.options || []).some(function(o){ return o.value === prevSelectedDb; });\n                if (hasPrev) dittaInput.value = prevSelectedDb;\n            }\n            if (dittaInput.value) {\n                window.tiCurrentSelectedDb = dittaInput.value;\n                if (dittaInput.value !== 'NEW_DB') localStorage.setItem('ti_saved_db', dittaInput.value);\n            }\n            if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n            if (window.renderDittePopup) window.renderDittePopup();\n            if(window.tiForced) {\n                dittaInput.style.display = 'none';\n                const picker = document.querySelector('.ti-ditta-picker'); if (picker) picker.style.display = 'none';\n                const sBtn = gE('ti-sort-btn'); if(sBtn) sBtn.style.display = 'none';\n                const fInp = gE('ti-filter-ditte'); if(fInp) fInp.style.display = 'none';\n            }\n        };\n\n        window.fetchDitteList = function(opts){\n            opts = opts || {};\n            const silent = !!opts.silent;\n            let forceRefresh1775 = !!opts.forceRefresh;\n            const prevVal = dom.ditta ? dom.ditta.value : '';\n            \/\/ 30.9.1933: il primo caricamento elenco della pagina e sempre Tutte, indipendentemente\n            \/\/ da login\/ruolo e da localStorage. Questo evita che un vecchio filtro Demo limiti ogni utente.\n            const initialFull1933 = !window.__tiInitialCompanyListReady1933;\n            if (initialFull1933) {\n                window.ditteStateFilter = 'all';\n                window.showSuspendedDitte = true;\n                window.showDemoDitteOnly = false;\n                window.showActiveDitteOnly = false;\n                forceRefresh1775 = true;\n                try {\n                    localStorage.setItem('ti_ditte_state_filter', 'all');\n                    localStorage.setItem('ti_show_suspended_ditte', '1');\n                    const filter1933 = gE('ti-filter-ditte');\n                    if (filter1933) filter1933.value = '';\n                    if (window.renderSuspendedToggle) window.renderSuspendedToggle();\n                } catch(e1933init) {}\n            }\n            \/\/ 30.9.1931: piu richieste elenco possono partire durante il bootstrap\/retry. Solo la\n            \/\/ risposta dell ultima richiesta puo ridisegnare la combo, evitando che una risposta\n            \/\/ precedente e parziale sovrascriva l elenco completo appena ricevuto.\n            window.__tiDitteFetchSeq1931 = Number(window.__tiDitteFetchSeq1931 || 0) + 1;\n            const fetchSeq1931 = window.__tiDitteFetchSeq1931;\n\n            \/\/ 30.9.1929: prima lettura completa ad ogni nuova pagina privilegiata.\n            \/\/ Non usa sessionStorage: un marker sopravvissuto a una release precedente non puo piu\n            \/\/ impedire il refresh completo. Dopo il primo esito i filtri tornano normalmente utilizzabili.\n            let privilegedFull1929 = false;\n            try {\n                const roleList1929 = String(window.tiRole || '').toLowerCase();\n                const privilegedList1929 = String(window.tiUser || '') === 'SSGlobalAdmin' || \/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|global\\s*admin|sysadmin\/.test(roleList1929);\n                if (privilegedList1929 && !window.__tiPrivilegedCompanyListReady1929) {\n                    privilegedFull1929 = true;\n                    window.ditteStateFilter = 'all';\n                    window.showSuspendedDitte = true;\n                    window.showDemoDitteOnly = false;\n                    window.showActiveDitteOnly = false;\n                    localStorage.setItem('ti_ditte_state_filter', 'all');\n                    localStorage.setItem('ti_show_suspended_ditte', '1');\n                    const filter1929 = gE('ti-filter-ditte');\n                    if (filter1929) filter1929.value = '';\n                    forceRefresh1775 = true;\n                    try { if (window.renderSuspendedToggle) window.renderSuspendedToggle(); } catch(e1929a) {}\n                }\n            } catch(e1929) {}\n\n            const stateFilter = (initialFull1933 || privilegedFull1929) ? 'all' : (['all','active','suspended','demo'].includes(window.ditteStateFilter) ? window.ditteStateFilter : 'all');\n            const currentForList1775 = String(window.tiForced || window.tiSessionDb || window.tiCurrentSelectedDb || prevVal || '').trim();\n            const url = window.tiUrl + '?ti_action=ti_ai_list_ditte&current_db=' + encodeURIComponent(currentForList1775) + '&state_filter=' + encodeURIComponent(stateFilter) + '&show_suspended=' + (stateFilter === 'all' ? '1' : '0') + '&show_demo_only=' + (stateFilter === 'demo' ? '1' : '0') + '&initial_full_1933=' + (initialFull1933 ? '1' : '0') + '&privileged_full_1929=' + (privilegedFull1929 ? '1' : '0') + '&ti_lang=' + encodeURIComponent((String(window.currLang || 'it').toLowerCase().indexOf('en') === 0) ? 'en' : 'it') + '&force_refresh=' + (forceRefresh1775 ? '1' : '0') + '&_ti_list_v=' + Date.now();\n            return window.fetchJsonSafe(url, {method:'GET'}).then(function(res){\n                if (fetchSeq1931 !== Number(window.__tiDitteFetchSeq1931 || 0)) return res;\n                if(res.success && dom.ditta) {\n                    window.ditteData = Array.isArray(res.data && res.data.ditte) ? res.data.ditte : [];\n                    try { if (res.data && res.data.diag_1935) console.info('[Shop-Service 1935 elenco ditte]', res.data.diag_1935); } catch(e1935diag) {}\n                    if (initialFull1933) window.__tiInitialCompanyListReady1933 = true;\n                    if (privilegedFull1929) window.__tiPrivilegedCompanyListReady1929 = true;\n                    window.renderDitteDropdown();\n                    \/\/ 30.9.1775: riallinea immediatamente anche i selettori Login\/Accesso diretto.\n                    try { if (window.syncLoginDbSelect) window.syncLoginDbSelect(); } catch(e) {}\n                    if(window.tiForced) {\n                        dom.ditta.value = window.tiForced;\n                        const fdReset = new FormData(); fdReset.append('ti_action', 'ti_ai_reset_flow'); fetch(window.tiUrl, {method:'POST', body:fdReset}).catch(function(){});\n                    } else {\n                        \/\/ 30.9.1979: stessa priorita della backup funzionante, senza azzeramento GlobalAdmin.\n                        let targetDb = prevVal || ((String(window.tiUser || '').trim() && String(window.tiSessionDb || '').trim()) ? window.tiSessionDb : '') || localStorage.getItem('ti_saved_db');\n                        if (targetDb && Array.from(dom.ditta.options).find(o => o.value === targetDb)) { dom.ditta.value = targetDb; window.tiCurrentSelectedDb = targetDb; }\n                    }\n                    if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n                    window.updCtx(silent);\n                }\n                return res;\n            }).catch(function(err){\n                if (fetchSeq1931 !== Number(window.__tiDitteFetchSeq1931 || 0)) return {success:false, stale_1931:true};\n                console.error('Errore fetchDitteList:', err);\n                window.ditteData = [];\n                if (dom.ditta) dom.ditta.innerHTML = '<option value=\"\">Errore caricamento ditte<\/option>';\n                if (err && err.maintenance) {\n                    throw err;\n                }\n                if (!silent && window.tiAlert) window.tiAlert('Errore caricamento ditte: ' + ((err && err.message) ? err.message : 'errore sconosciuto'));\n                throw err;\n            });\n        };\n\n        let forceCompanyRefresh1775 = false;\n        try {\n            const refreshDb1775 = String(sessionStorage.getItem('ti_force_company_list_refresh_1775') || '').trim();\n            if (refreshDb1775) {\n                forceCompanyRefresh1775 = true;\n                window.ditteStateFilter = 'all';\n                localStorage.setItem('ti_ditte_state_filter', 'all');\n                localStorage.setItem('ti_show_suspended_ditte', '1');\n                sessionStorage.removeItem('ti_force_company_list_refresh_1775');\n            }\n        } catch(e) {}\n        window.fetchDitteList({silent:false, forceRefresh:forceCompanyRefresh1775});\n\n        const dittaTrigger = gE('ti-ditta-trigger');\n        if (dittaTrigger) {\n            dittaTrigger.onclick = function(ev){\n                ev.preventDefault();\n                ev.stopPropagation();\n                window.toggleDittaPopup();\n            };\n        }\n        document.addEventListener('click', function(ev){\n            const picker = document.querySelector('.ti-ditta-picker');\n            if (!picker) return;\n            if (!picker.contains(ev.target)) window.closeDittaPopup();\n        });\n\n        const sospBtn = gE('ti-show-sospese-btn');\n        if(sospBtn) {\n            window.renderSuspendedToggle();\n            sospBtn.onclick = () => {\n                if (window.ditteStateFilter === 'all') window.ditteStateFilter = 'active';\n                else if (window.ditteStateFilter === 'active') window.ditteStateFilter = 'suspended';\n                else if (window.ditteStateFilter === 'suspended') window.ditteStateFilter = 'demo';\n                else window.ditteStateFilter = 'all';\n                localStorage.setItem('ti_ditte_state_filter', window.ditteStateFilter);\n                localStorage.setItem('ti_show_suspended_ditte', window.ditteStateFilter === 'all' ? '1' : '0');\n                window.renderSuspendedToggle();\n                window.fetchDitteList({silent:true});\n            };\n        }\n\n        const sortBtn = gE('ti-sort-btn');\n        if(sortBtn) { sortBtn.onclick = () => { window.sortMode = (window.sortMode === 'AZ') ? 'ATT' : 'AZ'; sortBtn.textContent = window.sortMode; window.renderDitteDropdown(); }; }\n\n        const filterInp = gE('ti-filter-ditte');\n        if(filterInp) {\n            filterInp.oninput = () => {\n                const prevVal = dom.ditta && dom.ditta.value ? dom.ditta.value : '';\n                window.renderDitteDropdown();\n                if (dom.ditta && prevVal && Array.from(dom.ditta.options).some(o => o.value === prevVal)) dom.ditta.value = prevVal;\n                if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n                if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n            };\n            filterInp.onkeydown = (e) => {\n                if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {\n                    e.preventDefault();\n                    const realOptions = Array.from(dom.ditta.options).filter(o => o.value && o.value !== 'NEW_DB' && !o.disabled);\n                    if (realOptions.length === 1) {\n                        dom.ditta.value = realOptions[0].value;\n                        dom.ditta.dispatchEvent(new Event('change'));\n                    }\n                }\n            };\n        }\n\n        if (dom.ditta) {\n            dom.ditta.onchange = () => {\n                 try { if (window.closeAssociatedFilePopups512) window.closeAssociatedFilePopups512(); else window.tiSuppressFileManagerUntil = Date.now() + 2500; } catch(e) {}\n                 let v = dom.ditta.value;\n                 \/\/ 30.9.1903: se la scelta deriva dal campo Cerca ditta\/attivita, conserva\n                 \/\/ la richiesta prima che filtri, reset o reload possano cancellarla.\n                 try {\n                     const f1903 = gE('ti-filter-ditte');\n                     const q1903 = String((window.__tiPendingCompanySearchText1903 || (f1903 ? f1903.value : '')) || '').replace(\/\\u00a0\/g,' ').trim();\n                     if (q1903 && v && v !== 'NEW_DB' && window.tiStoreCompanySearchCarry1903) window.tiStoreCompanySearchCarry1903(q1903, v);\n                     window.__tiPendingCompanySearchText1903 = '';\n                     if (f1903 && q1903) f1903.value = '';\n                 } catch(e1903) {}\n                 if (v === 'NEW_DB') { \n                     window.openModal('ti-new-db-ov'); dom.ditta.value = window.tiForced || localStorage.getItem('ti_saved_db') || ''; return; \n                 }\n\n                 \/\/ 30.9.1657: prima di rendere la nuova ditta elimina ogni stato client della precedente\n                 \/\/ e annulla eventuali risposte ancora in volo, evitando che ricompaiano dopo il reset chat.\n                 try { if (window.tiResetCompanyScopedState1657) window.tiResetCompanyScopedState1657(v); } catch(e1657) {}\n                 if(v !== '') { localStorage.setItem('ti_saved_db', v); window.tiCurrentSelectedDb = v; } else { localStorage.removeItem('ti_saved_db'); window.tiCurrentSelectedDb = ''; }\n                 if (window.applyDittaSelectVisual) window.applyDittaSelectVisual();\n                 const roleSwitch1741 = String(window.tiRole || '').toLowerCase();\n                 const canSwitchSession1741 = String(window.tiUser || '') === 'SSGlobalAdmin' || \/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|global admin|sysadmin\/.test(roleSwitch1741);\n                 const mustLogoutForCompanySwitch = !!(window.tiUser && !canSwitchSession1741 && window.tiSessionDb && v && v !== window.tiSessionDb);\n                 if (mustLogoutForCompanySwitch) {\n                     if(dom.chat) dom.chat.innerHTML = '';\n                     const fdReset = new FormData(); fdReset.append('ti_action', 'ti_ai_reset_flow');\n                     fetch(window.tiUrl, {method:'POST', body:fdReset}).catch(()=>{});\n                     const fdLogout = new FormData(); fdLogout.append('ti_action','ti_ai_logout');\n                     fetch(window.tiUrl,{method:'POST',body:fdLogout}).finally(()=>{ location.reload(); });\n                     return;\n                 }\n                 \/\/ 30.9.1927: per un profilo privilegiato che sta passando ad altra ditta NON avviare\n                 \/\/ ti_ai_reset_flow in parallelo. Quella richiesta leggerebbe ancora il cookie della ditta\n                 \/\/ precedente e potrebbe terminare dopo ti_ai_switch_session_db_1344, riscrivendo il vecchio\n                 \/\/ cookie e facendo tornare il bootstrap alla ditta di partenza. Lo switch 1344 ora pulisce\n                 \/\/ direttamente anche flow\/ordine e salva una sola sessione coerente.\n                 const privilegedTransition1927 = !!(window.tiUser && canSwitchSession1741 && v && v !== String(window.tiSessionDb || ''));\n                 if (privilegedTransition1927) {\n                     try { sessionStorage.setItem('ti_company_switch_pending_1927', v); } catch(e1927) {}\n                     if(dom.chat) dom.chat.innerHTML = '';\n                     window.hideOrderConfirmPanel();\n                     return;\n                 }\n                 if(dom.chat) dom.chat.innerHTML = '';\n                 window.hideOrderConfirmPanel();\n                 const fd = new FormData(); fd.append('ti_action', 'ti_ai_reset_flow');\n                 fetch(window.tiUrl, {method:'POST', body:fd}).finally(function(){ window.updCtx(false); });\n            };\n        }\n\n        window.loadRegisteredUserProfileWelcome = function(dbValue) {\n            try {\n                if (!window.tiUser || window.tiUser === 'SSGlobalAdmin' || String(window.tiUser || '').toLowerCase() === 'ssdemo') return;\n                if (!dbValue || dbValue === 'NEW_DB') return;\n                window.tiProfileWelcomeShown = window.tiProfileWelcomeShown || {};\n                const key = String(dbValue) + '|' + String(window.tiUser || '');\n                if (window.tiProfileWelcomeShown[key]) return;\n                window.tiProfileWelcomeShown[key] = true;\n                const fdProfile = new FormData();\n                fdProfile.append('ti_action', 'ti_ai_chat_start');\n                fdProfile.append('db', dbValue);\n                fdProfile.append('text', '__TI_PROFILE_WELCOME__');\n                fetch(window.tiUrl, {method:'POST', body:fdProfile})\n                    .then(function(r){ return r.json(); })\n                    .then(function(d){\n                        const currentDb1657 = (gE('ti-ditta') ? String(gE('ti-ditta').value || '') : '');\n                        if (window.tiNormalizeDb1657 && window.tiNormalizeDb1657(currentDb1657) !== window.tiNormalizeDb1657(dbValue)) return;\n                        const reply = d && d.success && d.data ? String(d.data.reply || '') : '';\n                        if (!reply) return;\n                        if (window.tiAddAiMessageTranslatedIfNeeded) window.tiAddAiMessageTranslatedIfNeeded(reply, String(d.data.voice || reply), dbValue);\n                        else { if (window.addMsg) window.addMsg('ai', reply, reply); if (d.data.voice && window.speakText) window.speakText(String(d.data.voice || '')); }\n                    })\n                    .catch(function(err){ console.warn('Profilazione utente non disponibile:', err); });\n            } catch(e) { console.warn('Profilazione utente non disponibile:', e); }\n        };\n\n        window.tiGetCompanyWelcomeTextForLanguage = function(optionEl, lang) {\n            if (!optionEl) return '';\n            lang = String(lang || window.currLang || 'it').toLowerCase() === 'en' ? 'en' : 'it';\n            const raw = String(optionEl.dataset && optionEl.dataset.acc ? optionEl.dataset.acc : '');\n            if (lang !== 'en') return raw;\n            const en = String(optionEl.dataset && optionEl.dataset.accEn ? optionEl.dataset.accEn : '');\n            if (en) return en;\n            return (window.tiTranslateLayoutStringToEn ? window.tiTranslateLayoutStringToEn(raw) : raw);\n        };\n        window.tiQueueCompanyWelcomeAccTranslation = function(optionEl, bubble, sourceHtml, dbValue) {\n            try {\n                if (!optionEl || !bubble || String(window.currLang || 'it').toLowerCase() !== 'en') return;\n                const rawAcc = String(optionEl.dataset && optionEl.dataset.acc ? optionEl.dataset.acc : '');\n                if (!rawAcc.trim()) return;\n                const accKey = window.tiHashString ? window.tiHashString(rawAcc) : String(rawAcc.length);\n                if (optionEl.dataset.accEn && optionEl.dataset.accEnKey === accKey) return;\n                if (!window.tiRemoteTranslateHtmlToLanguage) return;\n                window.tiRemoteTranslateHtmlToLanguage(rawAcc, 'en', dbValue || '', rawAcc).then(function(accEn){\n                    accEn = String(accEn || '').replace(\/<[^>]+>\/g, ' ').trim();\n                    if (!accEn || String(window.currLang || 'it').toLowerCase() !== 'en') return;\n                    optionEl.dataset.accEn = accEn;\n                    optionEl.dataset.accEnKey = accKey;\n                    if (bubble && sourceHtml && bubble.getAttribute('data-ti-it-html') === sourceHtml) {\n                        const translatedHtml = sourceHtml.replace(rawAcc, accEn);\n                        bubble.innerHTML = translatedHtml;\n                        if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(bubble);\n                        bubble.__tiChatHtmlByLang = bubble.__tiChatHtmlByLang || {};\n                        bubble.__tiChatHtmlByLang.en = bubble.innerHTML;\n                    }\n                }).catch(function(){});\n            } catch(e) {}\n        };\n\n        window.updCtx = function(silent) {\n             silent = !!silent;\n             const d = gE('ti-ditta');\n             if(!d || !d.value || d.value === 'NEW_DB') {\n                 gE('ti-company-name').textContent = \"Shop & Service\"; const companySub = gE('ti-company-sub'); if (companySub) { companySub.innerHTML = ''; companySub.style.display = 'none'; } if (window.updateCompanyReferenceDateTime) window.updateCompanyReferenceDateTime();\n                 if(!silent) {\n                     let welcomeName = window.tiUserDisplay ? \" Ciao <b>\" + window.tiUserDisplay + \"<\/b>!\" : \"\";\n                     let cfgWelcome = window.getConfiguratorWelcomeHtml ? window.getConfiguratorWelcomeHtml() : '';\n                     let htmlMsg = cfgWelcome || `Sono l'assistente virtuale di <b>Shop & Service<\/b>.${welcomeName}<br><br>Scegli una ditta dal menu in alto, oppure dimmi cosa stai cercando e ti consiglier\u00f2 l'attivit\u00e0 giusta per te!`;\n                     const welcomeVoice = `Sono l'assistente virtuale di Shop & Service. Ciao ${window.tiUserDisplay || ''}! Scegli una ditta dal menu in alto, oppure dimmi cosa stai cercando e ti consiglier\u00f2 l'attivit\u00e0 giusta per te!`;\n                     if (window.tiAddAiMessageTranslatedIfNeeded) window.tiAddAiMessageTranslatedIfNeeded(htmlMsg, welcomeVoice, '');\n                     else { if(window.addMsg) window.addMsg('ai', htmlMsg, htmlMsg); window.speakText(welcomeVoice); }\n                     if (cfgWelcome && window.showConfiguratorOperationalTipsPopup) setTimeout(function(){ window.showConfiguratorOperationalTipsPopup(false); }, 350);\n                 }\n                 return;\n             }\n             const s = d.options[d.selectedIndex];\n             if(s) {\n                 window.currentDittaName = s.dataset.name; gE('ti-company-name').textContent = s.dataset.name; if (window.updateCompanyReferenceDateTime) window.updateCompanyReferenceDateTime(); if (window.applyCompanyLimitedNotice) window.applyCompanyLimitedNotice(); \n                 const l = gE('ti-logo-img'); \n\n                 let directLink = \"\"; try { const base1964 = \"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/\"; const enc1964 = encodeURIComponent(String(s.value||'')).replace(\/[!'()*]\/g,function(c){return \"%\"+c.charCodeAt(0).toString(16).toUpperCase();}); directLink = base1964 + (String(base1964).indexOf(\"?\")>=0?\"&\":\"?\") + \"ti_ai_db=\" + enc1964; } catch(e1963) { directLink = \"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/\" + \"?ti_ai_db=\" + encodeURIComponent(String(s.value||'')).replace(\/[!'()*]\/g,function(c){return \"%\"+c.charCodeAt(0).toString(16).toUpperCase();}); }\n                 if(l && s.dataset.logo && s.dataset.logo !== \"undefined\") { \n                     let finalLogo = window.getFullImgUrl(s.dataset.logo, s.value, 'Config');\n                     l.src = finalLogo; \n                     l.style.display = 'block'; \n                     l.title = 'Copia link diretto della ditta';\n                     l.onclick = () => { navigator.clipboard.writeText(directLink).then(() => window.tiAlert(\"Link copiato:\\n\" + directLink)); };\n                 } else if(l) { l.style.display = 'none'; l.onclick = null; }\n\n                 const q = gE('ti-qr-img'); if(q && s.value && s.value !== \"NEW_DB\") { q.src=\"https:\/\/api.qrserver.com\/v1\/create-qr-code\/?size=100x100&data=\"+encodeURIComponent(directLink); q.style.display='block'; q.onclick = () => window.open(directLink, '_blank'); } else if (q) { q.style.display='none'; }\n\n                 const uAva = gE('ti-user-avatar');\n                 if(window.tiUser && window.tiUserFoto) { const fotoDb = window.tiUserFotoDb || s.value; const avaUrl = window.getSafePreviewUrl(window.tiUserFoto, fotoDb, (String(window.tiAccountTable||'Utenti').toLowerCase().indexOf('operator')>=0?'Operatori':'Utenti'), 'Immagine', window.tiUser || 'utente'); if(uAva && avaUrl) { uAva.src = avaUrl; uAva.style.display = 'block'; } } else if(uAva) { uAva.style.display = 'none'; }\n\n                 if(!silent) {\n                     let accTextForLang = window.tiGetCompanyWelcomeTextForLanguage ? window.tiGetCompanyWelcomeTextForLanguage(s, window.currLang) : (s.dataset.acc || '');\n                     let acc = accTextForLang && accTextForLang !== 'undefined' && accTextForLang !== '' ? `<br><br><b>${accTextForLang}<\/b>` : '';\n                     let welcomeName = window.tiUserDisplay ? \" Ciao <b>\" + window.tiUserDisplay + \"<\/b>!\" : \"\";\n                     let plainAcc = accTextForLang && accTextForLang !== 'undefined' ? accTextForLang : '';\n                     let plainWelcomeName = window.tiUserDisplay ? \" Ciao \" + window.tiUserDisplay + \"!\" : \"\";\n\n                     let cfgWelcome = window.getConfiguratorWelcomeHtml ? window.getConfiguratorWelcomeHtml() : '';\n                     const stateNoticeHtml = window.getCompanyLimitedNoticeHtml ? window.getCompanyLimitedNoticeHtml() : '';\n                     let htmlMsg = cfgWelcome || `Sono l'assistente virtuale di <b>${s.dataset.name}<\/b>.${welcomeName}${acc}<br>Per parlare con me usa il campo <b>scrivi qui<\/b><br><br>${stateNoticeHtml}Come posso aiutarti oggi?`;\n                     let voiceMsg = cfgWelcome ? `Ciao ${window.tiUserDisplay || 'configuratore'}, puoi configurare la ditta oppure usare la main form come utente registrato standard.` : `Sono l'assistente virtuale di ${s.dataset.name}. ${plainWelcomeName} ${plainAcc} Per parlare con me usa il campo scrivi qui. Come posso aiutarti oggi?`;\n\n                     let welcomeBubble = null;\n                     if (window.tiAddAiMessageTranslatedIfNeeded) welcomeBubble = window.tiAddAiMessageTranslatedIfNeeded(htmlMsg, voiceMsg, s.value);\n                     else { if(window.addMsg) welcomeBubble = window.addMsg('ai', htmlMsg, htmlMsg); window.speakText(voiceMsg); }\n                     if (window.tiQueueCompanyWelcomeAccTranslation) window.tiQueueCompanyWelcomeAccTranslation(s, welcomeBubble, htmlMsg, s.value);\n                     if (cfgWelcome && window.showConfiguratorOperationalTipsPopup) setTimeout(function(){ window.showConfiguratorOperationalTipsPopup(false); }, 350);\n                     if (window.loadRegisteredUserProfileWelcome) window.loadRegisteredUserProfileWelcome(s.value);\n                     \/\/ 30.9.1903: dopo l avvio della ditta riporta e invia una sola volta\n                     \/\/ l eventuale testo con cui l utente l ha cercata.\n                     if (window.tiConsumeCompanySearchCarry1903) window.tiConsumeCompanySearchCarry1903(s.value);\n                     window.resetIdleTimers(); \n                 }\n             }\n        };\n\nwindow.idleTimer1 = null; window.idleTimer2 = null; window.idleTimer3 = null;\n        window.idleIgnoreUntil = 0;\n        window.idleForceClosing = false;\n        window.idleAwaitingChoice = false;\n        window.idleLastUserActivityAt = Date.now();\n        window.idleFirstWarningAt = 0;\n        window.idleFinalWarningAt = 0;\n        window.idleCloseCheckAt = 0;\n        window.IDLE_FIRST_WARNING_MS = 180000;   \/\/ 3 minuti senza attivita utente\n        window.IDLE_SECOND_WARNING_MS = 120000;  \/\/ ulteriore attesa dopo il primo avviso per utenti standard\/responsabili\n        window.IDLE_CLOSE_AFTER_MS = 60000;      \/\/ chiusura finale per utenti standard\/responsabili\n        window.IDLE_ADMIN_CONFIG_CLOSE_AFTER_WARNING_MS = 3600000; \/\/ 1 ora dall ultimo avviso per amministratori\/configuratori\n        window.isIdleSessionActive = function() {\n            return !!(dom.ditta && dom.ditta.value && dom.ditta.value !== 'NEW_DB');\n        };\n        window.isIdleAdminConfiguratorRole = function() {\n            const role = String(window.tiRole || '').toLowerCase();\n            const user = String(window.tiUser || '').trim();\n            return user === 'SSGlobalAdmin' || \/amministratore|administrator|configuratore|configurator\/.test(role);\n        };\n        window.clearIdleTimers = function() {\n            clearTimeout(window.idleTimer1);\n            clearTimeout(window.idleTimer2);\n            clearTimeout(window.idleTimer3);\n            window.idleTimer1 = null;\n            window.idleTimer2 = null;\n            window.idleTimer3 = null;\n        };\n        window.scheduleIdleFirstWarning = function() {\n            if (window.idleForceClosing) return;\n            window.clearIdleTimers();\n            if (!window.isIdleSessionActive()) return;\n            const elapsed = Date.now() - (window.idleLastUserActivityAt || Date.now());\n            const wait = Math.max(0, window.IDLE_FIRST_WARNING_MS - elapsed);\n            window.idleTimer1 = setTimeout(window.showIdleFirstWarning, wait);\n        };\n        window.showIdleFirstWarning = function() {\n            if (window.idleForceClosing || !window.isIdleSessionActive()) return;\n            const elapsed = Date.now() - (window.idleLastUserActivityAt || Date.now());\n            if (elapsed < window.IDLE_FIRST_WARNING_MS - 250) {\n                window.scheduleIdleFirstWarning();\n                return;\n            }\n            window.idleFirstWarningAt = Date.now();\n            window.idleAwaitingChoice = true;\n            window.idleIgnoreUntil = Date.now() + 8000;\n            if(window.addMsg) window.addMsg('ai', \"\u23f3 Non rilevo attivit\u00e0 da 3 minuti. Vuoi continuare ?\");\n            window.speakText(\"Non rilevo attivit\u00e0 da 3 minuti. Vuoi continuare?\");\n            clearTimeout(window.idleTimer2);\n            clearTimeout(window.idleTimer3);\n            if (window.isIdleAdminConfiguratorRole && window.isIdleAdminConfiguratorRole()) {\n                window.idleCloseCheckAt = window.idleFirstWarningAt;\n                window.idleTimer3 = setTimeout(window.closeIdleSessionIfStillInactive, window.IDLE_ADMIN_CONFIG_CLOSE_AFTER_WARNING_MS);\n            } else {\n                window.idleTimer2 = setTimeout(window.showIdleFinalWarning, window.IDLE_SECOND_WARNING_MS);\n            }\n        };\n        window.showIdleFinalWarning = function() {\n            if (window.idleForceClosing || !window.isIdleSessionActive()) return;\n            if ((window.idleLastUserActivityAt || 0) > (window.idleFirstWarningAt || 0)) {\n                window.scheduleIdleFirstWarning();\n                return;\n            }\n            window.idleFinalWarningAt = Date.now();\n            window.idleCloseCheckAt = window.idleFinalWarningAt;\n            window.idleIgnoreUntil = Date.now() + 8000;\n            if(window.addMsg) window.addMsg('ai', \"\u23f3 Se non ricevo istruzioni chiuder\u00f2 la sessione a breve.\");\n            window.speakText(\"Se non ricevo istruzioni, chiuder\u00f2 la sessione a breve per proteggere i tuoi dati.\");\n            clearTimeout(window.idleTimer3);\n            window.idleTimer3 = setTimeout(window.closeIdleSessionIfStillInactive, window.IDLE_CLOSE_AFTER_MS);\n        };\n        window.closeIdleSessionIfStillInactive = function() {\n            if (window.idleForceClosing || !window.isIdleSessionActive()) return;\n            const checkAt = window.idleCloseCheckAt || window.idleFinalWarningAt || window.idleFirstWarningAt || 0;\n            if ((window.idleLastUserActivityAt || 0) > checkAt) {\n                window.scheduleIdleFirstWarning();\n                return;\n            }\n            window.idleForceClosing = true;\n            if(window.addMsg) window.addMsg('ai', \"\ud83d\udd12 Sessione chiusa per inattivit\u00e0.\");\n            window.speakText(\"Sessione chiusa per inattivit\u00e0.\");\n            window.doLogout(true);\n        };\n        window.resetIdleTimers = function(evt) {\n            if (window.idleForceClosing) return;\n            if (evt && evt.isTrusted === false) return;\n            if (window.idleIgnoreUntil && Date.now() < window.idleIgnoreUntil) return;\n            window.idleLastUserActivityAt = Date.now();\n            window.idleFirstWarningAt = 0;\n            window.idleFinalWarningAt = 0;\n            window.idleCloseCheckAt = 0;\n            window.scheduleIdleFirstWarning();\n        };\n        ['mousemove', 'keydown', 'wheel', 'touchstart', 'click'].forEach(evt => {\n            document.addEventListener(evt, function(e){ window.resetIdleTimers(e); }, {passive: true});\n        });\n\n        window.placeMainHelpButtonRight = function() {\n            const row = document.querySelector('#ti-ai-outer .ti-actions-row');\n            const btn = gE('ti-help-btn');\n            if (!row || !btn) return;\n            if (btn.parentNode !== row || row.lastElementChild !== btn) row.appendChild(btn);\n        };\n        window.getPrivilegedActionsRow = function() {\n            let row = gE('ti-admin-actions-row');\n            const host = document.querySelector('#ti-ai-outer .ti-input-wrap');\n            if (!row && host) {\n                row = document.createElement('div');\n                row.id = 'ti-admin-actions-row';\n                row.className = 'ti-admin-actions-row';\n                row.setAttribute('aria-label', 'Comandi amministrativi');\n                host.appendChild(row);\n            }\n            return row;\n        };\n        \/\/ 30.9.1639: Globale e Storage condividono una colonna; Storage resta stabilmente sotto Globale.\n        window.getGlobalStorageStack1639 = function() {\n            const row = window.getPrivilegedActionsRow ? window.getPrivilegedActionsRow() : gE('ti-admin-actions-row');\n            if (!row) return null;\n            let stack = gE('ti-global-storage-stack-1639');\n            if (!stack) {\n                stack = document.createElement('div');\n                stack.id = 'ti-global-storage-stack-1639';\n                stack.className = 'ti-global-storage-stack-1639';\n                stack.setAttribute('aria-label', 'Comandi globali e storage');\n                row.appendChild(stack);\n            } else if (stack.parentNode !== row) {\n                row.appendChild(stack);\n            }\n            return stack;\n        };\n        window.refreshPrivilegedActionsRow = function() {\n            const row = window.getPrivilegedActionsRow ? window.getPrivilegedActionsRow() : gE('ti-admin-actions-row');\n            if (!row) return;\n            const ids = ['ti-conf-toggle', 'ti-activation-toggle', 'ti-purchase-toggle', 'ti-clean-orphans-btn'];\n            let visible = false;\n            ids.forEach(id => {\n                const b = gE(id);\n                if (b && b.parentNode !== row) row.insertBefore(b, gE('ti-global-storage-stack-1639') || null);\n                if (b && b.style.display !== 'none') visible = true;\n            });\n            const stack = window.getGlobalStorageStack1639 ? window.getGlobalStorageStack1639() : null;\n            let stackVisible = false;\n            ['ti-global-action-toggle','ti-shared-setup-toggle'].forEach(id => {\n                const b = gE(id);\n                if (b && stack && b.parentNode !== stack) stack.appendChild(b);\n                if (b && b.style.display !== 'none') stackVisible = true;\n            });\n            if (stack) stack.style.display = stackVisible ? 'flex' : 'none';\n            if (stackVisible) visible = true;\n            row.style.display = visible ? 'flex' : 'none';\n        };\n\n        window.tiGetConfigRow = function(data) {\n            data = data || window.currentDbData || {};\n            const tables = data && data.Tabelle ? data.Tabelle : {};\n            const keys = Object.keys(tables || {});\n            let k = keys.find(x => String(x).toLowerCase() === 'config') || keys.find(x => \/config\/i.test(String(x))) || 'Config';\n            const rows = tables[k];\n            return Array.isArray(rows) && rows[0] && typeof rows[0] === 'object' ? rows[0] : {};\n        };\n        window.tiCiField = function(row, names, def) {\n            row = row || {}; names = Array.isArray(names) ? names : [names];\n            const keys = Object.keys(row || {});\n            const norm = function(v){ return String(v || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').toLowerCase().replace(\/[^a-z0-9]\/g,''); };\n            for (const n of names) {\n                const wn = norm(n);\n                for (const k of keys) if (norm(k) === wn) return String(row[k] == null ? '' : row[k]).trim();\n            }\n            return def || '';\n        };\n        window.tiCompanyActivationState = function(data) {\n            data = data || window.currentDbData || {};\n            const cfg = window.tiGetConfigRow(data);\n            const companyKey = window.tiCiField(cfg, ['ActiveID'], '') || String(data.__purchase_company_key || '').trim();\n            const stato = (typeof data.__shop_service_state !== 'undefined') ? String(data.__shop_service_state || '').trim() : window.tiCiField(cfg, ['Stato'], '');\n            const activeId = window.tiCiField(cfg, ['active_id','wc_activate_id','wc_activation_id'], '');\n            const activationOrderId1655 = window.tiCiField(cfg, ['wc_activation_order_id'], '');\n            const activationTrace1655 = !!(activationOrderId1655 || activeId || window.tiCiField(cfg, ['activation_id','base_activation_id'], ''));\n            const monthlyId = window.tiCiField(cfg, ['canone_id','active_canone_id','wc_canone_order_id','wc_monthly_order_id','wc_subscription_id','subscription_id','abbonamento_id'], '');\n            const monthlyState = window.tiCiField(cfg, ['Stato canone','Canone stato','stato_canone','Abbonamento stato'], '');\n            \/\/ I metadati server 1573 sono calcolati prima del filtro dei campi Config: sono quindi la fonte\n            \/\/ autorevole anche per Configuratore\/Responsabile, che non devono vedere i campi amministrativi grezzi.\n            const activationActive = (typeof data.__shop_service_activation_active !== 'undefined')\n                ? Number(data.__shop_service_activation_active || 0) === 1\n                : (\/^(attivo|operativo)$\/i.test(stato) || activationTrace1655);\n            const monthlyActive = (typeof data.__shop_service_monthly_active !== 'undefined')\n                ? Number(data.__shop_service_monthly_active || 0) === 1\n                : (\/^operativo$\/i.test(stato) || \/^(attivo|operativo)$\/i.test(monthlyState));\n            const purchaseReady = (typeof data.__shop_service_purchase_ready !== 'undefined')\n                ? Number(data.__shop_service_purchase_ready || 0) === 1\n                : companyKey !== '';\n            const canPrepareActiveId = (typeof data.__shop_service_can_prepare_activeid !== 'undefined') ? Number(data.__shop_service_can_prepare_activeid || 0) === 1 : true;\n            const canPurchaseActivation = (typeof data.__shop_service_can_purchase_activation !== 'undefined') ? Number(data.__shop_service_can_purchase_activation || 0) === 1 : !activationActive;\n            const canPurchaseMonthly = (typeof data.__shop_service_can_purchase_monthly !== 'undefined') ? Number(data.__shop_service_can_purchase_monthly || 0) === 1 : (activationActive && !monthlyActive);\n            const canPurchaseAiActs = (typeof data.__shop_service_can_purchase_ai_acts !== 'undefined') ? Number(data.__shop_service_can_purchase_ai_acts || 0) === 1 : (activationActive && monthlyActive);\n            const purchaseUrls = {\n                activation: String(data.__shop_service_activation_url || '').trim(),\n                monthly: String(data.__shop_service_monthly_url || '').trim(),\n                ai_acts: String(data.__shop_service_ai_acts_url || '').trim()\n            };\n            const num = function(v){ const n = parseInt(String(v == null ? '' : v).replace(\/[^0-9-]\/g,''),10); return Number.isFinite(n) ? n : 0; };\n            const totAiActs = (typeof data.__tot_ai_acts !== 'undefined') ? num(data.__tot_ai_acts) : num(window.tiCiField(cfg, ['TotAIActs'], '0'));\n            const aiActs = (typeof data.__ai_acts !== 'undefined') ? num(data.__ai_acts) : num(window.tiCiField(cfg, ['AIActs'], '0'));\n            const remainingAiActs = Math.max(0, (typeof data.__ai_acts_remaining !== 'undefined') ? num(data.__ai_acts_remaining) : (totAiActs - aiActs));\n            const thresholdAiActs90 = (typeof data.__ai_acts_threshold_90 !== 'undefined') ? num(data.__ai_acts_threshold_90) : (totAiActs > 0 ? Math.ceil(totAiActs * 0.90) : 0);\n            const usageAiActsPercent = (typeof data.__ai_acts_usage_percent !== 'undefined') ? Number(data.__ai_acts_usage_percent || 0) : (totAiActs > 0 ? ((aiActs \/ totAiActs) * 100) : (aiActs > 0 ? 100 : 0));\n            const nearLimitAiActs = (typeof data.__ai_acts_near_limit !== 'undefined') ? Number(data.__ai_acts_near_limit || 0) === 1 : (remainingAiActs <= 0 || (totAiActs > 0 && aiActs >= thresholdAiActs90));\n            const activeIdInconsistent = Number(data.__shop_service_activeid_inconsistent || 0) === 1;\n            const activeIdRepairSafe = Number(data.__shop_service_activeid_repair_safe || 0) === 1;\n            const extraAiActsActive = (typeof data.__shop_service_extra_ai_acts_active !== 'undefined')\n                ? Number(data.__shop_service_extra_ai_acts_active || 0) === 1\n                : Number(data.__ai_acts_extra_active || 0) === 1;\n            const activationCoverageDays = (typeof data.__shop_service_activation_days_remaining !== 'undefined' && data.__shop_service_activation_days_remaining !== null) ? Number(data.__shop_service_activation_days_remaining) : null;\n            const activationCoverageEnd = Number(data.__shop_service_activation_coverage_end || 0);\n            const activationAiRemaining = Number(data.__shop_service_activation_ai_remaining || 0);\n            const monthTotalProspective = Number(data.__shop_service_month_total_prospective || 0);\n            const monthTotalAfterExtraPurchase = Number(data.__shop_service_month_total_after_extra_purchase || 0);\n            const monthlyUnit = Math.max(1, Number(data.__shop_service_monthly_unit || 200));\n            const monthlyCoverageDays = (typeof data.__shop_service_monthly_days_remaining !== 'undefined' && data.__shop_service_monthly_days_remaining !== null) ? Number(data.__shop_service_monthly_days_remaining) : null;\n            const aiActsCoverageDays = (typeof data.__shop_service_ai_acts_days_remaining !== 'undefined' && data.__shop_service_ai_acts_days_remaining !== null) ? Number(data.__shop_service_ai_acts_days_remaining) : null;\n            return {companyKey, stato, activeId, activationOrderId1655, activationTrace1655, monthlyId, monthlyState, activationActive, monthlyActive, purchaseReady, canPrepareActiveId, canPurchaseActivation, canPurchaseMonthly, canPurchaseAiActs, purchaseUrls, totAiActs, aiActs, remainingAiActs, thresholdAiActs90, usageAiActsPercent, nearLimitAiActs, extraAiActsActive, activeIdInconsistent, activeIdRepairSafe, activationCoverageDays, activationCoverageEnd, activationAiRemaining, monthTotalProspective, monthTotalAfterExtraPurchase, monthlyUnit, monthlyCoverageDays, aiActsCoverageDays};\n        };\n        window.tiNormalizeShopServiceProductUrl = function(base, kind) {\n            kind = kind === 'ai_acts' ? 'ai_acts' : (kind === 'monthly' ? 'monthly' : 'activation');\n            const fallback = kind === 'monthly' ? 'https:\/\/www.tisoft.it\/prodotto\/shop-service\/' : (kind === 'activation' ? 'https:\/\/www.tisoft.it\/prodotto\/shop-service-attivazione\/' : '');\n            base = String(base || '').trim() || fallback;\n            if (kind === 'ai_acts' && !base) return '';\n            try {\n                const u = new URL(base, window.location.origin);\n                const host = String(u.hostname || '').toLowerCase();\n                const pathNorm = '\/' + String(u.pathname || '').replace(\/^\\\/+|\\\/+$\/g, '') + '\/';\n                if (host === 'www.tisoft.it' || host === 'tisoft.it') {\n                    if (kind === 'ai_acts' && (pathNorm === '\/shop-service\/' || pathNorm === '\/prodotto\/shop-service\/' || pathNorm === '\/prodotto\/shop-service-canone-mensile\/')) {\n                        return '';\n                    }\n                    if (kind === 'monthly' && (pathNorm === '\/shop-service\/' || pathNorm === '\/prodotto\/shop-service-canone-mensile\/')) {\n                        u.pathname = '\/prodotto\/shop-service\/';\n                    }\n                    if (kind === 'activation' && (pathNorm === '\/shop-service-attivazione\/' || pathNorm === '\/attivazione-shop-service\/')) {\n                        u.pathname = '\/prodotto\/shop-service-attivazione\/';\n                    }\n                }\n                return u.toString();\n            } catch(e) {\n                return fallback;\n            }\n        };\n        window.tiBuildShopServiceBuyUrl = function(kind, companyKey) {\n            kind = kind === 'ai_acts' ? 'ai_acts' : (kind === 'monthly' ? 'monthly' : 'activation');\n            const rawBase = kind === 'ai_acts'\n                ? (window.tiShopServiceAiActsProductUrl || '')\n                : (kind === 'monthly' ? (window.tiShopServiceMonthlyProductUrl || 'https:\/\/www.tisoft.it\/prodotto\/shop-service\/') : (window.tiShopServiceActivationProductUrl || 'https:\/\/www.tisoft.it\/prodotto\/shop-service-attivazione\/'));\n            if (kind === 'ai_acts' && !rawBase) return '';\n            const base = window.tiNormalizeShopServiceProductUrl(rawBase, kind);\n            try {\n                const url = new URL(base, window.location.origin);\n                url.searchParams.set('ss_company', companyKey || '');\n                url.searchParams.set('ss_service', kind);\n                return url.toString();\n            } catch(e) {\n                const sep = String(base).indexOf('?') === -1 ? '?' : '&';\n                return String(base) + sep + 'ss_company=' + encodeURIComponent(companyKey || '') + '&ss_service=' + encodeURIComponent(kind);\n            }\n        };\n        window.ensureShopServiceActivationModal = function() {\n            let ov = gE('ti-shopservice-activation-ov');\n            if (ov) return ov;\n            ov = document.createElement('div');\n            ov.id = 'ti-shopservice-activation-ov';\n            ov.className = 'ti-modal-overlay';\n            ov.style.display = 'none';\n            ov.style.zIndex = '99992';\n            ov.style.alignItems = 'center';\n            ov.style.justifyContent = 'center';\n            ov.innerHTML = `<div class=\"ti-modal\" style=\"width:min(520px,94vw);background:#0f172a;color:#fff;border-radius:16px;padding:18px;box-shadow:0 18px 60px rgba(0,0,0,.45);\">\n                <div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px;\">\n                    <div><h2 style=\"margin:0;font-size:20px;\">Attiva Shop & Service<\/h2><div id=\"ti-shopservice-activation-sub\" style=\"font-size:13px;color:#cbd5e1;margin-top:5px;\"><\/div><\/div>\n                    <button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"window.closeShopServiceActivationPopup()\">X<\/button>\n                <\/div>\n                <div id=\"ti-shopservice-activation-body\" style=\"display:grid;gap:10px;margin-top:12px;\"><\/div>\n                <div style=\"font-size:12px;color:#cbd5e1;margin-top:14px;line-height:1.35;\">Eventuali variazioni del servizio, del canone e del pacchetto attivit\u00e0 AI aggiuntive saranno gestite dal profilo e-commerce Shop &amp; Service <a href=\"https:\/\/www.tisoft.it\/\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color:#7dd3fc;text-decoration:underline;\">https:\/\/www.tisoft.it\/<\/a>, richiamando l'ordine attivo.<\/div>\n            <\/div>`;\n            document.body.appendChild(ov);\n            return ov;\n        };\n        window.closeShopServiceActivationPopup = function() {\n            const ov = gE('ti-shopservice-activation-ov');\n            if (!ov) return;\n            if (window.closeModal) window.closeModal(ov); else ov.style.display = 'none';\n        };\n        window.openShopServiceActivationPopup = function() {\n            const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Seleziona prima una ditta.'); return; }\n            const openWithData = function(data) {\n                window.currentDbData = data || window.currentDbData || {};\n                try { if (window.refreshShopServiceActivationButton) window.refreshShopServiceActivationButton(); } catch(e1655) {}\n                const st = window.tiCompanyActivationState(window.currentDbData);\n                if (!st.purchaseReady) {\n                    const role1551 = String(window.tiRole || '').toLowerCase();\n                    const user1551 = String(window.tiUser || '').toLowerCase();\n                    const isAdmin1551 = user1551 === 'ssglobaladmin' || \/amministratore|administrator|globaladmin|global admin|sysadmin|admin\/.test(role1551);\n                    const canPrepare1570 = isAdmin1551 || \/configuratore|configurator|responsabile|responsible\/.test(role1551);\n                    if (!st.canPrepareActiveId || !canPrepare1570 || user1551 === 'ssdemo') { window.tiAlert('Identificativo tecnico per gli acquisti non disponibile. Il profilo corrente non puo predisporlo nello stato attuale della ditta.'); return; }\n                    const ask1551 = function(){\n                        const fd1551 = new FormData(); fd1551.append('ti_action','ti_ai_ss_reactivate_company_1551'); fd1551.append('action','ti_ai_ss_reactivate_company_1551'); fd1551.append('db',dbVal);\n                        window.fetchJsonSafe(window.tiUrl,{method:'POST',body:fd1551}).then(function(r1551){\n                            if (!r1551 || !r1551.success) { window.tiAlert((r1551 && r1551.data && r1551.data.message) ? r1551.data.message : 'Preparazione attivazione non riuscita.'); return; }\n                            if (isAdmin1551 && r1551.data && r1551.data.db) {\n                                window.currentDbData = r1551.data.db;\n                                if (window.currentDbData) openWithData(window.currentDbData);\n                                return;\n                            }\n                            const prepared1570 = Object.assign({}, window.currentDbData || data || {});\n                            const rr1573 = (r1551 && r1551.data) ? r1551.data : {};\n                            prepared1570.__shop_service_state = String(rr1573.state || st.stato || '');\n                            prepared1570.__shop_service_purchase_ready = rr1573.purchase_ready ? 1 : 0;\n                            prepared1570.__shop_service_activation_active = rr1573.activation_active ? 1 : 0;\n                            prepared1570.__shop_service_monthly_active = rr1573.monthly_active ? 1 : 0;\n                            prepared1570.__shop_service_extra_ai_acts_active = rr1573.extra_ai_acts_active ? 1 : 0;\n                            prepared1570.__shop_service_can_purchase_activation = rr1573.can_purchase_activation ? 1 : 0;\n                            prepared1570.__shop_service_can_purchase_monthly = rr1573.can_purchase_monthly ? 1 : 0;\n                            prepared1570.__shop_service_can_purchase_ai_acts = rr1573.can_purchase_ai_acts ? 1 : 0;\n                            prepared1570.__shop_service_can_prepare_activeid = 1;\n                            if (rr1573.purchase_urls) {\n                                prepared1570.__shop_service_activation_url = String(rr1573.purchase_urls.activation || '');\n                                prepared1570.__shop_service_monthly_url = String(rr1573.purchase_urls.monthly || '');\n                                prepared1570.__shop_service_ai_acts_url = String(rr1573.purchase_urls.ai_acts || '');\n                            }\n                            const key1570 = String(rr1573.active_id || '').trim();\n                            if (key1570) prepared1570.__purchase_company_key = key1570;\n                            if (!prepared1570.__shop_service_purchase_ready) { window.tiAlert('Preparazione acquisti non riuscita: identificativo tecnico non disponibile.'); return; }\n                            window.currentDbData = prepared1570;\n                            openWithData(prepared1570);\n                        }).catch(function(e1551){ window.tiAlert('Errore preparazione attivazione: ' + e1551.message); });\n                    };\n                    \/\/ 30.9.1656: un mismatch dichiarato safe viene corretto direttamente. Il vecchio\n                    \/\/ ActiveID viene prima conservato lato server come alias, quindi non serve un secondo popup\n                    \/\/ che puo lasciare l'utente bloccato prima di vedere l'opzione di acquisto.\n                    if (st.activeIdRepairSafe) { ask1551(); return; }\n                    const alreadyEnabled1573 = \/^(attivo|operativo)$\/i.test(String(st.stato || '')) || !!st.activationActive;\n                    const msg1570 = st.activeIdRepairSafe\n                        ? 'Rilevata un incoerenza tecnica: ActiveID appartiene al nome di un altro database e non risultano acquisti gia acquisiti. Vuoi rigenerare automaticamente l identificativo corretto per questa ditta prima dell acquisto?'\n                        : (alreadyEnabled1573\n                            ? 'La ditta risulta ' + (st.stato || 'Attiva') + ' ma manca l identificativo tecnico usato per associare gli acquisti successivi. Vuoi ripristinarlo ora? Lo stato della ditta e l attivazione gia acquisita resteranno invariati; non verra riproposto SHOP-SERVICE-1.'\n                            : (isAdmin1551\n                                ? 'ActiveID non presente. Vuoi predisporre un nuovo identificativo per verificare o acquistare i servizi Shop & Service?'\n                                : 'La ditta non dispone ancora dell identificativo tecnico necessario ad associare l acquisto SHOP-SERVICE-1. Vuoi predisporlo ora? La ditta restera nello stato corrente (Configurazione\/Demo\/Sospesa) fino al pagamento e al riconoscimento dell ordine.'));\n                    if (window.tiConfirm) window.tiConfirm(msg1570, ask1551);\n                    else if (window.confirm(msg1570)) ask1551();\n                    return;\n                }\n                const ov = window.ensureShopServiceActivationModal();\n                const sub = gE('ti-shopservice-activation-sub');\n                const body = gE('ti-shopservice-activation-body');\n                const title1573 = ov ? ov.querySelector('h2') : null;\n                if (title1573) title1573.textContent = !st.activationActive ? 'Attiva Shop & Service' : (!st.monthlyActive ? 'Abbonati a Shop & Service' : 'Aggiungi AI');\n                if (sub) sub.textContent = 'Stato ditta: ' + (st.stato || 'non definito');\n                const buyUrl1573 = function(kind) {\n                    const direct = st.purchaseUrls && st.purchaseUrls[kind] ? String(st.purchaseUrls[kind] || '').trim() : '';\n                    return direct || window.tiBuildShopServiceBuyUrl(kind, st.companyKey);\n                };\n                const quotaCard = '<div style=\"padding:12px;border-radius:10px;background:#111827;border:1px solid #334155;line-height:1.55;\">' +\n                    '<b>Disponibilit\u00e0 attivit\u00e0 AI<\/b><br>' +\n                    'Totale attivit\u00e0 AI abilitate: <b>' + Number(st.totAiActs || 0).toLocaleString('it-IT') + '<\/b><br>' +\n                    'Attivit\u00e0 AI eseguite: <b>' + Number(st.aiActs || 0).toLocaleString('it-IT') + '<\/b><br>' +\n                    'Attivit\u00e0 AI disponibili: <b>' + Number(st.remainingAiActs || 0).toLocaleString('it-IT') + '<\/b><br>' +\n                    'Utilizzo attivit\u00e0 AI: <b style=\"' + (Number(st.usageAiActsPercent || 0) > 95 ? 'color:#ef4444;font-weight:900;' : '') + '\">' + Number(st.usageAiActsPercent || 0).toLocaleString('it-IT', {maximumFractionDigits:1}) + '%<\/b><\/div>';\n                const coverage = [];\n                const trialActive1772 = !!(data && data.__shop_service_trial_active_1772);\n                const trialEnd1772 = Number(data && data.__shop_service_trial_end_1772 || 0);\n                const trialDays1772 = Number(data && data.__shop_service_trial_days_1772 || 0);\n                if (trialActive1772 && trialEnd1772 > 0) {\n                    let trialDate1772=''; try{trialDate1772=new Date(trialEnd1772*1000).toLocaleDateString('it-IT',{day:'2-digit',month:'2-digit',year:'numeric'});}catch(e1772){}\n                    coverage.push('<div style=\"padding:10px 12px;border-radius:10px;background:#172554;border:1px solid #3b82f6;color:#dbeafe;\"><b>Periodo iniziale gratuito:<\/b> valido fino al <b>'+window.escapeHtml(trialDate1772)+'<\/b>. Giorni ancora disponibili: <b>'+Math.max(0,trialDays1772)+'<\/b>. La prova non sostituisce l attivazione commerciale Shop & Service.<\/div>');\n                }\n                \/\/ 30.9.1993: nel popup non serve esporre lo storico della copertura iniziale SHOP-SERVICE-1.\n                \/\/ L utente vede soltanto lo stato corrente del servizio e, se presente, il periodo mensile attivo.\n                if (st.activationActive) coverage.push('<div style=\"padding:10px 12px;border-radius:10px;background:#172554;border:1px solid #3b82f6;color:#dbeafe;font-weight:700;\"><b>SHOP &amp; SERVICE \u00e8 attivo<\/b><\/div>');\n                if (st.monthlyActive) coverage.push('<div style=\"padding:8px 10px;border-radius:9px;background:#082f49;border:1px solid #0ea5e9;color:#bae6fd;\"><b>SHOP &amp; SERVICE:<\/b> servizio mensile corrente attivo<\/div>');\n                if (st.extraAiActsActive && st.aiActsCoverageDays !== null) coverage.push('<div style=\"padding:8px 10px;border-radius:9px;background:#14532d;border:1px solid #22c55e;color:#bbf7d0;\"><b>SHOP-SERVICE-2:<\/b> servizio aggiuntivo mensile corrente, ' + Math.max(0,st.aiActsCoverageDays) + ' giorni residui.<\/div>');\n                const actions = [];\n                \/\/ Sequenza commerciale rigorosa: SHOP-SERVICE-1 -> SHOP-SERVICE -> SHOP-SERVICE-2.\n                \/\/ Una ditta gia Attiva\/Operativa non deve mai vedere di nuovo l acquisto SHOP-SERVICE-1.\n                if (!st.activationActive && st.canPurchaseActivation) {\n                    const activationUrl1573 = buyUrl1573('activation');\n                    if (activationUrl1573) actions.push('<a class=\"ti-btn\" style=\"display:block;text-align:center;background:#22c55e;color:#052e16;font-weight:800;padding:12px;border-radius:10px;text-decoration:none;\" target=\"_blank\" rel=\"noopener noreferrer\" href=\"' + window.escapeHtml(activationUrl1573) + '\">Acquista attivazione Shop & Service (+200 attivit\u00e0 AI una tantum)<\/a>');\n                }\n                if (st.activationActive && !st.monthlyActive && st.canPurchaseMonthly) {\n                    const monthlyUrl1573 = buyUrl1573('monthly');\n                    if (monthlyUrl1573) actions.push('<a class=\"ti-btn\" style=\"display:block;text-align:center;background:#38bdf8;color:#082f49;font-weight:800;padding:12px;border-radius:10px;text-decoration:none;\" target=\"_blank\" rel=\"noopener noreferrer\" href=\"' + window.escapeHtml(monthlyUrl1573) + '\">Acquista abbonamento Shop & Service (+200 attivit\u00e0 mese)<\/a>');\n                }\n                if (st.activationActive && st.monthlyActive && st.canPurchaseAiActs) {\n                    if (!st.extraAiActsActive) {\n                        const aiActsBuyUrl1553 = buyUrl1573('ai_acts');\n                        if (aiActsBuyUrl1553) {\n                            const prospective2020 = Math.max(0, Number(st.monthTotalAfterExtraPurchase || (Number(st.activationAiRemaining || 0) + Number(st.monthlyUnit || 200) * 2)));\n                            actions.push('<a class=\"ti-btn\" style=\"display:block;text-align:center;background:#a3e635;color:#1a2e05;font-weight:800;padding:12px;border-radius:10px;text-decoration:none;\" target=\"_blank\" rel=\"noopener noreferrer\" href=\"' + window.escapeHtml(aiActsBuyUrl1553) + '\">Acquista pacchetto aggiuntivo (+200 attivit\u00e0 mese) totale attivit\u00e0 mese prospettive [' + prospective2020.toLocaleString('it-IT') + ']<\/a>');\n                        }\n                        else actions.push('<div style=\"padding:10px 12px;border-radius:10px;background:#450a0a;border:1px solid #ef4444;color:#fecaca;font-weight:700;\">Prodotto WooCommerce SHOP-SERVICE-2 non risolto nel catalogo locale: verificare lo SKU del prodotto e, se presente, la sincronizzazione dell indice SKU WooCommerce.<\/div>');\n                    } else {\n                        actions.push('<div style=\"padding:10px 12px;border-radius:10px;background:#052e16;border:1px solid #16a34a;color:#bbf7d0;font-weight:700;\">Pacchetto attivit\u00e0 AI aggiuntive gi\u00e0 attivo: +200 attivit\u00e0 mese.<\/div>');\n                    }\n                }\n                if (!actions.length) {\n                    if (st.activationActive && st.monthlyActive && st.extraAiActsActive) actions.push('<div style=\"padding:10px 12px;border-radius:10px;background:#052e16;border:1px solid #16a34a;color:#bbf7d0;font-weight:700;\">SHOP &amp; SERVICE \u00e8 il servizio attivo; anche il pacchetto attivit\u00e0 AI aggiuntive risulta gi\u00e0 attivo.<\/div>');\n                    else if (!st.activationActive && !st.canPurchaseActivation) actions.push('<div style=\"padding:10px 12px;border-radius:10px;background:#422006;border:1px solid #f59e0b;color:#fde68a;font-weight:700;\">Nessun acquisto disponibile per il profilo corrente nello stato ' + window.escapeHtml(st.stato || 'non definito') + '.<\/div>');\n                }\n                if (Number(st.remainingAiActs || 0) <= 0) {\n                    actions.unshift('<div style=\"padding:10px 12px;border-radius:10px;background:#450a0a;border:1px solid #ef4444;color:#fecaca;\"><b>Attivit\u00e0 AI disponibili esaurite.<\/b> Le attivit\u00e0 AI disponibili sono 0. Come utente privilegiato puoi acquistare ulteriori attivit\u00e0 AI; il flusso seguente propone il servizio\/pacchetto acquistabile per lo stato corrente della ditta.<\/div>');\n                } else if (st.nearLimitAiActs && !st.extraAiActsActive) {\n                    actions.unshift('<div style=\"padding:10px 12px;border-radius:10px;background:#422006;border:1px solid #f59e0b;color:#fde68a;\"><b>Soglia 90% raggiunta.<\/b> Hai utilizzato ' + Number(st.usageAiActsPercent || 0).toLocaleString('it-IT', {maximumFractionDigits:1}) + '% delle attivit\u00e0 AI abilitate. Puoi aggiungere un pacchetto SHOP-SERVICE-2 da 200 attivit\u00e0 mese.<\/div>');\n                }\n                if (body) body.innerHTML = quotaCard + coverage.join('') + actions.join('');\n                if (window.showPluginModal) window.showPluginModal(ov); else ov.style.display = 'flex';\n            };\n            const loadFresh1554 = function(){\n                const fd = new FormData(); fd.append('ti_action','ti_ai_get_db_data'); fd.append('db', dbVal);\n                window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiShowTableReadWait:true, tiTableReadTitle:'Lettura stato attivazione', tiTableReadDetail:'Sto leggendo ActiveID, stato ditta, canone e disponibilit\u00e0 delle attivit\u00e0 AI.', tiTableReadItem:dbVal}).then(function(res){\n                    if (res && res.success) openWithData(res.data); else window.tiAlert((res && res.data && res.data.message) ? res.data.message : 'Errore lettura database.');\n                }).catch(function(err){ window.tiAlert('Errore lettura attivazione: ' + err.message); });\n            };\n            \/\/ 30.9.1554: Attiva forza prima la verifica degli acquisti gia effettuati per SHOP-SERVICE-1,\n            \/\/ SHOP-SERVICE e SHOP-SERVICE-2, poi rilegge il database per mostrare lo stato realmente aggiornato.\n            const fd1554 = new FormData(); fd1554.append('ti_action','ti_ai_ss_wc_reconcile_company_1554'); fd1554.append('action','ti_ai_ss_wc_reconcile_company_1554'); fd1554.append('db',dbVal);\n            window.fetchJsonSafe(window.tiUrl,{method:'POST',body:fd1554,tiShowTableReadWait:true,tiTableReadTitle:'Verifica acquisti Shop & Service',tiTableReadDetail:'Controllo attivazione, abbonamento e pacchetto attivit\u00e0 AI aggiuntive gi\u00e0 acquistati.',tiTableReadItem:dbVal}).then(function(){\n                loadFresh1554();\n            }).catch(function(){\n                \/\/ Se WooCommerce e su un sito esterno resta valido il webhook: non bloccare la lettura locale.\n                loadFresh1554();\n            });\n        };\n        window.__tiActivationVerify2070 = window.__tiActivationVerify2070 || {seq:0,db:'',verified:false,pending:false,data:null,promise:null};\n        window.tiActivationButtonPending2070 = function(btn, msg) {\n            if (!btn) return;\n            btn.disabled = true;\n            btn.setAttribute('aria-disabled','true');\n            btn.setAttribute('aria-busy','true');\n            btn.dataset.tiActivationVerified2070 = '0';\n            btn.innerHTML = '\u23f3 <b>Verifica SS...<\/b>';\n            btn.title = msg || 'Verifica stato Shop & Service direttamente sul database della ditta';\n            btn.style.setProperty('background','#6b7280','important');\n            btn.style.setProperty('color','#f8fafc','important');\n            btn.style.setProperty('border','1px solid #4b5563','important');\n            btn.style.setProperty('cursor','not-allowed','important');\n            btn.style.setProperty('opacity','0.88','important');\n            btn.style.display = 'inline-block';\n        };\n        window.tiApplyVerifiedActivationButton2070 = function(btn, data, db2070) {\n            if (!btn || !data) return false;\n            const st2070 = (typeof window.tiCompanyActivationState === 'function') ? window.tiCompanyActivationState(data) : {};\n            const enabled2070 = !!st2070.activationActive;\n            const subscribed2070 = !!st2070.monthlyActive;\n            if (!enabled2070) {\n                btn.innerHTML = '\u26a1 <b>Attiva SS<\/b>';\n                btn.title = 'Stato verificato sul database: acquista l attivazione Shop & Service';\n            } else if (!subscribed2070) {\n                btn.innerHTML = '\ud83d\uded2 <b>Abbonati<\/b>';\n                btn.title = 'Stato verificato sul database: acquista l abbonamento mensile Shop & Service';\n            } else {\n                btn.innerHTML = '\u2795 <b>Aggiungi AI<\/b>';\n                btn.title = 'Stato verificato sul database: aggiungi attivit\u00e0 AI con SHOP-SERVICE-2';\n            }\n            btn.disabled = false;\n            btn.removeAttribute('aria-disabled');\n            btn.removeAttribute('aria-busy');\n            btn.dataset.tiActivationVerified2070 = '1';\n            btn.dataset.tiActivationVerifiedDb2070 = String(db2070 || '');\n            btn.style.setProperty('background','#22c55e','important');\n            btn.style.setProperty('color','#052e16','important');\n            btn.style.setProperty('border','1px solid #15803d','important');\n            btn.style.setProperty('cursor','pointer','important');\n            btn.style.setProperty('opacity','1','important');\n            btn.style.display = 'inline-block';\n            return true;\n        };\n        window.refreshShopServiceActivationButton = function(force2070) {\n            const btn = gE('ti-activation-toggle');\n            if (!btn) return Promise.resolve(false);\n            const role = String(window.tiRole || '').toLowerCase();\n            const can = String(window.tiUser || '').toLowerCase() === 'ssglobaladmin' || role.includes('amministratore') || role.includes('configuratore') || role.includes('responsabile');\n            if (!can) { btn.style.display = 'none'; return Promise.resolve(false); }\n            const dbEl2070 = gE('ti-ditta') || gE('ti-db-select');\n            const db2070 = String((dbEl2070 && dbEl2070.value) || window.tiSessionDb || '').trim();\n            if (!db2070 || db2070 === 'NEW_DB' || db2070 === 'NEW' || db2070 === 'Global' || db2070 === 'shopservicemain.json') {\n                window.tiActivationButtonPending2070(btn, 'Seleziona una ditta valida: il tasto resta disabilitato finch\u00e9 lo stato non viene verificato sul database.');\n                return Promise.resolve(false);\n            }\n            const cache2070 = window.__tiActivationVerify2070 || (window.__tiActivationVerify2070={seq:0,db:'',verified:false,pending:false,data:null,promise:null});\n            if (!force2070 && cache2070.verified && cache2070.db === db2070 && cache2070.data) {\n                return Promise.resolve(window.tiApplyVerifiedActivationButton2070(btn, cache2070.data, db2070));\n            }\n            if (!force2070 && cache2070.pending && cache2070.db === db2070 && cache2070.promise) return cache2070.promise;\n\n            const seq2070 = ++cache2070.seq;\n            cache2070.db = db2070; cache2070.verified = false; cache2070.pending = true; cache2070.data = null;\n            window.tiActivationButtonPending2070(btn, 'Verifica in corso sul database ' + db2070 + '...');\n            const fd2070 = new FormData();\n            fd2070.append('ti_action','ti_ai_company_identity_1741');\n            fd2070.append('action','ti_ai_company_identity_1741');\n            fd2070.append('db',db2070);\n            const req2070 = window.fetchJsonSafe(window.tiUrl,{method:'POST',body:fd2070,credentials:'same-origin',cache:'no-store'}).then(function(res2070){\n                if (seq2070 !== cache2070.seq || cache2070.db !== db2070) return false;\n                if (!res2070 || !res2070.success || !res2070.data) throw new Error((res2070 && res2070.data && res2070.data.message) ? res2070.data.message : 'Stato ditta non verificato.');\n                const gotDb2070 = String(res2070.data.__db_name || '').trim();\n                const norm2070 = function(v){return String(v||'').replace(\/\\\\\/g,'\/').split('\/').pop().replace(\/\\.json$\/i,'').toLowerCase();};\n                if (gotDb2070 && norm2070(gotDb2070) !== norm2070(db2070)) throw new Error('Il database verificato non corrisponde alla ditta selezionata.');\n                cache2070.pending = false; cache2070.verified = true; cache2070.data = res2070.data;\n                try{console.info('[Shop-Service] stato Attiva SS verificato 2070',{db:db2070,state:window.tiCompanyActivationState?window.tiCompanyActivationState(res2070.data):{}});}catch(e){}\n                return window.tiApplyVerifiedActivationButton2070(btn,res2070.data,db2070);\n            }).catch(function(err2070){\n                if (seq2070 !== cache2070.seq) return false;\n                cache2070.pending = false; cache2070.verified = false; cache2070.data = null;\n                window.tiActivationButtonPending2070(btn,'Verifica database non riuscita: ' + String(err2070 && err2070.message ? err2070.message : err2070));\n                try{console.warn('[Shop-Service] verifica Attiva SS 2070 non riuscita',{db:db2070,error:String(err2070&&err2070.message?err2070.message:err2070)});}catch(e){}\n                return false;\n            });\n            cache2070.promise = req2070;\n            return req2070;\n        };\n\n\n        document.addEventListener('change', function(ev2070){\n            try{\n                const t2070 = ev2070 && ev2070.target;\n                if (!t2070 || (t2070.id !== 'ti-ditta' && t2070.id !== 'ti-db-select')) return;\n                if (window.__tiActivationVerify2070) { window.__tiActivationVerify2070.seq++; window.__tiActivationVerify2070.db=''; window.__tiActivationVerify2070.verified=false; window.__tiActivationVerify2070.pending=false; window.__tiActivationVerify2070.data=null; window.__tiActivationVerify2070.promise=null; }\n                const b2070 = gE('ti-activation-toggle'); if (b2070 && window.tiActivationButtonPending2070) window.tiActivationButtonPending2070(b2070,'Cambio ditta: verifico lo stato Shop & Service sul database selezionato.');\n                setTimeout(function(){try{if(window.refreshShopServiceActivationButton)window.refreshShopServiceActivationButton(true);}catch(e){}},0);\n            }catch(e2070){}\n        }, true);\n\n        window.ensureDeleteCompanyModal = function() {\n            let ov = gE('ti-delete-company-ov');\n            if (ov) return ov;\n            ov = document.createElement('div');\n            ov.id = 'ti-delete-company-ov';\n            ov.className = 'ti-modal-overlay';\n            ov.style.display = 'none';\n            ov.style.zIndex = '99994';\n            ov.style.alignItems = 'center';\n            ov.style.justifyContent = 'center';\n            ov.innerHTML = `<div class=\"ti-modal\" style=\"width:min(560px,94vw);background:#111827;color:#fff;border-radius:16px;padding:18px;box-shadow:0 18px 60px rgba(0,0,0,.55);border:1px solid #dc2626;\">\n                <div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px;\">\n                    <div><h2 style=\"margin:0;font-size:20px;color:#fecaca;\">Cancella ditta<\/h2><div id=\"ti-delete-company-sub\" style=\"font-size:13px;color:#e5e7eb;margin-top:5px;\"><\/div><\/div>\n                    <button type=\"button\" class=\"ti-btn\" style=\"background:#374151;color:#fff;\" onclick=\"window.closeDeleteCompanyPopup()\">X<\/button>\n                <\/div>\n                <div style=\"background:#7f1d1d;border:1px solid #ef4444;border-radius:12px;padding:12px;line-height:1.4;font-size:14px;\">\n                    <b>Avviso definitivo.<\/b><br>\n                    La ditta verr\u00e0 cancellata da Shop & Service ed eliminati tutti gli archivi finora trattati. Prima della cancellazione viene creata un ultima copia di salvataggio disponibile per future esigenze. Saranno inoltre disdetti gli abbonamenti in essere e inviata comunicazione ai configuratori\/amministratori della ditta e all email ditta.\n                <\/div>\n                <div style=\"margin-top:12px;font-size:13px;color:#e5e7eb;\">Per confermare inserisci la password dell utente loggato e premi <b>OK, cancella ditta<\/b>.<\/div>\n                <input id=\"ti-delete-company-password\" type=\"password\" class=\"ti-in\" autocomplete=\"current-password\" placeholder=\"Password\" style=\"margin-top:10px;width:100%;box-sizing:border-box;\">\n                <div id=\"ti-delete-company-status\" style=\"margin-top:10px;font-size:13px;color:#fde68a;min-height:18px;\"><\/div>\n                <div style=\"display:flex;gap:8px;justify-content:flex-end;margin-top:14px;flex-wrap:wrap;\">\n                    <button type=\"button\" class=\"ti-btn\" style=\"background:#374151;color:#fff;\" onclick=\"window.closeDeleteCompanyPopup()\">Annulla<\/button>\n                    <button type=\"button\" id=\"ti-delete-company-confirm-btn\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;border:1px solid #991b1b;font-weight:800;\" onclick=\"window.confirmDeleteCompany()\">OK, cancella ditta<\/button>\n                <\/div>\n            <\/div>`;\n            document.body.appendChild(ov);\n            return ov;\n        };\n        window.openDeleteCompanyPopup = function() {\n            const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Seleziona prima la ditta da cancellare.'); return; }\n            const ov = window.ensureDeleteCompanyModal();\n            const sub = gE('ti-delete-company-sub');\n            const pwd = gE('ti-delete-company-password');\n            const st = gE('ti-delete-company-status');\n            if (sub) sub.textContent = 'Ditta\/database selezionato: ' + dbVal;\n            if (pwd) pwd.value = '';\n            if (st) st.textContent = '';\n            if (window.showPluginModal) window.showPluginModal(ov); else ov.style.display = 'flex';\n            setTimeout(function(){ if (pwd) pwd.focus(); }, 150);\n        };\n        window.closeDeleteCompanyPopup = function() {\n            const ov = gE('ti-delete-company-ov');\n            if (!ov) return;\n            if (window.closeModal) window.closeModal(ov); else ov.style.display = 'none';\n        };\n        window.finishDeleteCompanySuccess = function(data) {\n            const m = (data && data.message) ? data.message : 'Ditta cancellata definitivamente.';\n            const st = gE('ti-delete-company-status');\n            if (st) st.textContent = m;\n            window.tiAlert(m);\n            window.closeDeleteCompanyPopup();\n            try { if (gE('ti-ditta')) gE('ti-ditta').value = ''; } catch(e) {}\n            if (typeof window.loadDitte === 'function') window.loadDitte();\n            if (data && data.logout) setTimeout(function(){ window.location.reload(); }, 900);\n        };\n        window.retryDeleteCompanyWithEmailChoice = function(opts) {\n            opts = opts || {};\n            const dbVal = opts.db || (gE('ti-ditta') ? gE('ti-ditta').value : '');\n            const pwd = opts.password || (gE('ti-delete-company-password') ? gE('ti-delete-company-password').value : '');\n            const st = gE('ti-delete-company-status');\n            const btn = gE('ti-delete-company-confirm-btn');\n            if (!dbVal || !pwd) { window.tiAlert('Ditta o password non disponibili per continuare la cancellazione.'); return; }\n            if (btn) btn.disabled = true;\n            if (st) st.textContent = opts.skipEmail ? 'Proseguo senza invio email dopo conferma finale...' : 'Riprovo invio backup all indirizzo indicato...';\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_delete_company');\n            fd.append('db', dbVal);\n            fd.append('password', pwd);\n            fd.append('confirm', 'OK');\n            if (opts.email) fd.append('delete_email', opts.email);\n            if (opts.skipEmail) { fd.append('skip_email', '1'); fd.append('confirm_no_email', 'OK'); }\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(function(res){\n                if (btn) btn.disabled = false;\n                if (!res || !res.success) {\n                    const m = (res && res.data && res.data.message) ? res.data.message : 'Errore cancellazione ditta.';\n                    if (st) st.textContent = m;\n                    window.tiAlert(m);\n                    return;\n                }\n                const data = res.data || {};\n                if (data.needs_email_choice) { window.handleDeleteCompanyEmailChoice(data, dbVal, pwd); return; }\n                window.finishDeleteCompanySuccess(data);\n            }).catch(function(err){\n                if (btn) btn.disabled = false;\n                const m = 'Errore cancellazione ditta: ' + (err && err.message ? err.message : err);\n                if (st) st.textContent = m;\n                window.tiAlert(m);\n            });\n        };\n        window.handleDeleteCompanyEmailChoice = function(data, dbVal, pwd) {\n            const st = gE('ti-delete-company-status');\n            const msg = (data && data.message) ? data.message : 'Backup finale creato, ma email non inviata.';\n            if (st) st.textContent = msg;\n            const chooseEmail = window.confirm(msg + '\\n\\nPremi OK per indicare un altro indirizzo email.\\nPremi Annulla per proseguire senza invio email.');\n            if (chooseEmail) {\n                const email = window.prompt('Indica indirizzo email a cui inviare il backup finale ZIP:', (data && data.email) ? data.email : '');\n                if (!email) { if (st) st.textContent = 'Cancellazione sospesa. Nessuna email indicata.'; return; }\n                window.retryDeleteCompanyWithEmailChoice({db:dbVal, password:pwd, email:String(email).trim()});\n                return;\n            }\n            const finalConfirm = window.confirm('Confermi definitivamente di cancellare la ditta SENZA inviare via email il link al backup finale?\\n\\nIl backup ZIP e stato creato nello storage del plugin. Questa scelta elimina comunque database e archivi ditta, conservando la cartella Backups.');\n            if (!finalConfirm) { if (st) st.textContent = 'Cancellazione sospesa. Backup creato, ditta non cancellata.'; return; }\n            window.retryDeleteCompanyWithEmailChoice({db:dbVal, password:pwd, skipEmail:true});\n        };\n\n        window.confirmDeleteCompany = function() {\n            const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            const pwdEl = gE('ti-delete-company-password');\n            const pwd = pwdEl ? pwdEl.value : '';\n            const st = gE('ti-delete-company-status');\n            const btn = gE('ti-delete-company-confirm-btn');\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Ditta non valida.'); return; }\n            if (!pwd) { if (st) st.textContent = 'Inserisci la password.'; return; }\n            const msg = 'Confermi definitivamente la cancellazione della ditta ' + dbVal + '?\\n\\nVerr\u00e0 creato un ultimo backup, la ditta verr\u00e0 disattivata, saranno disdetti gli abbonamenti in essere e verr\u00e0 inviata email ai configuratori\/amministratori della ditta e all email ditta. Solo dopo saranno eliminati gli archivi, conservando il backup finale.';\n            if (!window.confirm(msg)) return;\n            if (btn) btn.disabled = true;\n            if (st) st.textContent = 'Attendere: creo il backup finale, disattivo la ditta, disdico gli abbonamenti, invio le comunicazioni e cancello gli archivi...';\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_delete_company');\n            fd.append('db', dbVal);\n            fd.append('password', pwd);\n            fd.append('confirm', 'OK');\n            window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd}).then(function(res){\n                if (btn) btn.disabled = false;\n                if (!res || !res.success) {\n                    const m = (res && res.data && res.data.message) ? res.data.message : 'Errore cancellazione ditta.';\n                    if (st) st.textContent = m;\n                    window.tiAlert(m);\n                    return;\n                }\n                const data = res.data || {};\n                if (data.needs_email_choice) { window.handleDeleteCompanyEmailChoice(data, dbVal, pwd); return; }\n                window.finishDeleteCompanySuccess(data);\n            }).catch(function(err){\n                if (btn) btn.disabled = false;\n                const m = 'Errore cancellazione ditta: ' + (err && err.message ? err.message : err);\n                if (st) st.textContent = m;\n                window.tiAlert(m);\n            });\n        };\n\n        window.isPurchaseRoleEnabled = function(role, user) {\n            const r = String(role || '').toLowerCase();\n            const u = String(user || window.tiUser || '').toLowerCase();\n            const hasPurchaseRole = r.includes('acquisizioni') || r.includes('buyer') || r.includes('procurement');\n            return u === 'ssglobaladmin'\n                || r.includes('amministratore')\n                || r.includes('configuratore')\n                || r.includes('responsabile')\n                || hasPurchaseRole;\n        };\n\n        window.setAdminUI = function(user, role) {\n            const uName = gE('ti-user-name'); const uRole = gE('ti-user-role'); const uArea = gE('ti-user-area');\n            if(uName) uName.textContent = (user || ''); if(uRole) uRole.textContent = role ? (' - ' + role) : ''; if(uArea) uArea.style.display = 'flex';\n            if (window.tiCloseDirectLoginFallback) window.tiCloseDirectLoginFallback();\n            if (window.closeModal) window.closeModal('ti-login-ov');\n            gE('ti-login-btn').style.display = 'none'; gE('ti-logout-btn').style.display = 'inline-block';\n            if (typeof window.ensureStandardMainFormForCurrentUser === 'function') window.ensureStandardMainFormForCurrentUser();\n            const roleLower = String(role || '').toLowerCase();\n            const canOpenConfig = String(window.tiUser || user || '').toLowerCase() === 'ssglobaladmin' || roleLower.includes('amministratore') || roleLower.includes('configuratore') || roleLower.includes('responsabile');\n            const canOpenPurchases = window.isPurchaseRoleEnabled(role, window.tiUser || user);\n            if(canOpenConfig) {\n                let confBtn = gE('ti-conf-toggle');\n                if(!confBtn) { \n                    confBtn = document.createElement('button'); confBtn.type=\"button\"; confBtn.id = 'ti-conf-toggle'; confBtn.className = 'ti-btn ti-btn-conf-toggle'; confBtn.innerHTML = '\u2699\ufe0f <b>CONFIGURA<\/b>'; confBtn.style.background = '#10b981'; confBtn.style.color = '#ffffff'; confBtn.style.border = '1px solid #047857'; const adminRow = window.getPrivilegedActionsRow(); if (adminRow) adminRow.appendChild(confBtn); \n                }\n                confBtn.style.display = 'inline-block';\n                confBtn.onclick = () => {\n                    const requestedDb1657 = gE('ti-ditta') ? String(gE('ti-ditta').value || '') : '';\n                    const epoch1657 = Number(window.tiCompanyEpoch1657 || 0);\n                    const fd = new FormData(); fd.append('ti_action', 'ti_ai_get_db_data'); fd.append('db', requestedDb1657);\n                    window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiShowTableReadWait:true, tiTableReadTitle:'\u23f3 Lettura tabelle configurazione', tiTableReadDetail:'Sto leggendo tutte le tabelle della ditta prima di aprire la configurazione.', tiTableReadItem:requestedDb1657}).then(d=>{\n                        const nowDb1657 = gE('ti-ditta') ? String(gE('ti-ditta').value || '') : '';\n                        if (epoch1657 !== Number(window.tiCompanyEpoch1657 || 0) || (window.tiNormalizeDb1657 && window.tiNormalizeDb1657(nowDb1657) !== window.tiNormalizeDb1657(requestedDb1657))) return;\n                        if(d.success) {\n                            if (window.tiDbPayloadMatches1657 && !window.tiDbPayloadMatches1657(d.data, requestedDb1657)) {\n                                if (window.tiAlert) window.tiAlert('Dati ricevuti per una ditta diversa da quella selezionata. Configurazione non aperta.');\n                                return;\n                            }\n                            window.currentDbData = d.data; window.configOriginalDbData = JSON.parse(JSON.stringify(d.data || {})); window.configWasSaved = false; window.tiConfigDeletedRowsManifest = []; if(window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); if(window.refreshShopServiceActivationButton) window.refreshShopServiceActivationButton(); window.renderConfig(); window.openModal('ti-conf-ov');\n                        }\n                    });\n                };\n\n                let actBtn = gE('ti-activation-toggle');\n                if (!actBtn) {\n                    actBtn = document.createElement('button');\n                    actBtn.type = 'button';\n                    actBtn.id = 'ti-activation-toggle';\n                    actBtn.className = 'ti-btn';\n                    actBtn.innerHTML = '\u23f3 <b>Verifica SS...<\/b>';\n                    actBtn.title = 'Verifica stato Shop & Service sul database della ditta';\n                    actBtn.disabled = true;\n                    actBtn.setAttribute('aria-disabled','true');\n                    actBtn.setAttribute('aria-busy','true');\n                    actBtn.style.setProperty('background','#6b7280','important');\n                    actBtn.style.setProperty('color','#f8fafc','important');\n                    actBtn.style.setProperty('border','1px solid #4b5563','important');\n                    actBtn.style.setProperty('cursor','not-allowed','important');\n                    const adminRow = window.getPrivilegedActionsRow();\n                    if (adminRow) adminRow.appendChild(actBtn);\n                }\n                actBtn.style.display = 'inline-block';\n                actBtn.onclick = () => {\n                    if (!window.refreshShopServiceActivationButton) return false;\n                    return window.refreshShopServiceActivationButton(true).then(function(ok2070){\n                        if (!ok2070) return false;\n                        const b2070 = gE('ti-activation-toggle');\n                        if (!b2070 || b2070.dataset.tiActivationVerified2070 !== '1' || b2070.disabled) return false;\n                        window.openShopServiceActivationPopup();\n                        return true;\n                    });\n                };\n                if (window.refreshShopServiceActivationButton) window.refreshShopServiceActivationButton(true);\n\n                let purchBtn = gE('ti-purchase-toggle');\n                if(canOpenPurchases) {\n                    if(!purchBtn) {\n                        purchBtn = document.createElement('button');\n                        purchBtn.type = 'button';\n                        purchBtn.id = 'ti-purchase-toggle';\n                        purchBtn.className = 'ti-btn';\n                        purchBtn.innerHTML = '\ud83d\uded2 <b>ACQUISIZIONI<\/b>';\n                        purchBtn.title = 'Acquisizioni - disponibile per amministratore, configuratore, responsabile, ruolo acquisizioni o SSGlobalAdmin';\n                        purchBtn.style.background = '#0ea5e9';\n                        purchBtn.style.color = '#fff';\n                        purchBtn.style.border = '1px solid #0369a1';\n                        const adminRow = window.getPrivilegedActionsRow();\n                        if (adminRow) adminRow.appendChild(purchBtn);\n                    }\n                    purchBtn.style.display = 'inline-block';\n                    purchBtn.onclick = () => window.openPurchaseManualFlow();\n                } else if (purchBtn) {\n                    purchBtn.style.display = 'none';\n                    purchBtn.onclick = null;\n                }\n                let cleanBtn = gE('ti-clean-orphans-btn');\n                if (window.canRunLocalOrphanCleanup && window.canRunLocalOrphanCleanup()) {\n                    if(!cleanBtn) {\n                        cleanBtn = document.createElement('button');\n                        cleanBtn.type = 'button';\n                        cleanBtn.id = 'ti-clean-orphans-btn';\n                        cleanBtn.className = 'ti-btn';\n                        cleanBtn.innerHTML = '\ud83e\uddf9 <b>Pulisci file non associati<\/b>';\n                        cleanBtn.title = 'Elimina fisicamente dallo storage i file non associati alla ditta selezionata';\n                        cleanBtn.style.background = '#475569';\n                        cleanBtn.style.color = '#fff';\n                        cleanBtn.style.border = '1px solid #334155';\n                        cleanBtn.style.fontSize = '11px';\n                        const adminRow = window.getPrivilegedActionsRow();\n                        if (adminRow) adminRow.appendChild(cleanBtn);\n                    }\n                    cleanBtn.style.display = 'inline-block';\n                    cleanBtn.onclick = () => window.runOrphanFileCleanup();\n                } else if (cleanBtn) {\n                    cleanBtn.style.display = 'none';\n                    cleanBtn.onclick = null;\n                }\n                let delCompanyBtn = gE('ti-delete-company-toggle');\n                const canDeleteCompany = String(window.tiUser || user || '').toLowerCase() === 'ssglobaladmin' || roleLower.includes('amministratore') || roleLower.includes('configuratore');\n                if (canDeleteCompany) {\n                    if (!delCompanyBtn) {\n                        delCompanyBtn = document.createElement('button');\n                        delCompanyBtn.type = 'button';\n                        delCompanyBtn.id = 'ti-delete-company-toggle';\n                        delCompanyBtn.className = 'ti-btn';\n                        delCompanyBtn.innerHTML = '\ud83d\uddd1 <b>Cancella ditta<\/b>';\n                        delCompanyBtn.title = 'Cancellazione definitiva della ditta con backup finale e conferma password';\n                        delCompanyBtn.style.background = '#dc2626';\n                        delCompanyBtn.style.color = '#fff';\n                        delCompanyBtn.style.border = '1px solid #991b1b';\n                        delCompanyBtn.style.fontSize = '11px';\n                        const adminRow = window.getPrivilegedActionsRow();\n                        if (adminRow) adminRow.appendChild(delCompanyBtn);\n                    }\n                    delCompanyBtn.style.display = 'inline-block';\n                    delCompanyBtn.onclick = () => window.openDeleteCompanyPopup();\n                } else if (delCompanyBtn) {\n                    delCompanyBtn.style.display = 'none';\n                    delCompanyBtn.onclick = null;\n                }\n            } else {\n                const confBtnOff = gE('ti-conf-toggle');\n                if (confBtnOff) confBtnOff.style.display = 'none';\n                const actBtnOff = gE('ti-activation-toggle');\n                if (actBtnOff) { actBtnOff.style.display = 'none'; actBtnOff.onclick = null; }\n                const purchBtnOff = gE('ti-purchase-toggle');\n                if (purchBtnOff) { purchBtnOff.style.display = 'none'; purchBtnOff.onclick = null; }\n                const cleanBtnOff = gE('ti-clean-orphans-btn');\n                if (cleanBtnOff) { cleanBtnOff.style.display = 'none'; cleanBtnOff.onclick = null; }\n                const delCompanyBtnOff = gE('ti-delete-company-toggle');\n                if (delCompanyBtnOff) { delCompanyBtnOff.style.display = 'none'; delCompanyBtnOff.onclick = null; }\n            }\n            if (window.tiUser === 'SSGlobalAdmin') {\n                let gb = gE('ti-global-action-toggle');\n                if(!gb) {\n                    gb = document.createElement('button'); gb.type=\"button\"; gb.id='ti-global-action-toggle'; gb.className='ti-btn'; gb.innerHTML='\ud83e\ude84 <b>GLOBALE<\/b>'; gb.style.background='#8b5cf6'; gb.style.color='#fff'; gb.style.border='1px solid #5b21b6'; const globalStorageStack1639 = window.getGlobalStorageStack1639 ? window.getGlobalStorageStack1639() : window.getPrivilegedActionsRow(); if (globalStorageStack1639) globalStorageStack1639.appendChild(gb);\n                }\n                gb.style.display = 'inline-block';\n                gb.onclick = () => window.openModal('ti-global-action-ov');\n\n                let sb = gE('ti-shared-setup-toggle');\n                if(!sb) {\n                    sb = document.createElement('button'); sb.type='button'; sb.id='ti-shared-setup-toggle'; sb.className='ti-btn'; sb.innerHTML='\ud83d\uddc2 <b>STORAGE<\/b>'; sb.style.background='#a16207'; sb.style.color='#fff'; sb.style.border='1px solid #78350f'; const globalStorageStack1639 = window.getGlobalStorageStack1639 ? window.getGlobalStorageStack1639() : window.getPrivilegedActionsRow(); if (globalStorageStack1639) globalStorageStack1639.appendChild(sb);\n                }\n                sb.style.display = 'inline-block';\n                sb.onclick = () => window.openSharedSetupModal();\n\n                let gclean = gE('ti-clean-orphans-global-btn');\n                if (gclean) {\n                    gclean.style.display = 'block';\n                    gclean.onclick = () => window.runGlobalOrphanFileCleanup();\n                }\n            } else {\n                const gcleanOff = gE('ti-clean-orphans-global-btn');\n                if (gcleanOff) { gcleanOff.style.display = 'none'; gcleanOff.onclick = null; }\n            }\n            if (window.refreshOrphanCleanupButton) window.refreshOrphanCleanupButton();\n            window.refreshPrivilegedActionsRow();\n            window.placeMainHelpButtonRight();\n            try { if (window.updateActivitiesButtonVisibility) window.updateActivitiesButtonVisibility(); } catch(e) {}\n            try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(window.getPrivilegedActionsRow ? window.getPrivilegedActionsRow() : document.body); if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(window.getPrivilegedActionsRow ? window.getPrivilegedActionsRow() : document.body); } catch(e) {}\n        };\n\n        if(window.tiUser) { window.setAdminUI(window.tiUserDisplay || window.tiUser, window.tiRole); if (typeof window.ensureStandardMainFormForCurrentUser === 'function') window.ensureStandardMainFormForCurrentUser(); if (window.updateActivitiesButtonVisibility) window.updateActivitiesButtonVisibility(); } else { const uName = gE('ti-user-name'); const uRole = gE('ti-user-role'); const uArea = gE('ti-user-area'); if (uName) uName.textContent = 'Cliente\/Utente'; if (uRole) uRole.textContent = ''; if (uArea) uArea.style.display = 'flex'; ['ti-conf-toggle','ti-activation-toggle','ti-purchase-toggle','ti-clean-orphans-btn','ti-delete-company-toggle','ti-clean-orphans-global-btn','ti-global-action-toggle','ti-shared-setup-toggle'].forEach(function(id){ const b=gE(id); if(b){ b.style.display='none'; b.onclick=null; } }); const adminRow = gE('ti-admin-actions-row'); if (adminRow) adminRow.style.display = 'none'; }\n\n        window.isStructuredListinoFileName = function(fileName) {\n            const nm = String(fileName || '').toLowerCase().trim();\n            return \/\\.(txt|csv|tsv|xlsx|pdf)$\/i.test(nm);\n        };\n\n\n\n        window.ensurePurchaseModal = function() {\n            let ov = gE('ti-purchase-ov');\n            if (ov) return ov;\n            ov = document.createElement('div');\n            ov.id = 'ti-purchase-ov';\n            ov.className = 'ti-modal-overlay';\n            ov.style.display = 'none';\n            ov.style.zIndex = '99990';\n            ov.style.alignItems = 'center';\n            ov.style.justifyContent = 'center';\n            ov.innerHTML = `\n                <div class=\"ti-modal ti-purchase-modal\" style=\"width:min(1460px,98vw);max-width:98vw;max-height:92vh;overflow:auto;background:#0f172a;color:#fff;border-radius:16px;padding:18px;box-shadow:0 18px 60px rgba(0,0,0,.45);margin:0 auto;\">\n                    <div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;\">\n                        <div>\n                            <h2 style=\"margin:0;font-size:22px;\">Acquisizioni<\/h2>\n                            <div style=\"font-size:14px;color:#cbd5e1;margin-top:4px;\">Inserisci manualmente le righe nella tabella ordine acquisizione. L'import file resta disponibile come funzione aggiuntiva.<\/div>\n                        <\/div>\n                        <button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"window.closePurchaseManualFlow()\">X<\/button>\n                    <\/div>\n                    <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 14px 0;\">\n                        <button type=\"button\" class=\"ti-btn\" style=\"background:#22c55e;color:#052e16;font-weight:700;\" onclick=\"window.addPurchaseManualRow()\">+ Aggiungi riga manuale<\/button>\n                        <button type=\"button\" class=\"ti-btn\" style=\"background:#f59e0b;color:#111827;font-weight:700;\" onclick=\"window.pickPurchaseImportFile()\">Import file acquisizioni<\/button>\n                        <button type=\"button\" class=\"ti-btn\" style=\"background:#38bdf8;color:#082f49;font-weight:700;\" onclick=\"window.purchaseSendToChat()\">Invia righe acquisizione alla chat<\/button>\n                    <\/div>\n                    <div style=\"border:1px solid #334155;background:#111827;border-radius:12px;padding:10px;margin-bottom:12px;\">\n                        <label style=\"display:block;font-weight:700;margin-bottom:6px;\">Ricerca prodotti e servizi gi\u00e0 presenti nel database<\/label>\n                        <input id=\"ti-purchase-search\" type=\"text\" placeholder=\"Cerca prodotto o servizio...\" style=\"width:100%;box-sizing:border-box;padding:10px;border-radius:10px;border:1px solid #475569;background:#020617;color:#fff;font-size:15px;\" oninput=\"window.searchPurchaseCatalog(this.value)\">\n                        <div id=\"ti-purchase-search-results\" style=\"margin-top:8px;display:grid;gap:6px;\"><\/div>\n                    <\/div>\n                    <div style=\"overflow:auto;border:1px solid #334155;border-radius:12px;\">\n                        <table id=\"ti-purchase-table\" style=\"width:100%;border-collapse:collapse;min-width:1120px;background:#020617;\">\n                            <thead>\n                                <tr style=\"background:#1e293b;\">\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Voce<\/th>\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Tipo<\/th>\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Q.t\u00e0<\/th>\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Costo acquisizione<\/th>\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Prezzo vendita<\/th>\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">IVA<\/th>\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Note<\/th>\n                                    <th style=\"padding:8px;border-bottom:1px solid #334155;\">Azioni<\/th>\n                                <\/tr>\n                            <\/thead>\n                            <tbody id=\"ti-purchase-body\"><\/tbody>\n                        <\/table>\n                    <\/div>\n                    <div id=\"ti-purchase-total\" style=\"margin-top:10px;text-align:right;font-weight:700;color:#bbf7d0;\"><\/div>\n                    <div style=\"display:flex;justify-content:center;gap:8px;margin-top:14px;\">\n                        <button type=\"button\" class=\"ti-btn\" style=\"background:#38bdf8;color:#082f49;font-weight:700;\" onclick=\"window.purchaseSendToChat()\">Conferma righe in chat<\/button>\n                        <button type=\"button\" class=\"ti-btn btn-close\" onclick=\"window.closePurchaseManualFlow()\">Chiudi<\/button>\n                    <\/div>\n                <\/div>`;\n            document.body.appendChild(ov);\n            return ov;\n        };\n\n        window.purchaseGetCatalogItems = function() {\n            const data = window.currentDbData || {};\n            const tables = (data && data.Tabelle) ? data.Tabelle : {};\n            const out = [];\n            Object.keys(tables).forEach(function(tn){\n                if (!\/(prodott|serviz)\/i.test(tn)) return;\n                const rows = Array.isArray(tables[tn]) ? tables[tn] : [];\n                rows.forEach(function(r, idx){\n                    if (!r || typeof r !== 'object') return;\n                    const isServ = \/(serviz)\/i.test(tn);\n                    const name = String(r.Prodotto || r.Servizio || r.Nome || r.Titolo || r.Descrizione || '').trim();\n                    if (!name) return;\n                    out.push({\n                        table: tn,\n                        index: idx,\n                        type: isServ ? 'S' : 'P',\n                        name: name,\n                        desc: String(r.Descrizione || r.Note || '').trim(),\n                        cost: parseFloat(String(r.Costo || r.Costo_acquisto || r.Prezzo || '0').replace(',','.')) || 0,\n                        sale: parseFloat(String(r.Prezzo || r.Prezzo_vendita || '0').replace(',','.')) || 0,\n                        iva: parseFloat(String(r.IVA_VAT || r.IVA || '22').replace(',','.')) || 22\n                    });\n                });\n            });\n            return out;\n        };\n\n        window.openPurchaseManualFlow = function() {\n            if (!window.isPurchaseRoleEnabled || !window.isPurchaseRoleEnabled(window.tiRole, window.tiUser)) {\n                window.tiAlert('Funzione Acquisizioni non disponibile con il profilo corrente.');\n                return;\n            }\n            const dbSel = gE('ti-ditta');\n            const dbVal = dbSel ? dbSel.value : '';\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Seleziona prima una ditta.'); return; }\n            const openIt = function(){\n                const ov = window.ensurePurchaseModal();\n                if (window.showPluginModal) window.showPluginModal(ov); else ov.style.display = 'flex';\n                if (!gE('ti-purchase-body') || !gE('ti-purchase-body').children.length) window.addPurchaseManualRow();\n                window.refreshPurchaseTotals();\n            };\n            if (!window.currentDbData || !window.currentDbData.Tabelle) {\n                const fd = new FormData();\n                fd.append('ti_action', 'ti_ai_get_db_data');\n                fd.append('db', dbVal);\n                window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiShowTableReadWait:true, tiTableReadTitle:'\u23f3 Lettura prodotti e servizi', tiTableReadDetail:'Sto leggendo il database per preparare acquisizioni e ricerca.', tiTableReadItem:dbVal}).then(function(res){\n                    if (res && res.success) { window.currentDbData = res.data; openIt(); }\n                    else window.tiAlert((res && res.data && res.data.message) ? res.data.message : 'Errore lettura database.');\n                }).catch(function(err){ window.tiAlert('Errore lettura database: ' + err.message); });\n            } else {\n                openIt();\n            }\n        };\n\n        window.closePurchaseManualFlow = function() {\n            const ov = gE('ti-purchase-ov');\n            if (!ov) return;\n            if (window.closeModal) window.closeModal(ov); else ov.style.display = 'none';\n        };\n\n        window.addPurchaseManualRow = function(item) {\n            const body = gE('ti-purchase-body');\n            if (!body) return;\n            const tr = document.createElement('tr');\n            tr.className = 'ti-purchase-row';\n            const safe = item || {};\n            tr.innerHTML = `\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-name\" value=\"${window.escapeHtml(safe.name || '')}\" placeholder=\"Prodotto o servizio\" style=\"width:100%;box-sizing:border-box;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><select class=\"ti-pur-type\" style=\"width:70px;padding:8px;border-radius:8px;background:#0f172a;color:#fff;border:1px solid #334155;\"><option value=\"P\" ${safe.type === 'S' ? '' : 'selected'}>P<\/option><option value=\"S\" ${safe.type === 'S' ? 'selected' : ''}>S<\/option><\/select><\/td>\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-qty\" value=\"${safe.qty || '1'}\" inputmode=\"decimal\" style=\"width:80px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\" oninput=\"window.refreshPurchaseTotals()\"><\/td>\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-cost\" value=\"${safe.cost ? window.fmtNum(safe.cost) : ''}\" inputmode=\"decimal\" style=\"width:120px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\" oninput=\"window.refreshPurchaseTotals()\"><\/td>\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-sale\" value=\"${safe.sale ? window.fmtNum(safe.sale) : ''}\" inputmode=\"decimal\" style=\"width:120px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-iva\" value=\"${safe.iva || '22'}\" inputmode=\"decimal\" style=\"width:70px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-note\" value=\"${window.escapeHtml(safe.desc || '')}\" placeholder=\"Note\" style=\"width:100%;box-sizing:border-box;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:center;\"><button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"this.closest('tr').remove();window.refreshPurchaseTotals();\">X<\/button><\/td>`;\n            body.appendChild(tr);\n            window.refreshPurchaseTotals();\n        };\n\n        window.searchPurchaseCatalog = function(q) {\n            const box = gE('ti-purchase-search-results');\n            if (!box) return;\n            const query = String(q || '').trim().toLowerCase();\n            if (!query) { box.innerHTML = ''; return; }\n            const items = window.purchaseGetCatalogItems().filter(function(it){\n                return (it.name + ' ' + it.desc + ' ' + it.table).toLowerCase().indexOf(query) !== -1;\n            }).slice(0, 12);\n            if (!items.length) {\n                box.innerHTML = '<div style=\"color:#fca5a5;font-size:13px;\">Nessun prodotto o servizio trovato nel database.<\/div>';\n                return;\n            }\n            box.innerHTML = items.map(function(it, idx){\n                return `<button type=\"button\" class=\"ti-btn\" style=\"text-align:left;background:#1e293b;color:#fff;border:1px solid #334155;\" onclick=\"window.addPurchaseManualRow(window.purchaseSearchCache[${idx}])\"><b>${it.type} - ${window.escapeHtml(it.name)}<\/b><br><span style=\"font-size:12px;color:#cbd5e1;\">${window.escapeHtml(it.table)} \u00b7 costo ${window.fmtNum(it.cost)} \u00b7 prezzo vendita ${window.fmtNum(it.sale)}<\/span><\/button>`;\n            }).join('');\n            window.purchaseSearchCache = items;\n        };\n\n        window.refreshPurchaseTotals = function() {\n            let total = 0;\n            document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                const qty = window.parseQtyInput ? window.parseQtyInput((tr.querySelector('.ti-pur-qty') || {}).value || '0') : (parseFloat(String((tr.querySelector('.ti-pur-qty') || {}).value || '0').replace(',','.')) || 0);\n                const cost = parseFloat(String((tr.querySelector('.ti-pur-cost') || {}).value || '0').replace(\/\\.\/g,'').replace(',','.')) || 0;\n                total += qty * cost;\n            });\n            const out = gE('ti-purchase-total');\n            if (out) out.innerHTML = 'Totale acquisizione indicativo: \u20ac ' + window.fmtNum(total);\n        };\n\n        window.purchaseCollectRows = function() {\n            const rows = [];\n            document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                const name = String((tr.querySelector('.ti-pur-name') || {}).value || '').trim();\n                if (!name) return;\n                rows.push({\n                    type: String((tr.querySelector('.ti-pur-type') || {}).value || 'P'),\n                    name: name,\n                    qty: String((tr.querySelector('.ti-pur-qty') || {}).value || '1').trim(),\n                    cost: String((tr.querySelector('.ti-pur-cost') || {}).value || '').trim(),\n                    sale: String((tr.querySelector('.ti-pur-sale') || {}).value || '').trim(),\n                    iva: String((tr.querySelector('.ti-pur-iva') || {}).value || '22').trim(),\n                    note: String((tr.querySelector('.ti-pur-note') || {}).value || '').trim()\n                });\n            });\n            return rows;\n        };\n\n        window.purchaseSendToChat = function() {\n            const rows = window.purchaseCollectRows();\n            if (!rows.length) { window.tiAlert('Inserisci almeno una riga acquisizione.'); return; }\n            let txt = 'ACQUISTO - righe inserite manualmente\\\\n';\n            txt += 'Usa queste righe come tabella ordine acquisizione. Il campo prezzo rappresenta il costo di acquisizione; se presente riporta anche il prezzo di vendita nel prodotto.\\\\n\\\\n';\n            rows.forEach(function(r, i){\n                txt += (i+1) + '. ' + r.type + ' - ' + r.name + ' | Quantita: ' + r.qty + ' | Costo acquisizione: ' + r.cost + ' | Prezzo vendita: ' + r.sale + ' | IVA: ' + r.iva + (r.note ? ' | Note: ' + r.note : '') + '\\n';\n            });\n            window.closePurchaseManualFlow();\n            if (window.addMsg) window.addMsg('user', txt);\n            const msg = gE('ti-msg');\n            if (msg) {\n                msg.value = txt;\n                if (gE('ti-send')) gE('ti-send').click();\n            }\n        };\n\n        window.pickPurchaseImportFile = function() {\n            window.targetUploadContext = 'purchase-import-file';\n            if (window.tiOpenDirectUpload616) return window.tiOpenDirectUpload616('purchase-import-file');\n            return false;\n        };\n\n        window.startPurchaseFileImport = function(fileUrl, fileName) {\n            const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Seleziona una ditta prima di importare acquisizioni.'); return; }\n            const prompt = 'Import acquisizioni da file. Prima usa la tabella ordine acquisizione per anteprima e modifica manuale delle righe. Interpreta il file come acquisizione: il campo Prezzo rappresenta il costo di acquisizione; se presente un prezzo di vendita riportalo nel prodotto. Rendere disponibili ricerche su prodotti o servizi gi\u00e0 presenti.';\n            window.rememberLastFileContext(fileUrl, prompt, true);\n            window.lastUploadedFile = null;\n            if (window.addMsg) window.addMsg('user', prompt);\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_config_action');\n            fd.append('db', dbVal);\n            fd.append('mode', 'ai_ops');\n            fd.append('prompt', prompt);\n            fd.append('file_url', fileUrl);\n            let waitBubble = null;\n            try {\n                waitBubble = document.createElement('div');\n                waitBubble.className = 'ti-bubble ai';\n                waitBubble.innerHTML = window.getUserWaitingHtml('Import acquisizioni in corso...', 'Sto leggendo il file e preparo la tabella ordine acquisizione modificabile.');\n                if (dom.chat) { dom.chat.appendChild(waitBubble); dom.chat.scrollTop = dom.chat.scrollHeight; }\n            } catch(e) {}\n            window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n                if (waitBubble && waitBubble.remove) waitBubble.remove();\n                if (res && res.success) {\n                    const rawReply = ((res.data || {}).reply || '').trim();\n                    const cleanReply = rawReply.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                    window.addMsg('ai', window.formatTable(cleanReply || 'Import acquisizioni pronto.'), cleanReply || 'Import acquisizioni pronto.');\n                } else {\n                    window.addMsg('ai', '\u26a0\ufe0f ' + ((res && res.data && res.data.message) ? res.data.message : 'Import acquisizioni non riuscito'));\n                }\n            }).catch(function(err){\n                if (waitBubble && waitBubble.remove) waitBubble.remove();\n                window.addMsg('ai', '\u26a0\ufe0f Errore import acquisizioni: ' + ((err && err.message) ? err.message : 'errore sconosciuto'));\n            });\n        };\n\n\n        window.startAdminGenericFileAI = function(fileUrl, fileName) {\n            const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            const lowerName1742 = String(fileName || '').toLowerCase();\n            const isImg1742 = \/\\.(jpg|jpeg|png|webp|gif|heic|heif)$\/i.test(lowerName1742) || \/ti_action=ti_ai_get_image\/i.test(String(fileUrl || ''));\n            const prompt = isImg1742\n                ? 'Ho allegato una foto\/immagine. Analizzala, descrivi cosa vedi e leggi eventuali testi o dati visibili. Riporta una sintesi comprensibile e chiedimi cosa voglio fare con la foto o con i dati rilevati. Se il contenuto non e leggibile o e ambiguo, chiedimi di precisarlo.'\n                : 'Ho allegato un file che pu\u00f2 essere PDF con testo e immagini oppure un file tecnico. Analizza solo il testo leggibile o estraibile automaticamente; non inventare contenuti da immagini, scansioni o parti binarie non leggibili. Riporta una sintesi comprensibile e, se il contenuto \u00e8 parziale, chiedimi di precisarne il contenuto o cosa devo farne prima di modificare il database.';\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Seleziona una ditta prima di analizzare il file.'); return; }\n            window.rememberLastFileContext(fileUrl, prompt, false);\n            window.lastUploadedFile = null;\n            if (window.addMsg) window.addMsg('user', prompt);\n\n            let waitBubble = null;\n            try {\n                waitBubble = document.createElement('div');\n                waitBubble.className = 'ti-bubble ai';\n                waitBubble.innerHTML = window.getUserWaitingHtml('Analisi file in corso...', 'Sto leggendo il file allegato e preparo la risposta.');\n                if (dom.chat) { dom.chat.appendChild(waitBubble); dom.chat.scrollTop = dom.chat.scrollHeight; }\n            } catch(e) {}\n\n            let chatHist = [];\n            try {\n                const bubbles = dom.chat ? dom.chat.querySelectorAll('.ti-bubble') : [];\n                const startIdx = Math.max(0, (bubbles ? bubbles.length : 0) - 8);\n                for (let i = startIdx; i < (bubbles ? bubbles.length : 0); i++) {\n                    const bubble = bubbles[i];\n                    const role = bubble.classList.contains('user') ? 'user' : 'assistant';\n                    const clone = bubble.cloneNode(true);\n                    const tw = clone.querySelector('.ti-table-wrap'); if (tw) tw.remove();\n                    const msgTxt = (clone.innerText || '').trim();\n                    if (msgTxt && !msgTxt.includes('Fammi pensare...')) chatHist.push({role: role, content: msgTxt});\n                }\n            } catch(e) {}\n\n            let attempt1742 = 0;\n            const maxAttempts1742 = isImg1742 ? 3 : 1;\n            const isHttp5001742 = function(errOrMsg){\n                try {\n                    if (errOrMsg && Number(errOrMsg.httpStatus || 0) === 500) return true;\n                    const txt = String((errOrMsg && errOrMsg.message) ? errOrMsg.message : (errOrMsg || ''));\n                    return \/(?:^|\\s)HTTP\\s*500\\b|Errore\\s+Server\\s+500\\b\/i.test(txt);\n                } catch(e) { return false; }\n            };\n            const retryInfo1742 = function(nextAttempt){\n                try {\n                    if (waitBubble) waitBubble.innerHTML = window.getUserWaitingHtml('Analisi foto in corso...', 'Riprovo automaticamente (' + nextAttempt + '\/3).');\n                    if (typeof window.updateProgressPopup === 'function') window.updateProgressPopup(96, 'Analisi foto AI', 'Analisi temporaneamente non completata. Riprovo automaticamente (' + nextAttempt + '\/3).', String(fileName || 'foto'));\n                } catch(e) {}\n            };\n            const finalError1742 = function(msg){\n                if (waitBubble && waitBubble.remove) waitBubble.remove();\n                window.addMsg('ai', '\u26a0\ufe0f Errore analisi file: ' + (msg || 'errore sconosciuto'));\n                try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Errore analisi file', {notifyUser:true, errorMessage:'Errore analisi file: ' + (msg || 'errore sconosciuto')}); } catch(e) {}\n            };\n            const run1742 = function(){\n                attempt1742++;\n                const fd = new FormData();\n                fd.append('ti_action', 'ti_ai_chat_start');\n                fd.append('db', dbVal);\n                fd.append('analyze_file_only', '1');\n                fd.append('reset_flow_for_file_analysis', '1');\n                fd.append('text', prompt + ` [FILE_ALLEGATO: ${fileUrl}]`);\n                fd.append('history_context', JSON.stringify(chatHist));\n                fd.append('file_analysis_attempt_1742', String(attempt1742));\n                return window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n                    if (res && res.success) {\n                        if (waitBubble && waitBubble.remove) waitBubble.remove();\n                        const rawReply = ((res.data || {}).reply || '').trim();\n                        const cleanReply = rawReply.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                        window.addMsg('ai', window.formatTable(cleanReply || 'Analisi completata.'), cleanReply || 'Analisi completata.');\n                        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(true, 'Analisi file completata', {notifyUser:true, successMessage:'Analisi file completata. Risultato disponibile nella chat AI.'}); } catch(eProgressOk792) {}\n                        if (res.data && res.data.needs_reload) setTimeout(function(){ location.reload(); }, 1200);\n                        return;\n                    }\n                    const msg = (res && res.data && res.data.message) ? String(res.data.message) : 'Analisi file non riuscita';\n                    if (isImg1742 && isHttp5001742(msg) && attempt1742 < maxAttempts1742) {\n                        retryInfo1742(attempt1742 + 1);\n                        return new Promise(function(resolve){setTimeout(function(){resolve(run1742());},700*attempt1742);});\n                    }\n                    finalError1742(msg);\n                }).catch(function(err){\n                    if (isImg1742 && isHttp5001742(err) && attempt1742 < maxAttempts1742) {\n                        retryInfo1742(attempt1742 + 1);\n                        return new Promise(function(resolve){setTimeout(function(){resolve(run1742());},700*attempt1742);});\n                    }\n                    finalError1742((err && err.message) ? err.message : 'errore sconosciuto');\n                });\n            };\n            run1742();\n        };\n\n        window.askAdminUploadedFileAction = function(fileUrl, fileName) {\n            const looksStructured = window.isStructuredListinoFileName(fileName || '');\n            if (!looksStructured) {\n                window.startAdminGenericFileAI(fileUrl, fileName);\n                return;\n            }\n            const msg = `Il file caricato pu\u00f2 essere trattato come <b>listino<\/b> da importare nel database oppure come <b>documento generico<\/b> da leggere con la AI.<br><br>Premi <b>IMPORTA LISTINO<\/b> per creare l'anteprima di import.<br>Premi <b>LEGGI FILE<\/b> per trattarlo come file utente e decidere dopo cosa farne.`;\n            window.tiConfirmYesNoAction(msg,\n                function(){ window.startAdminListinoImport(fileUrl, fileName); },\n                function(){ window.startAdminGenericFileAI(fileUrl, fileName); },\n                'IMPORTA LISTINO',\n                'LEGGI FILE'\n            );\n        };\n\n        window.startAdminListinoImport = function(fileUrl, fileName) {\n            const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Seleziona una ditta prima di importare il listino.'); return; }\n            const prompt = 'Tratta il file allegato come listino da importare nel database della ditta, preferibilmente per creare prodotti. Se il file e PDF, ricerca le righe utili, proponi una prima struttura di import prodotti modificabile e, se trovi immagini disponibili per le righe, chiedi se collegarle ai singoli prodotti. Mostra sempre l anteprima finale prima del salvataggio.';\n            window.rememberLastFileContext(fileUrl, prompt, true);\n            window.lastUploadedFile = null;\n            if (window.addMsg) window.addMsg('user', prompt);\n\n            let waitBubble = null;\n            try {\n                waitBubble = document.createElement('div');\n                waitBubble.className = 'ti-bubble ai';\n                waitBubble.innerHTML = window.getUserWaitingHtml('Avvio import listino in corso...', 'Sto interpretando il listino e preparo l anteprima.');\n                if (dom.chat) { dom.chat.appendChild(waitBubble); dom.chat.scrollTop = dom.chat.scrollHeight; }\n            } catch(e) {}\n\n            const fd = new FormData();\n            fd.append('ti_action', 'ti_ai_config_action');\n            fd.append('db', dbVal);\n            fd.append('mode', 'ai_ops');\n            fd.append('prompt', prompt);\n            fd.append('file_url', fileUrl);\n\n            window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n                if (waitBubble && waitBubble.remove) waitBubble.remove();\n                if (res && res.success) {\n                    const rawReply = ((res.data || {}).reply || '').trim();\n                    const noVoice = !!((res.data || {}).no_voice) || rawReply.indexOf('[NO_VOICE]') !== -1;\n                    const cleanReply = rawReply.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                    window.addMsg('ai', window.formatTable(cleanReply || 'Import pronto.'), cleanReply || 'Import pronto.');\n                    if (!noVoice && cleanReply) window.speakText(cleanReply);\n                    if (res.data && res.data.needs_reload) setTimeout(function(){ location.reload(); }, 1200);\n                } else {\n                    const msg = (res && res.data && res.data.message) ? res.data.message : 'Import non riuscito';\n                    window.addMsg('ai', '\u26a0\ufe0f ' + msg);\n                }\n            }).catch(function(err){\n                if (waitBubble && waitBubble.remove) waitBubble.remove();\n                window.addMsg('ai', '\u26a0\ufe0f Errore import listino: ' + ((err && err.message) ? err.message : 'errore sconosciuto'));\n            });\n        };\n\n\n        window.prepareUploadFileForAI = function(file) {\n            return new Promise(function(resolve){\n                try {\n                    if (!(file instanceof File)) { resolve(file); return; }\n                    const fileName = String(file.name || '').toLowerCase();\n                    const mimeType = String(file.type || '').toLowerCase();\n                    const isImage = mimeType.indexOf('image\/') === 0 || \/\\.(jpg|jpeg|png|webp|gif|heic|heif)$\/i.test(fileName);\n                    if (!isImage) { resolve(file); return; }\n\n                    const reader = new FileReader();\n                    reader.onerror = function(){ resolve(file); };\n                    reader.onload = function(ev) {\n                        const img = new Image();\n                        img.onerror = function(){ resolve(file); };\n                        img.onload = function() {\n                            try {\n                                const maxSide = 1600;\n                                const srcW = img.naturalWidth || img.width || 0;\n                                const srcH = img.naturalHeight || img.height || 0;\n                                if (!srcW || !srcH) { resolve(file); return; }\n                                const scale = Math.min(1, maxSide \/ Math.max(srcW, srcH));\n                                const outW = Math.max(1, Math.round(srcW * scale));\n                                const outH = Math.max(1, Math.round(srcH * scale));\n                                const canvas = document.createElement('canvas');\n                                canvas.width = outW;\n                                canvas.height = outH;\n                                const ctx = canvas.getContext('2d');\n                                if (!ctx) { resolve(file); return; }\n                                ctx.drawImage(img, 0, 0, outW, outH);\n                                canvas.toBlob(function(blob){\n                                    if (!blob || blob.size >= file.size) { resolve(file); return; }\n                                    const baseName = String(file.name || 'camera').replace(\/\\.[^.]+$\/, '') || 'camera';\n                                    resolve(new File([blob], baseName + '.jpg', { type: 'image\/jpeg' }));\n                                }, 'image\/jpeg', 0.82);\n                            } catch(e) {\n                                resolve(file);\n                            }\n                        };\n                        img.src = String(ev.target && ev.target.result ? ev.target.result : '');\n                    };\n                    reader.readAsDataURL(file);\n                } catch(e) {\n                    resolve(file);\n                }\n            });\n        };\n\n        window.startUserUploadedFileAI = function(fileUrl, fileName) {\n            const dbVal = gE('ti-ditta') ? gE('ti-ditta').value : '';\n            const lowerName = String(fileName || '').toLowerCase();\n            const isImg = \/\\.(jpg|jpeg|png|webp|gif|heic|heif)$\/i.test(lowerName) || \/ti_action=ti_ai_get_image\/i.test(String(fileUrl || ''));\n            const prompt = isImg\n                ? 'Ho allegato una foto\/immagine. Analizzala, leggi eventuali testi o dati visibili, riportami una sintesi e chiedimi cosa voglio fare con il file o con i dati letti. Se il testo non \u00e8 leggibile o il contenuto \u00e8 ambiguo, chiedimi di precisarlo. Se riconosci prodotti o servizi presenti nel database, proponili automaticamente nella tabella ordine come righe da verificare e confermare.'\n                : 'Ho allegato un file che pu\u00f2 essere PDF con testo e immagini oppure un file tecnico. Usa per l interpretazione solo il testo leggibile o estraibile automaticamente; non inventare contenuti da immagini, scansioni o parti binarie non leggibili. Riporta una sintesi, chiedimi cosa voglio fare con il file o con i dati letti e, se il contenuto \u00e8 parziale, chiedimi di precisarlo. Se riconosci prodotti o servizi presenti nel database, proponili automaticamente nella tabella ordine come righe da verificare e confermare.';\n\n            if (!dbVal || dbVal === 'NEW_DB') { window.tiAlert('Seleziona una ditta prima di analizzare il file.'); return; }\n\n            try {\n                const shownName792 = String(fileName || 'file');\n                if (typeof window.updateProgressPopup === 'function') window.updateProgressPopup(94, 'Analisi file AI', 'File caricato. La AI sta leggendo il contenuto: attendi l esito.', shownName792);\n                else if (typeof window.showProgressPopup === 'function') window.showProgressPopup('Analisi file AI', 'File caricato. La AI sta leggendo il contenuto: attendi l esito.', {startPercent:94, targetPercent:98, stepMs:650, cancellable:true, currentItem:shownName792});\n            } catch(eProgress792) {}\n\n            window.rememberLastFileContext(fileUrl, prompt, false);\n            window.lastUploadedFile = null;\n            if (window.addMsg) window.addMsg('user', prompt);\n\n            let waitBubble = null;\n            try {\n                waitBubble = document.createElement('div');\n                waitBubble.className = 'ti-bubble ai';\n                waitBubble.innerHTML = window.getUserWaitingHtml('Analisi file in corso...', 'Sto leggendo il file allegato e preparo la risposta.');\n                if (dom.chat) { dom.chat.appendChild(waitBubble); dom.chat.scrollTop = dom.chat.scrollHeight; }\n            } catch(e) {}\n\n            let chatHist = [];\n            try {\n                const bubbles = dom.chat ? dom.chat.querySelectorAll('.ti-bubble') : [];\n                const startIdx = Math.max(0, (bubbles ? bubbles.length : 0) - 8);\n                for (let i = startIdx; i < (bubbles ? bubbles.length : 0); i++) {\n                    const bubble = bubbles[i];\n                    const role = bubble.classList.contains('user') ? 'user' : 'assistant';\n                    const clone = bubble.cloneNode(true);\n                    const tw = clone.querySelector('.ti-table-wrap'); if (tw) tw.remove();\n                    const msgTxt = (clone.innerText || '').trim();\n                    if (msgTxt && !msgTxt.includes('Fammi pensare...')) chatHist.push({role: role, content: msgTxt});\n                }\n            } catch(e) {}\n\n            const maxAttempts1742 = isImg ? 3 : 1;\n            let attempt1742 = 0;\n            const isHttp5001742 = function(errOrMsg) {\n                try {\n                    if (errOrMsg && Number(errOrMsg.httpStatus || 0) === 500) return true;\n                    const txt = String((errOrMsg && errOrMsg.message) ? errOrMsg.message : (errOrMsg || ''));\n                    return \/(?:^|\\s)HTTP\\s*500\\b|Errore\\s+Server\\s+500\\b\/i.test(txt);\n                } catch(e) { return false; }\n            };\n            const updateRetry1742 = function(nextAttempt) {\n                try {\n                    const detail = 'Analisi temporaneamente non completata. Riprovo automaticamente la foto (' + nextAttempt + '\/3).';\n                    if (typeof window.updateProgressPopup === 'function') window.updateProgressPopup(96, 'Analisi foto AI', detail, String(fileName || 'foto'));\n                    if (waitBubble) waitBubble.innerHTML = window.getUserWaitingHtml('Analisi foto in corso...', 'Riprovo automaticamente (' + nextAttempt + '\/3).');\n                } catch(e) {}\n            };\n            const finishError1742 = function(msg) {\n                if (waitBubble && waitBubble.remove) waitBubble.remove();\n                const errMsg792 = 'Errore analisi file: ' + (msg || 'errore sconosciuto');\n                window.addMsg('ai', '\u26a0\ufe0f ' + errMsg792);\n                try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Errore analisi file', {notifyUser:true, errorMessage:errMsg792}); } catch(eProgressCatch792) {}\n            };\n            const runAttempt1742 = function() {\n                attempt1742++;\n                const fd = new FormData();\n                fd.append('ti_action', 'ti_ai_chat_start');\n                fd.append('db', dbVal);\n                fd.append('analyze_file_only', '1');\n                fd.append('reset_flow_for_file_analysis', '1');\n                fd.append('text', prompt + ` [FILE_ALLEGATO: ${fileUrl}]`);\n                fd.append('history_context', JSON.stringify(chatHist));\n                fd.append('file_analysis_attempt_1742', String(attempt1742));\n\n                return window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n                    if (res && res.success) {\n                        if (waitBubble && waitBubble.remove) waitBubble.remove();\n                        const rawReply = ((res.data || {}).reply || '').trim();\n                        const cleanReply = rawReply.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                        window.addMsg('ai', window.formatTable(cleanReply || 'Analisi completata.'), cleanReply || 'Analisi completata.');\n                        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(true, 'Analisi file completata', {notifyUser:false, successMessage:'Analisi file completata.'}); } catch(eProgressOk1742) {}\n                        if (res.data && res.data.needs_reload) setTimeout(function(){ location.reload(); }, 1200);\n                        return;\n                    }\n                    const msg = (res && res.data && res.data.message) ? String(res.data.message) : 'Analisi file non riuscita';\n                    if (isImg && isHttp5001742(msg) && attempt1742 < maxAttempts1742) {\n                        updateRetry1742(attempt1742 + 1);\n                        return new Promise(function(resolve){ setTimeout(function(){ resolve(runAttempt1742()); }, 700 * attempt1742); });\n                    }\n                    finishError1742(msg);\n                }).catch(function(err){\n                    if (isImg && isHttp5001742(err) && attempt1742 < maxAttempts1742) {\n                        updateRetry1742(attempt1742 + 1);\n                        return new Promise(function(resolve){ setTimeout(function(){ resolve(runAttempt1742()); }, 700 * attempt1742); });\n                    }\n                    finishError1742((err && err.message) ? err.message : 'errore sconosciuto');\n                });\n            };\n\n            runAttempt1742();\n        };\n\n        window.handleFileUpload = function(file, typeName) {\n            let tbl = 'Chat'; const dbVal = gE('ti-ditta').value;\n            if(!dbVal) { window.tiAlert(\"Seleziona una ditta prima di caricare file.\"); return; }\n            window.prepareUploadFileForAI(file).then(function(uploadFile){\n                const realFile = (uploadFile instanceof File) ? uploadFile : file;\n                const fd=new FormData(); fd.append('ti_action','ti_ai_media_upload'); fd.append('db',dbVal); fd.append('file', realFile, realFile.name || file.name || 'upload'); fd.append('tbl', tbl);\n                if(window.addMsg) window.addMsg('ai',\"\u23f3 Analisi file in corso...\"); \n                window.fetchJsonSafe(window.tiUrl,{method:'POST',body:fd}).then(d=>{\n                    if(d.success) { \n                        window.lastUploadedFile = d.data && d.data.url ? d.data.url : (d.url ? d.url : ''); \n                        if (typeName === 'Immagine') {\n                            \/\/ 30.9.1742: la foto passa sempre dal percorso di analisi dedicato, che gestisce\n                            \/\/ automaticamente fino a 3 tentativi in caso di HTTP 500. Non simulare piu il click\n                            \/\/ della chat principale: quel percorso perdeva il contesto foto necessario al retry.\n                            try { if (window.log1088) window.log1088('1742 foto: avvio analisi dedicata con retry HTTP 500'); } catch(eL1742){}\n                            window.startUserUploadedFileAI(window.lastUploadedFile, realFile.name || file.name || 'foto.jpg');\n                        } else {\n                            window.startUserUploadedFileAI(window.lastUploadedFile, realFile.name || file.name || '');\n                        }\n                    } else { if(window.addMsg) window.addMsg('ai',`\u26a0\ufe0f Errore caricamento.`); }\n                }).catch(function(err){\n                    if(window.addMsg) window.addMsg('ai', '\u26a0\ufe0f Errore caricamento file: ' + ((err && err.message) ? err.message : 'errore sconosciuto'));\n                });\n            });\n        };\n\n        \/\/ 30.9.1771 - Nuova = reset completo layout\/conversazione, senza logout dell eventuale utente autenticato.\n        window.tiNewChatFullReset1771 = function(ev) {\n            try { if (ev) { ev.preventDefault(); ev.stopPropagation(); } } catch(e) {}\n            if (window.__tiNewChatFullReset1771) return false;\n            window.__tiNewChatFullReset1771 = true;\n\n            const keepDb1771 = (dom.ditta && dom.ditta.value && dom.ditta.value !== 'NEW_DB')\n                ? String(dom.ditta.value)\n                : String(window.tiSessionDb || window.tiCurrentSelectedDb || '');\n            try {\n                if (keepDb1771) {\n                    localStorage.setItem('ti_saved_db', keepDb1771);\n                    window.tiCurrentSelectedDb = keepDb1771;\n                }\n            } catch(e) {}\n\n            \/\/ Non modificare mai window.tiUser\/window.tiRole, cookie o sessione di autenticazione.\n            \/\/ Blocca invece qualsiasi risposta tardiva della chat corrente.\n            try {\n                const req1771 = window.tiMainChatActiveRequest1542;\n                if (req1771 && !req1771.done) {\n                    req1771.manualCancel = true;\n                    req1771.newChatReset1771 = true;\n                    if (req1771.controller) req1771.controller.abort();\n                }\n            } catch(e) {}\n            try { window.tiCompanyEpoch1657 = Number(window.tiCompanyEpoch1657 || 0) + 1; } catch(e) {}\n            try { if (window.clearLastFileContext) window.clearLastFileContext(); else window.lastFileContext = null; } catch(e) {}\n            try { if (window.resetClarifyCount) window.resetClarifyCount(); } catch(e) {}\n            try { if (window.hideOrderConfirmPanel) window.hideOrderConfirmPanel(true); } catch(e) {}\n            try { if (dom.chat) dom.chat.innerHTML = ''; } catch(e) {}\n            try { if (dom.msg) dom.msg.value = ''; else { const m1771=gE('ti-msg'); if(m1771)m1771.value=''; } } catch(e) {}\n            try { const h1771=gE('ti-order-confirm-host'); if(h1771)h1771.innerHTML=''; } catch(e) {}\n            try { const h1771=gE('ti-ai-response-host'); if(h1771)h1771.innerHTML=''; } catch(e) {}\n            try { window.lastUploadedFile=null; window.configBotFile=null; window.targetUploadContext=null; window.currentGenFilename=null; window.tiQuickReplyText=''; window.tiHiddenSendText=''; window.tiHiddenSendLabel=''; } catch(e) {}\n\n            \/\/ Elimina solo contesti temporanei UI; non tocca preferenze, lingua, ditta o autenticazione.\n            try {\n                ['tiLastDirectUploadCtx616','tiLastFileManagerCtx455','tiLastFileManagerCtx471','tiLastUploadContext356','tiNativeUploadCtx617','tiNativeUploadCtx620','tiNativeUploadCtx621','tiNativeUploadCtx646','tiNewDbOpen','tiPendingNewDb'].forEach(function(k){ sessionStorage.removeItem(k); });\n            } catch(e) {}\n\n            const b1771 = dom.btnNew || gE('ti-new');\n            if (b1771) { b1771.disabled = true; b1771.textContent = (String(window.currLang||'it').toLowerCase()==='en' ? 'Reset...' : 'Reset...'); }\n\n            let reloaded1771 = false;\n            const reload1771 = function(){\n                if (reloaded1771) return;\n                reloaded1771 = true;\n                try { window.location.reload(); } catch(e) { try { window.location.href = window.location.href; } catch(_) {} }\n            };\n\n            const fd1771 = new FormData();\n            fd1771.append('ti_action', 'ti_ai_reset_flow');\n            if (keepDb1771) fd1771.append('db', keepDb1771);\n            try {\n                fetch(window.tiUrl, {method:'POST', body:fd1771, credentials:'same-origin', cache:'no-store', keepalive:true})\n                    .then(function(){ reload1771(); })\n                    .catch(function(){ reload1771(); });\n            } catch(e) { reload1771(); }\n            \/\/ Fallback: il reset visuale deve comunque completarsi anche se una risposta HTTP resta pendente.\n            setTimeout(reload1771, 1800);\n            return false;\n        };\n        if(dom.btnNew) dom.btnNew.onclick = window.tiNewChatFullReset1771;\n\n        if(gE('ti-cam')) gE('ti-cam').onclick = (e) => { e.preventDefault(); window.openCamModal(); };\n        const camIn = gE('ti-cam-in'); if(camIn) camIn.onchange = (e) => { if(e.target.files.length) window.handleFileUpload(e.target.files[0], 'Immagine'); };\n        if(gE('ti-file')) gE('ti-file').onclick = (e) => { e.preventDefault(); window.showUploadChoice('chat'); }; \n        \/\/ 30.9.1691 - Cache paginata progressiva catalogo tabella ordine (router diretto obbligatorio).\n        \/\/ Prima pagina Prodotti precaricata in background dopo scelta ditta\/reset layout.\n        \/\/ Ogni pagina visualizzata prepara la successiva e conserva le precedenti in memoria.\n        (function(){\n            if (window.__tiCatalogProgressive1686Installed) return;\n            window.__tiCatalogProgressive1686Installed = true;\n            window.__tiCatalogCache1686 = window.__tiCatalogCache1686 || Object.create(null);\n            window.__tiCatalogPending1686 = window.__tiCatalogPending1686 || Object.create(null);\n            window.__tiCatalogPrefetchTimers1686 = window.__tiCatalogPrefetchTimers1686 || [];\n\n            function db1686(){\n                var e=document.getElementById('ti-ditta');\n                var v=e?String(e.value||''):'';\n                if(!v && window.currentDbData && window.currentDbData.__db_name) v=String(window.currentDbData.__db_name||'');\n                if(!v && window.tiCurrentSelectedDb) v=String(window.tiCurrentSelectedDb||'');\n                return v;\n            }\n            function lang1686(){\n                try{return String(window.currLang||document.documentElement.lang||'it').toLowerCase().indexOf('en')===0?'en':'it';}\n                catch(e){return'it';}\n            }\n            function kind1686(kind){return \/serviz\/i.test(String(kind||''))?'Servizi':'Prodotti';}\n            function page1686(page){return Math.max(1,parseInt(page||1,10)||1);}\n            function pageSize1851(){\n                var v='table';\n                try{v=window.getOrderViewPreference?String(window.getOrderViewPreference()||'table'):'table';}catch(e){v='table';}\n                return v==='table'?50:10;\n            }\n            function key1686(db,kind,page){return String(db||'')+'|'+kind1686(kind)+'|'+page1686(page)+'|'+pageSize1851();}\n            function esc1686(v){return String(v==null?'':v).replace(\/[&<>\\\"]\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\\\"':'&quot;'}[c]||c;});}\n            \/\/ 30.9.1691: il catalogo non usa mai admin-ajax.php. Il router diretto\n            \/\/ della pagina Shop-Service intercetta ti_action=ti_ai_catalog_page_1676 su init.\n            function directCatalogUrl1691(){\n                var u='';\n                try{u=String(window.tiUrl||'').trim();}catch(e){}\n                if(!u){try{u=String(window.location.href||'').split('#')[0].split('?')[0];}catch(e){u='';}}\n                return u||'\/shop-service\/';\n            }\n            function ajax1686(){return directCatalogUrl1691();}\n\n            \/\/ Circuit breaker: anche un eventuale handler storico rimasto nel DOM non puo\n            \/\/ piu spedire il catalogo ad admin-ajax.php. Vale solo per questa azione.\n            try{\n                if(window.fetch && !window.fetch.__tiCatalogDirect1691){\n                    var prevFetchCatalog1691=window.fetch;\n                    var fetchCatalog1691=function(input,init){\n                        try{\n                            var body1691=init&&init.body, act1691='';\n                            if(body1691&&typeof body1691.get==='function') act1691=String(body1691.get('ti_action')||body1691.get('action')||'');\n                            if(act1691==='ti_ai_catalog_page_1676'){\n                                input=directCatalogUrl1691();\n                                init=Object.assign({},init||{}, {credentials:'same-origin',cache:'no-store'});\n                            }\n                        }catch(e){}\n                        return prevFetchCatalog1691.call(this,input,init);\n                    };\n                    fetchCatalog1691.__tiCatalogDirect1691=true;\n                    fetchCatalog1691.__tiPrevFetchCatalog1691=prevFetchCatalog1691;\n                    window.fetch=fetchCatalog1691;\n                }\n            }catch(e){}\n\n            window.tiCatalogInvalidate1686=function(db){\n                var prefix=db?String(db)+'|':'';\n                Object.keys(window.__tiCatalogCache1686).forEach(function(k){if(!prefix||k.indexOf(prefix)===0)delete window.__tiCatalogCache1686[k];});\n                Object.keys(window.__tiCatalogPending1686).forEach(function(k){if(!prefix||k.indexOf(prefix)===0)delete window.__tiCatalogPending1686[k];});\n            };\n\n            function request1686(kind,page,dbv){\n                kind=kind1686(kind); page=page1686(page); dbv=String(dbv||db1686()||'');\n                if(!dbv||dbv==='NEW_DB') return Promise.reject(new Error(lang1686()==='en'?'Select a company first.':'Seleziona prima una ditta.'));\n                var k=key1686(dbv,kind,page);\n                if(window.__tiCatalogCache1686[k]) return Promise.resolve(window.__tiCatalogCache1686[k]);\n                if(window.__tiCatalogPending1686[k]) return window.__tiCatalogPending1686[k];\n                var fd=new FormData();\n                fd.append('action','ti_ai_catalog_page_1676');\n                fd.append('ti_action','ti_ai_catalog_page_1676');\n                fd.append('db',dbv);\n                fd.append('kind',kind);\n                fd.append('page',String(page));\n                fd.append('per_page',String(pageSize1851()));\n                var ctl=null,timer=null;\n                try{if(window.AbortController){ctl=new AbortController();timer=setTimeout(function(){try{ctl.abort();}catch(e){}},60000);}}catch(e){ctl=null;}\n                var opt={method:'POST',body:fd,credentials:'same-origin',cache:'no-store'};\n                if(ctl&&ctl.signal)opt.signal=ctl.signal;\n                var p=fetch(ajax1686(),opt).then(function(r){if(!r.ok)throw new Error('HTTP '+r.status);return r.text();}).then(function(t){\n                    var j;try{j=JSON.parse(String(t||'').replace(\/^\\uFEFF\/,''));}catch(e){throw new Error(lang1686()==='en'?'Invalid server response.':'Risposta server non valida.');}\n                    if(!j||j.success===false){var m=j&&j.data&&(j.data.message||j.data.reply)?(j.data.message||j.data.reply):'';throw new Error(m||(lang1686()==='en'?'Catalog loading error.':'Errore caricamento catalogo.'));}\n                    var d=j.data||j;\n                    d.__ti_db_1686=dbv; d.__ti_kind_1686=kind; d.__ti_page_1686=page;\n                    window.__tiCatalogCache1686[k]=d;\n                    return d;\n                }).finally(function(){try{if(timer)clearTimeout(timer);}catch(e){}delete window.__tiCatalogPending1686[k];});\n                window.__tiCatalogPending1686[k]=p;\n                return p;\n            }\n\n            function nav1686(d){\n                var p=page1686(d&&d.page),pages=Math.max(1,parseInt(d&&d.pages||1,10)||1),kind=kind1686(d&&d.kind);\n                var isEn=lang1686()==='en';\n                var meta=isEn?('Rows '+(d.from||0)+'-'+(d.to||0)+' of '+(d.total||0)+' - Page '+p+'\/'+pages):('Righe '+(d.from||0)+'-'+(d.to||0)+' di '+(d.total||0)+' - Pagina '+p+'\/'+pages);\n                return '<div class=\"ti-catalog-pagebar-1676\"><button type=\"button\" '+(p<=1?'disabled':'')+' onclick=\"return window.tiCatalogShow1686(\\''+kind+'\\','+(p-1)+',false)\">\u2212<\/button><span class=\"ti-cat-meta\">'+esc1686(meta)+'<\/span><button type=\"button\" '+(p>=pages?'disabled':'')+' onclick=\"return window.tiCatalogShow1686(\\''+kind+'\\','+(p+1)+',false)\">+<\/button><\/div>';\n            }\n            function fallbackCatalog1851(d){\n                var arr=Array.isArray(d&&d.items_1851)?d.items_1851:[];\n                if(!arr.length)return'';\n                var allowed=window.getOrderViewAllowedModes?window.getOrderViewAllowedModes():['table','small','medium','large'];\n                var pref=window.getOrderViewPreference?window.getOrderViewPreference():'table';\n                if(allowed.indexOf(pref)<0)pref=allowed[0]||'table';\n                function money(v){var n=parseFloat(v)||0;try{return window.fmtNum?window.fmtNum(n):n.toFixed(2).replace('.',',');}catch(e){return n.toFixed(2).replace('.',',');}}\n                var user1962=String(window.tiUser||'').trim().toLowerCase(),role1962=String(window.tiRole||'').trim().toLowerCase();\n                var showTypePrefix1962=!!user1962&&(user1962==='ssglobaladmin'||user1962==='globaladmin'||\/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|global admin|sysadmin|globale\/.test(role1962));\n                function stripTypePrefix1962(v){return String(v==null?'':v).replace(\/^\\s*[PS]\\s*-\\s*\/i,'').trim();}\n                var rows='',cards='';\n                arr.forEach(function(it,n){\n                    var id='ord-f1851-'+String(it.idx!=null?it.idx:n),isServ=\/serviz\/i.test(String(it.table||d.kind||''));\n                    var rawNameOriginal=String(it.name||'').trim(),rawName=stripTypePrefix1962(rawNameOriginal)||rawNameOriginal;\n                    var name=showTypePrefix1962?((isServ?'S - ':'P - ')+rawName):rawName,desc=String(it.desc||''),price=parseFloat(it.price)||0,iva=String(it.iva||'22');\n                    var instr1863=String(it.instruction||'').trim(),pFinal1863=price,pOrig1863=price;\n                    var pair1863=String(it.price_pair_1863||'');\n                    if(pair1863.indexOf('|||')>=0){var pp1863=pair1863.split('|||');pFinal1863=parseFloat(pp1863[0])||price;pOrig1863=parseFloat(pp1863[1])||price;}\n                    else if(instr1863&&window.extractInstructionPriceAdjustments){try{var adj1863=window.extractInstructionPriceAdjustments(instr1863,price);if(adj1863&&adj1863.isModified){pFinal1863=parseFloat(adj1863.finalPrice)||price;pOrig1863=parseFloat(adj1863.listPrice)||price;}}catch(_e1863){}}\n                    var changed1863=Math.abs(pFinal1863-pOrig1863)>0.009;\n                    price=pFinal1863;\n                    var cond1863=changed1863?((window.currLang==='en'?'Current price: \u20ac ':'Prezzo attuale: \u20ac ')+money(pFinal1863)+'\\n'+(window.currLang==='en'?'Reference price: \u20ac ':'Prezzo di riferimento: \u20ac ')+money(pOrig1863)+(instr1863?'\\n'+(window.currLang==='en'?'Reference condition: ':'Condizione di riferimento: ')+instr1863:'')):'';\n                    var warn1863=changed1863?'<button type=\"button\" class=\"ti-order-price-alert-1863\" data-price-condition=\"'+esc1686(encodeURIComponent(cond1863))+'\" onclick=\"event.stopPropagation();window.openOrderPriceCondition1863(this)\" title=\"'+(window.currLang==='en'?'Price condition':'Condizione prezzo')+'\">!<\/button>':'';\n                    var eName=esc1686(name),eDesc=esc1686(desc),eRaw=esc1686(rawName),p=money(price),pOrigTxt1863=money(pOrig1863);\n                    var priceHtml1863=changed1863?('<span style=\"display:block;font-size:14px;font-weight:800;color:#fff\">\u20ac '+p+'<\/span><span style=\"display:block;font-size:11px;color:#ef4444;text-decoration:line-through\">\u20ac '+pOrigTxt1863+'<\/span>'):('<span style=\"display:block;font-size:13px;color:#fff;font-weight:700\">\u20ac '+p+'<\/span>');\n                    var rawMedia2006=Array.isArray(it.files_2006)?it.files_2006:String(it.img||'').replace(\/&amp;\/gi,'&').replace(\/&#38;\/g,'&').split(\/[,;|\\r\\n]+\/);\n                    var rawImgs2003=Array.isArray(it.images_2004)?it.images_2004:(Array.isArray(it.images_2003)?it.images_2003:rawMedia2006);\n                    var gallery2003=[];rawImgs2003.forEach(function(u){u=String(u||'').trim();if(!u)return;var nm='';try{nm=window.getFileNameFromUrlOrValue?window.getFileNameFromUrlOrValue(u):u;}catch(_e){}if(\/^data:image\\\/\/i.test(u)||(window.isImageFileName&&(window.isImageFileName(nm)||window.isImageFileName(u)))){if(gallery2003.indexOf(u)<0)gallery2003.push(u);}});\n                    var docs2006=[];rawMedia2006.forEach(function(u){u=String(u||'').trim();if(!u)return;var nm='';try{nm=window.getFileNameFromUrlOrValue?window.getFileNameFromUrlOrValue(u):u;}catch(_e){}var im=\/^data:image\\\/\/i.test(u)||(window.isImageFileName&&(window.isImageFileName(nm)||window.isImageFileName(u)));if(!im&&docs2006.indexOf(u)<0)docs2006.push(u);});\n                    var imgUrl=gallery2003.length?gallery2003[0]:'',eImg=esc1686(imgUrl),fb='';\n                    try{fb=window.getCompanyOrderLogoUrl1968?String(window.getCompanyOrderLogoUrl1968(db1686())||''):(window.getCompanyFallbackMediaUrl?String(window.getCompanyFallbackMediaUrl(db1686())||''):'');}catch(_e1852){fb='';}\n                    var eFb=esc1686(fb),galleryAttr2003=gallery2003.length?' data-ti-order-images-2003=\"'+esc1686(encodeURIComponent(JSON.stringify(gallery2003)))+'\" data-ti-order-image-name-2003=\"'+eRaw+'\" onclick=\"event.stopPropagation();return window.openOrderImageGalleryData2003(this)\"':'';\n                    var docsAttr2006=docs2006.length?' data-ti-order-docs-2006=\"'+esc1686(encodeURIComponent(JSON.stringify(docs2006)))+'\" data-ti-order-media-name-2006=\"'+eRaw+'\" onclick=\"event.stopPropagation();return window.openOrderDocumentsData2006(this)\"':'';\n                    var galleryBadge2003=gallery2003.length>1?'<button type=\"button\" data-ti-order-images-2003=\"'+esc1686(encodeURIComponent(JSON.stringify(gallery2003)))+'\" data-ti-order-image-name-2003=\"'+eRaw+'\" onclick=\"event.stopPropagation();return window.openOrderImageGalleryData2003(this)\" title=\"'+gallery2003.length+' immagini disponibili\" style=\"border:0;border-radius:999px;background:#2563eb;color:#fff;font-size:9px;font-weight:800;padding:1px 5px;cursor:pointer;white-space:nowrap;\">'+gallery2003.length+'<\/button>':'';\n                    var docsBadge2006=docs2006.length?'<button type=\"button\" '+docsAttr2006+' title=\"'+docs2006.length+' documenti disponibili\" style=\"border:0;border-radius:999px;background:#7c3aed;color:#fff;font-size:9px;font-weight:800;padding:1px 5px;cursor:pointer;white-space:nowrap;\">'+docs2006.length+' doc<\/button>':'';\n                    var logoTable1968=fb?'<img decoding=\"async\" src=\"'+eFb+'\" class=\"ti-row-img\" title=\"Logo ditta\" data-ti-order-company-logo-1968=\"1\" data-no-lazy=\"1\">':'';\n                    var logoCard1968=fb?'<img decoding=\"async\" src=\"'+eFb+'\" alt=\"Logo ditta\" title=\"Logo ditta\" data-ti-order-company-logo-1968=\"1\">':'';\n                    var mediaTable=imgUrl?'<span style=\"display:inline-flex;align-items:center;gap:2px;\"><img decoding=\"async\" src=\"'+eImg+'\" data-fallback=\"'+eFb+'\" class=\"ti-row-img\" '+galleryAttr2003+' title=\"'+(gallery2003.length>1?'Apri elenco immagini':'Ingrandisci immagine')+'\" onerror=\"if(window.applyFallbackImage)window.applyFallbackImage(this)\" data-no-lazy=\"1\">'+galleryBadge2003+docsBadge2006+'<\/span>':'<span style=\"display:inline-flex;align-items:center;gap:2px;\">'+logoTable1968+docsBadge2006+'<\/span>';\n                    var mediaCard=imgUrl?'<div style=\"position:relative;width:100%;height:100%;\"><img decoding=\"async\" src=\"'+eImg+'\" alt=\"'+eRaw+'\" data-fallback=\"'+eFb+'\" '+galleryAttr2003+' title=\"'+(gallery2003.length>1?'Apri elenco immagini':'Ingrandisci immagine')+'\" onerror=\"if(window.applyFallbackImage)window.applyFallbackImage(this)\">'+(gallery2003.length>1?'<span style=\"position:absolute;right:5px;top:5px;border-radius:999px;background:#2563eb;color:#fff;font-size:9px;font-weight:800;padding:2px 5px;pointer-events:none;\">'+gallery2003.length+'<\/span>':'')+(docs2006.length?'<button type=\"button\" '+docsAttr2006+' style=\"position:absolute;right:5px;'+(gallery2003.length>1?'top:31px':'top:5px')+';border:0;border-radius:999px;background:#7c3aed;color:#fff;font-size:9px;font-weight:800;padding:2px 5px;cursor:pointer;z-index:4;\">'+docs2006.length+' doc<\/button>':'')+'<\/div>':'<div style=\"position:relative;width:100%;height:100%;\">'+logoCard1968+(docs2006.length?'<button type=\"button\" '+docsAttr2006+' style=\"position:absolute;right:5px;top:5px;border:0;border-radius:999px;background:#7c3aed;color:#fff;font-size:9px;font-weight:800;padding:2px 5px;cursor:pointer;z-index:4;\">'+docs2006.length+' doc<\/button>':'')+'<\/div>';\n                    rows+='<tr data-order-id=\"'+id+'\" data-name=\"'+eName+' '+eRaw+'\" data-desc=\"'+eDesc+'\" data-price=\"'+price+'\" data-iva=\"'+esc1686(iva)+'\"><td class=\"ti-col-img\">'+mediaTable+warn1863+'<\/td><td class=\"ti-col-art\"><span class=\"ti-item-name\" style=\"font-size:11px;font-weight:bold\">'+eName+'<\/span><\/td><td style=\"font-size:10px;color:#ccc\">'+eDesc+'<\/td><td><\/td><td class=\"ti-col-eur\" data-price=\"'+price+'\">'+priceHtml1863+'<\/td><td class=\"ti-col-qta\"><span class=\"ti-qty-stepper\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,-1)\">-<\/button><input type=\"text\" inputmode=\"decimal\" class=\"ti-inp ti-q ti-num-step\" data-order-id=\"'+id+'\" value=\"0,00\" placeholder=\"0,00\" aria-label=\"Quantit\u00e0\" onfocus=\"if(this.value===\\'0,00\\')this.value=\\'\\';\" onblur=\"if(this.value===\\'\\')this.value=\\'0,00\\';else this.value=window.formatQtyInput(this.value);window.syncOrderQty(this);\" oninput=\"window.syncOrderQty(this)\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,1)\">+<\/button><\/span><\/td><td class=\"ti-col-tot p-tot\" data-order-id=\"'+id+'\" data-price=\"'+price+'\">0,00<\/td><\/tr>';\n                    cards+='<div class=\"ti-order-card\" data-order-id=\"'+id+'\" data-name=\"'+eName+' '+eRaw+'\" data-desc=\"'+eDesc+'\" data-price=\"'+price+'\" data-iva=\"'+esc1686(iva)+'\"><div class=\"ti-order-card-media\">'+mediaCard+'<\/div><div class=\"ti-order-card-body\"><div class=\"ti-order-card-title\">'+eName+'<\/div><div class=\"ti-order-card-desc\">'+(eDesc||eRaw)+'<\/div><div class=\"ti-order-card-line\">Q.t\u00e0: <span class=\"ti-qty-stepper\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,-1)\">-<\/button><input type=\"text\" inputmode=\"decimal\" class=\"ti-q\" data-order-id=\"'+id+'\" value=\"0,00\" placeholder=\"0,00\" aria-label=\"Quantit\u00e0\" onfocus=\"if(this.value===\\'0,00\\')this.value=\\'\\';\" onblur=\"if(this.value===\\'\\')this.value=\\'0,00\\';else this.value=window.formatQtyInput(this.value);window.syncOrderQty(this);\" oninput=\"window.syncOrderQty(this)\"><button type=\"button\" class=\"ti-qty-btn\" onclick=\"window.stepQtyInput(this,1)\">+<\/button><\/span><\/div><div class=\"ti-order-card-line\">'+warn1863+'Prezzo: <span class=\"ti-order-inline-price\">'+priceHtml1863+'<\/span> <span class=\"ti-order-inline-total-wrap\">Totale: <span class=\"ti-order-card-total p-tot\" data-order-id=\"'+id+'\" data-price=\"'+price+'\">0,00<\/span><\/span><\/div><\/div><\/div>';\n                });\n                var buttons='';\n                if(allowed.length>1){[['small','Small'],['medium','Medium'],['large','Large']].forEach(function(x){if(allowed.indexOf(x[0])>=0)buttons+='<button type=\"button\" class=\"ti-order-view-btn '+(pref===x[0]?'active':'')+'\" data-view=\"'+x[0]+'\" onclick=\"window.setOrderView(this,\\''+x[0]+'\\')\">'+x[1]+'<\/button>';});}\n                return '<div class=\"ti-order-wrap ti-view-'+pref+' ti-catalog-fallback-1851\"><div class=\"ti-order-toolbar\"><div class=\"ti-order-toolbar-left\">'+buttons+'<\/div><div class=\"ti-order-toolbar-right\"><span class=\"ti-order-hint\">Descrizione \/ quantit\u00e0 \/ prezzo \/ totale<\/span><\/div><\/div><div class=\"ti-order-filterbar\"><div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Voce<\/span><input type=\"text\" class=\"ti-filter-input\" oninput=\"window.filterOrderWrap(this,\\'name\\')\" placeholder=\"Filtra voce\"><\/div><div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Descrizione<\/span><input type=\"text\" class=\"ti-filter-input\" oninput=\"window.filterOrderWrap(this,\\'desc\\')\" placeholder=\"Filtra descrizione\"><\/div><div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Prezzo<\/span><input type=\"text\" class=\"ti-filter-input\" oninput=\"window.filterOrderWrap(this,\\'price\\')\" placeholder=\"> 10 \/ < 20 \/ 15\"><\/div><div class=\"ti-order-filtercell\"><span class=\"ti-order-filterlabel\">Ordina<\/span><select class=\"ti-in\" onchange=\"window.sortOrderWrap(this)\"><option value=\"name_asc\">Voce A-Z<\/option><option value=\"name_desc\">Voce Z-A<\/option><option value=\"price_asc\">Prezzo crescente<\/option><option value=\"price_desc\">Prezzo decrescente<\/option><\/select><\/div><\/div><div class=\"ti-order-table-shell\"><div class=\"ti-order-table-view ti-table-wrap\"><table class=\"ti-prod-table\"><thead><tr><th class=\"ti-col-img\">Media<\/th><th>Voce<\/th><th>Descrizione<\/th><th class=\"ti-col-disp\">Disp<\/th><th class=\"ti-col-eur\">Prezzo<\/th><th class=\"ti-col-qta\">Qt\u00e0<\/th><th class=\"ti-col-tot\">Tot<\/th><\/tr><\/thead><tbody>'+rows+'<\/tbody><\/table><\/div><\/div><div class=\"ti-order-grid-view\">'+cards+'<\/div><\/div>';\n            }\n            \/\/ 30.9.1855: renderer strutturato riutilizzabile anche dal fast-path chatbot.\n            window.tiBuildStructuredCatalog1855=function(payload){\n                try{\n                    var src=payload||{}, arr=Array.isArray(src.items_1855)?src.items_1855:(Array.isArray(src.items_1851)?src.items_1851:[]);\n                    if(!arr.length)return '';\n                    return fallbackCatalog1851({items_1851:arr,kind:src.kind||'Prodotti'});\n                }catch(e){return '';}\n            };\n            window.tiNormalizeCatalogBubble1855=function(bubble){\n                try{\n                    if(!bubble||!bubble.querySelector||!bubble.querySelector('.ti-order-wrap'))return;\n                    bubble.setAttribute('data-ti-direct-catalog-1859','1');\n                    bubble.classList.add('ti-direct-catalog-1859');\n                    bubble.classList.remove('ti-long-ai-readable-804','ti-file-options-readable-813');\n                    bubble.style.setProperty('max-height','none','important');\n                    bubble.style.setProperty('height','auto','important');\n                    bubble.style.setProperty('min-height','0','important');\n                    bubble.style.setProperty('overflow','visible','important');\n                    bubble.style.setProperty('overflow-y','visible','important');\n                    bubble.style.setProperty('position','relative','important');\n                    bubble.style.setProperty('z-index','2','important');\n                    bubble.querySelectorAll('.ti-chat-scroll-tools-802').forEach(function(n){n.remove();});\n                    bubble.__tiScrollTools802=true;\n                    var wrap=bubble.querySelector('.ti-order-wrap');\n                    if(wrap){\n                        wrap.style.setProperty('height','auto','important');\n                        wrap.style.setProperty('max-height','none','important');\n                        wrap.style.setProperty('min-height','0','important');\n                        wrap.style.setProperty('overflow','visible','important');\n                        wrap.style.setProperty('visibility','visible','important');\n                        wrap.style.setProperty('opacity','1','important');\n                        var pref='table';try{pref=window.getOrderViewPreference?String(window.getOrderViewPreference()||'table'):'table';}catch(e){}\n                        var allowed=[];try{allowed=window.getOrderViewAllowedModes?window.getOrderViewAllowedModes():[];}catch(e){allowed=[];}\n                        if(allowed.length&&allowed.indexOf(pref)<0)pref=allowed[0];\n                        ['table','small','medium','large'].forEach(function(v){wrap.classList.remove('ti-view-'+v);});\n                        wrap.classList.add('ti-view-'+pref);\n                        var grid=wrap.querySelector('.ti-order-grid-view'), shell=wrap.querySelector('.ti-order-table-shell');\n                        if(pref==='table'){\n                            if(shell){shell.style.setProperty('display','block','important');shell.style.setProperty('visibility','visible','important');shell.style.setProperty('height','auto','important');}\n                            if(grid)grid.style.setProperty('display','none','important');\n                            wrap.querySelectorAll('.ti-prod-table tbody tr[data-order-id]').forEach(function(r){r.style.removeProperty('display');r.style.setProperty('visibility','visible','important');});\n                        }else{\n                            if(shell)shell.style.setProperty('display','none','important');\n                            if(grid){\n                                grid.style.setProperty('display','grid','important');\n                                grid.style.setProperty('visibility','visible','important');\n                                grid.style.setProperty('height','auto','important');\n                                grid.style.setProperty('min-height','1px','important');\n                                grid.style.setProperty('max-height','none','important');\n                                grid.style.setProperty('overflow','visible','important');\n                                grid.style.setProperty('opacity','1','important');\n                            }\n                            var cards=wrap.querySelectorAll('.ti-order-card');\n                            cards.forEach(function(card){\n                                card.style.setProperty('display','flex','important');\n                                card.style.setProperty('visibility','visible','important');\n                                card.style.setProperty('height','auto','important');\n                                card.style.setProperty('min-height','1px','important');\n                                card.style.setProperty('max-height','none','important');\n                                card.style.setProperty('overflow','hidden','important');\n                                card.style.setProperty('opacity','1','important');\n                                card.style.setProperty('position','relative','important');\n                                card.style.setProperty('z-index','1','important');\n                            });\n                        }\n                        var toolbar=wrap.querySelector('.ti-order-toolbar'), filters=wrap.querySelector('.ti-order-filterbar');\n                        if(toolbar)toolbar.style.setProperty('position','relative','important');\n                        if(filters)filters.style.setProperty('position','relative','important');\n                    }\n                }catch(e){}\n            };\n            function render1686(b,d){\n                if(!b||!d)return;\n                var raw=String(d.reply||''),body=window.formatTable?window.formatTable(raw):raw;\n                var bt=String(body||''),hasWrap=bt.indexOf('ti-order-wrap')>=0,hasRows=\/<tr\\b[^>]*data-order-id=\/i.test(bt),hasCards=\/class=[\"'][^\"']*ti-order-card\/i.test(bt);\n                var pref1854='table';\n                try{pref1854=window.getOrderViewPreference?String(window.getOrderViewPreference()||'table'):'table';}catch(_e1854){pref1854='table';}\n                var needCards1854=(pref1854==='small'||pref1854==='medium'||pref1854==='large');\n                var invalidActiveView1854=!hasWrap||(needCards1854?!hasCards:!hasRows);\n                if(invalidActiveView1854&&Array.isArray(d.items_1851)&&d.items_1851.length){var fb=fallbackCatalog1851(d);if(fb){body=fb;try{console.warn('[Shop-Service] catalogo 1854: fallback vista attiva',{items:d.items_1851.length,kind:d.kind,page:d.page,per_page:d.per_page,view:pref1854,hasRows:hasRows,hasCards:hasCards});}catch(e){}}}\n                var nav=(parseInt(d.pages||1,10)||1)>1?nav1686(d):'';\n                b.innerHTML=nav+body+nav;\n                try{\n                    var order1854=b.querySelector('.ti-order-wrap');\n                    if(order1854){\n                        var bubble1854=b.closest?b.closest('.ti-bubble.ai'):null;\n                        if(bubble1854){\n                            bubble1854.classList.remove('ti-long-ai-readable-804','ti-file-options-readable-813');\n                            bubble1854.style.maxHeight='none';\n                            bubble1854.style.overflow='visible';\n                            bubble1854.querySelectorAll('.ti-chat-scroll-tools-802').forEach(function(n){n.remove();});\n                        }\n                    }\n                }catch(_e1854b){}\n                b.setAttribute('data-ti-catalog-kind-1686',kind1686(d.kind));\n                b.setAttribute('data-ti-catalog-page-1686',page1686(d.page));\n                b.setAttribute('data-ti-catalog-db-1686',String(d.__ti_db_1686||db1686()||''));\n                try{if(window.tiI18nTranslateSubtree)window.tiI18nTranslateSubtree(b);if(window.initSyncScrollbars)window.initSyncScrollbars(b);if(window.refreshOrderConfirmPanel)window.refreshOrderConfirmPanel();}catch(e){}\n                try{var t=b.querySelector('.ti-order-toolbar')||b.querySelector('.ti-catalog-pagebar-1676');if(t&&t.scrollIntoView)t.scrollIntoView({behavior:'smooth',block:'start'});}catch(e){}\n            }\n            function bubble1686(kind,newRequest,loadingText){\n                if(newRequest&&window.addMsg)window.addMsg('user',kind);\n                var b=window.__tiCatalogBubble1676;\n                if(!b||!document.body.contains(b)||newRequest){\n                    b=window.addMsg?window.addMsg('ai',loadingText||''):null;\n                    window.__tiCatalogBubble1676=b;\n                }else if(loadingText){b.innerHTML=loadingText;}\n                return b;\n            }\n            function prefetch1686(kind,page,dbv){\n                kind=kind1686(kind); page=page1686(page); dbv=String(dbv||db1686()||'');\n                if(!dbv||dbv==='NEW_DB')return Promise.resolve(null);\n                return request1686(kind,page,dbv).catch(function(){return null;});\n            }\n            window.tiCatalogPrefetch1686=prefetch1686;\n\n            function prefetchAround1686(d,dbv){\n                if(!d)return;\n                var p=page1686(d.page),pages=Math.max(1,parseInt(d.pages||1,10)||1),kind=kind1686(d.kind);\n                \/\/ Dopo aver reso disponibile la pagina corrente, prepara la successiva.\n                if(p<pages)setTimeout(function(){prefetch1686(kind,p+1,dbv);},60);\n                \/\/ La precedente normalmente e' gia in cache; questo copre anche accessi non sequenziali.\n                if(p>1 && !window.__tiCatalogCache1686[key1686(dbv,kind,p-1)])setTimeout(function(){prefetch1686(kind,p-1,dbv);},120);\n            }\n\n            window.tiCatalogShow1686=function(kind,page,newRequest){\n                kind=kind1686(kind); page=page1686(page); var dbv=db1686(),isEn=lang1686()==='en';\n                if(!dbv||dbv==='NEW_DB'){if(window.tiAlert)window.tiAlert(isEn?'Select a company first.':'Seleziona prima una ditta.');return false;}\n                var k=key1686(dbv,kind,page),cached=window.__tiCatalogCache1686[k];\n                var loading='<div class=\"ti-catalog-loading-1676\"><b>'+(isEn?('Loading page '+page+'...'):('Caricamento pagina '+page+'...'))+'<\/b><\/div>';\n                var b=bubble1686(kind,!!newRequest,cached?'':loading);\n                if(cached){\n                    render1686(b,cached);\n                    prefetchAround1686(cached,dbv);\n                    return false;\n                }\n                request1686(kind,page,dbv).then(function(d){\n                    \/\/ Se nel frattempo la ditta e' cambiata, conserva la cache ma non mostra dati della vecchia ditta.\n                    if(db1686()!==dbv)return;\n                    render1686(b,d);\n                    prefetchAround1686(d,dbv);\n                }).catch(function(e){\n                    if(db1686()!==dbv)return;\n                    var m=(e&&e.name==='AbortError')?(isEn?'Catalog page timeout. Retry.':'Timeout pagina catalogo. Riprova.'):((e&&e.message)?e.message:(isEn?'Catalog loading error.':'Errore caricamento catalogo.'));\n                    if(b)b.innerHTML='<div style=\"color:#fecaca;font-weight:700\">\u26a0\ufe0f '+esc1686(m)+'<\/div><div style=\"margin-top:8px\"><button type=\"button\" class=\"ti-btn\" onclick=\"return window.tiCatalogShow1686(\\''+kind+'\\','+page+',false)\">'+(isEn?'Retry page':'Riprova pagina')+'<\/button><\/div>';\n                });\n                return false;\n            };\n\n            \/\/ Alias usati dai vari renderer storici: tutti convergono sulla cache 1686.\n            window.tiCatalogPage1676=function(kind,page){return window.tiCatalogShow1686(kind,page,false);};\n            window.tiOpenCatalogPage1676=function(kind,newRequest){return window.tiCatalogShow1686(kind,1,newRequest!==false);};\n            window.tiDirectCatalogPage1679=function(kind,page,newRequest){return window.tiCatalogShow1686(kind,page,newRequest);};\n            if(window.setOrderView&&!window.setOrderView.__ti1851){\n                var prevSetOrderView1851=window.setOrderView;\n                window.setOrderView=function(btn,view){\n                    var oldSize=pageSize1851(),r=prevSetOrderView1851.apply(this,arguments),newSize=pageSize1851();\n                    if(oldSize!==newSize){try{var wrap=btn&&btn.closest?btn.closest('.ti-order-wrap'):null,bub=wrap&&wrap.closest?wrap.closest('.ti-msg-ai'):null;if(!bub)bub=window.__tiCatalogBubble1676;var kind=bub?String(bub.getAttribute('data-ti-catalog-kind-1686')||'Prodotti'):'Prodotti';setTimeout(function(){window.tiCatalogShow1686(kind,1,false);},0);}catch(e){}}\n                    return r;\n                };\n                window.setOrderView.__ti1851=true;\n            }\n\n            function exactCatalog1686(v){\n                var n=String(v||'').toLowerCase();try{n=n.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'');}catch(e){}\n                n=n.replace(\/[^a-z0-9]+\/g,' ').trim();\n                if(\/^(prodotti|catalogo prodotti|elenco prodotti|(mostra|elenca|lista|visualizza|vedi) (tutti i )?prodotti( disponibili)?( in tabella ordine)?)$\/.test(n)||\/^(products|product catalog|product list|(show|list|display|view) (all )?(available )?products( in order table)?)$\/.test(n))return'Prodotti';\n                if(\/^(servizi|catalogo servizi|elenco servizi|(mostra|elenca|lista|visualizza|vedi) (tutti i )?servizi( disponibili)?( in tabella ordine)?)$\/.test(n)||\/^(services|service catalog|service list|(show|list|display|view) (all )?(available )?services( in order table)?)$\/.test(n))return'Servizi';\n                return'';\n            }\n            \/\/ Intercettazione su window\/capture: precede i vecchi listener document\/capture del catalogo.\n            window.addEventListener('click',function(ev){\n                var t=ev.target&&ev.target.closest?ev.target.closest('#ti-products-btn,#ti-services-btn,#ti-send'):null;if(!t)return;\n                var kind='';\n                if(t.id==='ti-products-btn')kind='Prodotti';\n                else if(t.id==='ti-services-btn')kind='Servizi';\n                else{var m=document.getElementById('ti-msg');kind=exactCatalog1686(m?m.value:'');}\n                if(!kind)return;\n                ev.preventDefault();ev.stopPropagation();if(ev.stopImmediatePropagation)ev.stopImmediatePropagation();\n                if(t.id==='ti-send'){var msg=document.getElementById('ti-msg');if(msg)msg.value='';}\n                try{window.lastUploadedFile=null;if(window.lastFileContext){window.lastFileContext.active=false;window.lastFileContext.awaitingReuseChoice=false;window.lastFileContext.pendingReusePrompt='';}}catch(e){}\n                window.tiCatalogShow1686(kind,1,true);return false;\n            },true);\n\n            function scheduleFirstProducts1686(dbv){\n                dbv=String(dbv||db1686()||'');if(!dbv||dbv==='NEW_DB')return;\n                \/\/ 30.9.1687: una sola richiesta silenziosa. La cache\/pending deduplica gli accessi successivi.\n                if(window.__tiCatalogCache1686[key1686(dbv,'Prodotti',1)]||window.__tiCatalogPending1686[key1686(dbv,'Prodotti',1)])return;\n                setTimeout(function(){if(db1686()===dbv)prefetch1686('Prodotti',1,dbv);},550);\n            }\n            window.tiCatalogWarmFirstProducts1686=scheduleFirstProducts1686;\n            document.addEventListener('change',function(ev){\n                if(!ev||!ev.target||ev.target.id!=='ti-ditta')return;\n                var dbv=String(ev.target.value||'');\n                if(!dbv||dbv==='NEW_DB')return;\n                scheduleFirstProducts1686(dbv);\n            },true);\n            function initialWarm1686(){var dbv=db1686();if(dbv&&dbv!=='NEW_DB')scheduleFirstProducts1686(dbv);}\n            if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',initialWarm1686,{once:true});else setTimeout(initialWarm1686,0);\n            window.addEventListener('load',function(){setTimeout(initialWarm1686,350);},{once:true});\n        })();\n        \/\/ 30.9.1691: loader legacy 1684 rimosso; Prodotti\/Servizi usano esclusivamente tiCatalogShow1686.\n        if (window.ensureActivitiesButton) window.ensureActivitiesButton();\n        if(gE('ti-activities-btn')) gE('ti-activities-btn').onclick = window.tiOpenUserActivities;\n        if (window.updateActivitiesButtonVisibility) {\n            window.updateActivitiesButtonVisibility();\n            setTimeout(window.updateActivitiesButtonVisibility, 250);\n            setTimeout(window.updateActivitiesButtonVisibility, 900);\n        }\n        \n\n        window.invalidClarifyCount = 0;\n        window.clarifyWarnTimer = null;\n        window.clarifyCloseTimer = null;\n        window.pendingClarifyClosure = false;\n        window.cancelClarifyClosure = function() {\n            if (window.clarifyWarnTimer) { clearTimeout(window.clarifyWarnTimer); window.clarifyWarnTimer = null; }\n            if (window.clarifyCloseTimer) { clearTimeout(window.clarifyCloseTimer); window.clarifyCloseTimer = null; }\n            window.pendingClarifyClosure = false;\n        };\n        window.resetClarifyCount = function() {\n            window.invalidClarifyCount = 0;\n            window.cancelClarifyClosure();\n        };\n        window.startFreshChatAfterClarifyLimit = function() {\n            window.cancelClarifyClosure();\n            window.invalidClarifyCount = 0;\n            if (window.doLogout) {\n                window.doLogout(true);\n                return;\n            }\n            const fd = new FormData(); fd.append('ti_action', 'ti_ai_reset_flow');\n            fetch(window.tiUrl, {method:'POST', body:fd}).finally(() => {\n                if(dom.chat) dom.chat.innerHTML = '';\n                window.updCtx();\n            });\n        };\n        window.scheduleClarifyClosure = function() {\n            window.cancelClarifyClosure();\n            window.pendingClarifyClosure = true;\n            window.clarifyWarnTimer = setTimeout(() => {\n                if (!window.pendingClarifyClosure) return;\n                const warn = \"Se non ricevo istruzioni chiuder\u00f2 la sessione a breve.\";\n                window.addMsg('ai', warn, warn);\n                window.speakText(\"Se non ricevo istruzioni chiuder\u00f2 la sessione a breve.\");\n                window.clarifyCloseTimer = setTimeout(() => {\n                    if (!window.pendingClarifyClosure) return;\n                    window.startFreshChatAfterClarifyLimit();\n                }, 60000);\n            }, 60000);\n        };\n        \/\/ 30.9.1743: retry automatico della chat principale solo per errori tecnici\/transitori.\n        window.__tiMainChatRetry1743 = window.__tiMainChatRetry1743 || {key:'', failures:0};\n        window.tiMainChatRetryKey1743 = function(db, prompt) {\n            return String(db || '') + '|' + String(prompt || '').replace(\/\\u00a0\/g,' ').trim();\n        };\n        window.tiMainChatRetryIsTransient1743 = function(message) {\n            const m = String(message || '').replace(\/\\u00a0\/g,' ').trim().toLowerCase();\n            if (\/attivit[a\u00e0] ai.*(?:0|esaur)|quota.*(?:0|esaur)|api key.*(?:mancante|non disponibile|non configurata)|accesso negato|non autorizzat|permess|sessione.*(?:non valida|scaduta)|seleziona prima una ditta\/.test(m)) return false;\n            if (!m) return true;\n            return \/http\\s*5\\d\\d|errore server\\s*5\\d\\d|internal server|timeout|timed out|failed to fetch|network|errore rete|temporane|temporar|servizio.*non disponibile|risposta.*(?:vuota|non disponibile)|errore richiesta ai|errore ai|sconosciuto\/.test(m);\n        };\n        window.tiMainChatRetryReset1743 = function(db, prompt) {\n            const key = window.tiMainChatRetryKey1743(db, prompt);\n            const st = window.__tiMainChatRetry1743 || {key:'', failures:0};\n            if (!key || st.key === key) window.__tiMainChatRetry1743 = {key:'', failures:0};\n        };\n        window.tiMainChatScheduleRetry1743 = function(message, db) {\n            if (!window.tiMainChatRetryIsTransient1743(message)) return false;\n            const prompt = String(window.lastUserPromptText || '').replace(\/\\u00a0\/g,' ').trim();\n            if (!prompt) return false;\n            const key = window.tiMainChatRetryKey1743(db, prompt);\n            let st = window.__tiMainChatRetry1743 || {key:'', failures:0};\n            if (st.key !== key) st = {key:key, failures:0};\n            st.failures = Number(st.failures || 0) + 1;\n            window.__tiMainChatRetry1743 = st;\n            if (st.failures >= 3) return false;\n            const msgEl = document.getElementById('ti-msg');\n            const sendBtn = document.getElementById('ti-send');\n            if (!msgEl || !sendBtn) return false;\n            window.__tiSuppressNextUserBubble1743 = true;\n            window.__tiMainChatAutoRetryAttempt1743 = st.failures + 1;\n            msgEl.value = prompt;\n            setTimeout(function(){\n                try { sendBtn.dispatchEvent(new MouseEvent('click',{bubbles:true,cancelable:true,view:window})); }\n                catch(e){ try { sendBtn.click(); } catch(_e){} }\n            }, 650);\n            return true;\n        };\n\n        window.handleClarifyReply = function(replyText, rawSource, noVoice) {\n            const safeReply = String(replyText || 'Non sono riuscito a completare la richiesta. Riprova oppure aggiungi un dettaglio utile.').trim();\n            window.invalidClarifyCount = (window.invalidClarifyCount || 0) + 1;\n            window.addMsg('ai', window.formatTable(safeReply), rawSource || safeReply);\n            if (!noVoice) window.speakText(safeReply);\n            if (window.invalidClarifyCount >= 3) {\n                window.scheduleClarifyClosure();\n            }\n            return false;\n        };\n\n        \/\/ 30.9.1989: Copia testo copia la chat utile e non avvia piu il vecchio flusso email.\n        if(gE('ti-copy')) gE('ti-copy').onclick = () => {\n            if(!dom.chat) return false;\n            const txt1989 = (typeof window.tiGetUsefulChatCopy1989 === 'function') ? window.tiGetUsefulChatCopy1989() : String(dom.chat.innerText || '').trim();\n            if(!txt1989) return false;\n            try { if(navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(txt1989); } catch(e1989) {}\n            return false;\n        };\n\n        window.tiSsUserChatText543 = function() {\n            const el = document.getElementById('ti-msg');\n            return el ? String(el.value || '').replace(\/\u00a0\/g, ' ').trim() : '';\n        };\n        window.tiSsIsBareYesNoOk543 = function(v) {\n            const t = String(v || '').replace(\/\u00a0\/g, ' ').trim().toLowerCase();\n            return \/^(ok|si|s\u00ec|s|yes|y|no|n|annulla|annullo|x)$\/i.test(t);\n        };\n        window.tiSsBlockEmptyUserChat543 = function(source) {\n            window.tiQuickReplyText = '';\n            window.tiHiddenSendText = '';\n            window.tiHiddenSendLabel = '';\n            const el = document.getElementById('ti-msg');\n            if (el) el.value = '';\n            return false;\n        };\n\n        \/\/ 30.9.1542: NO\/X\/ANNULLA interrompe anche la richiesta principale ancora in attesa.\n        \/\/ L AbortController chiude la fetch nel browser; il catch distingue l annullamento manuale\n        \/\/ dal timeout reale e non mostra popup di errore.\n        window.tiCancelActiveMainChat1542 = function(label) {\n            const active = window.tiMainChatActiveRequest1542;\n            if (!active || active.done || active.manualCancel || !active.controller || typeof active.controller.abort !== 'function') return false;\n            active.manualCancel = true;\n            try { if (active.timer) clearTimeout(active.timer); } catch(e) {}\n            try { active.controller.abort(); } catch(e) {}\n            try { if (active.bubble && active.bubble.parentNode) active.bubble.parentNode.removeChild(active.bubble); } catch(e) {}\n            const shown = String(label || 'NO').replace(\/\u00a0\/g, ' ').trim() || 'NO';\n            try { if (window.addMsg) window.addMsg('user', shown); } catch(e) {}\n            try { if (window.addMsg) window.addMsg('ai', 'Processo di chat in corso annullato.'); } catch(e) {}\n            try { if (window.speechSynthesis) window.speechSynthesis.cancel(); } catch(e) {}\n            return true;\n        };\n\n        window.tiSendQuickReply = function(text, label) {\n            try { if (window.tiStopCurrentChatSpeech1901) window.tiStopCurrentChatSpeech1901('tasto rapido'); else if (window.speechSynthesis) window.speechSynthesis.cancel(); } catch(eAudio1901) {}\n            const msgEl = document.getElementById('ti-msg');\n            const sendBtn = document.getElementById('ti-send');\n            const quickText = String(text || '').replace(\/\u00a0\/g, ' ').trim();\n            if (!quickText || !sendBtn) return false;\n            \/\/ 30.9.1542: le risposte rapide SI\/NO sono messaggi validi anche quando il campo testo e vuoto.\n            window.tiQuickReplyText = quickText;\n            if (label && String(label).trim() && String(label).trim() !== quickText) {\n                window.tiHiddenSendText = quickText;\n                window.tiHiddenSendLabel = String(label).trim();\n                window.tiQuickReplyText = '';\n            }\n            if (msgEl) msgEl.value = '';\n            try { sendBtn.dispatchEvent(new MouseEvent('click', {bubbles:true, cancelable:true, view:window})); }\n            catch(e) { try { sendBtn.click(); } catch(_e) {} }\n            return false;\n        };\n        if (!window.tiBookingNavDelegated210) {\n            window.tiBookingNavDelegated210 = true;\n            document.addEventListener('click', function(ev) {\n                const btn = ev.target && ev.target.closest ? ev.target.closest('[data-ti-booking-nav]') : null;\n                if (!btn) return;\n                ev.preventDefault();\n                ev.stopPropagation();\n                const cmd = String(btn.getAttribute('data-ti-booking-nav') || '').trim();\n                if (cmd && window.tiSendQuickReply) window.tiSendQuickReply(cmd, btn.textContent || cmd);\n            }, true);\n        }\n\n        if(dom.send) dom.send.onclick = () => {\n            if(!dom.msg) return;\n            const rawInput = (dom.msg.value || '');\n            const typedInput543 = String(rawInput || '').replace(\/\u00a0\/g, ' ').trim();\n            let txt = typedInput543;\n            if (window.tiQuickReplyText) {\n                txt = String(window.tiQuickReplyText || '').replace(\/\u00a0\/g, ' ').trim();\n                window.tiQuickReplyText = '';\n            }\n            let displayTxt = txt;\n            let textToSend = txt;\n            if (window.tiHiddenSendText) {\n                textToSend = String(window.tiHiddenSendText || '').replace(\/\u00a0\/g, ' ').trim();\n                displayTxt = String(window.tiHiddenSendLabel || 'Conferma ordine').replace(\/\u00a0\/g, ' ').trim();\n                window.tiHiddenSendText = '';\n                window.tiHiddenSendLabel = '';\n            }\n            if(!textToSend) { if (window.tiSsBlockEmptyUserChat543) window.tiSsBlockEmptyUserChat543('send-empty'); return false; }\n            \/\/ 30.9.1901: quando l utente prosegue la conversazione\/processo, interrompi sempre\n            \/\/ l audio della risposta corrente. Non cambia lo stato Audio: la risposta successiva\n            \/\/ potra essere letta normalmente da speakText.\n            try { if (window.tiStopCurrentChatSpeech1901) window.tiStopCurrentChatSpeech1901('nuovo messaggio utente'); else if (window.speechSynthesis) window.speechSynthesis.cancel(); } catch(eAudioSend1901) {}\n            \/\/ 30.9.1542: OK, SI, NO, X e ANNULLA inviati dal tasto INVIA o dai pulsanti rapidi\n            \/\/ sono risposte conversazionali valide. Si ignora soltanto il testo realmente vuoto.\n            const isCancelCommand1542 = \/^(no|n|x|annulla|annullo|cancella|stop|cancel)$\/i.test(String(textToSend || '').trim());\n            \/\/ 30.9.1900: una risposta SI\/OK o NO\/X a una domanda operativa dell ordine\n            \/\/ deve avere priorita sul dialogo di inattivita. In particolare per i guest un\n            \/\/ vecchio idleAwaitingChoice poteva consumare SI mostrando \"Ok, continuo la chat\"\n            \/\/ e impedire al server di ricevere la scelta di prenotazione\/consegna.\n            let tiOrderOperationalReply1900 = false;\n            try {\n                const bubbles1900 = dom.chat ? Array.from(dom.chat.querySelectorAll('.ti-bubble.ai')).slice(-6).reverse() : [];\n                const orderPrompt1900 = bubbles1900.find(function(n1900){\n                    const t1900 = String((n1900 && (n1900.innerText || n1900.textContent)) || '').replace(\/\\u00a0\/g,' ').replace(\/\\s+\/g,' ').toLowerCase();\n                    return \/vuoi prenotarlo per la consegna|vuoi prenotare per la consegna il prodotto|prodotto.{0,260}non risulta disponibile.{0,260}vuoi prenotarlo|termini di consegna prima del pagamento|prima data utile proposta|indica una data e ora desiderate|data e ora preferite\/.test(t1900);\n                });\n                const choice1900 = \/^(si|s\u00ec|s|ok|no|n|x)$\/i.test(String(textToSend || '').trim());\n                tiOrderOperationalReply1900 = !!(orderPrompt1900 && choice1900);\n                if (tiOrderOperationalReply1900) {\n                    window.idleAwaitingChoice = false;\n                    window.idleForceClosing = false;\n                    window.idleLastUserActivityAt = Date.now();\n                    window.idleFirstWarningAt = 0;\n                    window.idleFinalWarningAt = 0;\n                    window.idleCloseCheckAt = 0;\n                    try { if (window.clearIdleTimers) window.clearIdleTimers(); } catch(e1900a) {}\n                    try { if (window.scheduleIdleFirstWarning) window.scheduleIdleFirstWarning(); } catch(e1900b) {}\n                    try { console.info('[Shop-Service] ordine 1900: risposta ordine prioritaria rispetto a inattivita',{text:String(textToSend||'')}); } catch(e1900c) {}\n                }\n            } catch(e1900) {}\n            if (isCancelCommand1542 && !tiOrderOperationalReply1900 && window.tiCancelActiveMainChat1542 && window.tiCancelActiveMainChat1542(displayTxt || textToSend)) {\n                if (dom.msg) dom.msg.value = '';\n                return false;\n            }\n            if (window.cancelClarifyClosure) window.cancelClarifyClosure();\n            if (window.idleAwaitingChoice && !tiOrderOperationalReply1900) {\n                const idleAns = String(textToSend || '').trim().toLowerCase();\n                if (isCancelCommand1542) {\n                    window.idleAwaitingChoice = false;\n                    window.idleForceClosing = true;\n                    if (window.clearIdleTimers) window.clearIdleTimers();\n                    window.addMsg('user', displayTxt || textToSend);\n                    dom.msg.value = '';\n                    if(window.addMsg) window.addMsg('ai', '\ud83d\udd12 Sessione chiusa su richiesta. Avvio una nuova chat.');\n                    window.speakText('Sessione chiusa su richiesta. Avvio una nuova chat.');\n                    if (window.forceSessionCloseNow) window.forceSessionCloseNow(); else if (window.doLogout) window.doLogout(true);\n                    return;\n                }\n                if (\/^(si|s\u00ec|s|yes|ok|continua|continuare)$\/i.test(idleAns)) {\n                    window.idleAwaitingChoice = false;\n                    window.idleForceClosing = false;\n                    window.idleLastUserActivityAt = Date.now();\n                    window.idleFirstWarningAt = 0;\n                    window.idleFinalWarningAt = 0;\n                    window.idleCloseCheckAt = 0;\n                    if (window.clearIdleTimers) window.clearIdleTimers();\n                    if (window.scheduleIdleFirstWarning) window.scheduleIdleFirstWarning();\n                    window.addMsg('user', displayTxt || textToSend);\n                    dom.msg.value = '';\n                    if(window.addMsg) window.addMsg('ai', 'Ok, continuo la chat.');\n                    window.speakText('Ok, continuo la chat.');\n                    return;\n                }\n            }\n            const dittaInput = gE('ti-ditta'); const dbVal = dittaInput ? dittaInput.value : '';\n            const lastImportBubble = dom.chat ? Array.from(dom.chat.querySelectorAll('.ti-bubble.ai')).reverse().find(b => b.querySelector('.ti-import-map-select, .ti-import-group-target, #ti-import-price-formula, .ti-import-pdf-image-link')) : null;\n            if (lastImportBubble && \/^(ok|conferma|procedi|salva|importa|vai)$\/i.test(txt)) {\n                const mapping = window.collectImportMappingFromUI(lastImportBubble) || window.tiConfigImportLastMapping || {};\n                window.addMsg('user', txt); dom.msg.value='';\n                let b = document.createElement('div'); b.className='ti-bubble ai'; b.innerHTML = window.getUserWaitingHtml('Importazione in corso...', 'Sto salvando i dati confermati nel database.'); if(dom.chat){ dom.chat.appendChild(b); dom.chat.scrollTop=dom.chat.scrollHeight; }\n                const fdImp = new FormData();\n                fdImp.append('action','ti_ai_config_action');\n                fdImp.append('ti_action','ti_ai_config_action');\n                fdImp.append('db', dbVal);\n                fdImp.append('mode', 'confirm_import_preview');\n                fdImp.append('prompt', txt);\n                if (window.tiConfigImportToken) fdImp.append('import_token', window.tiConfigImportToken);\n                fdImp.append('mapping_json', JSON.stringify(mapping));\n                window.postFormDataJsonSafe(window.tiUrl, fdImp, {tiNoLongProcessSignal:true, cache:'no-store'}).then(res=>{\n                    if (b) b.remove();\n                    if (res.success) {\n                        const rawReply = res.data.reply || '';\n                        const noVoice = !!(res.data && res.data.no_voice) || rawReply.includes('[NO_VOICE]');\n                        const cleanReply = rawReply.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                        window.addMsg('ai', cleanReply);\n                        window.restoreLastUserPromptText();\n                        if (!noVoice) window.speakText(cleanReply);\n                        if (res.data.needs_reload) { window.tiConfigImportToken = null; setTimeout(() => { location.reload(); }, 1200); }\n                    } else {\n                        window.addMsg('ai', '\u26a0\ufe0f Errore import: ' + ((res.data && res.data.message) ? res.data.message : 'Sconosciuto'));\n                    }\n                }).catch((e)=>{ if (b) b.remove(); window.addMsg('ai', '\u26a0\ufe0f ' + e.message); });\n                return;\n            }\n\n            if(window.pendingEmail === 'manual') {\n                if (isCancelCommand1542) {\n                    window.pendingEmail = false;\n                    window.addMsg('user', displayTxt || textToSend);\n                    dom.msg.value = '';\n                    window.addMsg('ai', 'Invio email annullato.');\n                    if (window.speakText) window.speakText('Invio email annullato.');\n                    return;\n                }\n                window.addMsg('ai', \"\u23f3 Invio email in corso...\");\n                const fd=new FormData(); fd.append('ti_action','ti_ai_send_email'); fd.append('db',dbVal); fd.append('email',txt); fd.append('history',dom.chat.innerText);\n                fetch(window.tiUrl,{method:'POST',body:fd}).then(r=>r.json()).then(res=>{ window.addMsg('ai',res.data.reply, res.data.reply); window.speakText(res.data.reply); });\n                window.pendingEmail=false; dom.msg.value=''; return;\n            }\n\n            const txtNorm = txt.toLowerCase();\n            \/\/ 30.9.1904: una richiesta naturale come \"cosa c'e?\" dopo una foto deve continuare\n            \/\/ a riferirsi alla foto senza chiedere all utente di scrivere \"analizza file\".\n            const tiIsVisualFile1904 = function(url1904) {\n                let u1904 = String(url1904 || '');\n                try { u1904 = decodeURIComponent(u1904); } catch(e1904) {}\n                return \/\\.(?:jpe?g|png|webp)(?:$|[?#&])\/i.test(u1904) || \/(?:[?&](?:file|filename|name)=)[^&#]*\\.(?:jpe?g|png|webp)(?:&|$)\/i.test(u1904);\n            };\n            const tiIsVisualFollowup1904 = function(q1904) {\n                let n1904 = String(q1904 || '').toLowerCase();\n                try { n1904 = n1904.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,''); } catch(e1904b) {}\n                n1904 = n1904.replace(\/[^a-z0-9]+\/g,' ').replace(\/\\s+\/g,' ').trim();\n                if (!n1904) return false;\n                return \/^(?:cosa c e|cosa ce|che c e|che ce|cosa vedi|che cosa vedi|cosa mostra|che cosa mostra|cosa contiene|che cosa contiene|che cos e|cos e|cosa rappresenta|che cosa rappresenta|descrivi|descrivila|analizza|analizzala|leggi|leggila|riconosci|riconoscila)(?:\\b|$)\/.test(n1904)\n                    || \/\\b(?:questa foto|questa immagine|nella foto|nell immagine|foto allegata|immagine allegata|schema in foto|schema fotografato)\\b\/.test(n1904);\n            };\n            let tiVisualFileRequest1904 = false;\n            if (window.lastFileContext && window.lastFileContext.awaitingReuseChoice) {\n                if (\/^(si|s\u00ec|yes|ok|ripeti|riutilizza)$\/i.test(txt)) {\n                    txt = window.lastFileContext.pendingReusePrompt || window.lastFileContext.lastActionPrompt || 'Importa di nuovo i dati dal file caricato.';\n                    window.lastUploadedFile = window.lastFileContext.url;\n                    window.lastFileContext.awaitingReuseChoice = false;\n                    window.lastFileContext.pendingReusePrompt = '';\n                    dom.msg.value = txt;\n                } else if (\/^(no|annulla|x)$\/i.test(txt)) {\n                    window.clearLastFileContext();\n                    window.addMsg('ai', \"Ok, non riutilizzo l'ultimo file. Puoi caricarne un altro quando vuoi.\");\n                    dom.msg.value='';\n                    return;\n                }\n            } else if (!window.lastUploadedFile && window.lastFileContext && window.lastFileContext.url) {\n                const isImportFollowup = window.isImportFollowupText(txtNorm);\n                const asksAboutLastFile = \/(import|reimport|file caricat|ultimo file|riutilizz|ripeti l'ultima azione|ultima azione)\/i.test(txtNorm);\n                if (window.lastFileContext.active && tiIsVisualFile1904(window.lastFileContext.url) && tiIsVisualFollowup1904(displayTxt || textToSend)) {\n                    window.lastUploadedFile = window.lastFileContext.url;\n                    tiVisualFileRequest1904 = true;\n                } else if (asksAboutLastFile && !\/^(1|2|3|ok|si|s\u00ec|yes|no|x|annulla)$\/i.test(txt)) {\n                    if (window.askReuseLastFile(txt)) { dom.msg.value=''; return; }\n                } else if (window.lastFileContext.active && isImportFollowup) {\n                    window.lastUploadedFile = window.lastFileContext.url;\n                }\n            }\n\n            const asksCatalogOnly = \/\\b(mostra|vedi|tabella|ordine|prodotti|servizi|catalogo|elenco|lista)\\b\/i.test(txt) && !\/\\b(file|allegat|pdf|document|referto|immagine|listino)\\b\/i.test(txt);\n            if (asksCatalogOnly) {\n                window.lastUploadedFile = null;\n                if (window.lastFileContext) {\n                    window.lastFileContext.active = false;\n                    window.lastFileContext.awaitingReuseChoice = false;\n                    window.lastFileContext.pendingReusePrompt = '';\n                }\n            }\n            if(window.lastUploadedFile) {\n                tiVisualFileRequest1904 = tiVisualFileRequest1904 || (tiIsVisualFile1904(window.lastUploadedFile) && tiIsVisualFollowup1904(displayTxt || textToSend));\n                textToSend += ` [FILE_ALLEGATO: ${window.lastUploadedFile}]`;\n                window.lastUploadedFile = null;\n            }\n            window.lastUserPromptText = displayTxt;\n            const tiSuppressUser1743 = !!window.__tiSuppressNextUserBubble1743;\n            window.__tiSuppressNextUserBubble1743 = false;\n            if (!tiSuppressUser1743) window.addMsg('user',displayTxt);\n            dom.msg.value='';\n            \n            let chatHist = []; const bubbles = dom.chat.querySelectorAll('.ti-bubble'); let startIdx = Math.max(0, bubbles.length - 8); \n            for(let i=startIdx; i<bubbles.length; i++) {\n                let b = bubbles[i]; let role = b.classList.contains('user') ? 'user' : 'assistant'; let clone = b.cloneNode(true);\n                let tw = clone.querySelector('.ti-table-wrap'); if(tw) tw.remove(); \n                let msgTxt = clone.innerText.trim(); if(msgTxt && !msgTxt.includes(\"Fammi pensare...\")) { chatHist.push({role: role, content: msgTxt}); }\n            }\n\n            const fd=new FormData(); fd.append('ti_action','ti_ai_chat_start'); fd.append('text',textToSend); fd.append('db',dbVal); fd.append('history_context', JSON.stringify(chatHist)); fd.append('ti_direct_db', (window.tiForced ? '1' : '0'));\n            if (tiVisualFileRequest1904) {\n                fd.append('analyze_file_only','1');\n                fd.append('reset_flow_for_file_analysis','1');\n                fd.append('photo_orientation_1904','1');\n                try { console.info('[Shop-Service] foto 1904: richiesta visuale diretta',{text:String(displayTxt||''),db:String(dbVal||'')}); } catch(e1904c) {}\n            }\n\n            const tiInfoWait196 = window.tiIsInfoVerificationRequest ? window.tiIsInfoVerificationRequest(textToSend) : false;\n            const tiOrderConfirm1583 = \/^Conferma ordine$\/i.test(String(displayTxt || '').trim()) || \/RIEPILOGO ORDINE\/i.test(String(textToSend || ''));\n            let tiOrderCtx1706 = null;\n            if (tiOrderConfirm1583) {\n                const inherited1706 = window.__tiOrderRetryContext1706;\n                const current1706 = window.tiOrderRecoveryCurrent1706;\n                if (inherited1706 && inherited1706.db === dbVal && inherited1706.text === textToSend) tiOrderCtx1706 = inherited1706;\n                else if (current1706 && current1706.db === dbVal && current1706.text === textToSend) tiOrderCtx1706 = current1706;\n                else if (window.__tiOrderFixedRequestId1757) tiOrderCtx1706 = {db:dbVal, user:String(window.tiUser||'guest'), requestId:String(window.__tiOrderFixedRequestId1757), text:textToSend, retryCount:0, failedCount:0, phase:'order_confirm'};\n                else tiOrderCtx1706 = {db:dbVal, user:String(window.tiUser||'guest'), requestId:'ord-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2,10), text:textToSend, retryCount:0, failedCount:0, phase:'order_confirm'};\n                tiOrderCtx1706.phase='order_confirm'; window.__tiOrderRetryContext1706 = null; window.tiOrderRecoveryCurrent1706 = tiOrderCtx1706; window.tiOrderRecoverySave1706(tiOrderCtx1706);\n                fd.append('order_request_id_1706', tiOrderCtx1706.requestId);\n                try { fd.append('order_items_meta_1865', JSON.stringify(window.tiOrderItemsMeta1865 ? window.tiOrderItemsMeta1865() : [])); } catch(e1865) { fd.append('order_items_meta_1865','[]'); }\n                if (window.__tiOrderRevision1757) fd.append('order_revision_1757','1');\n                window.__tiOrderRevision1757=false;\n            }\n            const tiCatalogText1584 = String(displayTxt || textToSend || '').trim().toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/[^a-z0-9]+\/g, ' ').trim();\n            const tiProductsCommand1584 = \/^(prodotti|catalogo prodotti|elenco prodotti|(mostra|elenca|lista|visualizza|vedi) (tutti i )?prodotti( disponibili)?( in tabella ordine)?)$\/.test(tiCatalogText1584) || \/^(products|product catalog|product list|(show|list|display|view) (all )?(available )?products( in order table)?)$\/.test(tiCatalogText1584);\n            const tiServicesCommand1584 = \/^(servizi|catalogo servizi|elenco servizi|(mostra|elenca|lista|visualizza|vedi) (tutti i )?servizi( disponibili)?( in tabella ordine)?)$\/.test(tiCatalogText1584) || \/^(services|service catalog|service list|(show|list|display|view) (all )?(available )?services( in order table)?)$\/.test(tiCatalogText1584);\n            const tiCatalogCommand1584 = tiProductsCommand1584 || tiServicesCommand1584;\n            \/\/ 30.9.1679: catalogo esplicito sempre sul loader paginato inizializzato in wp_head.\n            \/\/ Nessuna dipendenza da wp_footer e nessuna ricaduta nel vecchio ti_ai_chat_start.\n            if (tiCatalogCommand1584) {\n                const tiCatalogKind1679 = tiProductsCommand1584 ? 'Prodotti' : 'Servizi';\n                window.__tiCatalogBubble1676 = null;\n                if (typeof window.tiCatalogShow1686 === 'function') {\n                    window.tiCatalogShow1686(tiCatalogKind1679, 1, false);\n                } else if (typeof window.tiDirectCatalogPage1679 === 'function') {\n                    window.tiDirectCatalogPage1679(tiCatalogKind1679, 1, false);\n                } else if (typeof window.tiOpenCatalogPage1676 === 'function') {\n                    window.tiOpenCatalogPage1676(tiCatalogKind1679, false);\n                } else {\n                    window.addMsg('ai', '\u26a0\ufe0f Errore interno caricatore catalogo.');\n                }\n                return;\n            }\n            \/\/ 30.9.1750\/1987: una sola bolla di attesa per richiesta, aggiornata progressivamente.\n            try {\n                const oldWait1750 = window.__tiMainChatWaitBubble1750;\n                if (oldWait1750 && oldWait1750.parentNode) oldWait1750.parentNode.removeChild(oldWait1750);\n            } catch(eWait1750a) {}\n            const tiRouteNorm1987 = String(displayTxt || textToSend || '').toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/[^a-z0-9]+\/g,' ').trim();\n            const tiCompanyRouteWait1987 = \/\\b(mi serve|mi servono|cerco|sto cercando|vorrei|voglio|ho bisogno|dove trovo|dove posso trovare|lavandino|lavello|rubinetto|sifone|caldaia|idraulico|francobollo|farmaco|auto|automobile|computer|software|pizza|mensola|ferramenta)\\b\/.test(tiRouteNorm1987);\n            let b = document.createElement('div');\n            b.className = 'ti-bubble ai' + (tiInfoWait196 ? ' ti-info-wait-bubble' : '');\n            b.setAttribute('data-ti-main-chat-wait-1750','1');\n            window.__tiMainChatWaitBubble1750 = b;\n            b.innerHTML = tiOrderConfirm1583\n                ? window.getUserWaitingHtml('Conferma ordine in corso...', 'Definisco i termini dell ordine e l eventuale appuntamento prima del pagamento.')\n                : (tiVisualFileRequest1904\n                    ? window.getUserWaitingHtml('Analisi foto in corso...', 'Sto analizzando la foto e verifico Prodotti e Servizi coerenti della ditta.')\n                    : (tiCatalogCommand1584\n                    ? window.getUserWaitingHtml(tiProductsCommand1584 ? 'Caricamento prodotti...' : 'Caricamento servizi...', 'Leggo direttamente il catalogo della ditta e preparo le voci disponibili.')\n                    : (tiInfoWait196\n                        ? window.getInfoVerificationWaitingHtml('\u23f3 Verifica informazioni in corso...', 'Sto elaborando la richiesta e verifico le informazioni disponibili.')\n                        : (tiCompanyRouteWait1987\n                            ? window.getUserWaitingHtml('\ud83d\udd0e Verifico la richiesta...', 'Controllo se \u00e8 coerente con la ditta corrente e, se necessario, cerco una ditta pi\u00f9 adatta.')\n                            : window.getUserWaitingHtml('Fammi pensare...', 'Sto elaborando la richiesta e verifico i dati disponibili.')))));\n            if(dom.chat){ dom.chat.appendChild(b); dom.chat.scrollTop=dom.chat.scrollHeight; }\n            var tiWaitFeedbackTimers1987 = [], tiProgressFeedbackBubbles1987 = [];\n            function tiAppendWaitFeedback1987(title1987, detail1987){\n                try{\n                    if(!dom.chat || !b || !b.parentNode)return;\n                    var pb1987=document.createElement('div');\n                    pb1987.className='ti-bubble ai ti-main-progress-1987';\n                    pb1987.setAttribute('data-ti-main-chat-progress-1987','1');\n                    pb1987.innerHTML = window.getUserWaitingHtml ? window.getUserWaitingHtml(title1987, detail1987) : '<strong>'+title1987+'<\/strong><div>'+detail1987+'<\/div>';\n                    dom.chat.appendChild(pb1987);tiProgressFeedbackBubbles1987.push(pb1987);dom.chat.scrollTop=dom.chat.scrollHeight;\n                }catch(e1987){}\n            }\n            function tiClearWaitFeedback1987(){\n                try{tiWaitFeedbackTimers1987.forEach(function(t){clearTimeout(t);});}catch(e1987){}\n                tiWaitFeedbackTimers1987=[];\n                try{tiProgressFeedbackBubbles1987.forEach(function(x){if(x&&x.parentNode)x.parentNode.removeChild(x);});}catch(e1987b){}\n                tiProgressFeedbackBubbles1987=[];\n            }\n            \/\/ 30.9.1987: se l elaborazione dura, la chatbot invia messaggi successivi visibili senza sostituire\n            \/\/ il precedente, cos\u00ec l utente vede che il processo continua realmente. I messaggi di stato vengono\n            \/\/ rimossi quando arriva il risultato finale per non lasciare in chat indicazioni ormai superate.\n            tiWaitFeedbackTimers1987.push(setTimeout(function(){\n                if(tiVisualFileRequest1904)tiAppendWaitFeedback1987('\u23f3 Analisi foto in corso ...','Sto completando l analisi e il confronto con i dati della ditta ...');\n                else if(tiCompanyRouteWait1987)tiAppendWaitFeedback1987('\u23f3 Verifica coerenza in corso ...','Sto confrontando la richiesta con l attivit\u00e0 della ditta corrente.');\n                else tiAppendWaitFeedback1987('\u23f3 Processo in corso ...','Sto verificando i dati disponibili. Ancora qualche istante.');\n            },10000));\n            tiWaitFeedbackTimers1987.push(setTimeout(function(){\n                if(tiVisualFileRequest1904)tiAppendWaitFeedback1987('\u23f3 Analisi ancora in corso ...','Sto completando la verifica del contenuto.');\n                else if(tiCompanyRouteWait1987)tiAppendWaitFeedback1987('\ud83d\udd0e Ricerca ditta in corso ...','Se la ditta corrente non \u00e8 coerente, sto confrontando le alternative disponibili.');\n                else tiAppendWaitFeedback1987('\u23f3 Processo ancora in corso ...','La richiesta \u00e8 attiva: continuo la verifica e ti aggiorno qui.');\n            },25000));\n            tiWaitFeedbackTimers1987.push(setTimeout(function(){\n                if(tiCompanyRouteWait1987)tiAppendWaitFeedback1987('\ud83d\udd0e Sto ancora cercando ...','La ricerca non \u00e8 ferma: sto completando il confronto tra le ditte coerenti.');\n                else tiAppendWaitFeedback1987('\u23f3 Elaborazione ancora attiva ...','Il processo continua. Ti mostrer\u00f2 il risultato appena disponibile.');\n            },50000));\n            var tiLongWaitTimer1585 = tiWaitFeedbackTimers1987[0];\n            \/\/ 30.9.1314: aggiunto timeout (in precedenza assente) alla richiesta principale della chat - un\n            \/\/ caso reale ha mostrato nessuna risposta per diversi minuti senza alcun avviso all'utente. 120s\n            \/\/ restano per Conferma ordine\/pagamento; dalla 1745 le richieste AI generali possono arrivare a 420s\n            \/\/ per database molto grandi, mentre il contesto ridotto dovrebbe normalmente chiuderle molto prima.\n            var t0_1314 = performance.now();\n            try {\n                if (window.tiLogAiRequest1315) {\n                    var isStdPrompt1315 = !!window.__tiNextAiRequestIsStandard1315;\n                    window.tiLogAiRequest1315(window.__tiNextAiRequestSource1315 || 'Click su Invia (chat principale)', isStdPrompt1315 ? 'Prompt standard (da codice)' : textToSend);\n                }\n                window.__tiNextAiRequestSource1315 = '';\n                window.__tiNextAiRequestIsStandard1315 = false;\n            } catch(eLog1315a){}\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1314: richiesta ti_ai_chat_start AVVIATA'); } catch(eL314a){}\n            var ctl1314 = null, timer1314 = null;\n            var tiRequestTimeout1706 = tiOrderConfirm1583 ? 120000 : (tiVisualFileRequest1904 ? 120000 : 420000); \/\/ 30.9.1904: foto visuale dedicata non deve restare appesa al timeout dei database grandi\n            try { if (window.AbortController) { ctl1314 = new AbortController(); timer1314 = setTimeout(function(){ try { ctl1314.abort(); } catch(e){} }, tiRequestTimeout1706); } } catch(e) { ctl1314 = null; }\n            var tiMainChatRequestId1542 = 'chat-' + Date.now() + '-' + Math.random().toString(36).slice(2);\n            var tiMainChatDb1657 = String(dbVal || '');\n            var tiMainChatEpoch1657 = Number(window.tiCompanyEpoch1657 || 0);\n            window.tiMainChatActiveRequest1542 = {id:tiMainChatRequestId1542, controller:ctl1314, timer:timer1314, bubble:b, manualCancel:false, done:false, db1657:tiMainChatDb1657, epoch1657:tiMainChatEpoch1657};\n            fetch(window.tiUrl,{method:'POST',body:fd, signal: ctl1314 ? ctl1314.signal : undefined}).then(r=> {\n                try { clearTimeout(timer1314); } catch(e){}\n                try { if (window.log1088) window.log1088('DIAGNOSTICA 1314: risposta ricevuta dopo ' + Math.round(performance.now()-t0_1314) + 'ms, status=' + r.status); } catch(eL314b){}\n                if (r.status === 413) throw new Error(\"File\/Testo troppo grande per i limiti del server (Errore 413).\"); if (!r.ok) throw new Error(\"Errore Server \" + r.status); return r.json();\n            }).then(res=>{\n                try { tiClearWaitFeedback1987(); } catch(e1585a) {}\n                const currentDb1657 = gE('ti-ditta') ? String(gE('ti-ditta').value || '') : '';\n                const switched1657 = (Number(window.tiCompanyEpoch1657 || 0) !== tiMainChatEpoch1657)\n                    || (window.tiNormalizeDb1657 && window.tiNormalizeDb1657(currentDb1657) !== window.tiNormalizeDb1657(tiMainChatDb1657));\n                if (switched1657) {\n                    try { if (b && b.parentNode) b.remove(); } catch(e1657) {}\n                    const stale1657 = window.tiMainChatActiveRequest1542;\n                    if (stale1657 && stale1657.id === tiMainChatRequestId1542) { stale1657.done = true; window.tiMainChatActiveRequest1542 = null; }\n                    return;\n                }\n                var active1542 = window.tiMainChatActiveRequest1542;\n                if (active1542 && active1542.id === tiMainChatRequestId1542) {\n                    active1542.done = true;\n                    window.tiMainChatActiveRequest1542 = null;\n                    if (active1542.manualCancel) { if (b) b.remove(); return; }\n                }\n                if(b) b.remove();\n                try { if (window.__tiMainChatWaitBubble1750 === b) window.__tiMainChatWaitBubble1750 = null; } catch(eWait1750b) {}\n                if(res.success) {\n                    try { if (window.tiMainChatRetryReset1743) window.tiMainChatRetryReset1743(dbVal, displayTxt); } catch(e1743ok) {}\n                    if (res.data && res.data.order_lock_1757 && window.tiOrderReviewLock1757) { try { window.tiOrderReviewLock1757(); } catch(e1757lock) {} }\n                    if (res.data && res.data.order_close_1759 && window.tiOrderReviewClose1759) { try { window.tiOrderReviewClose1759(); } catch(e1759close) {} }\n                    if (tiOrderConfirm1583 && res.data && res.data.order_pending_1706) {\n                        if (window.tiOrderRecoveryPersistent1706) window.tiOrderRecoveryPersistent1706(tiOrderCtx1706, res.data.reply || 'Il primo tentativo risulta ancora in elaborazione sul server.', performance.now()-t0_1314);\n                        window.restoreLastUserPromptText();\n                        return;\n                    }\n                    \/\/ 30.9.1606: la conferma server ha terminato il compito del riepilogo esterno.\n                    \/\/ Pagamento\/prenotazione\/fattura proseguono nella chat senza lasciare 'Ordine confermato' fisso.\n                    if (tiOrderConfirm1583) { try { if(window.tiOrderRecoveryClear1706) window.tiOrderRecoveryClear1706(tiOrderCtx1706); } catch(e1706clear) {} }\n                    if (tiOrderConfirm1583 && window.hideOrderConfirmPanel) {\n                        try { window.hideOrderConfirmPanel(true); } catch(e1606) {}\n                        try { window.tiHiddenSendText = ''; window.tiHiddenSendLabel = ''; } catch(e1606b) {}\n                    }\n                    if(res.data && res.data.empty_ignored) { window.restoreLastUserPromptText && window.restoreLastUserPromptText(); return; }\n                    if(res.data.clear_chat && dom.chat) dom.chat.innerHTML = '';\n                    if(res.data.needs_reload) {\n                        window.clearLastFileContext();\n                        setTimeout(() => { location.reload(); }, 2500);\n                    }\n                    if(res.data && res.data.admin_popup) {\n                        if (window.showPrivilegedCommunicationPopup) window.showPrivilegedCommunicationPopup(res.data.admin_popup, 'Comunicazione amministrativa', {text: (window.tiPlainTextFromHtml ? window.tiPlainTextFromHtml(res.data.admin_popup) : String(res.data.admin_popup || ''))});\n                        else if (window.tiAlert) window.tiAlert(res.data.admin_popup);\n                    }\n                    \n                    if(res.data.reply && res.data.reply.includes('[UPDATE_DB]')) {\n                        let aiReplyText = res.data.reply;\n                        let start = aiReplyText.indexOf('[UPDATE_DB]') + 11;\n                        let end = aiReplyText.indexOf('[\/UPDATE_DB]');\n                        if (end !== -1 && end > start) {\n                            let jsonStr = aiReplyText.substring(start, end);\n                            let cleanJson = jsonStr.replace(\/```json|```\/ig, '').trim();\n                            try {\n                                let newTabelle = JSON.parse(cleanJson);\n                                if (typeof newTabelle === 'object') {\n                                    let currentData = window.currentDbData || { Tabelle: {} };\n                                    \n                                    let incTabs = newTabelle.Tabelle || newTabelle;\n                                    for(let t in incTabs) {\n                                        if (!currentData.Tabelle[t]) currentData.Tabelle[t] = [];\n                                        currentData.Tabelle[t] = currentData.Tabelle[t].concat(incTabs[t]);\n                                    }\n\n                                    const fdUpdate = new FormData();\n                                    fdUpdate.append('ti_action', 'ti_ai_chat_start');\n                                    fdUpdate.append('db', dbVal);\n                                    fdUpdate.append('text', \"FULL_DB_UPDATE_B64|||\" + utoa(JSON.stringify(currentData)));\n                                    fdUpdate.append('db_version', (currentData && currentData.__db_version) ? currentData.__db_version : '');\n                                    fetch(window.tiUrl, {method:'POST', body:window.ensureAjaxActionField(fdUpdate)}).then(ru=>ru.json()).then(du=>{\n                                        if(du.success) {\n                                            if (currentData && du.data && du.data.db_version) currentData.__db_version = du.data.db_version;\n                                            window.clearLastFileContext();\n                                            let userFeedback = aiReplyText.substring(0, aiReplyText.indexOf('[UPDATE_DB]')) + \"\\n\\n\u2705 **Database aggiornato con successo dall'AI!**\";\n                                            window.addMsg('ai', userFeedback); window.speakText(\"Database aggiornato con successo.\");\n                                            setTimeout(() => { location.reload(); }, 2500);\n                                        }\n                                    });\n                                    return;\n                                }\n                            } catch(e) {\n                                window.addMsg('ai', aiReplyText.substring(0, aiReplyText.indexOf('[UPDATE_DB]')) + \"\\n\\n\u26a0\ufe0f L'AI ha provato a modificare i dati ma ha generato un formato JSON non valido.\"); return;\n                            }\n                        }\n                    }\n                    \n                    if(res.data.reply && res.data.reply.includes('[RESET_SESSION]')) {\n                        let cln = res.data.reply.replace('[RESET_SESSION]', '').trim();\n                        if(cln) { window.addMsg('ai', cln, cln); window.speakText(cln); }\n                        setTimeout(() => { window.doLogout(true); }, 2500); return;\n                    }\n                    \n                    const switchDb1989 = String((res.data && res.data.switch_db_1989) || '').trim();\n                    if(switchDb1989 || (res.data.reply && res.data.reply.includes('[SWITCH_DB:'))) {\n                        let match = res.data.reply ? res.data.reply.match(\/\\[SWITCH_DB:(.*?)\\]\/) : null;\n                        let targetDb = switchDb1989 || String((match && match[1]) || '').trim();\n                        if(targetDb) {\n                            let visibleSwitch1987 = String(res.data.reply || '').replace(\/\\[SWITCH_DB:.*?\\]\/g,'').replace(\/(?:[|\\[)documento associato(?:]|\\])\/gi,'').trim();\n                            if(visibleSwitch1987) window.addMsg('ai', visibleSwitch1987, visibleSwitch1987);\n                            let carry1987 = String((res.data && res.data.company_search_query_1987) || '').trim();\n                            if(carry1987 && !(res.data && res.data.company_switch_from_file_1919)) {\n                                try { if(window.tiStoreCompanySearchCarry1903) window.tiStoreCompanySearchCarry1903(carry1987,targetDb); } catch(eCarry1987) {}\n                                try { window.__tiPendingCompanySearchText1903 = carry1987; } catch(eCarry1987b) {}\n                            }\n                            window.addMsg('ai', carry1987\n                                ? '\u23f3 Sto aprendo la ditta selezionata. La tua richiesta verr\u00e0 ripresa automaticamente nella nuova chatbot.'\n                                : '\u23f3 Ti sto trasferendo alla ditta selezionata...');\n                            \/\/ 30.9.1988: non basta scrivere ti_saved_db e ricaricare. Per utenti autenticati\n                            \/\/ il bootstrap privilegia la sessione server e quindi tornerebbe alla ditta precedente.\n                            \/\/ Usa il percorso unico di selezione: imposta il select, genera change e lascia al\n                            \/\/ listener 1344\/1927 l aggiornamento del cookie\/sessione prima del reload.\n                            if (typeof window.tiChooseCompany1922 === 'function') {\n                                setTimeout(function(){\n                                    Promise.resolve(window.tiChooseCompany1922(targetDb, visibleSwitch1987 || targetDb, false)).catch(function(){\n                                        try { localStorage.setItem('ti_saved_db', targetDb); location.href = window.tiUrl; } catch(e1988sw) { try { location.reload(); } catch(ignore1988sw) {} }\n                                    });\n                                }, 350);\n                                return;\n                            }\n                            \/\/ Compatibilita estrema: se lo script unificato non e disponibile, prova almeno\n                            \/\/ a passare dal select\/change prima del vecchio reload locale.\n                            setTimeout(function(){\n                                try {\n                                    var sel1988 = document.getElementById('ti-ditta');\n                                    if (sel1988) {\n                                        var wanted1988 = String(targetDb || '').replace(\/\\\\\/g,'\/').split('\/').pop().toLowerCase();\n                                        var opt1988 = Array.from(sel1988.options || []).find(function(o){return String(o.value || '').replace(\/\\\\\/g,'\/').split('\/').pop().toLowerCase() === wanted1988;});\n                                        if (!opt1988) { opt1988=document.createElement('option'); opt1988.value=targetDb; opt1988.textContent=targetDb; sel1988.appendChild(opt1988); }\n                                        sel1988.value=opt1988.value; window.tiCurrentSelectedDb=opt1988.value; localStorage.setItem('ti_saved_db',opt1988.value);\n                                        sel1988.dispatchEvent(new Event('change',{bubbles:true}));\n                                        return;\n                                    }\n                                } catch(e1988select) {}\n                                try { localStorage.setItem('ti_saved_db', targetDb); location.href = window.tiUrl; } catch(e1988fallback) { try { location.reload(); } catch(ignore1988fallback) {} }\n                            }, 350); return;\n                        }\n                    }\n\n                    if(res.data.trigger_email) {\n                        const fd2=new FormData(); fd2.append('ti_action','ti_ai_send_email'); fd2.append('db',dbVal); fd2.append('email',res.data.trigger_email); fd2.append('subject',res.data.trigger_subj); \n                        fd2.append('history',res.data.trigger_hist); if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd2); if(res.data.admin_copy) fd2.append('admin_copy','1');\n                        if (res.data.trigger_cc) fd2.append('cc_email', res.data.trigger_cc);\n                        if (res.data.trigger_admin_to_email) fd2.append('admin_to_email', res.data.trigger_admin_to_email);\n                        if (res.data.trigger_admin_to_tel) fd2.append('admin_to_tel', res.data.trigger_admin_to_tel);\n                        if (res.data.trigger_send_email) fd2.append('send_email_opt', res.data.trigger_send_email);\n                        if (res.data.trigger_send_sms) fd2.append('send_sms_opt', res.data.trigger_send_sms);\n                        fetch(window.tiUrl,{method:'POST',body:window.ensureAjaxActionField(fd2)}).then(rr=>{ if(!rr.ok) throw new Error('Errore Server ' + rr.status); return rr.json(); }).then(rr=>{\n                            if (rr && rr.data && rr.data.admin_popup) {\n                                if (window.showPrivilegedCommunicationPopup) window.showPrivilegedCommunicationPopup(rr.data.admin_popup, 'Fattura elettronica', {text: (window.tiPlainTextFromHtml ? window.tiPlainTextFromHtml(rr.data.admin_popup) : String(rr.data.admin_popup || ''))});\n                                else if (window.tiAlert) window.tiAlert(rr.data.admin_popup);\n                            }\n                            const replyMsg = (rr && rr.data && rr.data.reply) ? rr.data.reply : ((rr && rr.success) ? 'Operazione completata.' : 'Errore invio notifica');\n                            const shownNotifyPopup = window.maybeShowPrivilegedCommunicationPopup ? window.maybeShowPrivilegedCommunicationPopup(replyMsg, 'Comunicazione notifica') : false;\n                            if (shownNotifyPopup) window.addMsg('ai', window.tiPopupPlaceholderMessage ? window.tiPopupPlaceholderMessage('Comunicazione notifica') : 'Comunicazione aperta in popup.');\n                            else { window.addMsg('ai', replyMsg, replyMsg); window.speakText(replyMsg); }\n                            window.restoreLastUserPromptText();\n                            if(res.data.force_refresh) { const fd3=new FormData(); fd3.append('ti_action','ti_ai_chat_start'); fd3.append('text',''); fd3.append('force_refresh_flow','1'); fd3.append('db',dbVal); fetch(window.tiUrl,{method:'POST',body:window.ensureAjaxActionField(fd3)}).then(r3=>{ if(!r3.ok) throw new Error('Errore Server ' + r3.status); return r3.json(); }).then(r3=>{ const r3msg = (r3 && r3.data && r3.data.reply) ? r3.data.reply : ''; if (r3msg) { window.addMsg('ai', r3msg, r3msg); window.speakText(r3msg); } }); }\n                        }).catch((err)=>{ const em = (err && err.message) ? err.message : 'Errore invio notifica'; window.addMsg('ai', '\u26a0\ufe0f ' + em); window.restoreLastUserPromptText(); });\n                    } else {\n                        const rawReply = res.data.reply || '';\n                        const noVoice = !!(res.data && res.data.no_voice) || rawReply.includes('[NO_VOICE]');\n                        let cleanReply = rawReply.replace(\/\\[NO_VOICE\\]\/g, '').trim();\n                        if (\/mi dispiace|non ho capito bene|scriv(?:i|ila) in un altro modo|aggiung(?:i|ere) un dettaglio in piu\/i.test(cleanReply)) {\n                            cleanReply = 'La verifica non ha prodotto una corrispondenza sufficiente. Aggiungi un dettaglio utile su ci\u00f2 che stai cercando.';\n                        }\n                        if (res.data && res.data.clarify_request) {\n                            if (tiCatalogCommand1584) {\n                                window.resetClarifyCount();\n                                var catalogFallback1584 = cleanReply;\n                                if (!catalogFallback1584 || \/mi dispiace|non ho capito|scriverla in un altro modo\/i.test(catalogFallback1584)) {\n                                    catalogFallback1584 = tiProductsCommand1584 ? 'Non sono riuscito a completare il caricamento dei prodotti. Riprova.' : 'Non sono riuscito a completare il caricamento dei servizi. Riprova.';\n                                }\n                                window.addMsg('ai', window.formatTable(catalogFallback1584), catalogFallback1584);\n                                if (!noVoice) window.speakText(catalogFallback1584);\n                            } else {\n                                window.handleClarifyReply(cleanReply, cleanReply, noVoice);\n                                if (res.data.reset_chat) {\n                                    setTimeout(() => { window.startFreshChatAfterClarifyLimit(); }, 1200);\n                                }\n                            }\n                        } else {\n                            window.resetClarifyCount();\n                            const formattedReply = window.formatTable(cleanReply);\n                            \/\/ 30.9.1894: le domande operative ordine\/prenotazione devono restare nella chat anche\n                            \/\/ per Amministratore\/Configuratore. Se finiscono nel popup privilegiato, i pulsanti\n                            \/\/ OK\/SI e X\/NO non hanno piu il contesto conversazionale e vengono disabilitati.\n                            const quickOrderReply1894 = !!(res.data && (res.data.quick_reply_required_1894 || res.data.order_terms_pending_1757))\n                                || \/vuoi\\s+prenotarlo\\s+per\\s+la\\s+consegna|vuoi\\s+prenotare\\s+per\\s+la\\s+consegna\\s+il\\s+prodotto|si\\s+o\\s+tasto\\s+ok\\s*\\\/\\s*no\\s+o\\s+tasto\\s+x|prima\\s+data\\s+utile[^.]{0,220}(?:si\\s*\\\/\\s*ok|ok\\s*\\\/\\s*si)\/i.test(cleanReply);\n                            const forceChatReply = !!(res.data && (res.data.force_chat || res.data.no_admin_popup || res.data.activity_chat)) || quickOrderReply1894;\n                            const shownPrivPopup = forceChatReply ? false : (window.maybeShowPrivilegedCommunicationPopup ? window.maybeShowPrivilegedCommunicationPopup(formattedReply, 'Comunicazione \/ report') : false);\n                            if (shownPrivPopup) {\n                                window.addMsg('ai', window.tiPopupPlaceholderMessage ? window.tiPopupPlaceholderMessage('Comunicazione \/ report') : 'Comunicazione\/report aperto in popup.');\n                            } else {\n                                \/\/ 30.9.1855: il fast-path di ricerca nome catalogo usa direttamente i dati strutturati.\n                                \/\/ Evita che una singola voce (es. Aspirina) venga persa\/coperta dal parser formatTable.\n                                if (res.data && \/^direct_catalog_18\\d+$\/.test(String(res.data.fast_path||'')) && Array.isArray(res.data.items_1855) && res.data.items_1855.length && window.tiBuildStructuredCatalog1855) {\n                                    var directHtml1855 = window.tiBuildStructuredCatalog1855({items_1855:res.data.items_1855,kind:'Prodotti'});\n                                    var directBubble1855 = window.addMsg('ai', directHtml1855 || formattedReply, cleanReply);\n                                    var normalize1855 = function(){\n                                        var b1855 = directBubble1855 && directBubble1855.nodeType===1 ? directBubble1855 : null;\n                                        if(!b1855){try{var c1855=document.getElementById('ti-chat-box')||document.getElementById('ti-chat');var a1855=c1855?c1855.querySelectorAll('.ti-bubble.ai'):[];b1855=a1855&&a1855.length?a1855[a1855.length-1]:null;}catch(e){}}\n                                        if(window.tiNormalizeCatalogBubble1855)window.tiNormalizeCatalogBubble1855(b1855);\n                                    };\n                                    normalize1855();setTimeout(normalize1855,40);setTimeout(normalize1855,180);setTimeout(normalize1855,500);setTimeout(normalize1855,1200);\n                                    try{console.info('[Shop-Service] catalogo 1859: fast-path strutturato visibile',{items:res.data.items_1855.length});}catch(e){}\n                                } else {\n                                    window.addMsg('ai', formattedReply, cleanReply);\n                                }\n                                if (quickOrderReply1894) {\n                                    try {\n                                        \/\/ 30.9.1900: il prompt operativo ordine sostituisce qualsiasi\n                                        \/\/ precedente richiesta di continuazione sessione per inattivita.\n                                        window.idleAwaitingChoice = false;\n                                        window.idleForceClosing = false;\n                                        window.idleLastUserActivityAt = Date.now();\n                                        window.idleFirstWarningAt = 0;\n                                        window.idleFinalWarningAt = 0;\n                                        window.idleCloseCheckAt = 0;\n                                        try { if (window.clearIdleTimers) window.clearIdleTimers(); } catch(e1900d) {}\n                                        try { if (window.scheduleIdleFirstWarning) window.scheduleIdleFirstWarning(); } catch(e1900e) {}\n                                        window.__tiQuickReplyRequired1627 = true;\n                                        ['ti-ok','ti-x'].forEach(function(id1894){\n                                            var qb1894=document.getElementById(id1894); if(!qb1894)return;\n                                            qb1894.disabled=false; qb1894.removeAttribute('disabled'); qb1894.setAttribute('aria-disabled','false');\n                                            qb1894.style.setProperty('pointer-events','auto','important'); qb1894.style.setProperty('opacity','1','important'); qb1894.style.setProperty('cursor','pointer','important');\n                                        });\n                                        [0,80,250,700].forEach(function(ms1894){setTimeout(function(){try{if(window.tiUpdateQuickReplyButtons1627)window.tiUpdateQuickReplyButtons1627();if(window.tiEnableBookingQuickReplies1766)window.tiEnableBookingQuickReplies1766();}catch(e1894){}},ms1894);});\n                                        console.info('[Shop-Service] ordine 1894: OK\/SI e X\/NO abilitati per scelta prenotazione');\n                                    } catch(e1894) {}\n                                }\n                                if (!noVoice) window.speakText(cleanReply);\n                            }\n                        }\n                        window.restoreLastUserPromptText();\n                    }\n                } else {\n                    if (tiOrderConfirm1583) {\n                        const orderErr1706 = (res && res.data && res.data.message) ? res.data.message : 'Errore durante la conferma ordine o l avvio del pagamento.';\n                        if (window.tiHandleOrderPaymentFailure1706) window.tiHandleOrderPaymentFailure1706(tiOrderCtx1706, orderErr1706, performance.now()-t0_1314);\n                        window.restoreLastUserPromptText();\n                        return;\n                    }\n                    const roleNow = String(window.tiRole || '').toLowerCase();\n                    const isPrivilegedNow = (!!window.tiUser && window.tiUser === 'SSGlobalAdmin') || \/amministratore|configuratore|responsabile|globale\/.test(roleNow);\n                    if (isPrivilegedNow) {\n                        const errHtml = \"\u26a0\ufe0f Errore AI: \" + (res.data && res.data.message ? res.data.message : 'Sconosciuto');\n                        const shownErrPopup = window.showPrivilegedCommunicationPopup ? window.showPrivilegedCommunicationPopup(errHtml, 'Errore \/ comunicazione', {text: errHtml}) : false;\n                        window.addMsg('ai', shownErrPopup && window.tiPopupPlaceholderMessage ? window.tiPopupPlaceholderMessage('Errore \/ comunicazione') : errHtml);\n                    } else {\n                        if (tiOrderConfirm1583) {\n                            window.addMsg('ai', '\u26a0\ufe0f Errore durante la conferma ordine o l\u2019avvio del pagamento. L\u2019ordine non viene reinviato automaticamente: riprova una sola volta oppure verifica la configurazione del metodo di pagamento.');\n                        } else if (tiCatalogCommand1584) {\n                            window.resetClarifyCount();\n                            window.addMsg('ai', tiProductsCommand1584 ? '\u26a0\ufe0f Non sono riuscito a caricare l\u2019elenco prodotti. Riprova.' : '\u26a0\ufe0f Non sono riuscito a caricare l\u2019elenco servizi. Riprova.');\n                        } else {\n                            const tiFailMsg1743 = (res && res.data && (res.data.message || res.data.msg || res.data.reply)) ? String(res.data.message || res.data.msg || res.data.reply) : 'Errore richiesta AI';\n                            if (window.tiMainChatScheduleRetry1743 && window.tiMainChatScheduleRetry1743(tiFailMsg1743, dbVal)) return;\n                            window.handleClarifyReply(\"Non sono riuscito a completare la richiesta. Riprova oppure aggiungi un dettaglio utile.\", '', true);\n                        }\n                    }\n                    window.restoreLastUserPromptText();\n                }\n            }).catch((e)=>{ \n                try { clearTimeout(timer1314); } catch(eClr314){}\n                try { tiClearWaitFeedback1987(); } catch(eLong1706){}\n                var active1542 = window.tiMainChatActiveRequest1542;\n                var manualCancel1542 = !!(active1542 && active1542.id === tiMainChatRequestId1542 && active1542.manualCancel);\n                if (active1542 && active1542.id === tiMainChatRequestId1542) { active1542.done = true; window.tiMainChatActiveRequest1542 = null; }\n                if (manualCancel1542) { try { if (b) b.remove(); if (window.__tiMainChatWaitBubble1750 === b) window.__tiMainChatWaitBubble1750 = null; } catch(eRm1542){} return; }\n                try { if (window.log1088) window.log1088('DIAGNOSTICA 1314: richiesta FALLITA dopo ' + Math.round(performance.now()-t0_1314) + 'ms - nome=' + (e && e.name) + ' messaggio=' + (e && e.message)); } catch(eL314c){}\n                const msg = (e && e.name === 'AbortError') ? (tiOrderConfirm1583 ? 'Il server non ha risposto entro 2 minuti durante la conferma ordine.' : 'Il server non ha risposto entro il tempo previsto.') : ((e && e.message) ? e.message : 'Errore richiesta AI');\n                \/\/ 30.9.1750: la bolla del tentativo concluso non deve restare in chat prima del retry.\n                try { if (b && b.parentNode) b.remove(); } catch(eWait1750c) {}\n                try { if (window.__tiMainChatWaitBubble1750 === b) window.__tiMainChatWaitBubble1750 = null; } catch(eWait1750d) {}\n                if (tiOrderConfirm1583) {\n                    try { if (b && b.parentNode) b.remove(); } catch(eB1706){}\n                    try { if (window.hideProgressPopup) window.hideProgressPopup(false); } catch(eP1706){}\n                    if (window.tiHandleOrderPaymentFailure1706) window.tiHandleOrderPaymentFailure1706(tiOrderCtx1706, msg, performance.now()-t0_1314);\n                    window.restoreLastUserPromptText();\n                    return;\n                }\n                const roleNow = String(window.tiRole || '').toLowerCase();\n                const isPrivilegedNow = (!!window.tiUser && window.tiUser === 'SSGlobalAdmin') || \/amministratore|configuratore|responsabile|globale\/.test(roleNow);\n                window.hideProgressPopup(false, 'Errore richiesta AI', {notifyUser:isPrivilegedNow, errorMessage:msg}); \n                if (isPrivilegedNow) {\n                    const errHtml = \"\u26a0\ufe0f \" + msg;\n                    const shownErrPopup = window.showPrivilegedCommunicationPopup ? window.showPrivilegedCommunicationPopup(errHtml, 'Errore \/ comunicazione', {text: errHtml}) : false;\n                    if (!shownErrPopup && window.tiAlert && \/API Key|documenti AI|formato|500\/i.test(msg)) window.tiAlert(msg);\n                    window.addMsg('ai', shownErrPopup && window.tiPopupPlaceholderMessage ? window.tiPopupPlaceholderMessage('Errore \/ comunicazione') : errHtml);\n                } else {\n                    if (tiOrderConfirm1583) {\n                        window.addMsg('ai', '\u26a0\ufe0f ' + msg + '<br>Il processo ordine\/pagamento non \u00e8 stato completato.');\n                    } else if (tiCatalogCommand1584) {\n                        window.resetClarifyCount();\n                        window.addMsg('ai', (tiProductsCommand1584 ? '\u26a0\ufe0f Non sono riuscito a caricare l\u2019elenco prodotti. ' : '\u26a0\ufe0f Non sono riuscito a caricare l\u2019elenco servizi. ') + msg);\n                    } else {\n                        if (window.tiMainChatScheduleRetry1743 && window.tiMainChatScheduleRetry1743(msg, dbVal)) return;\n                        window.handleClarifyReply(\"Non sono riuscito a completare la richiesta. Riprova oppure aggiungi un dettaglio utile.\", '', true);\n                    }\n                }\n                window.restoreLastUserPromptText(); \n            });\n        };\n\n        \/\/ 30.9.1542: i due tasti sono risposte AI esplicite e non dipendono dal contenuto del textarea.\n        if(gE('ti-ok')) { gE('ti-ok').onclick=()=>{ if(dom.msg) dom.msg.value=''; if(window.tiSendQuickReply) return window.tiSendQuickReply('SI', 'SI'); window.tiQuickReplyText = 'SI'; if(dom.send) dom.send.click(); return false; }; }\n        if(gE('ti-x')) { gE('ti-x').onclick=()=>{ if(dom.msg) dom.msg.value=''; if(window.tiSendQuickReply) return window.tiSendQuickReply('NO', 'NO'); window.tiQuickReplyText = 'NO'; if(dom.send) dom.send.click(); return false; }; }\n        if(window.placeMainHelpButtonRight) window.placeMainHelpButtonRight();\n        if(gE('ti-help-btn')) { gE('ti-help-btn').onclick = () => window.openHelpModal(); }\n        if(gE('ti-help-support-toggle')) { gE('ti-help-support-toggle').onclick = () => window.toggleSupportFeedbackBox(); }\n        if(gE('ti-support-send')) { gE('ti-support-send').onclick = () => window.sendSupportFeedback(); }\n        if(gE('ti-kbd-btn')) {\n            gE('ti-kbd-btn').onclick = () => { \n                const k = gE('ti-kbd-cnt'); \n                if(k && k.innerHTML === '') { \n                    [\"1234567890\", \"QWERTYUIOP\", \"ASDFGHJKL\", \"ZXCVBNM\", \"@_-.\u20ac?!+=\"].forEach(row => { \n                        const rDiv = document.createElement('div'); rDiv.className = 'ti-kbd-row'; \n                        row.split('').forEach(c=>{ const b=document.createElement('button'); b.type=\"button\"; b.innerText=c; b.onclick=()=>{ if(gE('ti-kbd-prev')) { gE('ti-kbd-prev').value+=c; } }; rDiv.appendChild(b); }); k.appendChild(rDiv); \n                    }); \n                } \n                if(gE('ti-kbd-prev')) { gE('ti-kbd-prev').value = ''; }\n                window.openModal('ti-kbd-ov'); \n            };\n        }\n\n        if(gE('ti-mic')) {\n            gE('ti-mic').onclick = () => {\n                const SR = window.SpeechRecognition || window.webkitSpeechRecognition; \n                if(!SR) return window.tiAlert(\"Il microfono non \u00e8 supportato dal browser in uso (usa Chrome, Edge o Safari).\");\n                const r = new SR(); r.lang = 'it-IT'; gE('ti-mic').style.background = '#b91c1c'; gE('ti-mic').style.color = '#fff';\n                r.onresult = e => { if(dom.msg) dom.msg.value = e.results[0][0].transcript; if(dom.send) dom.send.click(); };\n                r.onend = () => { gE('ti-mic').style.background = '#222'; gE('ti-mic').style.color = '#ccc'; }; \n                r.start(); \n                setTimeout(() => { r.stop(); gE('ti-mic').style.background = '#222'; gE('ti-mic').style.color = '#ccc'; }, 10000);\n            };\n        }\n    }); \n    (function(){\n        function tiInstallFixPersi181(){\n        try {\n            const byId = function(id){ return document.getElementById(id); };\n            const escapeSafe = function(v){\n                if (window.escapeHtml) return window.escapeHtml(String(v == null ? '' : v));\n                return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; });\n            };\n            const parseNumSafe = function(v){\n                if (v === null || v === undefined) return 0;\n                let s = String(v).trim();\n                if (!s) return 0;\n                s = s.replace(\/[\u20ac\\s]\/g, '');\n                if (s.indexOf(',') !== -1 && s.indexOf('.') !== -1) s = s.replace(\/\\.\/g, '').replace(',', '.');\n                else if (s.indexOf(',') !== -1) s = s.replace(',', '.');\n                const n = parseFloat(s.replace(\/[^0-9.\\-]\/g, ''));\n                return isNaN(n) ? 0 : n;\n            };\n            const fmtSafe = function(n){\n                const num = Math.round((parseFloat(n) || 0) * 100) \/ 100;\n                if (window.fmtNum) return window.fmtNum(num);\n                return num.toLocaleString('it-IT', {minimumFractionDigits:2, maximumFractionDigits:2});\n            };\n            const normKey = function(s){\n                return String(s || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/[^a-z0-9]\/g, '');\n            };\n            const realTableName = function(data, wanted, fallback){\n                const tables = data && data.Tabelle ? data.Tabelle : {};\n                const want = normKey(wanted);\n                const keys = Object.keys(tables || {});\n                for (let i=0;i<keys.length;i++) if (normKey(keys[i]) === want) return keys[i];\n                for (let i=0;i<keys.length;i++) if (normKey(keys[i]).indexOf(want) !== -1 || want.indexOf(normKey(keys[i])) !== -1) return keys[i];\n                return fallback || wanted;\n            };\n            const getField = function(row, names, fallback){\n                row = row || {};\n                const keys = Object.keys(row);\n                for (let i=0;i<names.length;i++) {\n                    const want = normKey(names[i]);\n                    for (let j=0;j<keys.length;j++) if (normKey(keys[j]) === want) return row[keys[j]];\n                }\n                return fallback;\n            };\n            const setField = function(row, names, value){\n                row = row || {};\n                const keys = Object.keys(row);\n                for (let i=0;i<names.length;i++) {\n                    const want = normKey(names[i]);\n                    for (let j=0;j<keys.length;j++) if (normKey(keys[j]) === want) { row[keys[j]] = value; return; }\n                }\n                row[names[0]] = value;\n            };\n            const marginAdjustedNet = function(costNet, marginText){\n                const cost = parseNumSafe(costNet);\n                let m = String(marginText || '').trim();\n                if (!m) return Math.max(0, cost);\n                const isPct = m.indexOf('%') !== -1;\n                m = m.replace(\/[%\u20ac\\s]\/g, '');\n                let sign = 1;\n                if (m.charAt(0) === '-') { sign = -1; m = m.slice(1); }\n                else if (m.charAt(0) === '+') { m = m.slice(1); }\n                const val = parseNumSafe(m);\n                const net = isPct ? (cost + (cost * sign * val \/ 100)) : (cost + sign * val);\n                return Math.max(0, net);\n            };\n            const saleGross = function(costNet, marginText, ivaText){\n                let iva = parseNumSafe(ivaText);\n                if (iva <= 0) iva = 22;\n                return Math.round(marginAdjustedNet(costNet, marginText) * (1 + iva \/ 100) * 100) \/ 100;\n            };\n            const todayParts = function(){\n                const d = new Date();\n                const dd = String(d.getDate()).padStart(2,'0');\n                const mm = String(d.getMonth()+1).padStart(2,'0');\n                const yyyy = d.getFullYear();\n                const hh = String(d.getHours()).padStart(2,'0');\n                const mi = String(d.getMinutes()).padStart(2,'0');\n                return {date: dd + '\/' + mm + '\/' + yyyy, time: hh + ':' + mi};\n            };\n            const base64Utf8 = function(str){\n                try { return btoa(unescape(encodeURIComponent(str))); }\n                catch(e) { return btoa(str); }\n            };\n            window.tiPurchaseCalcSaleGross = saleGross;\n            window.tiPurchaseMarginAdjustedNet = marginAdjustedNet;\n\n            window.purchaseGetCatalogItems = function() {\n                const data = window.currentDbData || {};\n                const tables = data && data.Tabelle ? data.Tabelle : {};\n                const out = [];\n                Object.keys(tables || {}).forEach(function(tn){\n                    if (!\/(prodott|serviz)\/i.test(tn)) return;\n                    const rows = Array.isArray(tables[tn]) ? tables[tn] : [];\n                    rows.forEach(function(r, idx){\n                        if (!r || typeof r !== 'object') return;\n                        const isServ = \/(serviz)\/i.test(tn);\n                        const name = String(getField(r, isServ ? ['Servizio','Descrizione','Nome','Titolo'] : ['Prodotto','Descrizione','Nome','Titolo'], '') || '').trim();\n                        if (!name) return;\n                        out.push({\n                            table: tn,\n                            index: idx,\n                            type: isServ ? 'S' : 'P',\n                            typeLabel: isServ ? 'servizio' : 'prodotto',\n                            name: name,\n                            desc: String(getField(r, ['Descrizione','Note','Nota'], '') || '').trim(),\n                            cost: parseNumSafe(getField(r, ['Costo','Costo_acquisto','Costo acquisizione'], 0)),\n                            sale: parseNumSafe(getField(r, ['Prezzo','Prezzo_vendita','Prezzo vendita'], 0)),\n                            iva: parseNumSafe(getField(r, ['IVA_VAT','IVA','Iva','VAT'], 22)) || 22\n                        });\n                    });\n                });\n                return out;\n            };\n\n            window.ensurePurchaseModal = function() {\n                let ov = byId('ti-purchase-ov');\n                if (ov && ov.dataset && ov.dataset.v181 === '1') return ov;\n                if (ov && ov.parentNode) ov.parentNode.removeChild(ov);\n                ov = document.createElement('div');\n                ov.id = 'ti-purchase-ov';\n                ov.className = 'ti-modal-overlay ti-ov ti-closable-ov';\n                ov.dataset.v181 = '1';\n                ov.style.display = 'none';\n                ov.style.zIndex = '2147482000';\n                ov.style.alignItems = 'center';\n                ov.style.justifyContent = 'center';\n                ov.innerHTML = `\n                    <div class=\"ti-modal ti-purchase-modal\" style=\"width:min(1460px,98vw);max-width:98vw;max-height:92vh;overflow:auto;background:#0f172a;color:#fff;border-radius:16px;padding:18px;box-shadow:0 18px 60px rgba(0,0,0,.45);margin:0 auto;\">\n                        <div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;\">\n                            <div>\n                                <h2 style=\"margin:0;font-size:22px;\">Acquisizioni<\/h2>\n                                <div style=\"font-size:14px;color:#cbd5e1;margin-top:4px;\">Inserisci o modifica le righe acquisizione. Il costo \u00e8 netto IVA; il prezzo vendita proposto include margine e IVA.<\/div>\n                            <\/div>\n                            <button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"window.closePurchaseManualFlow()\">X<\/button>\n                        <\/div>\n                        <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 14px 0;\">\n                            <button type=\"button\" class=\"ti-btn ti-ss-add-manual-row\" style=\"background:#22c55e;color:#052e16;font-weight:700;\" onclick=\"window.addPurchaseManualRow()\">+ Aggiungi riga manuale<\/button>\n                            <button type=\"button\" class=\"ti-btn\" style=\"background:#f59e0b;color:#111827;font-weight:700;\" onclick=\"window.pickPurchaseImportFile()\">Import file acquisizioni<\/button>\n                        <\/div>\n                        <div class=\"ti-purchase-table-wrap\" style=\"overflow:auto;border:1px solid #334155;border-radius:12px;\">\n                            <table id=\"ti-purchase-table\" style=\"width:100%;border-collapse:collapse;min-width:1060px;background:#020617;\">\n                                <thead>\n                                    <tr style=\"background:#1e293b;\">\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Prodotto o servizio<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Tipo<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Q.t\u00e0<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Costo netto<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Margine<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Prezzo vendita ivato<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">IVA %<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Note<\/th>\n                                        <th style=\"padding:8px;border-bottom:1px solid #334155;\">Azioni<\/th>\n                                    <\/tr>\n                                <\/thead>\n                                <tbody id=\"ti-purchase-body\"><\/tbody>\n                            <\/table>\n                        <\/div>\n                        <div id=\"ti-purchase-total\" style=\"margin-top:10px;text-align:right;font-weight:700;color:#bbf7d0;\"><\/div>\n                        <div style=\"display:flex;justify-content:center;gap:8px;margin-top:14px;flex-wrap:wrap;\">\n                            <button type=\"button\" class=\"ti-btn ti-btn-ok\" style=\"background:#22c55e;color:#052e16;font-weight:900;\" onclick=\"window.confirmPurchaseRows()\">Conferma righe acquisizione<\/button>\n                            <button type=\"button\" class=\"ti-btn btn-close\" onclick=\"window.closePurchaseManualFlow()\">Chiudi<\/button>\n                        <\/div>\n                    <\/div>`;\n                document.body.appendChild(ov);\n                return ov;\n            };\n\n            window.closePurchaseSearchPopover = function(){\n                const p = byId('ti-purchase-row-search-popover');\n                if (p && p.parentNode) p.parentNode.removeChild(p);\n            };\n            window.selectPurchaseCatalogItemForRow = function(item, row){\n                try {\n                    row = row || window.__tiPurchaseActiveRow;\n                    if (!item || !row) return;\n                    const name = row.querySelector('.ti-pur-name');\n                    const type = row.querySelector('.ti-pur-type');\n                    const cost = row.querySelector('.ti-pur-cost');\n                    const sale = row.querySelector('.ti-pur-sale');\n                    const iva = row.querySelector('.ti-pur-iva');\n                    const note = row.querySelector('.ti-pur-note');\n                    if (name) name.value = item.name || '';\n                    if (type) type.value = item.type || 'P';\n                    if (cost) cost.value = item.cost ? String(item.cost).replace('.', ',') : '';\n                    if (iva) iva.value = item.iva || '22';\n                    if (note && !note.value) note.value = item.desc || '';\n                    row.dataset.catalogTable = item.table || '';\n                    row.dataset.catalogIndex = String(item.index != null ? item.index : -1);\n                    row.dataset.targetType = item.typeLabel || (item.type === 'S' ? 'servizio' : 'prodotto');\n                    window.recalcPurchaseRow(row, true);\n                    if (sale && item.sale && !sale.value) sale.value = String(item.sale).replace('.', ',');\n                    window.closePurchaseSearchPopover();\n                    window.refreshPurchaseTotals();\n                } catch(e) {}\n            };\n            window.showPurchaseRowSearch = function(input){\n                try {\n                    if (!input) return;\n                    const row = input.closest('tr');\n                    window.__tiPurchaseActiveRow = row;\n                    const q = String(input.value || '').trim().toLowerCase();\n                    window.closePurchaseSearchPopover();\n                    if (q.length < 1) return;\n                    const items = window.purchaseGetCatalogItems().filter(function(it){\n                        return (String(it.name||'') + ' ' + String(it.desc||'') + ' ' + String(it.table||'')).toLowerCase().indexOf(q) !== -1;\n                    }).slice(0, 16);\n                    const pop = document.createElement('div');\n                    pop.id = 'ti-purchase-row-search-popover';\n                    pop.className = 'ti-purchase-row-search-popover';\n                    if (!items.length) {\n                        pop.innerHTML = '<div style=\"color:#fca5a5;font-size:11px;padding:7px;\">Nessun prodotto o servizio trovato nel database.<\/div>';\n                    } else {\n                        pop.innerHTML = items.map(function(it, idx){\n                            return '<button type=\"button\" class=\"ti-purchase-result-row\" data-idx=\"' + idx + '\"><b>' + escapeSafe(it.typeLabel) + ' - ' + escapeSafe(it.name) + '<\/b><small>' + escapeSafe(it.table) + ' \u00b7 costo ' + escapeSafe(fmtSafe(it.cost)) + ' \u00b7 prezzo ' + escapeSafe(fmtSafe(it.sale)) + ' \u00b7 IVA ' + escapeSafe(it.iva) + '%<\/small><\/button>';\n                        }).join('');\n                    }\n                    document.body.appendChild(pop);\n                    const rect = input.getBoundingClientRect();\n                    const margin = 8;\n                    const topBelow = rect.bottom + margin;\n                    const estimatedH = Math.min(320, Math.max(70, items.length * 48 + 18));\n                    const top = (topBelow + estimatedH > window.innerHeight && rect.top > estimatedH) ? Math.max(margin, rect.top - estimatedH - margin) : topBelow;\n                    pop.style.left = Math.max(margin, Math.min(rect.left, window.innerWidth - Math.min(520, Math.max(240, rect.width)) - margin)) + 'px';\n                    pop.style.top = top + 'px';\n                    pop.style.width = Math.min(520, Math.max(240, rect.width)) + 'px';\n                    pop.querySelectorAll('.ti-purchase-result-row').forEach(function(btn){\n                        const handler = function(ev){\n                            ev.preventDefault(); ev.stopPropagation();\n                            const idx = parseInt(btn.getAttribute('data-idx'), 10);\n                            window.selectPurchaseCatalogItemForRow(items[idx], row);\n                        };\n                        btn.addEventListener('mousedown', handler);\n                        btn.addEventListener('touchstart', handler, {passive:false});\n                        btn.addEventListener('click', handler);\n                    });\n                } catch(e) {}\n            };\n            if (!window.__tiPurchaseSearchCloseBound) {\n                document.addEventListener('pointerdown', function(ev){\n                    const p = byId('ti-purchase-row-search-popover');\n                    if (!p) return;\n                    if (p.contains(ev.target)) return;\n                    if (ev.target && ev.target.closest && ev.target.closest('.ti-pur-name')) return;\n                    window.closePurchaseSearchPopover();\n                }, true);\n                window.addEventListener('resize', function(){ window.closePurchaseSearchPopover(); }, {passive:true});\n                window.__tiPurchaseSearchCloseBound = true;\n            }\n\n            window.recalcPurchaseRow = function(row, force){\n                try {\n                    if (!row) return;\n                    const cost = row.querySelector('.ti-pur-cost');\n                    const margin = row.querySelector('.ti-pur-margin');\n                    const sale = row.querySelector('.ti-pur-sale');\n                    const iva = row.querySelector('.ti-pur-iva');\n                    if (!sale) return;\n                    const gross = saleGross(cost ? cost.value : 0, margin ? margin.value : '', iva ? iva.value : '22');\n                    if (force || document.activeElement !== sale) sale.value = gross ? String(gross).replace('.', ',') : '';\n                } catch(e) {}\n            };\n\n            window.addPurchaseManualRow = function(item) {\n                try {\n                    const ov = byId('ti-purchase-ov') || window.ensurePurchaseModal();\n                    const body = byId('ti-purchase-body');\n                    if (!body) return;\n                    if (ov) { ov.style.display = 'flex'; }\n                    const safe = item || {};\n                    const tr = document.createElement('tr');\n                    tr.className = 'ti-purchase-row';\n                    tr.dataset.catalogTable = safe.table || '';\n                    tr.dataset.catalogIndex = String(safe.index != null ? safe.index : -1);\n                    tr.dataset.targetType = safe.type === 'S' ? 'servizio' : 'prodotto';\n                    const iva = safe.iva || '22';\n                    const cost = safe.cost ? String(safe.cost).replace('.', ',') : '';\n                    const sale = safe.sale ? String(safe.sale).replace('.', ',') : '';\n                    tr.innerHTML = `\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-name ti-purchase-row-search\" value=\"${escapeSafe(safe.name || '')}\" placeholder=\"Cerca prodotto o servizio\" autocomplete=\"off\" style=\"width:100%;min-width:230px;box-sizing:border-box;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><select class=\"ti-pur-type\" style=\"width:76px;padding:8px;border-radius:8px;background:#0f172a;color:#fff;border:1px solid #334155;\"><option value=\"P\" ${safe.type === 'S' ? '' : 'selected'}>P<\/option><option value=\"S\" ${safe.type === 'S' ? 'selected' : ''}>S<\/option><\/select><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-qty\" value=\"${escapeSafe(safe.qty || '1')}\" inputmode=\"decimal\" style=\"width:72px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-cost\" value=\"${escapeSafe(cost)}\" inputmode=\"decimal\" style=\"width:100px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-margin\" value=\"${escapeSafe(safe.margin || '')}\" placeholder=\"+10%\" style=\"width:86px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-sale\" value=\"${escapeSafe(sale)}\" inputmode=\"decimal\" style=\"width:112px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-iva\" value=\"${escapeSafe(iva)}\" inputmode=\"decimal\" style=\"width:68px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-note\" value=\"${escapeSafe(safe.desc || '')}\" placeholder=\"Note\" style=\"width:100%;min-width:170px;box-sizing:border-box;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                        <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:center;\"><button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"this.closest('tr').remove();window.refreshPurchaseTotals();\">X<\/button><\/td>`;\n                    body.appendChild(tr);\n                    const name = tr.querySelector('.ti-pur-name');\n                    if (name) {\n                        name.addEventListener('input', function(){ window.showPurchaseRowSearch(name); });\n                        name.addEventListener('focus', function(){ if (String(name.value||'').trim()) window.showPurchaseRowSearch(name); });\n                    }\n                    ['.ti-pur-qty','.ti-pur-cost','.ti-pur-margin','.ti-pur-iva'].forEach(function(sel){\n                        const el = tr.querySelector(sel);\n                        if (el) el.addEventListener('input', function(){ window.recalcPurchaseRow(tr); window.refreshPurchaseTotals(); });\n                    });\n                    window.recalcPurchaseRow(tr, !sale);\n                    window.refreshPurchaseTotals();\n                } catch(e) { if (window.tiAlert) window.tiAlert('Errore aggiunta riga acquisizione: ' + (e.message || e)); }\n            };\n\n            window.refreshPurchaseTotals = function() {\n                try {\n                    let total = 0;\n                    document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                        const qty = parseNumSafe((tr.querySelector('.ti-pur-qty') || {}).value || '0');\n                        const cost = parseNumSafe((tr.querySelector('.ti-pur-cost') || {}).value || '0');\n                        total += qty * cost;\n                    });\n                    const out = byId('ti-purchase-total');\n                    if (out) out.innerHTML = 'Totale acquisizione netta indicativo: \u20ac ' + fmtSafe(total);\n                } catch(e) {}\n            };\n            window.purchaseCollectRows = function() {\n                const rows = [];\n                try {\n                    document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                        const name = String((tr.querySelector('.ti-pur-name') || {}).value || '').trim();\n                        if (!name) return;\n                        rows.push({\n                            type: String((tr.querySelector('.ti-pur-type') || {}).value || 'P'),\n                            name: name,\n                            qty: String((tr.querySelector('.ti-pur-qty') || {}).value || '1').trim(),\n                            cost: String((tr.querySelector('.ti-pur-cost') || {}).value || '').trim(),\n                            margin: String((tr.querySelector('.ti-pur-margin') || {}).value || '').trim(),\n                            sale: String((tr.querySelector('.ti-pur-sale') || {}).value || '').trim(),\n                            iva: String((tr.querySelector('.ti-pur-iva') || {}).value || '22').trim(),\n                            note: String((tr.querySelector('.ti-pur-note') || {}).value || '').trim(),\n                            table: tr.dataset.catalogTable || '',\n                            index: parseInt(tr.dataset.catalogIndex || '-1', 10)\n                        });\n                    });\n                } catch(e) {}\n                return rows;\n            };\n            window.confirmPurchaseRows = function(){\n                try {\n                    const rows = window.purchaseCollectRows();\n                    if (!rows.length) { if (window.tiAlert) window.tiAlert('Inserisci almeno una riga acquisizione.'); return; }\n                    const dbEl = byId('ti-ditta');\n                    const dbVal = dbEl ? dbEl.value : '';\n                    if (!dbVal || dbVal === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona prima una ditta.'); return; }\n                    const source = window.currentDbData;\n                    if (!source || !source.Tabelle) { if (window.tiAlert) window.tiAlert('Database non caricato. Riapri Acquisizioni dopo aver selezionato la ditta.'); return; }\n                    const data = JSON.parse(JSON.stringify(source));\n                    const prodTable = realTableName(data, 'Prodotti', 'Prodotti');\n                    const servTable = realTableName(data, 'Servizi', 'Servizi');\n                    const actTable = realTableName(data, 'Attivita', 'Attivita');\n                    if (!data.Tabelle[prodTable]) data.Tabelle[prodTable] = [];\n                    if (!data.Tabelle[servTable]) data.Tabelle[servTable] = [];\n                    if (!data.Tabelle[actTable]) data.Tabelle[actTable] = [];\n                    const now = todayParts();\n                    const makeId = function(table){ return (Array.isArray(data.Tabelle[table]) ? data.Tabelle[table].length : 0) + 1; };\n                    rows.forEach(function(r){\n                        const isServ = String(r.type || 'P') === 'S';\n                        const t = isServ ? servTable : prodTable;\n                        const nameFields = isServ ? ['Servizio','Nome','Descrizione'] : ['Prodotto','Nome','Descrizione'];\n                        const tableRows = Array.isArray(data.Tabelle[t]) ? data.Tabelle[t] : (data.Tabelle[t] = []);\n                        let idx = (r.table === t && r.index >= 0 && tableRows[r.index]) ? r.index : -1;\n                        if (idx < 0) {\n                            const wanted = normKey(r.name);\n                            idx = tableRows.findIndex(function(row){ return normKey(getField(row, nameFields, '')) === wanted; });\n                        }\n                        let rec;\n                        if (idx >= 0) rec = tableRows[idx];\n                        else { rec = {}; setField(rec, ['ID','Id','id'], makeId(t)); setField(rec, nameFields, r.name); tableRows.push(rec); }\n                        setField(rec, nameFields, r.name);\n                        setField(rec, ['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'], parseNumSafe(r.cost));\n                        const gross = parseNumSafe(r.sale) || saleGross(r.cost, r.margin, r.iva);\n                        setField(rec, ['Prezzo','Prezzo vendita','Prezzo_vendita'], gross);\n                        setField(rec, ['IVA_VAT','IVA','Iva','VAT'], parseNumSafe(r.iva) || 22);\n                        if (r.note) setField(rec, ['Note','Nota','Descrizione'], r.note);\n                        if (!isServ) {\n                            const oldQty = parseNumSafe(getField(rec, ['Quantit\u00e0','Quantita','Disponibilita','Disponibilit\u00e0'], 0));\n                            setField(rec, ['Quantit\u00e0','Quantita'], oldQty + parseNumSafe(r.qty));\n                        }\n                        const act = {};\n                        setField(act, ['ID','Id','id'], makeId(actTable));\n                        setField(act, ['Username','Utente','user'], window.tiUser || '');\n                        setField(act, ['Descrizione attivit\u00e0','Descrizione attivita','Descrizione','Dettaglio','Note'], 'Acquisizione ' + r.name);\n                        setField(act, ['Prodotto'], r.name);\n                        setField(act, ['Prezzo'], parseNumSafe(r.cost));\n                        setField(act, ['Quantit\u00e0','Quantita'], parseNumSafe(r.qty));\n                        setField(act, ['Totale'], Math.round(parseNumSafe(r.cost) * parseNumSafe(r.qty) * 100) \/ 100);\n                        setField(act, ['Esito'], 'acquisizione');\n                        setField(act, ['Data'], now.date);\n                        setField(act, ['Ora'], now.time);\n                        setField(act, ['Stato'], 'Attivo');\n                        data.Tabelle[actTable].push(act);\n                    });\n                    const fd = new FormData();\n                    fd.append('ti_action', 'ti_ai_save_full_db');\n                    fd.append('db', dbVal);\n                    fd.append('payload', base64Utf8(JSON.stringify(data)));\n                    const done = function(res){\n                        if (res && res.success) {\n                            window.currentDbData = data;\n                            window.closePurchaseManualFlow();\n                            if (window.tiAlert) window.tiAlert('\u2705 Righe acquisizione confermate e salvate nel database.');\n                            if (res.data && res.data.needs_reload) setTimeout(function(){ location.reload(); }, 900);\n                        } else {\n                            const msg = (res && res.data && res.data.message) ? res.data.message : 'Salvataggio acquisizione non riuscito.';\n                            if (window.tiAlert) window.tiAlert('\u26a0\ufe0f ' + msg);\n                        }\n                    };\n                    if (window.fetchJsonSafe) window.fetchJsonSafe((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(done).catch(function(e){ if (window.tiAlert) window.tiAlert('Errore salvataggio acquisizione: ' + (e.message || e)); });\n                    else fetch((window.tiAjaxUrl || window.tiUrl), {method:'POST', body:fd, credentials:'same-origin'}).then(r=>r.json()).then(done).catch(function(e){ if (window.tiAlert) window.tiAlert('Errore salvataggio acquisizione: ' + (e.message || e)); });\n                } catch(e) { if (window.tiAlert) window.tiAlert('Errore conferma acquisizione: ' + (e.message || e)); }\n            };\n            window.purchaseSendToChat = function(){ window.confirmPurchaseRows(); };\n            if (!window.__tiPurchaseDelegated181) {\n                document.addEventListener('click', function(ev){\n                    const btn = ev.target && ev.target.closest ? ev.target.closest('.ti-ss-add-manual-row') : null;\n                    if (!btn) return;\n                    ev.preventDefault();\n                    window.addPurchaseManualRow();\n                });\n                window.__tiPurchaseDelegated181 = true;\n            }\n\n            window.normalizeActivityOutcome = function(row){\n                row = row || {};\n                const current = String(row.Esito || '').trim();\n                if (\/vendit\/i.test(current)) return 'vendita';\n                if (\/acquist\/i.test(current)) return 'acquisizione';\n                if (\/configur\/i.test(current)) return current || 'configurazione';\n                if (\/appunt\/i.test(current)) return current || 'appuntamento';\n                const txt = String(row.Descrizione || row.Dettaglio || row.Note || row.Nota || '').toLowerCase();\n                if (\/acquist|fornitor\/.test(txt)) return current || 'acquisizione';\n                if (\/appuntament|prenotaz\/.test(txt)) return current || 'appuntamento';\n                if (\/configur|setup|modifica database\/.test(txt)) return current || 'configurazione';\n                const price = parseNumSafe(row.Prezzo || row.Totale || 0);\n                const hasProduct = String(row.Prodotto || row.Servizio || '').trim() !== '';\n                if (!current && (hasProduct || price > 0)) return 'vendita';\n                return current;\n            };\n            if (typeof window.getActivityRowsNormalized === 'function' && !window.__tiActivityOutcomeWrap181) {\n                const oldRowsNorm = window.getActivityRowsNormalized;\n                window.getActivityRowsNormalized = function(){\n                    const arr = oldRowsNorm.apply(this, arguments) || [];\n                    return arr.map(function(r){ if (r && typeof r === 'object') r.Esito = window.normalizeActivityOutcome(r); return r; });\n                };\n                window.__tiActivityOutcomeWrap181 = true;\n            }\n            window.activityOutcomeStorageKey = function(){\n                const u = window.tiUser || 'guest';\n                const db = (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : (window.tiForced || 'global');\n                return 'ti_activity_report_outcome_' + u + '_' + db;\n            };\n            window.loadActivityOutcomeFilter = function(){ try { return localStorage.getItem(window.activityOutcomeStorageKey()) || ''; } catch(e) { return ''; } };\n            window.saveActivityOutcomeFilter = function(v){ try { localStorage.setItem(window.activityOutcomeStorageKey(), String(v || '')); } catch(e) {} };\n            window.setActivityOutcomeFilter = function(v){\n                if (!window.activityReportState) window.activityReportState = {};\n                window.activityReportState.outcomeFilter = String(v || '');\n                window.saveActivityOutcomeFilter(window.activityReportState.outcomeFilter);\n                window.renderActivityReport();\n            };\n            if (typeof window.getFilteredActivityRows === 'function' && !window.__tiActivityFilterWrap181) {\n                const oldFilteredRows = window.getFilteredActivityRows;\n                window.getFilteredActivityRows = function(includeExcludedRows){\n                    let rows = oldFilteredRows.apply(this, arguments) || [];\n                    const f = window.activityReportState ? String(window.activityReportState.outcomeFilter || '') : '';\n                    if (f) rows = rows.filter(function(r){ return String(r.Esito || '') === f; });\n                    return rows;\n                };\n                window.__tiActivityFilterWrap181 = true;\n            }\n            window.injectActivityOutcomeFilter = function(){\n                try {\n                    const toolbar = document.querySelector('#ti-report-cnt .ti-report-toolbar');\n                    if (!toolbar || toolbar.querySelector('.ti-report-outcome-filter-wrap')) return;\n                    const rawRows = (window.getActivityRowsNormalized ? window.getActivityRowsNormalized() : []);\n                    const opts = [];\n                    rawRows.forEach(function(r){ const e = String(r && r.Esito ? r.Esito : '').trim(); if (e && opts.indexOf(e) === -1) opts.push(e); });\n                    opts.sort(function(a,b){ return a.localeCompare(b, 'it'); });\n                    const current = window.activityReportState ? String(window.activityReportState.outcomeFilter || '') : '';\n                    const label = document.createElement('label');\n                    label.className = 'ti-report-outcome-filter-wrap';\n                    let html = '<span>Esito<\/span><select class=\"ti-report-outcome-filter\" onchange=\"window.setActivityOutcomeFilter(this.value)\"><option value=\"\">Tutti<\/option><option value=\"__empty__\" ' + (current === '__empty__' ? 'selected' : '') + '>Senza esito<\/option>';\n                    opts.forEach(function(o){ html += '<option value=\"' + escapeSafe(o) + '\" ' + (o === current ? 'selected' : '') + '>' + escapeSafe(o) + '<\/option>'; });\n                    if (current && current !== '__empty__' && opts.indexOf(current) === -1) html += '<option value=\"' + escapeSafe(current) + '\" selected>' + escapeSafe(current) + '<\/option>';\n                    html += '<\/select>';\n                    label.innerHTML = html;\n                    toolbar.appendChild(label);\n                } catch(e) {}\n            };\n            if (typeof window.renderActivityReport === 'function' && !window.__tiActivityRenderWrap181) {\n                const oldRender = window.renderActivityReport;\n                window.renderActivityReport = function(){ oldRender.apply(this, arguments); window.injectActivityOutcomeFilter(); };\n                window.__tiActivityRenderWrap181 = true;\n            }\n            if (typeof window.openActivityReport === 'function' && !window.__tiActivityOpenWrap181) {\n                const oldOpenReport = window.openActivityReport;\n                window.openActivityReport = function(){\n                    oldOpenReport.apply(this, arguments);\n                    if (!window.activityReportState) window.activityReportState = {};\n                    window.activityReportState.outcomeFilter = window.loadActivityOutcomeFilter();\n                    window.renderActivityReport();\n                };\n                window.__tiActivityOpenWrap181 = true;\n            }\n\n            window.drawPie3D = function(canvasId, rows) {\n                const cv = byId(canvasId); if(!cv) return; const ctx = cv.getContext('2d');\n                const selectedMetrics = window.getActivitySelectedMetrics ? window.getActivitySelectedMetrics() : ['Totale'];\n                const groupField = window.getActivitySelectedGroupField ? window.getActivitySelectedGroupField() : 'Username';\n                const metrics = (Array.isArray(selectedMetrics) && selectedMetrics.length) ? selectedMetrics : ['Totale'];\n                const cols = 1;\n                const blockW = 780;\n                const blockH = 310;\n                cv.width = Math.max(900, blockW + 40);\n                cv.height = Math.max(360, metrics.length * blockH + 40);\n                ctx.clearRect(0,0,cv.width,cv.height);\n                const colors=['#38bdf8','#22c55e','#f59e0b','#ef4444','#a855f7','#14b8a6','#f97316','#06b6d4','#84cc16','#fb7185','#60a5fa','#e879f9'];\n                const buildEntriesForMetric = function(metric) {\n                    const groups = {};\n                    rows.forEach(function(r){\n                        const label = String(r[groupField] || 'N\/D').trim() || 'N\/D';\n                        const value = parseNumSafe(r[metric]) || 0;\n                        groups[label] = (groups[label] || 0) + value;\n                    });\n                    return Object.entries(groups).filter(function(e){ return e[1] > 0; }).sort(function(a,b){ return b[1]-a[1]; }).slice(0, 14);\n                };\n                let drew = false;\n                metrics.forEach(function(metric, metricIndex){\n                    const entries = buildEntriesForMetric(metric);\n                    const originX = 20;\n                    const originY = 20 + metricIndex * blockH;\n                    const cx = originX + 145;\n                    const cy = originY + 145;\n                    const rad = 82;\n                    const depth = 16;\n                    const legendX = originX + 280;\n                    ctx.fillStyle = '#fff'; ctx.font = 'bold 14px Arial'; ctx.fillText(window.getActivityMetricLabel ? window.getActivityMetricLabel([metric]) : metric, originX + 8, originY + 20);\n                    if (!entries.length) { ctx.fillStyle = '#cbd5e1'; ctx.font = '12px Arial'; ctx.fillText('Nessun dato', originX + 8, originY + 48); return; }\n                    drew = true;\n                    const total = entries.reduce(function(a,b){ return a+b[1]; },0);\n                    let start = -Math.PI\/2;\n                    entries.forEach(function(entry,i){\n                        const ang = total > 0 ? (entry[1]\/total)*Math.PI*2 : 0;\n                        ctx.fillStyle='rgba(0,0,0,0.35)'; ctx.beginPath(); ctx.moveTo(cx, cy+depth); ctx.arc(cx, cy+depth, rad, start, start+ang); ctx.closePath(); ctx.fill();\n                        ctx.fillStyle=colors[i%colors.length]; ctx.beginPath(); ctx.moveTo(cx, cy); ctx.arc(cx, cy, rad, start, start+ang); ctx.closePath(); ctx.fill();\n                        start += ang;\n                    });\n                    entries.forEach(function(entry,i){\n                        const pct = total > 0 ? (entry[1] \/ total * 100) : 0;\n                        const ly = originY + 44 + i * 18;\n                        ctx.fillStyle = colors[i%colors.length]; ctx.fillRect(legendX, ly - 10, 11, 11);\n                        ctx.fillStyle = '#fff'; ctx.font = '11px Arial';\n                        const label = String(entry[0]).length > 30 ? String(entry[0]).slice(0, 29) + '\u2026' : String(entry[0]);\n                        ctx.fillText(label + ' - ' + fmtSafe(entry[1]) + ' (' + fmtSafe(pct) + '%)', legendX + 18, ly);\n                    });\n                    ctx.fillStyle = '#94a3b8'; ctx.font = '11px Arial'; ctx.fillText('Raggruppa per: ' + groupField, originX + 8, originY + blockH - 12);\n                });\n                if (!drew) { ctx.fillStyle='#fff'; ctx.font='14px Arial'; ctx.fillText('Nessun dato',20,20); }\n            };\n            window.drawTrend3D = function(canvasId, rows) {\n                const cv = byId(canvasId); if(!cv) return; const ctx = cv.getContext('2d');\n                const selectedMetrics = window.getActivitySelectedMetrics ? window.getActivitySelectedMetrics() : ['Totale'];\n                const groupField = window.getActivitySelectedGroupField ? window.getActivitySelectedGroupField() : 'Username';\n                const metrics = (Array.isArray(selectedMetrics) && selectedMetrics.length) ? selectedMetrics : ['Totale'];\n                const blockW = 860;\n                const blockH = 330;\n                cv.width = Math.max(980, blockW + 40);\n                cv.height = Math.max(380, metrics.length * blockH + 40);\n                ctx.clearRect(0,0,cv.width,cv.height);\n                const colors=['#38bdf8','#22c55e','#f59e0b','#ef4444','#a855f7','#14b8a6','#60a5fa','#e879f9'];\n                const buildMetricTimeline = function(metric) {\n                    const timeline = {}; const groupTotals = {};\n                    rows.forEach(function(r){\n                        const timeKey = (r.Data || '') + ' ' + (r.Ora || '00:00');\n                        const grp = String(r[groupField] || 'N\/D').trim() || 'N\/D';\n                        const value = parseNumSafe(r[metric]) || 0;\n                        if (!timeline[timeKey]) timeline[timeKey] = {};\n                        timeline[timeKey][grp] = (timeline[timeKey][grp] || 0) + value;\n                        groupTotals[grp] = (groupTotals[grp] || 0) + value;\n                    });\n                    const entries = Object.entries(timeline).sort(function(a,b){ return a[0].localeCompare(b[0]); }).slice(-12);\n                    const groups = Object.entries(groupTotals).sort(function(a,b){ return b[1]-a[1]; }).slice(0,6).map(function(e){ return e[0]; });\n                    return {entries:entries, groups:groups, totals:groupTotals};\n                };\n                let drew = false;\n                metrics.forEach(function(metric, metricIndex){\n                    const data = buildMetricTimeline(metric);\n                    const entries = data.entries; const groups = data.groups;\n                    const originX = 20; const originY = 20 + metricIndex * blockH;\n                    const chartW = 610;\n                    const legendX = originX + chartW + 28;\n                    ctx.fillStyle = '#fff'; ctx.font = 'bold 14px Arial'; ctx.fillText(window.getActivityMetricLabel ? window.getActivityMetricLabel([metric]) : metric, originX + 8, originY + 20);\n                    if (!entries.length || !groups.length) { ctx.fillStyle='#cbd5e1'; ctx.font='12px Arial'; ctx.fillText('Nessun dato', originX+8, originY+48); return; }\n                    drew = true;\n                    const max = Math.max(1, ...entries.flatMap(function(e){ return groups.map(function(g){ return e[1][g] || 0; }); }));\n                    const baseY = originY + 250;\n                    const left = originX + 52;\n                    const step = Math.max(36, Math.floor((chartW - 70) \/ Math.max(1, entries.length)));\n                    const barW = Math.max(6, Math.floor(28 \/ Math.max(1, groups.length)));\n                    ctx.strokeStyle='#94a3b8'; ctx.beginPath(); ctx.moveTo(left, originY + 38); ctx.lineTo(left, baseY); ctx.lineTo(left + step * entries.length, baseY); ctx.stroke();\n                    entries.forEach(function(entry, i){\n                        const label = entry[0]; const metricsAtTime = entry[1];\n                        const groupX = left + 10 + i * step;\n                        groups.forEach(function(grp, gi){\n                            const val = metricsAtTime[grp] || 0;\n                            const h = (val\/max)*170;\n                            const x = groupX + gi*(barW+3);\n                            ctx.fillStyle='rgba(0,0,0,0.25)'; ctx.fillRect(x+4, baseY-h+4, barW, h);\n                            ctx.fillStyle=colors[gi%colors.length]; ctx.fillRect(x, baseY-h, barW, h);\n                            if (h > 0) { ctx.fillStyle='#fff'; ctx.font='9px Arial'; ctx.fillText(fmtSafe(val), x-2, baseY-h-6); }\n                        });\n                        ctx.save(); ctx.fillStyle='#fff'; ctx.font='9px Arial'; ctx.translate(groupX, baseY+14); ctx.rotate(-0.6); ctx.fillText(String(label).slice(0,16),0,0); ctx.restore();\n                    });\n                    groups.forEach(function(grp, gi){\n                        const ly = originY + 46 + gi * 20;\n                        ctx.fillStyle = colors[gi%colors.length]; ctx.fillRect(legendX, ly - 10, 12, 12);\n                        ctx.fillStyle = '#fff'; ctx.font = '11px Arial';\n                        const label = String(grp).length > 25 ? String(grp).slice(0,24) + '\u2026' : String(grp);\n                        ctx.fillText(label + ' - ' + fmtSafe(data.totals[grp] || 0), legendX + 18, ly);\n                    });\n                    ctx.fillStyle = '#cbd5e1'; ctx.font = '11px Arial'; ctx.fillText('Raggruppa per: ' + groupField, originX + 8, originY + blockH - 12);\n                });\n                if (!drew) { ctx.fillStyle='#fff'; ctx.font='14px Arial'; ctx.fillText('Nessun dato',20,20); }\n            };\n        } catch(e) {\n            try { console.error('Shop & Service fix 30.9.664 non applicato:', e); } catch(ignore) {}\n        }\n        }\n        if (document.readyState === 'loading') {\n            document.addEventListener('DOMContentLoaded', function(){ setTimeout(tiInstallFixPersi181, 0); });\n        } else {\n            setTimeout(tiInstallFixPersi181, 0);\n        }\n    })();\n\n\n    (function(){\n        function tiInstallPurchaseReport182(){\n            try {\n                const byId = function(id){ return document.getElementById(id); };\n                const esc = function(v){\n                    if (window.escapeHtml) return window.escapeHtml(String(v == null ? '' : v));\n                    return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; });\n                };\n                const parseNum = function(v){\n                    if (v === null || v === undefined) return 0;\n                    let s = String(v).trim();\n                    if (!s) return 0;\n                    s = s.replace(\/[\u20ac\\s]\/g, '');\n                    if (s.indexOf(',') !== -1 && s.indexOf('.') !== -1) s = s.replace(\/\\.\/g, '').replace(',', '.');\n                    else if (s.indexOf(',') !== -1) s = s.replace(',', '.');\n                    const n = parseFloat(s.replace(\/[^0-9.\\-]\/g, ''));\n                    return isNaN(n) ? 0 : n;\n                };\n                const fmt = function(n){\n                    const num = Math.round((parseFloat(n) || 0) * 100) \/ 100;\n                    if (window.fmtNum) return window.fmtNum(num);\n                    return num.toLocaleString('it-IT', {minimumFractionDigits:2, maximumFractionDigits:2});\n                };\n                const norm = function(s){\n                    return String(s || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/[^a-z0-9]\/g, '');\n                };\n                const realTableName = function(data, wanted, fallback){\n                    const tables = data && data.Tabelle ? data.Tabelle : {};\n                    const want = norm(wanted);\n                    const keys = Object.keys(tables || {});\n                    for (let i=0;i<keys.length;i++) if (norm(keys[i]) === want) return keys[i];\n                    for (let i=0;i<keys.length;i++) if (norm(keys[i]).indexOf(want) !== -1 || want.indexOf(norm(keys[i])) !== -1) return keys[i];\n                    return fallback || wanted;\n                };\n                const getField = function(row, names, fallback){\n                    row = row || {};\n                    const keys = Object.keys(row);\n                    for (let i=0;i<names.length;i++) {\n                        const want = norm(names[i]);\n                        for (let j=0;j<keys.length;j++) if (norm(keys[j]) === want) return row[keys[j]];\n                    }\n                    return fallback;\n                };\n                const setField = function(row, names, value){\n                    row = row || {};\n                    const keys = Object.keys(row);\n                    for (let i=0;i<names.length;i++) {\n                        const want = norm(names[i]);\n                        for (let j=0;j<keys.length;j++) if (norm(keys[j]) === want) { row[keys[j]] = value; return; }\n                    }\n                    row[names[0]] = value;\n                };\n                const marginNet = function(costNet, marginText){\n                    const cost = parseNum(costNet);\n                    let m = String(marginText || '').trim();\n                    if (!m) return Math.max(0, cost);\n                    const isPct = m.indexOf('%') !== -1;\n                    m = m.replace(\/[%\u20ac\\s]\/g, '');\n                    let sign = 1;\n                    if (m.charAt(0) === '-') { sign = -1; m = m.slice(1); }\n                    else if (m.charAt(0) === '+') { m = m.slice(1); }\n                    const val = parseNum(m);\n                    return Math.max(0, isPct ? (cost + (cost * sign * val \/ 100)) : (cost + sign * val));\n                };\n                const grossSale = function(costNet, marginText, ivaText){\n                    let iva = parseNum(ivaText);\n                    if (iva <= 0) iva = 22;\n                    return Math.round(marginNet(costNet, marginText) * (1 + iva \/ 100) * 100) \/ 100;\n                };\n                const dateParts = function(){\n                    const d = new Date();\n                    return {\n                        date:String(d.getDate()).padStart(2,'0') + '\/' + String(d.getMonth()+1).padStart(2,'0') + '\/' + d.getFullYear(),\n                        time:String(d.getHours()).padStart(2,'0') + ':' + String(d.getMinutes()).padStart(2,'0')\n                    };\n                };\n                const base64Utf8 = function(str){\n                    try { return btoa(unescape(encodeURIComponent(str))); }\n                    catch(e) { return btoa(str); }\n                };\n                window.tiPurchaseCalcSaleGross = grossSale;\n                window.tiPurchaseMarginAdjustedNet = marginNet;\n\n                window.purchaseGetCatalogItems = function(){\n                    const data = window.currentDbData || {};\n                    const tables = data && data.Tabelle ? data.Tabelle : {};\n                    const out = [];\n                    Object.keys(tables || {}).forEach(function(tn){\n                        if (!\/(prodott|serviz)\/i.test(tn)) return;\n                        const rows = Array.isArray(tables[tn]) ? tables[tn] : [];\n                        rows.forEach(function(r, idx){\n                            if (!r || typeof r !== 'object') return;\n                            const isServ = \/(serviz)\/i.test(tn);\n                            const name = String(getField(r, isServ ? ['Servizio','Descrizione','Nome','Titolo'] : ['Prodotto','Descrizione','Nome','Titolo'], '') || '').trim();\n                            if (!name) return;\n                            out.push({\n                                table:tn,\n                                index:idx,\n                                type:isServ ? 'S' : 'P',\n                                typeLabel:isServ ? 'servizio' : 'prodotto',\n                                name:name,\n                                desc:String(getField(r, ['Descrizione','Note','Nota'], '') || '').trim(),\n                                cost:parseNum(getField(r, ['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'], 0)),\n                                sale:parseNum(getField(r, ['Prezzo','Prezzo vendita','Prezzo_vendita'], 0)),\n                                iva:parseNum(getField(r, ['IVA_VAT','IVA','Iva','VAT'], 22)) || 22\n                            });\n                        });\n                    });\n                    return out;\n                };\n\n                window.ensurePurchaseModal = function(){\n                    let ov = byId('ti-purchase-ov');\n                    if (ov && ov.dataset && ov.dataset.v182 === '1') return ov;\n                    if (ov && ov.parentNode) ov.parentNode.removeChild(ov);\n                    ov = document.createElement('div');\n                    ov.id = 'ti-purchase-ov';\n                    ov.className = 'ti-modal-overlay ti-ov ti-closable-ov';\n                    ov.dataset.v182 = '1';\n                    ov.style.display = 'none';\n                    ov.style.zIndex = '2147482000';\n                    ov.style.alignItems = 'center';\n                    ov.style.justifyContent = 'center';\n                    ov.innerHTML = `\n                        <div class=\"ti-modal ti-purchase-modal\" style=\"width:min(1480px,98vw);max-width:98vw;max-height:92vh;overflow:auto;background:#0f172a;color:#fff;border-radius:16px;padding:18px;box-shadow:0 18px 60px rgba(0,0,0,.45);margin:0 auto;\">\n                            <div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;\">\n                                <div>\n                                    <h2 style=\"margin:0;font-size:22px;\">Acquisizioni<\/h2>\n                                    <div style=\"font-size:14px;color:#cbd5e1;margin-top:4px;\">Gestisci le righe acquisizione. Il costo \u00e8 netto IVA; il prezzo vendita proposto include margine e IVA.<\/div>\n                                <\/div>\n                                <button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"window.closePurchaseManualFlow()\">X<\/button>\n                            <\/div>\n                            <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 14px 0;\">\n                                <button type=\"button\" class=\"ti-btn ti-purchase-add-row\" style=\"background:#22c55e;color:#052e16;font-weight:700;\">+ Aggiungi riga manuale<\/button>\n                                <button type=\"button\" class=\"ti-btn\" style=\"background:#f59e0b;color:#111827;font-weight:700;\" onclick=\"window.pickPurchaseImportFile()\">Import file acquisizioni<\/button>\n                                <button type=\"button\" class=\"ti-btn\" style=\"background:#64748b;color:#fff;font-weight:700;\" onclick=\"window.clearPurchaseRows()\">Svuota righe<\/button>\n                            <\/div>\n                            <div class=\"ti-purchase-table-wrap\" style=\"overflow:auto;border:1px solid #334155;border-radius:12px;\">\n                                <table id=\"ti-purchase-table\" style=\"width:100%;border-collapse:collapse;min-width:1240px;background:#020617;\">\n                                    <thead>\n                                        <tr style=\"background:#1e293b;\">\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Prodotto o servizio<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Tipo<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Q.t\u00e0<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Costo netto<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Margine<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Prezzo vendita IVA incl.<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">IVA %<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Tot. acquisizione netta<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Tot. vendita<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Note<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:center;\">Azioni<\/th>\n                                        <\/tr>\n                                    <\/thead>\n                                    <tbody id=\"ti-purchase-body\"><\/tbody>\n                                <\/table>\n                            <\/div>\n                            <div id=\"ti-purchase-total\" class=\"ti-purchase-summary-grid\" aria-live=\"polite\"><\/div>\n                            <div class=\"ti-purchase-toolbar-fixed\" style=\"display:flex;justify-content:center;gap:8px;margin-top:14px;flex-wrap:wrap;\">\n                                <button type=\"button\" id=\"ti-purchase-confirm-btn\" class=\"ti-btn\" style=\"background:#38bdf8;color:#082f49;font-weight:800;\" onclick=\"window.confirmPurchaseRows()\">Conferma righe acquisizione<\/button>\n                                <button type=\"button\" class=\"ti-btn btn-close\" onclick=\"window.closePurchaseManualFlow()\">Chiudi<\/button>\n                            <\/div>\n                        <\/div>`;\n                    document.body.appendChild(ov);\n                    return ov;\n                };\n\n                window.clearPurchaseRows = function(){\n                    const body = byId('ti-purchase-body');\n                    if (!body) return;\n                    if (body.children.length && window.confirm && !window.confirm('Svuotare tutte le righe acquisizione?')) return;\n                    body.innerHTML = '';\n                    window.addPurchaseManualRow();\n                    window.refreshPurchaseTotals();\n                };\n\n                window.recalcPurchaseRow = function(row, force){\n                    try {\n                        if (!row) return;\n                        const qty = parseNum((row.querySelector('.ti-pur-qty') || {}).value || '0');\n                        const costEl = row.querySelector('.ti-pur-cost');\n                        const marginEl = row.querySelector('.ti-pur-margin');\n                        const saleEl = row.querySelector('.ti-pur-sale');\n                        const ivaEl = row.querySelector('.ti-pur-iva');\n                        const cost = parseNum(costEl ? costEl.value : 0);\n                        const sale = grossSale(cost, marginEl ? marginEl.value : '', ivaEl ? ivaEl.value : '22');\n                        if (saleEl && (force || document.activeElement !== saleEl || saleEl.dataset.auto === '1')) {\n                            saleEl.value = sale ? String(sale).replace('.', ',') : '';\n                            saleEl.dataset.auto = '1';\n                        }\n                        const rowSale = saleEl ? (parseNum(saleEl.value) || sale) : sale;\n                        const netTot = Math.round(qty * cost * 100) \/ 100;\n                        const grossTot = Math.round(qty * rowSale * 100) \/ 100;\n                        const netOut = row.querySelector('.ti-pur-row-total-net');\n                        const grossOut = row.querySelector('.ti-pur-row-total-gross');\n                        if (netOut) netOut.textContent = fmt(netTot);\n                        if (grossOut) grossOut.textContent = fmt(grossTot);\n                    } catch(e) {}\n                };\n\n                window.validatePurchaseRows = function(mark){\n                    const errors = [];\n                    document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr, idx){\n                        tr.classList.remove('is-invalid');\n                        const n = String((tr.querySelector('.ti-pur-name') || {}).value || '').trim();\n                        const q = parseNum((tr.querySelector('.ti-pur-qty') || {}).value || '0');\n                        const c = parseNum((tr.querySelector('.ti-pur-cost') || {}).value || '0');\n                        const ivaEl = tr.querySelector('.ti-pur-iva');\n                        if (ivaEl && !String(ivaEl.value || '').trim()) ivaEl.value = '22';\n                        const bad = !n || q <= 0 || c < 0;\n                        if (bad) {\n                            if (mark) tr.classList.add('is-invalid');\n                            if (!n) errors.push('Riga ' + (idx + 1) + ': prodotto\/servizio mancante');\n                            if (q <= 0) errors.push('Riga ' + (idx + 1) + ': quantit\u00e0 non valida');\n                            if (c < 0) errors.push('Riga ' + (idx + 1) + ': costo non valido');\n                        }\n                    });\n                    return errors;\n                };\n\n                window.addPurchaseManualRow = function(item){\n                    try {\n                        const ov = byId('ti-purchase-ov') || window.ensurePurchaseModal();\n                        const body = byId('ti-purchase-body');\n                        if (!body) return;\n                        if (ov) ov.style.display = 'flex';\n                        const safe = item || {};\n                        const tr = document.createElement('tr');\n                        tr.className = 'ti-purchase-row';\n                        tr.dataset.catalogTable = safe.table || '';\n                        tr.dataset.catalogIndex = String(safe.index != null ? safe.index : -1);\n                        tr.dataset.targetType = safe.type === 'S' ? 'servizio' : 'prodotto';\n                        const iva = safe.iva || '22';\n                        const cost = safe.cost ? String(safe.cost).replace('.', ',') : '';\n                        const sale = safe.sale ? String(safe.sale).replace('.', ',') : '';\n                        tr.innerHTML = `\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-name ti-purchase-row-search\" value=\"${esc(safe.name || '')}\" placeholder=\"Cerca prodotto o servizio\" autocomplete=\"off\" style=\"width:100%;min-width:230px;box-sizing:border-box;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><select class=\"ti-pur-type\" style=\"width:76px;padding:8px;border-radius:8px;background:#0f172a;color:#fff;border:1px solid #334155;\"><option value=\"P\" ${safe.type === 'S' ? '' : 'selected'}>P<\/option><option value=\"S\" ${safe.type === 'S' ? 'selected' : ''}>S<\/option><\/select><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-qty\" value=\"${esc(safe.qty || '1')}\" inputmode=\"decimal\" style=\"width:72px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-cost\" value=\"${esc(cost)}\" inputmode=\"decimal\" style=\"width:100px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-margin\" value=\"${esc(safe.margin || '')}\" placeholder=\"+10%\" style=\"width:86px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-sale\" data-auto=\"${sale ? '0' : '1'}\" value=\"${esc(sale)}\" inputmode=\"decimal\" style=\"width:112px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-iva\" value=\"${esc(iva)}\" inputmode=\"decimal\" style=\"width:68px;text-align:right;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:right;\"><span class=\"ti-pur-row-total-net\">0,00<\/span><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:right;\"><span class=\"ti-pur-row-total-gross\">0,00<\/span><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-note\" value=\"${esc(safe.desc || '')}\" placeholder=\"Note\" style=\"width:100%;min-width:160px;box-sizing:border-box;padding:8px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#fff;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:center;white-space:nowrap;\"><button type=\"button\" class=\"ti-btn ti-pur-dup\" title=\"Duplica riga\" style=\"background:#2563eb;color:#fff;margin-right:4px;\">\u2197<\/button><button type=\"button\" class=\"ti-btn ti-pur-del\" title=\"Elimina riga\" style=\"background:#dc2626;color:#fff;\">X<\/button><\/td>`;\n                        body.appendChild(tr);\n                        const name = tr.querySelector('.ti-pur-name');\n                        if (name) {\n                            name.addEventListener('input', function(){ window.__tiPurchaseActiveRow = tr; window.showPurchaseRowSearch(name); });\n                            name.addEventListener('focus', function(){ window.__tiPurchaseActiveRow = tr; if (String(name.value || '').trim()) window.showPurchaseRowSearch(name); });\n                        }\n                        const typeEl = tr.querySelector('.ti-pur-type');\n                        if (typeEl) typeEl.addEventListener('change', function(){ tr.dataset.targetType = this.value === 'S' ? 'servizio' : 'prodotto'; });\n                        ['.ti-pur-qty','.ti-pur-cost','.ti-pur-margin','.ti-pur-iva'].forEach(function(sel){\n                            const el = tr.querySelector(sel);\n                            if (el) el.addEventListener('input', function(){\n                                const saleEl = tr.querySelector('.ti-pur-sale');\n                                if (saleEl) saleEl.dataset.auto = '1';\n                                window.recalcPurchaseRow(tr, true);\n                                window.refreshPurchaseTotals();\n                            });\n                        });\n                        const saleEl = tr.querySelector('.ti-pur-sale');\n                        if (saleEl) saleEl.addEventListener('input', function(){ saleEl.dataset.auto = '0'; window.recalcPurchaseRow(tr, false); window.refreshPurchaseTotals(); });\n                        const del = tr.querySelector('.ti-pur-del');\n                        if (del) del.addEventListener('click', function(){ tr.remove(); if (!body.children.length) window.addPurchaseManualRow(); window.refreshPurchaseTotals(); });\n                        const dup = tr.querySelector('.ti-pur-dup');\n                        if (dup) dup.addEventListener('click', function(){ window.addPurchaseManualRow(window.purchaseRowToItem(tr)); });\n                        window.recalcPurchaseRow(tr, !sale);\n                        window.refreshPurchaseTotals();\n                        if (!safe.name && name) { try { name.focus(); } catch(ignore) {} }\n                    } catch(e) { if (window.tiAlert) window.tiAlert('Errore aggiunta riga acquisizione: ' + (e.message || e)); }\n                };\n\n                window.purchaseRowToItem = function(tr){\n                    tr = tr || {};\n                    return {\n                        table:tr.dataset ? (tr.dataset.catalogTable || '') : '',\n                        index:tr.dataset ? parseInt(tr.dataset.catalogIndex || '-1', 10) : -1,\n                        type:String(((tr.querySelector && tr.querySelector('.ti-pur-type')) || {}).value || 'P'),\n                        name:String(((tr.querySelector && tr.querySelector('.ti-pur-name')) || {}).value || ''),\n                        qty:String(((tr.querySelector && tr.querySelector('.ti-pur-qty')) || {}).value || '1'),\n                        cost:String(((tr.querySelector && tr.querySelector('.ti-pur-cost')) || {}).value || ''),\n                        margin:String(((tr.querySelector && tr.querySelector('.ti-pur-margin')) || {}).value || ''),\n                        sale:String(((tr.querySelector && tr.querySelector('.ti-pur-sale')) || {}).value || ''),\n                        iva:String(((tr.querySelector && tr.querySelector('.ti-pur-iva')) || {}).value || '22'),\n                        desc:String(((tr.querySelector && tr.querySelector('.ti-pur-note')) || {}).value || '')\n                    };\n                };\n\n                window.refreshPurchaseTotals = function(){\n                    try {\n                        let rows = 0, qtyTot = 0, netTot = 0, saleTot = 0;\n                        document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                            window.recalcPurchaseRow(tr, false);\n                            const qty = parseNum((tr.querySelector('.ti-pur-qty') || {}).value || '0');\n                            const cost = parseNum((tr.querySelector('.ti-pur-cost') || {}).value || '0');\n                            const sale = parseNum((tr.querySelector('.ti-pur-sale') || {}).value || '0');\n                            rows += 1;\n                            qtyTot += qty;\n                            netTot += qty * cost;\n                            saleTot += qty * sale;\n                        });\n                        const out = byId('ti-purchase-total');\n                        if (out) out.innerHTML = '<div class=\"ti-purchase-summary-card\">Righe<b>' + rows + '<\/b><\/div>'\n                            + '<div class=\"ti-purchase-summary-card\">Quantit\u00e0<b>' + fmt(qtyTot) + '<\/b><\/div>'\n                            + '<div class=\"ti-purchase-summary-card\">Totale acquisizione netta<b>\u20ac ' + fmt(netTot) + '<\/b><\/div>'\n                            + '<div class=\"ti-purchase-summary-card\">Totale vendita IVA incl.<b>\u20ac ' + fmt(saleTot) + '<\/b><\/div>';\n                    } catch(e) {}\n                };\n\n                window.selectPurchaseCatalogItemForRow = function(item, row){\n                    try {\n                        item = item || {};\n                        row = row || window.__tiPurchaseActiveRow;\n                        if (!row) return;\n                        row.dataset.catalogTable = item.table || '';\n                        row.dataset.catalogIndex = String(item.index != null ? item.index : -1);\n                        row.dataset.targetType = item.type === 'S' ? 'servizio' : 'prodotto';\n                        const setVal = function(sel, val){ const el = row.querySelector(sel); if (el) el.value = val == null ? '' : String(val).replace('.', ','); };\n                        setVal('.ti-pur-name', item.name || '');\n                        setVal('.ti-pur-type', item.type === 'S' ? 'S' : 'P');\n                        setVal('.ti-pur-cost', item.cost || '');\n                        setVal('.ti-pur-iva', item.iva || '22');\n                        setVal('.ti-pur-note', item.desc || '');\n                        const sale = row.querySelector('.ti-pur-sale');\n                        if (sale) { sale.dataset.auto = '1'; sale.value = item.sale ? String(item.sale).replace('.', ',') : ''; }\n                        window.recalcPurchaseRow(row, !item.sale);\n                        window.refreshPurchaseTotals();\n                        window.closePurchaseSearchPopover && window.closePurchaseSearchPopover();\n                    } catch(e) {}\n                };\n\n                window.purchaseCollectRows = function(){\n                    const rows = [];\n                    document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                        const item = window.purchaseRowToItem(tr);\n                        item.table = tr.dataset.catalogTable || '';\n                        item.index = parseInt(tr.dataset.catalogIndex || '-1', 10);\n                        if (String(item.name || '').trim()) rows.push(item);\n                    });\n                    return rows;\n                };\n\n                window.confirmPurchaseRows = function(){\n                    const btn = byId('ti-purchase-confirm-btn');\n                    try {\n                        const errors = window.validatePurchaseRows(true);\n                        if (errors.length) { if (window.tiAlert) window.tiAlert('Correggi le righe acquisizione:\\n' + errors.slice(0, 8).join('\\n')); return; }\n                        const rows = window.purchaseCollectRows();\n                        if (!rows.length) { if (window.tiAlert) window.tiAlert('Inserisci almeno una riga acquisizione.'); return; }\n                        const dbEl = byId('ti-ditta');\n                        const dbVal = dbEl ? dbEl.value : '';\n                        if (!dbVal || dbVal === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona prima una ditta.'); return; }\n                        const source = window.currentDbData;\n                        if (!source || !source.Tabelle) { if (window.tiAlert) window.tiAlert('Database non caricato. Riapri Acquisizioni dopo aver selezionato la ditta.'); return; }\n                        if (btn) { btn.disabled = true; btn.dataset.oldText = btn.innerHTML; btn.innerHTML = 'Salvataggio...'; }\n                        const data = JSON.parse(JSON.stringify(source));\n                        const prodTable = realTableName(data, 'Prodotti', 'Prodotti');\n                        const servTable = realTableName(data, 'Servizi', 'Servizi');\n                        const actTable = realTableName(data, 'Attivita', 'Attivita');\n                        if (!data.Tabelle[prodTable]) data.Tabelle[prodTable] = [];\n                        if (!data.Tabelle[servTable]) data.Tabelle[servTable] = [];\n                        if (!data.Tabelle[actTable]) data.Tabelle[actTable] = [];\n                        const now = dateParts();\n                        const nextId = function(table){ return (Array.isArray(data.Tabelle[table]) ? data.Tabelle[table].length : 0) + 1; };\n                        rows.forEach(function(r){\n                            const isServ = String(r.type || 'P') === 'S';\n                            const t = isServ ? servTable : prodTable;\n                            const nameFields = isServ ? ['Servizio','Nome','Descrizione'] : ['Prodotto','Nome','Descrizione'];\n                            const tableRows = Array.isArray(data.Tabelle[t]) ? data.Tabelle[t] : (data.Tabelle[t] = []);\n                            let idx = (r.table === t && r.index >= 0 && tableRows[r.index]) ? r.index : -1;\n                            if (idx < 0) {\n                                const wanted = norm(r.name);\n                                idx = tableRows.findIndex(function(row){ return norm(getField(row, nameFields, '')) === wanted; });\n                            }\n                            let rec;\n                            if (idx >= 0) rec = tableRows[idx];\n                            else { rec = {}; setField(rec, ['ID','Id','id'], nextId(t)); tableRows.push(rec); }\n                            setField(rec, nameFields, r.name);\n                            setField(rec, ['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'], parseNum(r.cost));\n                            setField(rec, ['Margine'], String(r.margin || ''));\n                            const gross = parseNum(r.sale) || grossSale(r.cost, r.margin, r.iva);\n                            setField(rec, ['Prezzo','Prezzo vendita','Prezzo_vendita'], gross);\n                            setField(rec, ['IVA_VAT','IVA','Iva','VAT'], parseNum(r.iva) || 22);\n                            if (r.note) setField(rec, ['Note','Nota','Descrizione'], r.note);\n                            if (!isServ) {\n                                const oldQty = parseNum(getField(rec, ['Quantit\u00e0','Quantita','Disponibilita','Disponibilit\u00e0'], 0));\n                                setField(rec, ['Quantit\u00e0','Quantita'], Math.round((oldQty + parseNum(r.qty)) * 100) \/ 100);\n                            }\n                            const act = {};\n                            setField(act, ['ID','Id','id'], nextId(actTable));\n                            setField(act, ['Username','Utente','user'], window.tiUser || '');\n                            setField(act, ['Descrizione attivit\u00e0','Descrizione attivita','Descrizione','Dettaglio','Note'], 'Acquisizione ' + r.name);\n                            setField(act, ['Prodotto'], r.name);\n                            setField(act, ['Prezzo'], parseNum(r.cost));\n                            setField(act, ['Quantit\u00e0','Quantita'], parseNum(r.qty));\n                            setField(act, ['Totale'], Math.round(parseNum(r.cost) * parseNum(r.qty) * 100) \/ 100);\n                            setField(act, ['Margine'], String(r.margin || ''));\n                            setField(act, ['IVA_VAT','IVA','Iva','VAT'], parseNum(r.iva) || 22);\n                            setField(act, ['Prezzo vendita','Prezzo_vendita'], gross);\n                            setField(act, ['Esito'], 'acquisizione');\n                            setField(act, ['Data'], now.date);\n                            setField(act, ['Ora'], now.time);\n                            setField(act, ['Stato'], 'Attivo');\n                            data.Tabelle[actTable].push(act);\n                        });\n                        const fd = new FormData();\n                        fd.append('ti_action', 'ti_ai_save_full_db');\n                        fd.append('db', dbVal);\n                        fd.append('payload', base64Utf8(JSON.stringify(data)));\n                        const done = function(res){\n                            if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText || 'Conferma righe acquisizione'; }\n                            if (res && res.success) {\n                                window.currentDbData = data;\n                                window.closePurchaseManualFlow && window.closePurchaseManualFlow();\n                                if (window.tiAlert) window.tiAlert('\u2705 Righe acquisizione confermate e salvate nel database.');\n                                if (res.data && res.data.needs_reload) setTimeout(function(){ location.reload(); }, 900);\n                            } else {\n                                const msg = (res && res.data && res.data.message) ? res.data.message : 'Salvataggio acquisizione non riuscito.';\n                                if (window.tiAlert) window.tiAlert('\u26a0\ufe0f ' + msg);\n                            }\n                        };\n                        const fail = function(e){\n                            if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText || 'Conferma righe acquisizione'; }\n                            if (window.tiAlert) window.tiAlert('Errore salvataggio acquisizione: ' + ((e && e.message) || e));\n                        };\n                        const url = window.tiAjaxUrl || window.tiUrl;\n                        if (window.fetchJsonSafe) window.fetchJsonSafe(url, {method:'POST', body:fd, credentials:'same-origin'}).then(done).catch(fail);\n                        else fetch(url, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ return r.json(); }).then(done).catch(fail);\n                    } catch(e) {\n                        if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText || 'Conferma righe acquisizione'; }\n                        if (window.tiAlert) window.tiAlert('Errore conferma acquisizione: ' + (e.message || e));\n                    }\n                };\n                window.purchaseSendToChat = function(){ window.confirmPurchaseRows(); };\n\n                if (!window.__tiPurchaseDelegated182) {\n                    document.addEventListener('click', function(ev){\n                        const btn = ev.target && ev.target.closest ? ev.target.closest('.ti-purchase-add-row,.ti-ss-add-manual-row') : null;\n                        if (!btn) return;\n                        ev.preventDefault();\n                        ev.stopPropagation();\n                        if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                        window.addPurchaseManualRow();\n                    }, true);\n                    window.__tiPurchaseDelegated182 = true;\n                }\n\n                window.ti182NormalizeActivityOutcome = function(row){\n                    row = row || {};\n                    const current = String(row.Esito || '').trim();\n                    if (\/vendit\/i.test(current)) return 'vendita';\n                    if (\/acquist\/i.test(current)) return 'acquisizione';\n                    if (\/configur\/i.test(current)) return current || 'configurazione';\n                    if (\/appunt|prenot\/i.test(current)) return current || 'appuntamento';\n                    const txt = String(row.Descrizione || row.Dettaglio || row.Note || row.Nota || row.Istruzioni || '').toLowerCase();\n                    if (\/acquist|fornitor\/.test(txt)) return current || 'acquisizione';\n                    if (\/appuntament|prenotaz\/.test(txt)) return current || 'appuntamento';\n                    if (\/configur|setup|modifica database\/.test(txt)) return current || 'configurazione';\n                    const price = parseNum(row.Prezzo || row.Totale || 0);\n                    const hasProduct = String(row.Prodotto || row.Servizio || '').trim() !== '';\n                    if (!current && (hasProduct || price > 0)) return 'vendita';\n                    return current;\n                };\n                if (typeof window.getActivityRowsNormalized === 'function' && !window.__tiActivityOutcomeWrap182) {\n                    const prevRowsNorm = window.getActivityRowsNormalized;\n                    window.getActivityRowsNormalized = function(){\n                        const arr = prevRowsNorm.apply(this, arguments) || [];\n                        return arr.map(function(r){ if (r && typeof r === 'object') r.Esito = window.ti182NormalizeActivityOutcome(r); return r; });\n                    };\n                    window.__tiActivityOutcomeWrap182 = true;\n                }\n                window.ti182OutcomeMatches = function(row, filter){\n                    filter = String(filter || '');\n                    const val = String(row && row.Esito ? row.Esito : '').trim();\n                    if (!filter) return true;\n                    if (filter === '__empty__') return !val;\n                    return val === filter;\n                };\n                if (typeof window.getActivityRowsNormalized === 'function') {\n                    window.getFilteredActivityRows = function(includeExcludedRows){\n                        let rows = window.getActivityRowsNormalized() || [];\n                        const state = window.activityReportState || {filters:{}, rowFlags:{}};\n                        const rowFlags = state.rowFlags || {};\n                        if (state.excludeConfigActivities && window.userCanSeeConfigurationActivities && window.userCanSeeConfigurationActivities()) rows = rows.filter(function(r){ return !r.__isConfigActivity; });\n                        rows = rows.filter(function(r){\n                            return Object.entries(state.filters || {}).every(function(pair){\n                                const k = pair[0], v = pair[1];\n                                if (!v) return true;\n                                return String(r[k] == null ? '' : r[k]).toLowerCase().indexOf(String(v).toLowerCase()) !== -1;\n                            });\n                        });\n                        const outcomeFilter = String(state.outcomeFilter || '');\n                        if (outcomeFilter) rows = rows.filter(function(r){ return window.ti182OutcomeMatches(r, outcomeFilter); });\n                        if (!includeExcludedRows) rows = rows.filter(function(r){ return !rowFlags[r.__rowKey]; });\n                        const dir = state.sortDir === 'asc' ? 1 : -1;\n                        const col = state.sortCol || 'DataOra';\n                        rows.sort(function(a,b){\n                            const av = col === 'DataOra' ? a.__dataora : a[col];\n                            const bv = col === 'DataOra' ? b.__dataora : b[col];\n                            if (typeof av === 'number' && typeof bv === 'number') return (av - bv) * dir;\n                            return String(av == null ? '' : av).localeCompare(String(bv == null ? '' : bv), 'it', {numeric:true, sensitivity:'base'}) * dir;\n                        });\n                        return rows;\n                    };\n                    window.getActivityIncludedRows = function(){ return window.getFilteredActivityRows(false); };\n                }\n                window.injectActivityOutcomeFilter = function(){\n                    try {\n                        const toolbar = document.querySelector('#ti-report-cnt .ti-report-toolbar');\n                        if (!toolbar) return;\n                        const old = toolbar.querySelector('.ti-report-outcome-filter-wrap');\n                        if (old) old.remove();\n                        const rawRows = window.getActivityRowsNormalized ? window.getActivityRowsNormalized() : [];\n                        const opts = [];\n                        rawRows.forEach(function(r){ const e = String(r && r.Esito ? r.Esito : '').trim(); if (e && opts.indexOf(e) === -1) opts.push(e); });\n                        opts.sort(function(a,b){ return a.localeCompare(b, 'it'); });\n                        const current = window.activityReportState ? String(window.activityReportState.outcomeFilter || '') : '';\n                        const label = document.createElement('label');\n                        label.className = 'ti-report-outcome-filter-wrap';\n                        let html = '<span>Esito<\/span><select class=\"ti-report-outcome-filter\" onchange=\"window.setActivityOutcomeFilter(this.value)\"><option value=\"\">Tutti<\/option><option value=\"__empty__\" ' + (current === '__empty__' ? 'selected' : '') + '>Senza esito<\/option>';\n                        opts.forEach(function(o){ html += '<option value=\"' + esc(o) + '\" ' + (o === current ? 'selected' : '') + '>' + esc(o) + '<\/option>'; });\n                        if (current && current !== '__empty__' && opts.indexOf(current) === -1) html += '<option value=\"' + esc(current) + '\" selected>' + esc(current) + '<\/option>';\n                        html += '<\/select>';\n                        label.innerHTML = html;\n                        toolbar.appendChild(label);\n                    } catch(e) {}\n                };\n                window.setActivityOutcomeFilter = function(v){\n                    if (!window.activityReportState) window.activityReportState = {};\n                    window.activityReportState.outcomeFilter = String(v || '');\n                    try { localStorage.setItem((window.activityOutcomeStorageKey ? window.activityOutcomeStorageKey() : 'ti_activity_report_outcome'), window.activityReportState.outcomeFilter); } catch(e) {}\n                    if (typeof window.renderActivityReport === 'function') window.renderActivityReport();\n                };\n                if (typeof window.renderActivityReport === 'function' && !window.__tiActivityRenderWrap182) {\n                    const oldRender182 = window.renderActivityReport;\n                    window.renderActivityReport = function(){ oldRender182.apply(this, arguments); window.injectActivityOutcomeFilter(); };\n                    window.__tiActivityRenderWrap182 = true;\n                }\n                if (typeof window.openActivityReport === 'function' && !window.__tiActivityOpenWrap182) {\n                    const oldOpen182 = window.openActivityReport;\n                    window.openActivityReport = function(){\n                        oldOpen182.apply(this, arguments);\n                        if (!window.activityReportState) window.activityReportState = {};\n                        try { window.activityReportState.outcomeFilter = localStorage.getItem(window.activityOutcomeStorageKey ? window.activityOutcomeStorageKey() : 'ti_activity_report_outcome') || ''; } catch(e) {}\n                        if (typeof window.renderActivityReport === 'function') window.renderActivityReport();\n                    };\n                    window.__tiActivityOpenWrap182 = true;\n                }\n                if (typeof window.exportActivityReportCsv === 'function' && !window.__tiActivityExportWrap182) {\n                    window.exportActivityReportCsv = function(){\n                        const rows = window.getFilteredActivityRows(false);\n                        const cols = window.getActivityVisibleCols ? window.getActivityVisibleCols() : Object.keys(rows[0] || {});\n                        const csv = cols.join(';') + '\\n' + rows.map(function(r){ return cols.map(function(c){\n                            const raw = (c === 'Prezzo' || c === 'Quantit\u00e0' || c === 'Totale') ? fmt(r[c] || 0) : (r[c] == null ? '' : r[c]);\n                            return '\"' + String(raw).replace(\/\"\/g,'\"\"') + '\"';\n                        }).join(';'); }).join('\\n');\n                        const blob = new Blob([csv], {type:'text\/csv;charset=utf-8;'});\n                        const a = document.createElement('a');\n                        a.href = URL.createObjectURL(blob);\n                        a.download = 'report-attivita.csv';\n                        a.click();\n                        setTimeout(function(){ URL.revokeObjectURL(a.href); }, 500);\n                    };\n                    window.__tiActivityExportWrap182 = true;\n                }\n            } catch(e) {\n                try { console.error('Shop & Service fix 30.9.664 non applicato:', e); } catch(ignore) {}\n            }\n        }\n        if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ setTimeout(tiInstallPurchaseReport182, 0); });\n        else setTimeout(tiInstallPurchaseReport182, 0);\n    })();\n\n    (function(){\n        function ti183InstallPurchaseBaseFix(){\n            try {\n                if (window.__tiPurchaseBaseFix183) return;\n                window.__tiPurchaseBaseFix183 = true;\n\n                const byId = function(id){ return document.getElementById(id); };\n                const esc = function(v){\n                    if (window.escapeHtml) return window.escapeHtml(String(v == null ? '' : v));\n                    return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; });\n                };\n                const parseNum = function(v){\n                    if (v === null || v === undefined) return 0;\n                    let s = String(v).trim();\n                    if (!s) return 0;\n                    s = s.replace(\/[\u20ac\\s]\/g, '');\n                    if (s.indexOf(',') !== -1 && s.indexOf('.') !== -1) s = s.replace(\/\\.\/g, '').replace(',', '.');\n                    else if (s.indexOf(',') !== -1) s = s.replace(',', '.');\n                    const n = parseFloat(s.replace(\/[^0-9.\\-]\/g, ''));\n                    return isNaN(n) ? 0 : n;\n                };\n                const fmt = function(n){\n                    const num = Math.round((parseFloat(n) || 0) * 100) \/ 100;\n                    if (window.fmtNum) return window.fmtNum(num);\n                    return num.toLocaleString('it-IT', {minimumFractionDigits:2, maximumFractionDigits:2});\n                };\n                const norm = function(s){\n                    return String(s || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/[^a-z0-9]\/g, '');\n                };\n                const getField = function(row, names, fallback){\n                    row = row || {};\n                    const keys = Object.keys(row);\n                    for (let i=0;i<names.length;i++) {\n                        const wanted = norm(names[i]);\n                        for (let j=0;j<keys.length;j++) if (norm(keys[j]) === wanted) return row[keys[j]];\n                    }\n                    return fallback;\n                };\n                const setField = function(row, names, value){\n                    row = row || {};\n                    const keys = Object.keys(row);\n                    for (let i=0;i<names.length;i++) {\n                        const wanted = norm(names[i]);\n                        for (let j=0;j<keys.length;j++) if (norm(keys[j]) === wanted) { row[keys[j]] = value; return; }\n                    }\n                    row[names[0]] = value;\n                };\n                const realTableName = function(data, wanted, fallback){\n                    const tables = data && data.Tabelle ? data.Tabelle : {};\n                    const wantedNorm = norm(wanted);\n                    const keys = Object.keys(tables || {});\n                    for (let i=0;i<keys.length;i++) if (norm(keys[i]) === wantedNorm) return keys[i];\n                    for (let i=0;i<keys.length;i++) if (norm(keys[i]).indexOf(wantedNorm) !== -1 || wantedNorm.indexOf(norm(keys[i])) !== -1) return keys[i];\n                    return fallback || wanted;\n                };\n                const marginNet = function(costNet, marginText){\n                    const cost = parseNum(costNet);\n                    let m = String(marginText || '').trim();\n                    if (!m) return Math.max(0, cost);\n                    const isPct = m.indexOf('%') !== -1;\n                    m = m.replace(\/[%\u20ac\\s]\/g, '');\n                    let sign = 1;\n                    if (m.charAt(0) === '-') { sign = -1; m = m.slice(1); }\n                    else if (m.charAt(0) === '+') { m = m.slice(1); }\n                    const val = parseNum(m);\n                    return Math.max(0, isPct ? cost + (cost * sign * val \/ 100) : cost + sign * val);\n                };\n                const saleGross = function(costNet, marginText, ivaText){\n                    let iva = parseNum(ivaText);\n                    if (iva <= 0) iva = 22;\n                    return Math.round(marginNet(costNet, marginText) * (1 + iva \/ 100) * 100) \/ 100;\n                };\n                const dateParts = function(){\n                    const d = new Date();\n                    return {\n                        date:String(d.getDate()).padStart(2,'0') + '\/' + String(d.getMonth()+1).padStart(2,'0') + '\/' + d.getFullYear(),\n                        time:String(d.getHours()).padStart(2,'0') + ':' + String(d.getMinutes()).padStart(2,'0')\n                    };\n                };\n                const base64Utf8 = function(str){\n                    try { return btoa(unescape(encodeURIComponent(str))); }\n                    catch(e) { return btoa(str); }\n                };\n\n                function injectPurchaseStyle(){\n                    if (byId('ti-purchase-base-fix-183-css')) return;\n                    const st = document.createElement('style');\n                    st.id = 'ti-purchase-base-fix-183-css';\n                    st.textContent = `\n#ti-purchase-ov.ti-purchase-open{display:flex!important;align-items:center!important;justify-content:center!important;pointer-events:auto!important;}\n#ti-purchase-ov .ti-purchase-modal{width:min(1480px,98vw)!important;max-width:98vw!important;max-height:92vh!important;overflow:auto!important;}\n#ti-purchase-ov .ti-purchase-table-wrap{display:block!important;width:100%!important;max-width:100%!important;overflow-x:auto!important;overflow-y:visible!important;-webkit-overflow-scrolling:touch!important;touch-action:pan-x pan-y!important;border:1px solid #334155!important;border-radius:12px!important;}\n#ti-purchase-ov #ti-purchase-table{display:table!important;width:100%!important;min-width:1280px!important;border-collapse:collapse!important;background:#020617!important;}\n#ti-purchase-ov #ti-purchase-table thead{display:table-header-group!important;}\n#ti-purchase-ov #ti-purchase-table tbody{display:table-row-group!important;}\n#ti-purchase-ov #ti-purchase-table tr{display:table-row!important;}\n#ti-purchase-ov #ti-purchase-table th,#ti-purchase-ov #ti-purchase-table td{display:table-cell!important;white-space:nowrap!important;}\n#ti-purchase-ov .ti-purchase-row input,#ti-purchase-ov .ti-purchase-row select{background:#0f172a!important;color:#fff!important;-webkit-text-fill-color:#fff!important;caret-color:#fff!important;border:1px solid #334155!important;}\n#ti-purchase-ov .ti-purchase-toolbar-fixed{position:sticky!important;bottom:0!important;z-index:5!important;background:#0f172a!important;padding-top:10px!important;border-top:1px solid #334155!important;}\n#ti-purchase-ov .ti-purchase-summary-grid{display:grid!important;grid-template-columns:repeat(4,minmax(120px,1fr))!important;gap:8px!important;margin-top:10px!important;}\n#ti-purchase-ov .ti-purchase-summary-card{background:#020617!important;border:1px solid #334155!important;border-radius:10px!important;padding:8px!important;color:#e5e7eb!important;font-size:12px!important;}\n#ti-purchase-ov .ti-purchase-summary-card b{display:block!important;color:#bbf7d0!important;font-size:15px!important;margin-top:2px!important;}\n.ti-purchase-row-search-popover{position:fixed!important;z-index:2147483647!important;background:#020617!important;border:1px solid #38bdf8!important;border-radius:10px!important;box-shadow:0 16px 44px rgba(0,0,0,.65)!important;max-height:min(320px,52vh)!important;overflow:auto!important;padding:6px!important;min-width:230px!important;max-width:min(92vw,560px)!important;color:#fff!important;pointer-events:auto!important;-webkit-overflow-scrolling:touch!important;}\n.ti-purchase-row-search-popover .ti-purchase-result-row{display:block!important;width:100%!important;text-align:left!important;margin:0 0 5px 0!important;padding:7px 8px!important;border-radius:8px!important;border:1px solid #334155!important;background:#1e293b!important;color:#fff!important;font-size:12px!important;line-height:1.25!important;cursor:pointer!important;}\n.ti-purchase-row-search-popover .ti-purchase-result-row small{display:block!important;color:#cbd5e1!important;font-size:10.5px!important;margin-top:2px!important;}\n@media (max-width:767px) and (orientation:portrait){#ti-purchase-ov .ti-purchase-modal{width:98vw!important;max-width:98vw!important;padding:10px!important;}#ti-purchase-ov #ti-purchase-table{min-width:980px!important;}#ti-purchase-ov #ti-purchase-table th,#ti-purchase-ov #ti-purchase-table td{font-size:10.5px!important;padding:4px!important;}#ti-purchase-ov #ti-purchase-table input,#ti-purchase-ov #ti-purchase-table select,#ti-purchase-ov #ti-purchase-table button{font-size:10.5px!important;padding:4px!important;min-height:27px!important;}#ti-purchase-ov .ti-pur-name{min-width:190px!important;}.ti-purchase-row-search-popover .ti-purchase-result-row{font-size:10.5px!important;padding:6px!important;}.ti-purchase-row-search-popover .ti-purchase-result-row small{font-size:9.5px!important;}}\n@media (max-width:920px) and (orientation:landscape){#ti-purchase-ov .ti-purchase-modal{width:98vw!important;max-width:98vw!important;padding:10px!important;}#ti-purchase-ov #ti-purchase-table{min-width:900px!important;}#ti-purchase-ov #ti-purchase-table th,#ti-purchase-ov #ti-purchase-table td{font-size:10px!important;padding:3px!important;}#ti-purchase-ov #ti-purchase-table input,#ti-purchase-ov #ti-purchase-table select,#ti-purchase-ov #ti-purchase-table button{font-size:10px!important;padding:3px!important;min-height:25px!important;}}\n`;\n                    document.head.appendChild(st);\n                }\n\n\n                function injectPurchaseLandscapeCompact189(){\n                    try {\n                        if (document.getElementById('ti-purchase-landscape-compact-189-css')) return;\n                        const st = document.createElement('style');\n                        st.id = 'ti-purchase-landscape-compact-189-css';\n                        st.textContent = `\n@media (max-width:980px) and (orientation:landscape){\n#ti-purchase-ov.ti-purchase-open{align-items:flex-start!important;padding:2px!important;}\n#ti-purchase-ov .ti-purchase-modal{width:99vw!important;max-width:99vw!important;max-height:96vh!important;margin:2px auto!important;padding:5px!important;border-radius:10px!important;overflow:auto!important;}\n#ti-purchase-ov .ti-purchase-modal h3,#ti-purchase-ov .ti-purchase-modal h4{font-size:11px!important;line-height:1.05!important;margin:0 0 4px 0!important;}\n#ti-purchase-ov .ti-purchase-table-wrap{overflow:visible!important;}\n#ti-purchase-ov #ti-purchase-table{min-width:790px!important;table-layout:auto!important;}\n#ti-purchase-ov #ti-purchase-table th,#ti-purchase-ov #ti-purchase-table td{font-size:8.5px!important;line-height:1.05!important;padding:1px 2px!important;height:22px!important;max-height:22px!important;vertical-align:middle!important;}\n#ti-purchase-ov #ti-purchase-table input,#ti-purchase-ov #ti-purchase-table select,#ti-purchase-ov #ti-purchase-table textarea,#ti-purchase-ov #ti-purchase-table button{font-size:8.5px!important;line-height:1.05!important;padding:1px 2px!important;height:20px!important;min-height:20px!important;max-height:20px!important;border-radius:4px!important;box-sizing:border-box!important;}\n#ti-purchase-ov .ti-pur-name{min-width:145px!important;max-width:165px!important;}#ti-purchase-ov .ti-pur-type{width:42px!important;min-width:42px!important;}#ti-purchase-ov .ti-pur-qty{width:46px!important;min-width:46px!important;}#ti-purchase-ov .ti-pur-cost{width:62px!important;min-width:62px!important;}#ti-purchase-ov .ti-pur-margin{width:56px!important;min-width:56px!important;}#ti-purchase-ov .ti-pur-sale{width:70px!important;min-width:70px!important;}#ti-purchase-ov .ti-pur-iva{width:42px!important;min-width:42px!important;}#ti-purchase-ov .ti-pur-note{min-width:96px!important;max-width:115px!important;}\n#ti-purchase-ov .ti-pur-row-total-net,#ti-purchase-ov .ti-pur-row-total-gross{display:inline-block!important;min-width:42px!important;font-size:8.5px!important;line-height:1!important;}\n#ti-purchase-ov .ti-pur-dup,#ti-purchase-ov .ti-pur-del{width:21px!important;min-width:21px!important;height:20px!important;min-height:20px!important;padding:0!important;margin:0 1px!important;font-size:9px!important;line-height:1!important;}\n#ti-purchase-ov .ti-purchase-summary-grid{grid-template-columns:repeat(4,minmax(70px,1fr))!important;gap:4px!important;margin-top:4px!important;}#ti-purchase-ov .ti-purchase-summary-card{font-size:8.5px!important;line-height:1.05!important;padding:4px!important;border-radius:7px!important;}#ti-purchase-ov .ti-purchase-summary-card b{font-size:10px!important;line-height:1.05!important;}#ti-purchase-ov .ti-purchase-toolbar-fixed{padding-top:4px!important;gap:4px!important;}#ti-purchase-ov .ti-purchase-toolbar-fixed .ti-btn,#ti-purchase-ov .ti-purchase-toolbar-fixed button{font-size:9px!important;line-height:1.05!important;padding:4px 6px!important;min-height:23px!important;height:23px!important;}\n.ti-purchase-row-search-popover .ti-purchase-result-row{font-size:9px!important;line-height:1.08!important;padding:4px 5px!important;margin-bottom:3px!important;}.ti-purchase-row-search-popover .ti-purchase-result-row small{font-size:8px!important;line-height:1.05!important;}\n}`;\n                        document.head.appendChild(st);\n                    } catch(e) {}\n                }\n                injectPurchaseLandscapeCompact189();\n                document.addEventListener('DOMContentLoaded', injectPurchaseLandscapeCompact189);\n\n                window.tiPurchaseCalcSaleGross = saleGross;\n                window.tiPurchaseMarginAdjustedNet = marginNet;\n\n                window.purchaseGetCatalogItems = function(){\n                    const data = window.currentDbData || {};\n                    const tables = data && data.Tabelle ? data.Tabelle : {};\n                    const out = [];\n                    Object.keys(tables || {}).forEach(function(tn){\n                        if (!\/(prodott|serviz)\/i.test(tn)) return;\n                        const rows = Array.isArray(tables[tn]) ? tables[tn] : [];\n                        rows.forEach(function(r, idx){\n                            if (!r || typeof r !== 'object') return;\n                            const isServ = \/(serviz)\/i.test(tn);\n                            const name = String(getField(r, isServ ? ['Servizio','Descrizione','Nome','Titolo'] : ['Prodotto','Descrizione','Nome','Titolo'], '') || '').trim();\n                            if (!name) return;\n                            out.push({\n                                table:tn,\n                                index:idx,\n                                type:isServ ? 'S' : 'P',\n                                typeLabel:isServ ? 'servizio' : 'prodotto',\n                                name:name,\n                                desc:String(getField(r, ['Descrizione','Note','Nota'], '') || '').trim(),\n                                cost:parseNum(getField(r, ['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'], 0)),\n                                sale:parseNum(getField(r, ['Prezzo','Prezzo vendita','Prezzo_vendita'], 0)),\n                                iva:parseNum(getField(r, ['IVA_VAT','IVA','Iva','VAT'], 22)) || 22\n                            });\n                        });\n                    });\n                    return out;\n                };\n\n                window.closePurchaseSearchPopover = function(){\n                    const p = byId('ti-purchase-row-search-popover');\n                    if (p) p.remove();\n                };\n                window.selectPurchaseCatalogItemForRow = function(item, row){\n                    try {\n                        item = item || {};\n                        row = row || window.__tiPurchaseActiveRow;\n                        if (!row) return;\n                        row.dataset.catalogTable = item.table || '';\n                        row.dataset.catalogIndex = String(item.index != null ? item.index : -1);\n                        row.dataset.targetType = item.type === 'S' ? 'servizio' : 'prodotto';\n                        const setVal = function(sel, val){ const el = row.querySelector(sel); if (el) el.value = val == null ? '' : String(val).replace('.', ','); };\n                        setVal('.ti-pur-name', item.name || '');\n                        setVal('.ti-pur-type', item.type === 'S' ? 'S' : 'P');\n                        setVal('.ti-pur-cost', item.cost || '');\n                        setVal('.ti-pur-iva', item.iva || '22');\n                        setVal('.ti-pur-note', item.desc || '');\n                        const sale = row.querySelector('.ti-pur-sale');\n                        if (sale) { sale.dataset.auto = '1'; sale.value = item.sale ? String(item.sale).replace('.', ',') : ''; }\n                        window.recalcPurchaseRow(row, !item.sale);\n                        window.refreshPurchaseTotals();\n                        window.closePurchaseSearchPopover();\n                    } catch(e) {}\n                };\n                window.showPurchaseRowSearch = function(input){\n                    try {\n                        if (!input) return;\n                        const row = input.closest('tr');\n                        window.__tiPurchaseActiveRow = row;\n                        const q = String(input.value || '').trim().toLowerCase();\n                        const all = window.purchaseGetCatalogItems ? window.purchaseGetCatalogItems() : [];\n                        const filtered = q ? all.filter(function(it){ return (String(it.name || '') + ' ' + String(it.desc || '') + ' ' + String(it.typeLabel || '')).toLowerCase().indexOf(q) !== -1; }).slice(0, 40) : all.slice(0, 20);\n                        window.closePurchaseSearchPopover();\n                        if (!filtered.length) return;\n                        const pop = document.createElement('div');\n                        pop.id = 'ti-purchase-row-search-popover';\n                        pop.className = 'ti-purchase-row-search-popover';\n                        filtered.forEach(function(it){\n                            const b = document.createElement('button');\n                            b.type = 'button';\n                            b.className = 'ti-purchase-result-row';\n                            b.innerHTML = '<b>' + esc(it.name) + '<\/b><small>' + esc(it.typeLabel || it.type || '') + ' - ' + esc(it.table || '') + ' - costo ' + fmt(it.cost || 0) + ' - prezzo ' + fmt(it.sale || 0) + ' - IVA ' + fmt(it.iva || 22) + '%<\/small>';\n                            const choose = function(ev){ if (ev) { ev.preventDefault(); ev.stopPropagation(); } window.selectPurchaseCatalogItemForRow(it, row); };\n                            b.addEventListener('pointerdown', choose);\n                            b.addEventListener('click', choose);\n                            pop.appendChild(b);\n                        });\n                        document.body.appendChild(pop);\n                        const r = input.getBoundingClientRect();\n                        const width = Math.max(r.width, Math.min(560, window.innerWidth - 24));\n                        let left = Math.max(8, Math.min(r.left, window.innerWidth - width - 8));\n                        let top = r.bottom + 6;\n                        setTimeout(function(){\n                            const ph = pop.offsetHeight || 260;\n                            if (top + ph > window.innerHeight - 8) top = Math.max(8, r.top - ph - 6);\n                            pop.style.left = left + 'px';\n                            pop.style.top = top + 'px';\n                            pop.style.width = width + 'px';\n                        }, 0);\n                    } catch(e) {}\n                };\n\n                window.ensurePurchaseModal = function(){\n                    injectPurchaseStyle();\n                    let ov = byId('ti-purchase-ov');\n                    if (ov && ov.dataset && ov.dataset.v183 === '1') return ov;\n                    if (ov && ov.parentNode) ov.parentNode.removeChild(ov);\n                    ov = document.createElement('div');\n                    ov.id = 'ti-purchase-ov';\n                    ov.className = 'ti-modal-overlay ti-ov ti-closable-ov';\n                    ov.dataset.v183 = '1';\n                    ov.style.display = 'none';\n                    ov.style.zIndex = '2147482000';\n                    ov.innerHTML = `\n                        <div class=\"ti-modal ti-purchase-modal\" style=\"background:#0f172a;color:#fff;border-radius:16px;padding:18px;box-shadow:0 18px 60px rgba(0,0,0,.45);margin:0 auto;\">\n                            <div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;\">\n                                <div>\n                                    <h2 style=\"margin:0;font-size:22px;\">Acquisizioni<\/h2>\n                                    <div style=\"font-size:14px;color:#cbd5e1;margin-top:4px;\">Gestisci le righe acquisizione manuale. Il costo \u00e8 netto IVA; il prezzo vendita proposto include margine e IVA.<\/div>\n                                <\/div>\n                                <button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"window.closePurchaseManualFlow()\">X<\/button>\n                            <\/div>\n                            <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 14px 0;\">\n                                <button type=\"button\" class=\"ti-btn ti-purchase-add-row ti-ss-add-manual-row\" style=\"background:#22c55e;color:#052e16;font-weight:700;\" onclick=\"window.ti183ForceAddPurchaseRow(event)\">+ Aggiungi riga manuale<\/button>\n                                <button type=\"button\" class=\"ti-btn\" style=\"background:#f59e0b;color:#111827;font-weight:700;\" onclick=\"window.pickPurchaseImportFile && window.pickPurchaseImportFile()\">Import file acquisizioni<\/button>\n                                <button type=\"button\" class=\"ti-btn\" style=\"background:#64748b;color:#fff;font-weight:700;\" onclick=\"window.clearPurchaseRows()\">Svuota righe<\/button>\n                            <\/div>\n                            <div class=\"ti-purchase-table-wrap\">\n                                <table id=\"ti-purchase-table\">\n                                    <thead>\n                                        <tr style=\"background:#1e293b;\">\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Prodotto o servizio<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Tipo<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Q.t\u00e0<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Costo netto<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Margine<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Prezzo vendita IVA incl.<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">IVA %<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Tot. acquisizione netta<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:right;\">Tot. vendita<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:left;\">Note<\/th>\n                                            <th style=\"padding:8px;border-bottom:1px solid #334155;text-align:center;\">Azioni<\/th>\n                                        <\/tr>\n                                    <\/thead>\n                                    <tbody id=\"ti-purchase-body\"><\/tbody>\n                                <\/table>\n                            <\/div>\n                            <div id=\"ti-purchase-total\" class=\"ti-purchase-summary-grid\" aria-live=\"polite\"><\/div>\n                            <div class=\"ti-purchase-toolbar-fixed\" style=\"display:flex;justify-content:center;gap:8px;margin-top:14px;flex-wrap:wrap;\">\n                                <button type=\"button\" id=\"ti-purchase-confirm-btn\" class=\"ti-btn\" style=\"background:#38bdf8;color:#082f49;font-weight:800;\" onclick=\"window.confirmPurchaseRows()\">Conferma righe acquisizione<\/button>\n                                <button type=\"button\" class=\"ti-btn btn-close\" onclick=\"window.closePurchaseManualFlow()\">Chiudi<\/button>\n                            <\/div>\n                        <\/div>`;\n                    document.body.appendChild(ov);\n                    return ov;\n                };\n                window.closePurchaseManualFlow = function(){\n                    const ov = byId('ti-purchase-ov');\n                    window.closePurchaseSearchPopover();\n                    if (!ov) return;\n                    ov.classList.remove('ti-purchase-open', 'ti-modal-open');\n                    if (window.closeModal) window.closeModal(ov); else ov.style.display = 'none';\n                };\n                function openPurchaseOverlay(){\n                    const ov = window.ensurePurchaseModal();\n                    ov.classList.add('ti-purchase-open', 'ti-modal-open');\n                    ov.style.display = 'flex';\n                    ov.style.pointerEvents = 'auto';\n                    ov.setAttribute('aria-hidden', 'false');\n                    return ov;\n                }\n                window.ti183ForcePurchaseTableActive = function(){\n                    const ov = openPurchaseOverlay();\n                    const wrap = ov.querySelector('.ti-purchase-table-wrap');\n                    const table = byId('ti-purchase-table');\n                    const body = byId('ti-purchase-body');\n                    if (wrap) wrap.style.display = 'block';\n                    if (table) table.style.display = 'table';\n                    if (body && !body.children.length) window.addPurchaseManualRow();\n                    window.refreshPurchaseTotals();\n                    return body;\n                };\n                window.ti183ForceAddPurchaseRow = function(ev){\n                    if (ev) { ev.preventDefault(); ev.stopPropagation(); }\n                    openPurchaseOverlay();\n                    window.addPurchaseManualRow();\n                };\n                window.openPurchaseManualFlow = function(){\n                    const dbSel = byId('ti-ditta');\n                    const dbVal = dbSel ? dbSel.value : '';\n                    const openNow = function(){ window.ti183ForcePurchaseTableActive(); };\n                    if (!dbVal || dbVal === 'NEW_DB') { openNow(); return; }\n                    if (window.currentDbData && window.currentDbData.Tabelle) { openNow(); return; }\n                    const fd = new FormData();\n                    fd.append('ti_action', 'ti_ai_get_db_data');\n                    fd.append('db', dbVal);\n                    const url = window.tiAjaxUrl || window.tiUrl;\n                    if (url && window.fetchJsonSafe) {\n                        window.fetchJsonSafe(url, {method:'POST', body:fd, credentials:'same-origin'}).then(function(res){\n                            if (res && res.success) window.currentDbData = res.data;\n                            openNow();\n                        }).catch(function(){ openNow(); });\n                    } else openNow();\n                };\n\n                window.recalcPurchaseRow = function(row, force){\n                    try {\n                        if (!row) return;\n                        const qty = parseNum((row.querySelector('.ti-pur-qty') || {}).value || '0');\n                        const costEl = row.querySelector('.ti-pur-cost');\n                        const marginEl = row.querySelector('.ti-pur-margin');\n                        const saleEl = row.querySelector('.ti-pur-sale');\n                        const ivaEl = row.querySelector('.ti-pur-iva');\n                        const cost = parseNum(costEl ? costEl.value : 0);\n                        const sale = saleGross(cost, marginEl ? marginEl.value : '', ivaEl ? ivaEl.value : '22');\n                        if (saleEl && (force || document.activeElement !== saleEl || saleEl.dataset.auto === '1')) {\n                            saleEl.value = sale ? String(sale).replace('.', ',') : '';\n                            saleEl.dataset.auto = '1';\n                        }\n                        const rowSale = saleEl ? (parseNum(saleEl.value) || sale) : sale;\n                        const netTot = Math.round(qty * cost * 100) \/ 100;\n                        const grossTot = Math.round(qty * rowSale * 100) \/ 100;\n                        const netOut = row.querySelector('.ti-pur-row-total-net');\n                        const grossOut = row.querySelector('.ti-pur-row-total-gross');\n                        if (netOut) netOut.textContent = fmt(netTot);\n                        if (grossOut) grossOut.textContent = fmt(grossTot);\n                    } catch(e) {}\n                };\n                window.refreshPurchaseTotals = function(){\n                    try {\n                        let rows = 0, qtyTot = 0, netTot = 0, saleTot = 0;\n                        document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                            window.recalcPurchaseRow(tr, false);\n                            const qty = parseNum((tr.querySelector('.ti-pur-qty') || {}).value || '0');\n                            const cost = parseNum((tr.querySelector('.ti-pur-cost') || {}).value || '0');\n                            const sale = parseNum((tr.querySelector('.ti-pur-sale') || {}).value || '0');\n                            rows += 1; qtyTot += qty; netTot += qty * cost; saleTot += qty * sale;\n                        });\n                        const out = byId('ti-purchase-total');\n                        if (out) out.innerHTML = '<div class=\"ti-purchase-summary-card\">Righe<b>' + rows + '<\/b><\/div>'\n                            + '<div class=\"ti-purchase-summary-card\">Quantit\u00e0<b>' + fmt(qtyTot) + '<\/b><\/div>'\n                            + '<div class=\"ti-purchase-summary-card\">Totale acquisizione netta<b>\u20ac ' + fmt(netTot) + '<\/b><\/div>'\n                            + '<div class=\"ti-purchase-summary-card\">Totale vendita IVA incl.<b>\u20ac ' + fmt(saleTot) + '<\/b><\/div>';\n                    } catch(e) {}\n                };\n                window.addPurchaseManualRow = function(item){\n                    try {\n                        const body = byId('ti-purchase-body') || window.ti183ForcePurchaseTableActive();\n                        if (!body) return;\n                        const now = Date.now();\n                        if (!item && window.__tiLastPurchaseManualRowAt && now - window.__tiLastPurchaseManualRowAt < 180) return;\n                        if (!item) window.__tiLastPurchaseManualRowAt = now;\n                        const safe = item || {};\n                        const tr = document.createElement('tr');\n                        tr.className = 'ti-purchase-row';\n                        tr.dataset.catalogTable = safe.table || '';\n                        tr.dataset.catalogIndex = String(safe.index != null ? safe.index : -1);\n                        tr.dataset.targetType = safe.type === 'S' ? 'servizio' : 'prodotto';\n                        const iva = safe.iva || '22';\n                        const cost = safe.cost ? String(safe.cost).replace('.', ',') : '';\n                        const sale = safe.sale ? String(safe.sale).replace('.', ',') : '';\n                        tr.innerHTML = `\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-name ti-purchase-row-search\" value=\"${esc(safe.name || '')}\" placeholder=\"Cerca prodotto o servizio\" autocomplete=\"off\" style=\"width:100%;min-width:230px;box-sizing:border-box;padding:8px;border-radius:8px;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><select class=\"ti-pur-type\" style=\"width:76px;padding:8px;border-radius:8px;\"><option value=\"P\" ${safe.type === 'S' ? '' : 'selected'}>P<\/option><option value=\"S\" ${safe.type === 'S' ? 'selected' : ''}>S<\/option><\/select><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-qty\" value=\"${esc(safe.qty || '1')}\" inputmode=\"decimal\" style=\"width:72px;text-align:right;padding:8px;border-radius:8px;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-cost\" value=\"${esc(cost)}\" inputmode=\"decimal\" style=\"width:100px;text-align:right;padding:8px;border-radius:8px;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-margin\" value=\"${esc(safe.margin || '')}\" placeholder=\"+10%\" style=\"width:86px;text-align:right;padding:8px;border-radius:8px;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-sale\" data-auto=\"${sale ? '0' : '1'}\" value=\"${esc(sale)}\" inputmode=\"decimal\" style=\"width:112px;text-align:right;padding:8px;border-radius:8px;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-iva\" value=\"${esc(iva)}\" inputmode=\"decimal\" style=\"width:68px;text-align:right;padding:8px;border-radius:8px;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:right;\"><span class=\"ti-pur-row-total-net\">0,00<\/span><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:right;\"><span class=\"ti-pur-row-total-gross\">0,00<\/span><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;\"><input class=\"ti-pur-note\" value=\"${esc(safe.desc || '')}\" placeholder=\"Note\" style=\"width:100%;min-width:160px;box-sizing:border-box;padding:8px;border-radius:8px;\"><\/td>\n                            <td style=\"padding:6px;border-bottom:1px solid #1f2937;text-align:center;white-space:nowrap;\"><button type=\"button\" class=\"ti-btn ti-pur-dup\" title=\"Duplica riga\" style=\"background:#2563eb;color:#fff;margin-right:4px;\">\u2197<\/button><button type=\"button\" class=\"ti-btn ti-pur-del\" title=\"Elimina riga\" style=\"background:#dc2626;color:#fff;\">X<\/button><\/td>`;\n                        body.appendChild(tr);\n                        const name = tr.querySelector('.ti-pur-name');\n                        if (name) {\n                            name.addEventListener('input', function(){ window.__tiPurchaseActiveRow = tr; window.showPurchaseRowSearch(name); });\n                            name.addEventListener('focus', function(){ window.__tiPurchaseActiveRow = tr; if (String(name.value || '').trim()) window.showPurchaseRowSearch(name); });\n                        }\n                        const typeEl = tr.querySelector('.ti-pur-type');\n                        if (typeEl) typeEl.addEventListener('change', function(){ tr.dataset.targetType = this.value === 'S' ? 'servizio' : 'prodotto'; });\n                        ['.ti-pur-qty','.ti-pur-cost','.ti-pur-margin','.ti-pur-iva'].forEach(function(sel){\n                            const el = tr.querySelector(sel);\n                            if (el) el.addEventListener('input', function(){ const saleEl = tr.querySelector('.ti-pur-sale'); if (saleEl) saleEl.dataset.auto = '1'; window.recalcPurchaseRow(tr, true); window.refreshPurchaseTotals(); });\n                        });\n                        const saleEl = tr.querySelector('.ti-pur-sale');\n                        if (saleEl) saleEl.addEventListener('input', function(){ saleEl.dataset.auto = '0'; window.recalcPurchaseRow(tr, false); window.refreshPurchaseTotals(); });\n                        const del = tr.querySelector('.ti-pur-del');\n                        if (del) del.addEventListener('click', function(){ tr.remove(); if (!body.children.length) window.addPurchaseManualRow(); window.refreshPurchaseTotals(); });\n                        const dup = tr.querySelector('.ti-pur-dup');\n                        if (dup) dup.addEventListener('click', function(){ window.addPurchaseManualRow(window.purchaseRowToItem(tr)); });\n                        window.recalcPurchaseRow(tr, !sale);\n                        window.refreshPurchaseTotals();\n                        if (!safe.name && name) { try { name.focus(); } catch(ignore) {} }\n                    } catch(e) { if (window.tiAlert) window.tiAlert('Errore aggiunta riga acquisizione: ' + (e.message || e)); }\n                };\n                window.purchaseRowToItem = function(tr){\n                    tr = tr || {};\n                    return {\n                        table:tr.dataset ? (tr.dataset.catalogTable || '') : '',\n                        index:tr.dataset ? parseInt(tr.dataset.catalogIndex || '-1', 10) : -1,\n                        type:String(((tr.querySelector && tr.querySelector('.ti-pur-type')) || {}).value || 'P'),\n                        name:String(((tr.querySelector && tr.querySelector('.ti-pur-name')) || {}).value || ''),\n                        qty:String(((tr.querySelector && tr.querySelector('.ti-pur-qty')) || {}).value || '1'),\n                        cost:String(((tr.querySelector && tr.querySelector('.ti-pur-cost')) || {}).value || ''),\n                        margin:String(((tr.querySelector && tr.querySelector('.ti-pur-margin')) || {}).value || ''),\n                        sale:String(((tr.querySelector && tr.querySelector('.ti-pur-sale')) || {}).value || ''),\n                        iva:String(((tr.querySelector && tr.querySelector('.ti-pur-iva')) || {}).value || '22'),\n                        desc:String(((tr.querySelector && tr.querySelector('.ti-pur-note')) || {}).value || '')\n                    };\n                };\n                window.clearPurchaseRows = function(){\n                    const body = byId('ti-purchase-body') || window.ti183ForcePurchaseTableActive();\n                    if (!body) return;\n                    if (body.children.length && window.confirm && !window.confirm('Svuotare tutte le righe acquisizione?')) return;\n                    body.innerHTML = '';\n                    window.addPurchaseManualRow();\n                    window.refreshPurchaseTotals();\n                };\n                window.validatePurchaseRows = function(mark){\n                    const errors = [];\n                    document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr, idx){\n                        tr.classList.remove('is-invalid');\n                        const n = String((tr.querySelector('.ti-pur-name') || {}).value || '').trim();\n                        const q = parseNum((tr.querySelector('.ti-pur-qty') || {}).value || '0');\n                        const ivaEl = tr.querySelector('.ti-pur-iva');\n                        if (ivaEl && !String(ivaEl.value || '').trim()) ivaEl.value = '22';\n                        if (!n || q <= 0) {\n                            if (mark) tr.classList.add('is-invalid');\n                            if (!n) errors.push('Riga ' + (idx + 1) + ': prodotto\/servizio mancante');\n                            if (q <= 0) errors.push('Riga ' + (idx + 1) + ': quantit\u00e0 non valida');\n                        }\n                    });\n                    return errors;\n                };\n                window.purchaseCollectRows = function(){\n                    const rows = [];\n                    document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n                        const item = window.purchaseRowToItem(tr);\n                        if (String(item.name || '').trim()) rows.push(item);\n                    });\n                    return rows;\n                };\n                window.confirmPurchaseRows = function(){\n                    const btn = byId('ti-purchase-confirm-btn');\n                    try {\n                        const errors = window.validatePurchaseRows(true);\n                        if (errors.length) { if (window.tiAlert) window.tiAlert('Correggi le righe acquisizione:\\n' + errors.slice(0, 8).join('\\n')); return; }\n                        const rows = window.purchaseCollectRows();\n                        if (!rows.length) { if (window.tiAlert) window.tiAlert('Inserisci almeno una riga acquisizione.'); return; }\n                        const dbEl = byId('ti-ditta');\n                        const dbVal = dbEl ? dbEl.value : '';\n                        if (!dbVal || dbVal === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona prima una ditta.'); return; }\n                        const source = window.currentDbData;\n                        if (!source || !source.Tabelle) { if (window.tiAlert) window.tiAlert('Database non caricato. Seleziona la ditta e riapri Acquisizioni.'); return; }\n                        if (btn) { btn.disabled = true; btn.dataset.oldText = btn.innerHTML; btn.innerHTML = 'Salvataggio...'; }\n                        const data = JSON.parse(JSON.stringify(source));\n                        const prodTable = realTableName(data, 'Prodotti', 'Prodotti');\n                        const servTable = realTableName(data, 'Servizi', 'Servizi');\n                        const actTable = realTableName(data, 'Attivita', 'Attivita');\n                        if (!data.Tabelle[prodTable]) data.Tabelle[prodTable] = [];\n                        if (!data.Tabelle[servTable]) data.Tabelle[servTable] = [];\n                        if (!data.Tabelle[actTable]) data.Tabelle[actTable] = [];\n                        const now = dateParts();\n                        const nextId = function(table){ return (Array.isArray(data.Tabelle[table]) ? data.Tabelle[table].length : 0) + 1; };\n                        rows.forEach(function(r){\n                            const isServ = String(r.type || 'P') === 'S';\n                            const t = isServ ? servTable : prodTable;\n                            const nameFields = isServ ? ['Servizio','Nome','Descrizione'] : ['Prodotto','Nome','Descrizione'];\n                            const tableRows = Array.isArray(data.Tabelle[t]) ? data.Tabelle[t] : (data.Tabelle[t] = []);\n                            let idx = (r.table === t && r.index >= 0 && tableRows[r.index]) ? r.index : -1;\n                            if (idx < 0) {\n                                const wanted = norm(r.name);\n                                idx = tableRows.findIndex(function(row){ return norm(getField(row, nameFields, '')) === wanted; });\n                            }\n                            let rec;\n                            if (idx >= 0) rec = tableRows[idx];\n                            else { rec = {}; setField(rec, ['ID','Id','id'], nextId(t)); tableRows.push(rec); }\n                            setField(rec, nameFields, r.name);\n                            setField(rec, ['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'], parseNum(r.cost));\n                            setField(rec, ['Margine'], String(r.margin || ''));\n                            const gross = parseNum(r.sale) || saleGross(r.cost, r.margin, r.iva);\n                            setField(rec, ['Prezzo','Prezzo vendita','Prezzo_vendita'], gross);\n                            setField(rec, ['IVA_VAT','IVA','Iva','VAT'], parseNum(r.iva) || 22);\n                            if (!isServ) {\n                                const oldQty = parseNum(getField(rec, ['Quantit\u00e0','Quantita','Disponibilita','Disponibilit\u00e0'], 0));\n                                setField(rec, ['Quantit\u00e0','Quantita'], Math.round((oldQty + parseNum(r.qty)) * 100) \/ 100);\n                            }\n                            const act = {};\n                            setField(act, ['ID','Id','id'], nextId(actTable));\n                            setField(act, ['Username','Utente','user'], window.tiUser || '');\n                            setField(act, ['Descrizione attivit\u00e0','Descrizione attivita','Descrizione','Dettaglio','Note'], 'Acquisizione ' + r.name);\n                            setField(act, ['Prodotto'], r.name);\n                            setField(act, ['Prezzo'], parseNum(r.cost));\n                            setField(act, ['Quantit\u00e0','Quantita'], parseNum(r.qty));\n                            setField(act, ['Totale'], Math.round(parseNum(r.cost) * parseNum(r.qty) * 100) \/ 100);\n                            setField(act, ['Margine'], String(r.margin || ''));\n                            setField(act, ['IVA_VAT','IVA','Iva','VAT'], parseNum(r.iva) || 22);\n                            setField(act, ['Prezzo vendita','Prezzo_vendita'], gross);\n                            setField(act, ['Esito'], 'acquisizione');\n                            setField(act, ['Data'], now.date);\n                            setField(act, ['Ora'], now.time);\n                            setField(act, ['Stato'], 'Attivo');\n                            data.Tabelle[actTable].push(act);\n                        });\n                        const fd = new FormData();\n                        fd.append('ti_action', 'ti_ai_save_full_db');\n                        fd.append('db', dbVal);\n                        fd.append('payload', base64Utf8(JSON.stringify(data)));\n                        const done = function(res){\n                            if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText || 'Conferma righe acquisizione'; }\n                            if (res && res.success) {\n                                window.currentDbData = data;\n                                window.closePurchaseManualFlow();\n                                if (window.tiAlert) window.tiAlert('\u2705 Righe acquisizione confermate e salvate nel database.');\n                                if (res.data && res.data.needs_reload) setTimeout(function(){ location.reload(); }, 900);\n                            } else if (window.tiAlert) window.tiAlert('\u26a0\ufe0f Salvataggio acquisizione non riuscito.');\n                        };\n                        const fail = function(e){\n                            if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText || 'Conferma righe acquisizione'; }\n                            if (window.tiAlert) window.tiAlert('Errore salvataggio acquisizione: ' + ((e && e.message) || e));\n                        };\n                        const url = window.tiAjaxUrl || window.tiUrl;\n                        if (window.fetchJsonSafe) window.fetchJsonSafe(url, {method:'POST', body:fd, credentials:'same-origin'}).then(done).catch(fail);\n                        else fetch(url, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ return r.json(); }).then(done).catch(fail);\n                    } catch(e) {\n                        if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText || 'Conferma righe acquisizione'; }\n                        if (window.tiAlert) window.tiAlert('Errore conferma acquisizione: ' + (e.message || e));\n                    }\n                };\n                window.purchaseSendToChat = function(){ window.confirmPurchaseRows(); };\n\n                document.addEventListener('click', function(ev){\n                    const target = ev.target && ev.target.closest ? ev.target.closest('#ti-purchase-toggle,.ti-purchase-add-row,.ti-ss-add-manual-row') : null;\n                    if (!target) return;\n                    if (target.id === 'ti-purchase-toggle') {\n                        ev.preventDefault();\n                        if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                        window.openPurchaseManualFlow();\n                        return;\n                    }\n                    if (target.classList.contains('ti-purchase-add-row') || target.classList.contains('ti-ss-add-manual-row')) {\n                        ev.preventDefault();\n                        if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                        window.ti183ForceAddPurchaseRow();\n                    }\n                }, true);\n                document.addEventListener('click', function(ev){\n                    const pop = byId('ti-purchase-row-search-popover');\n                    if (!pop) return;\n                    if (pop.contains(ev.target)) return;\n                    if (ev.target && ev.target.closest && ev.target.closest('.ti-purchase-row-search')) return;\n                    window.closePurchaseSearchPopover();\n                });\n                const pbtn = byId('ti-purchase-toggle');\n                if (pbtn) pbtn.onclick = function(ev){ if (ev) ev.preventDefault(); window.openPurchaseManualFlow(); };\n            } catch(e) {\n                try { console.error('Shop & Service purchase base fix 30.9.664 non applicato:', e); } catch(ignore) {}\n            }\n        }\n        if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ setTimeout(ti183InstallPurchaseBaseFix, 0); });\n        else setTimeout(ti183InstallPurchaseBaseFix, 0);\n    })();\n\n\n    <\/script>\n\n<script id=\"ti-purchase-manual-rescue-184\">\n(function(){\n    \"use strict\";\n    var AJAX_URL = \"https:\/\/www.tisoft.it\/wp-admin\/admin-ajax.php\";\n    if (window.__tiPurchaseManualRescue184) return;\n    window.__tiPurchaseManualRescue184 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function norm(v){ return String(v || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').toLowerCase().replace(\/[^a-z0-9]\/g,''); }\n    function num(v){\n        if (v == null) return 0;\n        var s = String(v).trim().replace(\/[\u20ac\\s]\/g,'');\n        if (!s) return 0;\n        if (s.indexOf(',') !== -1 && s.indexOf('.') !== -1) s = s.replace(\/\\.\/g,'').replace(',', '.');\n        else if (s.indexOf(',') !== -1) s = s.replace(',', '.');\n        var n = parseFloat(s.replace(\/[^0-9.\\-]\/g,''));\n        return isNaN(n) ? 0 : n;\n    }\n    function fmt(n){\n        n = Math.round((parseFloat(n) || 0) * 100) \/ 100;\n        try { return n.toLocaleString('it-IT', {minimumFractionDigits:2, maximumFractionDigits:2}); }\n        catch(e){ return String(n.toFixed(2)).replace('.', ','); }\n    }\n    function field(row, names, fallback){\n        row = row || {}; var keys = Object.keys(row);\n        for (var i=0;i<names.length;i++) { var w = norm(names[i]); for (var j=0;j<keys.length;j++) if (norm(keys[j]) === w) return row[keys[j]]; }\n        return fallback;\n    }\n    function setField(row, names, value){\n        row = row || {}; var keys = Object.keys(row);\n        for (var i=0;i<names.length;i++) { var w = norm(names[i]); for (var j=0;j<keys.length;j++) if (norm(keys[j]) === w) { row[keys[j]] = value; return; } }\n        row[names[0]] = value;\n    }\n    function realTable(data, wanted, fallback){\n        var tables = data && data.Tabelle ? data.Tabelle : {}; var keys = Object.keys(tables); var w = norm(wanted);\n        for (var i=0;i<keys.length;i++) if (norm(keys[i]) === w) return keys[i];\n        for (var j=0;j<keys.length;j++) { var k = norm(keys[j]); if (k.indexOf(w) !== -1 || w.indexOf(k) !== -1) return keys[j]; }\n        return fallback || wanted;\n    }\n    function marginNet(cost, margin){\n        cost = num(cost); var m = String(margin || '').trim();\n        if (!m) return Math.max(0, cost);\n        var pct = m.indexOf('%') !== -1; m = m.replace(\/[%\u20ac\\s]\/g,'');\n        var sign = 1; if (m.charAt(0) === '-') { sign = -1; m = m.slice(1); } else if (m.charAt(0) === '+') m = m.slice(1);\n        var v = num(m); return Math.max(0, pct ? cost + cost * sign * v \/ 100 : cost + sign * v);\n    }\n    function grossSale(cost, margin, iva){ iva = num(iva); if (iva <= 0) iva = 22; return Math.round(marginNet(cost, margin) * (1 + iva\/100) * 100) \/ 100; }\n    function base64Utf8(str){ try { return btoa(unescape(encodeURIComponent(str))); } catch(e) { return btoa(str); } }\n    function ajaxForm(tiAction, extra){\n        var fd = new FormData(); fd.append('ti_action', tiAction);\n        Object.keys(extra || {}).forEach(function(k){ fd.append(k, extra[k]); });\n        var url = window.tiAjaxUrl || window.tiUrl || AJAX_URL;\n        if (window.fetchJsonSafe) return window.fetchJsonSafe(url, {method:'POST', body:fd, credentials:'same-origin'});\n        return fetch(url, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ return r.json(); });\n    }\n    function selectedDb(){ var el = byId('ti-ditta'); return el ? String(el.value || '') : ''; }\n    function loadDb(){\n        if (window.currentDbData && window.currentDbData.Tabelle) {\n            try { if (window.refreshShopServiceActivationButton) window.refreshShopServiceActivationButton(); } catch(e) {}\n            return Promise.resolve(window.currentDbData);\n        }\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') return Promise.resolve(window.currentDbData || {Tabelle:{}});\n        return ajaxForm('ti_ai_get_db_data', {db:db}).then(function(res){ if (res && res.success) window.currentDbData = res.data; return window.currentDbData || {Tabelle:{}}; }).catch(function(){ return window.currentDbData || {Tabelle:{}}; });\n    }\n\n    function injectCss(){\n        if (byId('ti-purchase-rescue-184-css')) return;\n        var st = document.createElement('style'); st.id = 'ti-purchase-rescue-184-css';\n        st.textContent = '#ti-purchase-ov.ti-purchase-rescue-open{display:flex!important;align-items:center!important;justify-content:center!important;pointer-events:auto!important;z-index:2147482000!important}'\n        + '#ti-purchase-ov .ti-purchase-modal{width:min(1480px,98vw)!important;max-width:98vw!important;max-height:92vh!important;overflow:auto!important;background:#0f172a!important;color:#fff!important;border-radius:16px!important;padding:18px!important;box-sizing:border-box!important}'\n        + '#ti-purchase-ov .ti-purchase-table-wrap{display:block!important;width:100%!important;max-width:100%!important;overflow-x:auto!important;overflow-y:visible!important;-webkit-overflow-scrolling:touch!important;touch-action:pan-x pan-y!important;border:1px solid #334155!important;border-radius:12px!important}'\n        + '#ti-purchase-ov #ti-purchase-table{display:table!important;width:100%!important;min-width:1240px!important;border-collapse:collapse!important;background:#020617!important}'\n        + '#ti-purchase-ov #ti-purchase-table thead{display:table-header-group!important}#ti-purchase-ov #ti-purchase-table tbody{display:table-row-group!important}#ti-purchase-ov #ti-purchase-table tr{display:table-row!important}#ti-purchase-ov #ti-purchase-table th,#ti-purchase-ov #ti-purchase-table td{display:table-cell!important;white-space:nowrap!important;vertical-align:middle!important}'\n        + '#ti-purchase-ov input,#ti-purchase-ov select,#ti-purchase-ov textarea{background:#0f172a!important;color:#fff!important;-webkit-text-fill-color:#fff!important;caret-color:#fff!important;border:1px solid #334155!important}'\n        + '#ti-purchase-row-pop-184{position:fixed!important;z-index:2147483647!important;background:#020617!important;border:1px solid #38bdf8!important;border-radius:10px!important;box-shadow:0 16px 44px rgba(0,0,0,.65)!important;max-height:min(320px,52vh)!important;overflow:auto!important;padding:6px!important;min-width:230px!important;max-width:min(92vw,560px)!important;color:#fff!important;pointer-events:auto!important;-webkit-overflow-scrolling:touch!important}'\n        + '#ti-purchase-row-pop-184 button{display:block!important;width:100%!important;text-align:left!important;margin:0 0 5px!important;padding:7px 8px!important;border-radius:8px!important;border:1px solid #334155!important;background:#1e293b!important;color:#fff!important;font-size:12px!important;line-height:1.25!important;cursor:pointer!important}'\n        + '#ti-purchase-row-pop-184 small{display:block!important;color:#cbd5e1!important;font-size:10.5px!important;margin-top:2px!important}'\n        + '#ti-purchase-total{display:grid!important;grid-template-columns:repeat(4,minmax(120px,1fr))!important;gap:8px!important;margin-top:10px!important}.ti-purchase-summary-card{background:#020617!important;border:1px solid #334155!important;border-radius:10px!important;padding:8px!important;color:#e5e7eb!important;font-size:12px!important}.ti-purchase-summary-card b{display:block!important;color:#bbf7d0!important;font-size:15px!important;margin-top:2px!important}'\n        + '@media (max-width:767px) and (orientation:portrait){#ti-purchase-ov .ti-purchase-modal{width:98vw!important;max-width:98vw!important;padding:10px!important}#ti-purchase-ov #ti-purchase-table{min-width:1060px!important}#ti-purchase-ov #ti-purchase-table th,#ti-purchase-ov #ti-purchase-table td{font-size:10.5px!important;padding:4px!important}#ti-purchase-ov #ti-purchase-table input,#ti-purchase-ov #ti-purchase-table select,#ti-purchase-ov #ti-purchase-table button{font-size:10.5px!important;padding:4px!important;min-height:27px!important}#ti-purchase-ov .ti-pur-name{min-width:190px!important}#ti-purchase-row-pop-184 button{font-size:10.5px!important;padding:6px!important}#ti-purchase-row-pop-184 small{font-size:9.5px!important}}'\n        + '@media (max-width:920px) and (orientation:landscape){#ti-purchase-ov .ti-purchase-modal{width:98vw!important;max-width:98vw!important;padding:10px!important}#ti-purchase-ov #ti-purchase-table{min-width:980px!important}#ti-purchase-ov #ti-purchase-table th,#ti-purchase-ov #ti-purchase-table td{font-size:10px!important;padding:3px!important}#ti-purchase-ov #ti-purchase-table input,#ti-purchase-ov #ti-purchase-table select,#ti-purchase-ov #ti-purchase-table button{font-size:10px!important;padding:3px!important;min-height:25px!important}}';\n        document.head.appendChild(st);\n    }\n\n    function ensureModal(){\n        injectCss();\n        var ov = byId('ti-purchase-ov');\n        if (ov && ov.dataset && ov.dataset.rescue184 === '1') return ov;\n        if (ov && ov.parentNode) ov.parentNode.removeChild(ov);\n        ov = document.createElement('div');\n        ov.id = 'ti-purchase-ov'; ov.className = 'ti-modal-overlay ti-ov ti-closable-ov'; ov.dataset.rescue184 = '1';\n        ov.style.display = 'none'; ov.style.zIndex = '2147482000';\n        ov.innerHTML = '<div class=\"ti-modal ti-purchase-modal\">'\n            + '<div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px\"><div><h2 style=\"margin:0;font-size:22px\">Acquisizioni<\/h2><div style=\"font-size:14px;color:#cbd5e1;margin-top:4px\">Tabella acquisizione prodotti e servizi. Il costo \u00e8 netto IVA; il prezzo vendita proposto include margine e IVA.<\/div><\/div><button type=\"button\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff\" onclick=\"window.closePurchaseManualFlow()\">X<\/button><\/div>'\n            + '<div style=\"display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 14px 0\"><button type=\"button\" class=\"ti-btn ti-purchase-add-row ti-ss-add-manual-row\" style=\"background:#22c55e;color:#052e16;font-weight:700\">+ Aggiungi riga manuale<\/button><button type=\"button\" class=\"ti-btn\" style=\"background:#f59e0b;color:#111827;font-weight:700\" onclick=\"window.pickPurchaseImportFile&&window.pickPurchaseImportFile()\">Import file acquisizioni<\/button><button type=\"button\" class=\"ti-btn\" style=\"background:#64748b;color:#fff;font-weight:700\" onclick=\"window.clearPurchaseRows()\">Svuota righe<\/button><\/div>'\n            + '<div class=\"ti-purchase-table-wrap\"><table id=\"ti-purchase-table\"><thead><tr style=\"background:#1e293b\"><th>Prodotto o servizio<\/th><th>Codice<\/th><th>Tipo<\/th><th>Q.t\u00e0<\/th><th>Costo netto<\/th><th>Margine<\/th><th>Prezzo vendita IVA incl.<\/th><th>IVA %<\/th><th>Tot. acquisizione netta<\/th><th>Tot. vendita<\/th><th>Note<\/th><th>Azioni<\/th><\/tr><\/thead><tbody id=\"ti-purchase-body\"><\/tbody><\/table><\/div>'\n            + '<div id=\"ti-purchase-total\" aria-live=\"polite\"><\/div><div style=\"display:flex;justify-content:center;gap:8px;margin-top:14px;flex-wrap:wrap;position:sticky;bottom:0;background:#0f172a;padding-top:10px;border-top:1px solid #334155\"><button type=\"button\" id=\"ti-purchase-confirm-btn\" class=\"ti-btn\" style=\"background:#38bdf8;color:#082f49;font-weight:800\" onclick=\"window.confirmPurchaseRows()\">Conferma righe acquisizione<\/button><button type=\"button\" class=\"ti-btn btn-close\" onclick=\"window.closePurchaseManualFlow()\">Chiudi<\/button><\/div><\/div>';\n        document.body.appendChild(ov);\n        return ov;\n    }\n    function showModal(){ var ov = ensureModal(); ov.classList.add('ti-purchase-rescue-open','ti-modal-open'); ov.style.display='flex'; ov.style.pointerEvents='auto'; ov.setAttribute('aria-hidden','false'); return ov; }\n    function closeModal(){ closePopover(); var ov=byId('ti-purchase-ov'); if(ov){ ov.classList.remove('ti-purchase-rescue-open','ti-modal-open'); ov.style.display='none'; ov.style.pointerEvents='none'; } }\n    function getBody(){ return ensureModal().querySelector('#ti-purchase-body'); }\n\n    function catalog(){\n        var data = window.currentDbData || {}; var tables = data.Tabelle || {}; var out = [];\n        function add(table, type, rows){ if (!Array.isArray(rows)) return; rows.forEach(function(r, idx){ var name = field(r, type === 'S' ? ['Servizio','Nome','Descrizione'] : ['Prodotto','Nome','Descrizione'], ''); if (!String(name||'').trim()) return; out.push({table:table,index:idx,type:type,typeLabel:type==='S'?'Servizio':'Prodotto',name:String(name),code:String(field(r,['Codice','Codice prodotto','Codice servizio','SKU','AIC','BARCode'], '')||''),desc:String(field(r,['Descrizione','Note','Nota'], '')||''),cost:num(field(r,['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'],0)),sale:num(field(r,['Prezzo','Prezzo vendita','Prezzo_vendita'],0)),iva:num(field(r,['IVA_VAT','IVA','Iva','VAT'],22))||22}); }); }\n        Object.keys(tables).forEach(function(t){ var nt = norm(t); if (nt.indexOf('serviz') !== -1) add(t,'S',tables[t]); else if (nt.indexOf('prodott') !== -1 || nt === 'listino') add(t,'P',tables[t]); });\n        return out;\n    }\n    function closePopover(){ var p = byId('ti-purchase-row-pop-184'); if (p) p.remove(); }\n    function selectItem(item, row){\n        row = row || window.__tiPurchaseActiveRow184; if (!row || !item) return;\n        row.dataset.catalogTable = item.table || ''; row.dataset.catalogIndex = String(item.index != null ? item.index : -1); row.dataset.targetType = item.type === 'S' ? 'servizio' : 'prodotto';\n        function val(sel,v){ var el=row.querySelector(sel); if(el) el.value = v == null ? '' : String(v).replace('.', ','); }\n        val('.ti-pur-name', item.name || ''); val('.ti-pur-code', item.code || ''); val('.ti-pur-type', item.type === 'S' ? 'S' : 'P'); val('.ti-pur-cost', item.cost || ''); val('.ti-pur-iva', item.iva || 22); val('.ti-pur-note', item.desc || '');\n        var sale = row.querySelector('.ti-pur-sale'); if (sale) { sale.value = item.sale ? String(item.sale).replace('.', ',') : ''; sale.dataset.auto = item.sale ? '0' : '1'; }\n        recalcRow(row, !item.sale); totals(); closePopover();\n    }\n    function showSearch(input){\n        if (!input) return; var row = input.closest('tr'); window.__tiPurchaseActiveRow184 = row;\n        var q = String(input.value || '').toLowerCase().trim(); var list = catalog().filter(function(it){ return !q || (it.name + ' ' + it.code + ' ' + it.desc + ' ' + it.typeLabel).toLowerCase().indexOf(q) !== -1; }).slice(0, q ? 40 : 20);\n        closePopover(); if (!list.length) return;\n        var pop = document.createElement('div'); pop.id = 'ti-purchase-row-pop-184';\n        list.forEach(function(it){ var b = document.createElement('button'); b.type='button'; b.innerHTML = '<b>' + esc(it.typeLabel) + ' - ' + esc(it.name) + '<\/b><small>' + (it.code ? 'Codice ' + esc(it.code) + ' - ' : '') + esc(it.table) + ' - costo ' + fmt(it.cost) + ' - prezzo ' + fmt(it.sale) + ' - IVA ' + fmt(it.iva) + '%<\/small>'; var choose=function(ev){ if(ev){ev.preventDefault();ev.stopPropagation();} selectItem(it,row); }; b.addEventListener('pointerdown', choose); b.addEventListener('click', choose); pop.appendChild(b); });\n        document.body.appendChild(pop); var r = input.getBoundingClientRect(); var w = Math.max(r.width, Math.min(560, window.innerWidth - 24)); var left = Math.max(8, Math.min(r.left, window.innerWidth - w - 8)); var top = r.bottom + 6; setTimeout(function(){ var h=pop.offsetHeight||260; if(top+h>window.innerHeight-8) top=Math.max(8,r.top-h-6); pop.style.left=left+'px'; pop.style.top=top+'px'; pop.style.width=w+'px'; },0);\n    }\n    function rowItem(tr){ return {table:tr.dataset.catalogTable||'', index:parseInt(tr.dataset.catalogIndex||'-1',10), type:(tr.querySelector('.ti-pur-type')||{}).value||'P', name:(tr.querySelector('.ti-pur-name')||{}).value||'', code:(tr.querySelector('.ti-pur-code')||{}).value||'', qty:(tr.querySelector('.ti-pur-qty')||{}).value||'1', cost:(tr.querySelector('.ti-pur-cost')||{}).value||'', margin:(tr.querySelector('.ti-pur-margin')||{}).value||'', sale:(tr.querySelector('.ti-pur-sale')||{}).value||'', iva:(tr.querySelector('.ti-pur-iva')||{}).value||'22', desc:(tr.querySelector('.ti-pur-note')||{}).value||''}; }\n    function recalcRow(row, force){\n        if (!row) return; var qty=num((row.querySelector('.ti-pur-qty')||{}).value||0); var cost=num((row.querySelector('.ti-pur-cost')||{}).value||0); var margin=(row.querySelector('.ti-pur-margin')||{}).value||''; var iva=(row.querySelector('.ti-pur-iva')||{}).value||'22'; var saleEl=row.querySelector('.ti-pur-sale'); var sale=grossSale(cost, margin, iva);\n        if (saleEl && (force || saleEl.dataset.auto === '1' || document.activeElement !== saleEl)) { saleEl.value = sale ? String(sale).replace('.', ',') : ''; saleEl.dataset.auto='1'; }\n        var saleVal = saleEl ? (num(saleEl.value) || sale) : sale; var net=row.querySelector('.ti-pur-row-total-net'); var gross=row.querySelector('.ti-pur-row-total-gross'); if(net) net.textContent=fmt(qty*cost); if(gross) gross.textContent=fmt(qty*saleVal);\n    }\n    function totals(){\n        var rows=0, qty=0, net=0, gross=0; document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){ recalcRow(tr,false); rows++; qty += num((tr.querySelector('.ti-pur-qty')||{}).value||0); net += num((tr.querySelector('.ti-pur-qty')||{}).value||0) * num((tr.querySelector('.ti-pur-cost')||{}).value||0); gross += num((tr.querySelector('.ti-pur-qty')||{}).value||0) * num((tr.querySelector('.ti-pur-sale')||{}).value||0); });\n        var out=byId('ti-purchase-total'); if(out) out.innerHTML='<div class=\"ti-purchase-summary-card\">Righe<b>'+rows+'<\/b><\/div><div class=\"ti-purchase-summary-card\">Quantit\u00e0<b>'+fmt(qty)+'<\/b><\/div><div class=\"ti-purchase-summary-card\">Totale acquisizione netta<b>\u20ac '+fmt(net)+'<\/b><\/div><div class=\"ti-purchase-summary-card\">Totale vendita IVA incl.<b>\u20ac '+fmt(gross)+'<\/b><\/div>';\n    }\n    function addRow(item){\n        var body = getBody(); if (!body) return; showModal(); item = item || {}; var tr=document.createElement('tr'); tr.className='ti-purchase-row'; tr.dataset.catalogTable=item.table||''; tr.dataset.catalogIndex=String(item.index!=null?item.index:-1); tr.dataset.targetType=item.type==='S'?'servizio':'prodotto';\n        var cost=item.cost?String(item.cost).replace('.', ','):''; var sale=item.sale?String(item.sale).replace('.', ','):''; var iva=item.iva||'22';\n        tr.innerHTML='<td><input class=\"ti-pur-name ti-purchase-row-search\" value=\"'+esc(item.name||'')+'\" placeholder=\"Cerca prodotto o servizio\" autocomplete=\"off\" style=\"width:100%;min-width:230px;box-sizing:border-box;padding:8px;border-radius:8px\"><\/td><td><input class=\"ti-pur-code\" value=\"'+esc(item.code||'')+'\" placeholder=\"Codice\" autocomplete=\"off\" style=\"width:110px;padding:8px;border-radius:8px\"><\/td><td><select class=\"ti-pur-type\" style=\"width:76px;padding:8px;border-radius:8px\"><option value=\"P\" '+(item.type==='S'?'':'selected')+'>P<\/option><option value=\"S\" '+(item.type==='S'?'selected':'')+'>S<\/option><\/select><\/td><td><input class=\"ti-pur-qty\" value=\"'+esc(item.qty||'1')+'\" inputmode=\"decimal\" style=\"width:72px;text-align:right;padding:8px;border-radius:8px\"><\/td><td><input class=\"ti-pur-cost\" value=\"'+esc(cost)+'\" inputmode=\"decimal\" style=\"width:100px;text-align:right;padding:8px;border-radius:8px\"><\/td><td><input class=\"ti-pur-margin\" value=\"'+esc(item.margin||'')+'\" placeholder=\"+10%\" style=\"width:86px;text-align:right;padding:8px;border-radius:8px\"><\/td><td><input class=\"ti-pur-sale\" data-auto=\"'+(sale?'0':'1')+'\" value=\"'+esc(sale)+'\" inputmode=\"decimal\" style=\"width:112px;text-align:right;padding:8px;border-radius:8px\"><\/td><td><input class=\"ti-pur-iva\" value=\"'+esc(iva)+'\" inputmode=\"decimal\" style=\"width:68px;text-align:right;padding:8px;border-radius:8px\"><\/td><td style=\"text-align:right\"><span class=\"ti-pur-row-total-net\">0,00<\/span><\/td><td style=\"text-align:right\"><span class=\"ti-pur-row-total-gross\">0,00<\/span><\/td><td><input class=\"ti-pur-note\" value=\"'+esc(item.desc||'')+'\" style=\"width:180px;padding:8px;border-radius:8px\"><\/td><td style=\"text-align:center\"><button type=\"button\" class=\"ti-btn ti-pur-dup\" style=\"background:#64748b;color:#fff;margin-right:4px\">Duplica<\/button><button type=\"button\" class=\"ti-btn ti-pur-del\" style=\"background:#dc2626;color:#fff\">X<\/button><\/td>';\n        body.appendChild(tr); var name=tr.querySelector('.ti-pur-name'); if(name){ name.addEventListener('input', function(){ showSearch(name); }); name.addEventListener('focus', function(){ showSearch(name); }); }\n        tr.querySelectorAll('input,select').forEach(function(el){ if(!el.classList.contains('ti-purchase-row-search')) el.addEventListener('input', function(){ if(el.classList.contains('ti-pur-sale')) el.dataset.auto='0'; recalcRow(tr,false); totals(); }); });\n        var del=tr.querySelector('.ti-pur-del'); if(del) del.addEventListener('click', function(){ tr.remove(); if(!body.children.length) addRow(); totals(); }); var dup=tr.querySelector('.ti-pur-dup'); if(dup) dup.addEventListener('click', function(){ addRow(rowItem(tr)); }); recalcRow(tr,!sale); totals(); if(!item.name && name) setTimeout(function(){ try{name.focus();}catch(e){} }, 50);\n    }\n    function openFlow(){ loadDb().then(function(){ showModal(); var body=getBody(); if(body && !body.children.length) addRow(); totals(); }).catch(function(errCatch){ var msg='Acquisizioni: errore apertura flusso - ' + (errCatch && errCatch.message ? errCatch.message : String(errCatch)); try { if (window.log1088) window.log1088(msg); } catch(eLog){} try { if (window.console && console.error) console.error(msg, errCatch); } catch(eConsole){} }); }\n    function clearRows(){ var body=getBody(); if(!body) return; if(body.children.length && window.confirm && !window.confirm('Svuotare tutte le righe acquisizione?')) return; body.innerHTML=''; addRow(); totals(); }\n    function collect(){ var rows=[]; document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){ var it=rowItem(tr); if(String(it.name||'').trim()) rows.push(it); }); return rows; }\n    function validate(){ var err=[]; document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr,i){ var n=String((tr.querySelector('.ti-pur-name')||{}).value||'').trim(); var q=num((tr.querySelector('.ti-pur-qty')||{}).value||0); var iva=tr.querySelector('.ti-pur-iva'); if(iva && !String(iva.value||'').trim()) iva.value='22'; if(!n) err.push('Riga '+(i+1)+': prodotto\/servizio mancante'); if(q<=0) err.push('Riga '+(i+1)+': quantit\u00e0 non valida'); }); return err; }\n    function confirmRows(){\n        var btn=byId('ti-purchase-confirm-btn'); var err=validate(); if(err.length){ if(window.tiAlert) window.tiAlert('Correggi le righe acquisizione:\\n'+err.slice(0,8).join('\\n')); else alert(err.join('\\n')); return; }\n        var rows=collect(); if(!rows.length){ if(window.tiAlert) window.tiAlert('Inserisci almeno una riga acquisizione.'); else alert('Inserisci almeno una riga acquisizione.'); return; }\n        var db=selectedDb(); if(!db || db==='NEW_DB'){ if(window.tiAlert) window.tiAlert('Seleziona prima una ditta.'); else alert('Seleziona prima una ditta.'); return; }\n        loadDb().then(function(source){ if(!source || !source.Tabelle){ throw new Error('Database non caricato'); } if(btn){ btn.disabled=true; btn.dataset.oldText=btn.innerHTML; btn.innerHTML='Salvataggio...'; }\n            var data=JSON.parse(JSON.stringify(source)); var prod=realTable(data,'Prodotti','Prodotti'); var serv=realTable(data,'Servizi','Servizi'); var act=realTable(data,'Attivita','Attivita'); if(!data.Tabelle[prod]) data.Tabelle[prod]=[]; if(!data.Tabelle[serv]) data.Tabelle[serv]=[]; if(!data.Tabelle[act]) data.Tabelle[act]=[];\n            var d=new Date(); var date=String(d.getDate()).padStart(2,'0')+'\/'+String(d.getMonth()+1).padStart(2,'0')+'\/'+d.getFullYear(); var time=String(d.getHours()).padStart(2,'0')+':'+String(d.getMinutes()).padStart(2,'0'); var nextId=function(t){ return (Array.isArray(data.Tabelle[t])?data.Tabelle[t].length:0)+1; };\n            rows.forEach(function(r){ var isS=String(r.type||'P')==='S'; var t=isS?serv:prod; var names=isS?['Servizio','Nome','Descrizione']:['Prodotto','Nome','Descrizione']; var arr=Array.isArray(data.Tabelle[t])?data.Tabelle[t]:(data.Tabelle[t]=[]); var idx=(r.table===t && r.index>=0 && arr[r.index])?r.index:-1; if(idx<0){ var wanted=norm(r.name); idx=arr.findIndex(function(x){ return norm(field(x,names,''))===wanted; }); } var rec=idx>=0?arr[idx]:{}; if(idx<0){ setField(rec,['ID','Id','id'],nextId(t)); arr.push(rec); } setField(rec,names,r.name); setField(rec,['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'],num(r.cost)); setField(rec,['Margine'],String(r.margin||'')); var sale=num(r.sale)||grossSale(r.cost,r.margin,r.iva); setField(rec,['Prezzo','Prezzo vendita','Prezzo_vendita'],sale); setField(rec,['IVA_VAT','IVA','Iva','VAT'],num(r.iva)||22); if(!isS){ var old=num(field(rec,['Quantit\u00e0','Quantita','Disponibilita','Disponibilit\u00e0'],0)); setField(rec,['Quantit\u00e0','Quantita'],Math.round((old+num(r.qty))*100)\/100); } var a={}; setField(a,['ID','Id','id'],nextId(act)); setField(a,['Username','Utente','user'],window.tiUser||''); setField(a,['Descrizione attivit\u00e0','Descrizione attivita','Descrizione','Dettaglio','Note'],'Acquisizione '+r.name); setField(a,['Prodotto'],r.name); setField(a,['Prezzo'],num(r.cost)); setField(a,['Quantit\u00e0','Quantita'],num(r.qty)); setField(a,['Totale'],Math.round(num(r.cost)*num(r.qty)*100)\/100); setField(a,['Margine'],String(r.margin||'')); setField(a,['IVA_VAT','IVA','Iva','VAT'],num(r.iva)||22); setField(a,['Prezzo vendita','Prezzo_vendita'],sale); setField(a,['Esito'],'acquisizione'); setField(a,['Data'],date); setField(a,['Ora'],time); setField(a,['Stato'],'Attivo'); data.Tabelle[act].push(a); });\n            return ajaxForm('ti_ai_save_full_db', {db:db, payload:base64Utf8(JSON.stringify(data))}).then(function(res){ if(btn){btn.disabled=false;btn.innerHTML=btn.dataset.oldText||'Conferma righe acquisizione';} if(res && res.success){ window.currentDbData=data; closeModal(); if(window.tiAlert) window.tiAlert('\u2705 Righe acquisizione confermate e salvate nel database.'); else alert('Righe acquisizione confermate.'); if(res.data && res.data.needs_reload) setTimeout(function(){ location.reload(); },900); } else { if(window.tiAlert) window.tiAlert('\u26a0\ufe0f Salvataggio acquisizione non riuscito.'); else alert('Salvataggio acquisizione non riuscito.'); } });\n        }).catch(function(e){ if(btn){btn.disabled=false;btn.innerHTML=btn.dataset.oldText||'Conferma righe acquisizione';} if(window.tiAlert) window.tiAlert('Errore conferma acquisizione: '+(e.message||e)); else alert('Errore conferma acquisizione: '+(e.message||e)); });\n    }\n\n    window.ensurePurchaseModal = ensureModal;\n    window.openPurchaseManualFlow = openFlow;\n    window.addPurchaseManualRow = addRow;\n    window.ti183ForceAddPurchaseRow = function(ev){ if(ev){ ev.preventDefault(); ev.stopPropagation(); } addRow(); };\n    window.ti183ForcePurchaseTableActive = function(){ showModal(); var body=getBody(); if(body && !body.children.length) addRow(); totals(); return body; };\n    window.closePurchaseManualFlow = closeModal;\n    window.clearPurchaseRows = clearRows;\n    window.confirmPurchaseRows = confirmRows;\n    window.purchaseSendToChat = confirmRows;\n    window.refreshPurchaseTotals = totals;\n    window.recalcPurchaseRow = recalcRow;\n\n    function isAddButton(el){ return el && el.closest && el.closest('.ti-purchase-add-row,.ti-ss-add-manual-row'); }\n    function isPurchaseButton(el){\n        if (!el || !el.closest) return null;\n        var b = el.closest('#ti-purchase-toggle,button,a'); if(!b) return null;\n        var txt = String(b.textContent || '').toLowerCase();\n        if (b.id === 'ti-purchase-toggle') return b;\n        if (txt.indexOf('aggiungi riga manuale') !== -1) return null;\n        if (txt.indexOf('import') !== -1) return null;\n        if (txt.indexOf('acquisizioni') !== -1 || txt.indexOf('acquisizione') !== -1 || txt.indexOf('acquisti') !== -1 || txt.indexOf('acquisto') !== -1) return b;\n        return null;\n    }\n    document.addEventListener('click', function(ev){\n        var add = isAddButton(ev.target); if(add){ ev.preventDefault(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); addRow(); return; }\n        var p = isPurchaseButton(ev.target); if(p){ ev.preventDefault(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); openFlow(); }\n    }, true);\n    document.addEventListener('click', function(ev){ var pop=byId('ti-purchase-row-pop-184'); if(pop && !pop.contains(ev.target) && !(ev.target.closest && ev.target.closest('.ti-purchase-row-search'))) closePopover(); });\n    function bindButtons(){\n        var b=byId('ti-purchase-toggle');\n        if(b && !b.__tiPurchaseBound184){ b.__tiPurchaseBound184=true; b.onclick=function(ev){ if(ev) ev.preventDefault(); openFlow(); return false; }; }\n        document.querySelectorAll('.ti-purchase-add-row,.ti-ss-add-manual-row').forEach(function(x){\n            if(x.__tiPurchaseBound184) return;\n            x.__tiPurchaseBound184=true;\n            x.onclick=function(ev){ if(ev) ev.preventDefault(); addRow(); return false; };\n        });\n    }\n    if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bindButtons, {once:true}); else bindButtons();\n    \/\/ I pulsanti dinamici sono gia gestiti dal listener delegato document.addEventListener('click', ...).\n})();\n<\/script>\n\n\n<style id=\"ti-dark-input-and-purchase-close-185\">\n#ti-ai-outer input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n#ti-ai-outer textarea,\n#ti-ai-outer select,\n#ti-plugin-modal-root input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n#ti-plugin-modal-root textarea,\n#ti-plugin-modal-root select,\n#ti-mobile-direct-login input,\n#ti-mobile-direct-login select,\n.ti-ov input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n.ti-ov textarea,\n.ti-ov select,\n.ti-in,\n.ti-msg {\n    background:#020617 !important;\n    color:#ffffff !important;\n    -webkit-text-fill-color:#ffffff !important;\n    caret-color:#ffffff !important;\n    border-color:#334155 !important;\n}\n#ti-ai-outer input:focus,\n#ti-ai-outer textarea:focus,\n#ti-ai-outer select:focus,\n#ti-plugin-modal-root input:focus,\n#ti-plugin-modal-root textarea:focus,\n#ti-plugin-modal-root select:focus,\n#ti-mobile-direct-login input:focus,\n#ti-mobile-direct-login select:focus,\n.ti-ov input:focus,\n.ti-ov textarea:focus,\n.ti-ov select:focus,\n.ti-in:focus,\n.ti-msg:focus {\n    background:#000000 !important;\n    color:#ffffff !important;\n    -webkit-text-fill-color:#ffffff !important;\n    caret-color:#ffffff !important;\n    outline:2px solid rgba(56,189,248,.45) !important;\n    outline-offset:1px !important;\n}\n#ti-ai-outer input::placeholder,\n#ti-ai-outer textarea::placeholder,\n#ti-plugin-modal-root input::placeholder,\n#ti-plugin-modal-root textarea::placeholder,\n#ti-mobile-direct-login input::placeholder,\n.ti-ov input::placeholder,\n.ti-ov textarea::placeholder,\n.ti-in::placeholder,\n.ti-msg::placeholder {\n    color:#cbd5e1 !important;\n    -webkit-text-fill-color:#cbd5e1 !important;\n    opacity:1 !important;\n}\n#ti-ai-outer select option,\n#ti-plugin-modal-root select option,\n#ti-mobile-direct-login select option,\n.ti-ov select option,\n.ti-in option {\n    background:#020617 !important;\n    color:#ffffff !important;\n}\n#ti-ai-outer input:-webkit-autofill,\n#ti-ai-outer input:-webkit-autofill:hover,\n#ti-ai-outer input:-webkit-autofill:focus,\n#ti-plugin-modal-root input:-webkit-autofill,\n#ti-plugin-modal-root input:-webkit-autofill:hover,\n#ti-plugin-modal-root input:-webkit-autofill:focus,\n#ti-mobile-direct-login input:-webkit-autofill,\n#ti-mobile-direct-login input:-webkit-autofill:hover,\n#ti-mobile-direct-login input:-webkit-autofill:focus,\n.ti-ov input:-webkit-autofill,\n.ti-ov input:-webkit-autofill:hover,\n.ti-ov input:-webkit-autofill:focus {\n    -webkit-text-fill-color:#ffffff !important;\n    caret-color:#ffffff !important;\n    box-shadow:0 0 0 1000px #020617 inset !important;\n    transition:background-color 9999s ease-in-out 0s !important;\n}\n#ti-purchase-ov [data-ti-purchase-close=\"1\"],\n#ti-purchase-ov .ti-purchase-close-185 {\n    cursor:pointer !important;\n    pointer-events:auto !important;\n}\n<\/style>\n<script id=\"ti-purchase-close-and-input-fix-185\">\n(function(){\n    \"use strict\";\n    if (window.__tiPurchaseCloseInputFix185) return;\n    window.__tiPurchaseCloseInputFix185 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function safeText(el){ return String((el && el.textContent) || '').trim().toLowerCase(); }\n\n    function hardClosePurchase(){\n        try { if (typeof window.closePopover === 'function') window.closePopover(); } catch(ignore) {}\n        var pop = byId('ti-purchase-row-pop-184');\n        if (pop && pop.parentNode) pop.parentNode.removeChild(pop);\n        var ov = byId('ti-purchase-ov');\n        if (ov) {\n            ov.classList.remove('ti-purchase-rescue-open','ti-modal-open','ti-open','open','active','show');\n            ov.style.setProperty('display','none','important');\n            ov.style.setProperty('pointer-events','none','important');\n            ov.setAttribute('aria-hidden','true');\n        }\n        document.documentElement.classList.remove('ti-modal-open','ti-purchase-rescue-open');\n        document.body.classList.remove('ti-modal-open','ti-purchase-rescue-open');\n        document.body.style.removeProperty('overflow');\n        return false;\n    }\n\n    window.closePurchaseManualFlow = hardClosePurchase;\n    window.tiClosePurchaseManualFlow = hardClosePurchase;\n\n    function markPurchaseCloseButtons(){\n        var ov = byId('ti-purchase-ov');\n        if (!ov) return;\n        ov.querySelectorAll('button').forEach(function(btn){\n            var t = safeText(btn);\n            var hasCloseCall = \/closePurchaseManualFlow|tiClosePurchaseManualFlow|closeModal\\(['\\\"]ti-purchase-ov\/.test(String(btn.getAttribute('onclick') || ''));\n            if (hasCloseCall || t === 'x' || t === 'chiudi' || t === 'annulla') {\n                btn.setAttribute('data-ti-purchase-close','1');\n                btn.classList.add('ti-purchase-close-185');\n                btn.onclick = function(ev){\n                    if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }\n                    return hardClosePurchase();\n                };\n            }\n        });\n    }\n\n    document.addEventListener('click', function(ev){\n        var target = ev.target;\n        if (!target || !target.closest) return;\n        var ov = byId('ti-purchase-ov');\n        if (!ov || !ov.contains(target)) return;\n        var btn = target.closest('button,[role=\"button\"],.btn-close,.ti-btn');\n        if (!btn) return;\n        var t = safeText(btn);\n        var attr = String(btn.getAttribute('data-ti-purchase-close') || '');\n        var inline = String(btn.getAttribute('onclick') || '');\n        if (attr === '1' || \/closePurchaseManualFlow|tiClosePurchaseManualFlow|closeModal\\(['\\\"]ti-purchase-ov\/.test(inline) || t === 'x' || t === 'chiudi' || t === 'annulla') {\n            ev.preventDefault();\n            ev.stopPropagation();\n            if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n            hardClosePurchase();\n        }\n    }, true);\n\n    document.addEventListener('keydown', function(ev){\n        if (ev.key === 'Escape') {\n            var ov = byId('ti-purchase-ov');\n            if (ov && (ov.classList.contains('ti-purchase-rescue-open') || ov.style.display !== 'none')) hardClosePurchase();\n        }\n    }, true);\n\n    function restyleDarkInputs(){\n        var roots = [byId('ti-ai-outer'), byId('ti-plugin-modal-root'), document.body];\n        roots.forEach(function(root){\n            if (!root) return;\n            root.querySelectorAll('input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]), textarea, select').forEach(function(el){\n                el.style.setProperty('background','#020617','important');\n                el.style.setProperty('color','#ffffff','important');\n                el.style.setProperty('-webkit-text-fill-color','#ffffff','important');\n                el.style.setProperty('caret-color','#ffffff','important');\n                if (!el.style.borderColor || el.style.borderColor === 'transparent') el.style.setProperty('border-color','#334155','important');\n            });\n        });\n    }\n\n    function boot(){ markPurchaseCloseButtons(); }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, {once:true});\n    else boot();\n    \/\/ 30.9.1483: nessun observer globale. La chiusura dinamica resta coperta dalla delegazione click\/keydown.\n})();\n<\/script>\n\n\n<style id=\"ti-login-input-purchase-fix-186-css\">\n#ti-ai-outer input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n#ti-ai-outer textarea,\n#ti-ai-outer select,\n#ti-plugin-modal-root input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n#ti-plugin-modal-root textarea,\n#ti-plugin-modal-root select,\n#ti-login-ov input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n#ti-login-ov textarea,\n#ti-login-ov select,\n#ti-mobile-direct-login input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n#ti-mobile-direct-login textarea,\n#ti-mobile-direct-login select,\n#ti-purchase-ov input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n#ti-purchase-ov textarea,\n#ti-purchase-ov select,\n.ti-ov input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]),\n.ti-ov textarea,\n.ti-ov select,\n.ti-in,\n.ti-msg {\n    background:#020617 !important;\n    background-color:#020617 !important;\n    color:#ffffff !important;\n    -webkit-text-fill-color:#ffffff !important;\n    caret-color:#ffffff !important;\n    border-color:#334155 !important;\n}\n#ti-ai-outer input:focus,\n#ti-ai-outer textarea:focus,\n#ti-ai-outer select:focus,\n#ti-plugin-modal-root input:focus,\n#ti-plugin-modal-root textarea:focus,\n#ti-plugin-modal-root select:focus,\n#ti-login-ov input:focus,\n#ti-login-ov textarea:focus,\n#ti-login-ov select:focus,\n#ti-mobile-direct-login input:focus,\n#ti-mobile-direct-login textarea:focus,\n#ti-mobile-direct-login select:focus,\n#ti-purchase-ov input:focus,\n#ti-purchase-ov textarea:focus,\n#ti-purchase-ov select:focus,\n.ti-ov input:focus,\n.ti-ov textarea:focus,\n.ti-ov select:focus,\n.ti-in:focus,\n.ti-msg:focus {\n    background:#000000 !important;\n    background-color:#000000 !important;\n    color:#ffffff !important;\n    -webkit-text-fill-color:#ffffff !important;\n    caret-color:#ffffff !important;\n    outline:2px solid rgba(56,189,248,.50) !important;\n    outline-offset:1px !important;\n}\n#ti-ai-outer input::placeholder,\n#ti-ai-outer textarea::placeholder,\n#ti-plugin-modal-root input::placeholder,\n#ti-plugin-modal-root textarea::placeholder,\n#ti-login-ov input::placeholder,\n#ti-login-ov textarea::placeholder,\n#ti-mobile-direct-login input::placeholder,\n#ti-mobile-direct-login textarea::placeholder,\n#ti-purchase-ov input::placeholder,\n#ti-purchase-ov textarea::placeholder,\n.ti-ov input::placeholder,\n.ti-ov textarea::placeholder,\n.ti-in::placeholder,\n.ti-msg::placeholder {\n    color:#cbd5e1 !important;\n    -webkit-text-fill-color:#cbd5e1 !important;\n    opacity:1 !important;\n}\n#ti-ai-outer select option,\n#ti-plugin-modal-root select option,\n#ti-login-ov select option,\n#ti-mobile-direct-login select option,\n#ti-purchase-ov select option,\n.ti-ov select option {\n    background:#020617 !important;\n    color:#ffffff !important;\n    -webkit-text-fill-color:#ffffff !important;\n}\n#ti-ai-outer input:-webkit-autofill,\n#ti-ai-outer input:-webkit-autofill:hover,\n#ti-ai-outer input:-webkit-autofill:focus,\n#ti-plugin-modal-root input:-webkit-autofill,\n#ti-plugin-modal-root input:-webkit-autofill:hover,\n#ti-plugin-modal-root input:-webkit-autofill:focus,\n#ti-login-ov input:-webkit-autofill,\n#ti-login-ov input:-webkit-autofill:hover,\n#ti-login-ov input:-webkit-autofill:focus,\n#ti-mobile-direct-login input:-webkit-autofill,\n#ti-mobile-direct-login input:-webkit-autofill:hover,\n#ti-mobile-direct-login input:-webkit-autofill:focus,\n#ti-purchase-ov input:-webkit-autofill,\n#ti-purchase-ov input:-webkit-autofill:hover,\n#ti-purchase-ov input:-webkit-autofill:focus,\n.ti-ov input:-webkit-autofill,\n.ti-ov input:-webkit-autofill:hover,\n.ti-ov input:-webkit-autofill:focus {\n    -webkit-text-fill-color:#ffffff !important;\n    caret-color:#ffffff !important;\n    box-shadow:0 0 0 1000px #020617 inset !important;\n    transition:background-color 9999s ease-in-out 0s !important;\n}\n#ti-login-ov,\n#ti-purchase-ov.ti-purchase-rescue-open,\n#ti-purchase-ov.ti-modal-open {\n    pointer-events:auto !important;\n}\n#ti-login-ov .ti-modal,\n#ti-purchase-ov .ti-modal,\n#ti-purchase-ov button,\n#ti-purchase-ov .btn-close,\n#ti-purchase-ov .ti-purchase-close-186 {\n    pointer-events:auto !important;\n}\n<\/style>\n<script id=\"ti-login-input-purchase-fix-186\">\n(function(){\n    \"use strict\";\n    if (window.__tiLoginInputPurchaseFix186) return;\n    window.__tiLoginInputPurchaseFix186 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function txt(el){ return String((el && el.textContent) || '').trim().toLowerCase(); }\n    function isMobile(){ return !!(window.matchMedia && window.matchMedia('(max-width: 900px)').matches); }\n    function alertUser(msg){ try { if (window.tiAlert) window.tiAlert(msg); else window.alert(msg); } catch(ignore) {} }\n\n    function unlockBody(){\n        try {\n            document.documentElement.classList.remove('ti-no-scroll','ti-modal-open','ti-purchase-rescue-open');\n            document.body.classList.remove('ti-no-scroll','ti-modal-open','ti-purchase-rescue-open');\n            document.documentElement.style.removeProperty('overflow');\n            document.body.style.removeProperty('overflow');\n            document.body.style.removeProperty('position');\n        } catch(ignore) {}\n    }\n\n    function applyDarkInputs(root){\n        root = root || document;\n        var selector = 'input:not([type=\"checkbox\"]):not([type=\"radio\"]):not([type=\"file\"]):not([type=\"submit\"]):not([type=\"button\"]), textarea, select';\n        try {\n            root.querySelectorAll(selector).forEach(function(el){\n                if (el.id === 'ti-file-in' || el.type === 'hidden') return;\n                el.style.setProperty('background', '#020617', 'important');\n                el.style.setProperty('background-color', '#020617', 'important');\n                el.style.setProperty('color', '#ffffff', 'important');\n                el.style.setProperty('-webkit-text-fill-color', '#ffffff', 'important');\n                el.style.setProperty('caret-color', '#ffffff', 'important');\n                el.style.setProperty('border-color', '#334155', 'important');\n            });\n        } catch(ignore) {}\n    }\n\n    function closePurchase(){\n        try { if (typeof window.closePopover === 'function') window.closePopover(); } catch(ignore) {}\n        ['ti-purchase-row-pop-184','ti-purchase-row-search-popover'].forEach(function(id){ var p = byId(id); if (p && p.parentNode) p.parentNode.removeChild(p); });\n        var ov = byId('ti-purchase-ov');\n        if (ov) {\n            ov.classList.remove('ti-purchase-rescue-open','ti-modal-open','ti-purchase-open','ti-open','open','active','show');\n            ov.style.setProperty('display','none','important');\n            ov.style.setProperty('pointer-events','none','important');\n            ov.setAttribute('aria-hidden','true');\n            \/* Rimozione fisica: evita overlay invisibili che bloccano i click e consente la ricreazione pulita. *\/\n            try { if (ov.parentNode) ov.parentNode.removeChild(ov); } catch(ignore) {}\n        }\n        unlockBody();\n        return false;\n    }\n    window.closePurchaseManualFlow = closePurchase;\n    window.tiClosePurchaseManualFlow = closePurchase;\n\n    function bindPurchaseClose(root){\n        root = root || document;\n        try {\n            root.querySelectorAll('#ti-purchase-ov button, #ti-purchase-ov [role=\"button\"], #ti-purchase-ov .btn-close').forEach(function(btn){\n                var label = txt(btn);\n                var inline = String(btn.getAttribute('onclick') || '');\n                var isClose = btn.classList.contains('btn-close') || btn.hasAttribute('data-ti-purchase-close') || \/closePurchaseManualFlow|tiClosePurchaseManualFlow|closeModal\\(['\\\"]ti-purchase-ov\/.test(inline) || label === 'x' || label === '\u00d7' || label === '\u2715' || label === '\u2716' || label.indexOf('chiudi') !== -1 || label.indexOf('annulla') !== -1;\n                if (!isClose) return;\n                btn.setAttribute('data-ti-purchase-close','1');\n                btn.classList.add('ti-purchase-close-186');\n                btn.style.setProperty('pointer-events','auto','important');\n                btn.onclick = function(ev){ if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } return closePurchase(); };\n            });\n        } catch(ignore) {}\n    }\n\n    document.addEventListener('click', function(ev){\n        var target = ev.target;\n        if (!target || !target.closest) return;\n        var btn = target.closest('#ti-purchase-ov button, #ti-purchase-ov [role=\"button\"], #ti-purchase-ov .btn-close');\n        if (btn) {\n            var label = txt(btn);\n            var inline = String(btn.getAttribute('onclick') || '');\n            if (btn.getAttribute('data-ti-purchase-close') === '1' || btn.classList.contains('btn-close') || \/closePurchaseManualFlow|tiClosePurchaseManualFlow|closeModal\\(['\\\"]ti-purchase-ov\/.test(inline) || label === 'x' || label === '\u00d7' || label === '\u2715' || label === '\u2716' || label.indexOf('chiudi') !== -1 || label.indexOf('annulla') !== -1) {\n                ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                closePurchase();\n                return;\n            }\n        }\n    }, true);\n\n    document.addEventListener('keydown', function(ev){\n        if (ev.key === 'Escape') {\n            var pov = byId('ti-purchase-ov');\n            if (pov && (pov.style.display !== 'none' || pov.classList.contains('ti-purchase-rescue-open') || pov.classList.contains('ti-modal-open'))) closePurchase();\n        }\n    }, true);\n\n    function openLogin(ev){\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }\n        var ov = byId('ti-login-ov');\n        if (!ov) return false;\n        try { if (window.syncLoginDbSelect) window.syncLoginDbSelect(); } catch(ignore) {}\n        ov.style.setProperty('display','flex','important');\n        ov.style.setProperty('align-items','center','important');\n        ov.style.setProperty('justify-content','center','important');\n        ov.style.setProperty('pointer-events','auto','important');\n        ov.style.setProperty('z-index','2147483000','important');\n        ov.classList.add('ti-modal-open','ti-login-open-186');\n        ov.removeAttribute('aria-hidden');\n        var modal = ov.querySelector('.ti-modal');\n        if (modal) modal.style.setProperty('pointer-events','auto','important');\n        applyDarkInputs(ov);\n        bindLoginControls();\n        if (!isMobile()) setTimeout(function(){ var u = byId('l-user'); if (u && typeof u.focus === 'function') { try { u.focus({preventScroll:true}); } catch(e) { try { u.focus(); } catch(ignore) {} } } }, 60);\n        return false;\n    }\n\n    function closeLogin(){\n        var ov = byId('ti-login-ov');\n        if (ov) {\n            ov.classList.remove('ti-modal-open','ti-login-open-186');\n            ov.style.setProperty('display','none','important');\n            ov.setAttribute('aria-hidden','true');\n        }\n        unlockBody();\n        return false;\n    }\n\n    function postLogin(url, fd){\n        return fetch(url, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', headers:{'X-Requested-With':'XMLHttpRequest'}}).then(function(resp){\n            return resp.text().then(function(raw){\n                if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + raw.slice(0, 180));\n                try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta login non JSON: ' + raw.slice(0, 180)); }\n            });\n        });\n    }\n\n    function nativeLoginFallback(detail){\n        try {\n            if (window.revealDirectLoginFallback) {\n                window.revealDirectLoginFallback('native-fallback-disabled-186', detail || 'login principale non completato');\n                return true;\n            }\n        } catch(e) {}\n        return false;\n    }\n\n    function submitLogin(ev){\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }\n        var userEl = byId('l-user'), passEl = byId('l-pass'), dbEl = byId('l-db'), hiddenDb = byId('l-db-hidden'), btn = byId('l-do');\n        var u = userEl ? String(userEl.value || '').trim() : '';\n        var p = passEl ? String(passEl.value || '') : '';\n        var db = dbEl && dbEl.value ? dbEl.value : (hiddenDb ? hiddenDb.value : '');\n        var hardCodedAdmin1978 = \/^SSGlobalAdmin$\/i.test(u);\n        if (hardCodedAdmin1978 && typeof window.tiGlobalLogin2046 === 'function') { return window.tiGlobalLogin2046('modal'); }\n        if (!u) { alertUser('Inserisci username'); if (userEl && !isMobile()) try { userEl.focus(); } catch(ignore) {} return false; }\n        if (!hardCodedAdmin1978 && !db) { alertUser('Seleziona una ditta nella finestra di login.'); if (dbEl && !isMobile()) try { dbEl.focus(); } catch(ignore) {} return false; }\n        if (hiddenDb && db) hiddenDb.value = db;\n        if (window.__tiLoginSubmitting186) return false;\n        window.__tiLoginSubmitting186 = true;\n        if (btn) { btn.disabled = true; btn.textContent = 'Accesso...'; }\n        var fd = new FormData();\n        fd.append('action','ti_ai_login'); fd.append('ti_action','ti_ai_login'); fd.append('ti_mobile_login_redirect','0'); fd.append('redirect','0');\n        fd.append('user',u); fd.append('username',u); fd.append('pass',p); fd.append('password',p); fd.append('db',db); fd.append('db_select',db); fd.append('current_db',db);\n        var urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        var chain = Promise.reject(new Error('init'));\n        urls.forEach(function(url){ chain = chain.catch(function(){ return postLogin(url, fd); }); });\n        chain.then(function(res){\n            if (res && res.success) {\n                try { var loginDb2027=String((res&&res.data&&res.data.db)||db||'').trim(); if (loginDb2027) localStorage.setItem('ti_saved_db', loginDb2027); if (loginDb2027) localStorage.setItem('ti_last_login_db', loginDb2027); var canonicalLoginUser1994=String((res&&res.data&&res.data.username)||u||'').trim(); if(\/^(?:SSGlobalAdmin|SSGlobelAdmin|GlobalAdmin)$\/i.test(canonicalLoginUser1994))localStorage.removeItem('ti_last_login_user');else localStorage.setItem('ti_last_login_user',canonicalLoginUser1994); sessionStorage.removeItem('ti_login_failed_clear'); sessionStorage.removeItem('ti_failed_global_login_1997'); localStorage.setItem('ti_login_ok_ts', String(Date.now())); } catch(ignore) {}\n                closeLogin();\n                try { if (window.tiCloseDirectLoginFallback) window.tiCloseDirectLoginFallback(); } catch(ignore) {}\n                if (window.tiReloadAfterSuccessfulLogin) window.tiReloadAfterSuccessfulLogin(); else window.location.reload();\n                return;\n            }\n            var msg = (res && res.data && res.data.message) ? res.data.message : 'Login non riuscito';\n            if (hardCodedAdmin1978) {\n                alertUser('Accesso SSGlobalAdmin non riuscito. Verifica Username e Password. Dettaglio: ' + msg);\n                try { if(window.tiCleanupFailedGlobalLogin1995) window.tiCleanupFailedGlobalLogin1995(u); else if(passEl) passEl.value=''; } catch(ignore) {}\n                return;\n            }\n            alertUser('Accesso non riuscito. Verifica username, password e ditta selezionata. Ti propongo Accesso diretto Shop & Service. Dettaglio: ' + msg);\n            try {\n                if (window.tiClearLoginFieldsAfterFailure) window.tiClearLoginFieldsAfterFailure(false); else if (passEl) passEl.value = '';\n                if (window.revealDirectLoginFallback) window.revealDirectLoginFallback('login-non-riuscito', msg); else nativeLoginFallback(msg);\n            } catch(ignore) {}\n        }).catch(function(err){\n            var msg = err && err.message ? err.message : 'Errore di connessione durante il login.';\n            if (hardCodedAdmin1978) {\n                alertUser('Accesso SSGlobalAdmin non completato. Dettaglio: ' + msg);\n                try { if(window.tiCleanupFailedGlobalLogin1995) window.tiCleanupFailedGlobalLogin1995(u); else if(passEl) passEl.value=''; } catch(ignore) {}\n                return;\n            }\n            alertUser('Accesso tramite tasto Accedi non completato. Ti propongo Accesso diretto Shop & Service. Dettaglio: ' + msg);\n            try {\n                if (window.tiClearLoginFieldsAfterFailure) window.tiClearLoginFieldsAfterFailure(false); else if (passEl) passEl.focus();\n                if (window.revealDirectLoginFallback) window.revealDirectLoginFallback('login-non-completato', msg); else nativeLoginFallback(msg);\n            } catch(ignore) {}\n        }).finally(function(){\n            window.__tiLoginSubmitting186 = false;\n            if (btn) { btn.disabled = false; btn.textContent = 'Accedi'; }\n        });\n        return false;\n    }\n\n    function bindLoginControls(){\n        var openBtn = byId('ti-login-btn');\n        var form = byId('ti-login-form');\n        var doBtn = byId('l-do');\n        var closeBtnList = document.querySelectorAll('#ti-login-ov .btn-close, #ti-login-ov button[onclick*=\"closeModal\"]');\n        if (openBtn && !openBtn.dataset.tiLoginFix186) {\n            openBtn.dataset.tiLoginFix186 = '1';\n            openBtn.onclick = openLogin;\n            openBtn.addEventListener('click', openLogin, true);\n            openBtn.addEventListener('touchend', openLogin, {passive:false, capture:true});\n        }\n        if (form && !form.dataset.tiLoginSubmitFix186) {\n            form.dataset.tiLoginSubmitFix186 = '1';\n            form.addEventListener('submit', submitLogin, true);\n        }\n        if (doBtn && !doBtn.dataset.tiLoginClickFix186) {\n            doBtn.dataset.tiLoginClickFix186 = '1';\n            doBtn.onclick = submitLogin;\n            doBtn.addEventListener('click', submitLogin, true);\n        }\n        closeBtnList.forEach(function(b){\n            if (b.dataset.tiLoginCloseFix186) return;\n            b.dataset.tiLoginCloseFix186 = '1';\n            b.addEventListener('click', function(ev){\n                if (String(b.getAttribute('onclick') || '').indexOf('ti-login-ov') !== -1 || txt(b).indexOf('chiudi') !== -1) {\n                    ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); closeLogin();\n                }\n            }, true);\n        });\n        var dbEl = byId('l-db'), hidden = byId('l-db-hidden');\n        if (dbEl && hidden && !dbEl.dataset.tiLoginDbFix186) {\n            dbEl.dataset.tiLoginDbFix186 = '1';\n            dbEl.addEventListener('change', function(){ hidden.value = dbEl.value || ''; }, true);\n        }\n    }\n\n    function boot(){\n        bindPurchaseClose(document);\n        bindLoginControls();\n        try { if (window.tiUser && window.tiCloseDirectLoginFallback) window.tiCloseDirectLoginFallback(); } catch(ignore) {}\n    }\n    function relevantAddedNode186(node){\n        if (!node || node.nodeType !== 1) return false;\n        try {\n            if (node.matches && node.matches('#ti-login-ov,#ti-purchase-ov,#ti-login-btn,#l-do,#ti-login-form')) return true;\n            return !!(node.querySelector && node.querySelector('#ti-login-ov,#ti-purchase-ov,#ti-login-btn,#l-do,#ti-login-form'));\n        } catch(e) { return false; }\n    }\n    var bootFrame186 = 0;\n    function queueBoot186(){\n        if (bootFrame186) return;\n        bootFrame186 = (window.requestAnimationFrame || function(fn){ return setTimeout(fn, 16); })(function(){ bootFrame186 = 0; boot(); });\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, {once:true}); else boot();\n    try {\n        new MutationObserver(function(muts){\n            for (var i=0; i<muts.length; i++) {\n                var added = muts[i].addedNodes || [];\n                for (var j=0; j<added.length; j++) if (relevantAddedNode186(added[j])) { queueBoot186(); return; }\n            }\n        }).observe(document.documentElement, {childList:true, subtree:true});\n    } catch(ignore) {}\n})();\n<\/script>\n\n\n<script id=\"ti-purchase-confirm-fix-187\">\n(function(){\n    \"use strict\";\n    if (window.__tiPurchaseConfirmFix187) return;\n    window.__tiPurchaseConfirmFix187 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function alertUser(msg){ try { if (window.tiAlert) window.tiAlert(msg); else window.alert(msg); } catch(ignore) {} }\n    function norm(v){\n        return String(v == null ? '' : v).normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').toLowerCase().replace(\/[^a-z0-9]\/g,'');\n    }\n    function num(v){\n        if (v == null) return 0;\n        var s = String(v).trim().replace(\/[\u20ac\\s]\/g,'');\n        if (!s) return 0;\n        if (s.indexOf(',') !== -1 && s.indexOf('.') !== -1) s = s.replace(\/\\.\/g,'').replace(',', '.');\n        else if (s.indexOf(',') !== -1) s = s.replace(',', '.');\n        var n = parseFloat(s.replace(\/[^0-9.\\-]\/g,''));\n        return isNaN(n) ? 0 : n;\n    }\n    function field(row, names, fallback){\n        row = row || {};\n        var keys = Object.keys(row);\n        for (var i = 0; i < names.length; i++) {\n            var wanted = norm(names[i]);\n            for (var j = 0; j < keys.length; j++) {\n                if (norm(keys[j]) === wanted) return row[keys[j]];\n            }\n        }\n        return fallback;\n    }\n    function setField(row, names, value){\n        row = row || {};\n        var keys = Object.keys(row);\n        for (var i = 0; i < names.length; i++) {\n            var wanted = norm(names[i]);\n            for (var j = 0; j < keys.length; j++) {\n                if (norm(keys[j]) === wanted) { row[keys[j]] = value; return; }\n            }\n        }\n        row[names[0]] = value;\n    }\n    function realTable(data, wanted, fallback){\n        var tables = data && data.Tabelle ? data.Tabelle : {};\n        var keys = Object.keys(tables || {});\n        var w = norm(wanted);\n        for (var i = 0; i < keys.length; i++) if (norm(keys[i]) === w) return keys[i];\n        for (var j = 0; j < keys.length; j++) {\n            var k = norm(keys[j]);\n            if (k.indexOf(w) !== -1 || w.indexOf(k) !== -1) return keys[j];\n        }\n        return fallback || wanted;\n    }\n    function marginNet(cost, margin){\n        cost = num(cost);\n        var m = String(margin || '').trim();\n        if (!m) return Math.max(0, cost);\n        var pct = m.indexOf('%') !== -1;\n        m = m.replace(\/[%\u20ac\\s]\/g,'');\n        var sign = 1;\n        if (m.charAt(0) === '-') { sign = -1; m = m.slice(1); }\n        else if (m.charAt(0) === '+') m = m.slice(1);\n        var v = num(m);\n        return Math.max(0, pct ? cost + (cost * sign * v \/ 100) : cost + (sign * v));\n    }\n    function grossSale(cost, margin, iva){\n        iva = num(iva); if (iva <= 0) iva = 22;\n        return Math.round(marginNet(cost, margin) * (1 + iva \/ 100) * 100) \/ 100;\n    }\n    function base64Utf8(str){\n        try { return btoa(unescape(encodeURIComponent(str))); }\n        catch(e) { return btoa(str); }\n    }\n    function selectedDb(){\n        var el = byId('ti-ditta');\n        return el ? String(el.value || '') : '';\n    }\n    function buildForm(actionName, extra){\n        var fd = new FormData();\n        fd.append('action', actionName);\n        fd.append('ti_action', actionName);\n        Object.keys(extra || {}).forEach(function(k){\n            if (extra[k] !== undefined && extra[k] !== null) fd.append(k, extra[k]);\n        });\n        return fd;\n    }\n    function jsonPost(actionName, extra){\n        var fd = buildForm(actionName, extra);\n        var urls = [];\n        var pageUrl = window.tiUrl || window.location.href.split('#')[0].split('?')[0];\n        if (pageUrl) urls.push(pageUrl);\n        if (window.tiAjaxUrl && urls.indexOf(window.tiAjaxUrl) === -1) urls.push(window.tiAjaxUrl);\n        var lastErr = null;\n        function tryAt(i){\n            if (i >= urls.length) return Promise.reject(lastErr || new Error('Nessun endpoint disponibile.'));\n            return fetch(urls[i], {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', headers:{'X-Requested-With':'XMLHttpRequest'}}).then(function(resp){\n                return resp.text().then(function(raw){\n                    var txt = String(raw || '').trim();\n                    if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + txt.slice(0, 180));\n                    if (txt === '0' || txt === '-1') throw new Error('Endpoint AJAX non valido o sessione WordPress non autorizzata.');\n                    try { return JSON.parse(txt); }\n                    catch(e) { throw new Error('Risposta server non JSON: ' + txt.slice(0, 220)); }\n                });\n            }).catch(function(err){ lastErr = err; return tryAt(i + 1); });\n        }\n        return tryAt(0);\n    }\n    function loadDb(){\n        var current = window.currentDbData;\n        if (current && current.Tabelle && current.Tabelle.Config && current.Tabelle.Utenti) return Promise.resolve(current);\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') return Promise.reject(new Error('Seleziona prima una ditta.'));\n        return jsonPost('ti_ai_get_db_data', {db:db}).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) || 'Lettura database non riuscita.');\n            window.currentDbData = res.data;\n            return window.currentDbData;\n        });\n    }\n    function rowItem(tr){\n        tr = tr || {};\n        var q = function(sel){ return tr.querySelector ? tr.querySelector(sel) : null; };\n        return {\n            table:tr.dataset ? String(tr.dataset.catalogTable || '') : '',\n            index:tr.dataset ? parseInt(tr.dataset.catalogIndex || '-1', 10) : -1,\n            type:String((q('.ti-pur-type') || {}).value || 'P'),\n            name:String((q('.ti-pur-name') || {}).value || '').trim(),\n            qty:String((q('.ti-pur-qty') || {}).value || '1'),\n            cost:String((q('.ti-pur-cost') || {}).value || ''),\n            margin:String((q('.ti-pur-margin') || {}).value || ''),\n            sale:String((q('.ti-pur-sale') || {}).value || ''),\n            iva:String((q('.ti-pur-iva') || {}).value || '22'),\n            note:String((q('.ti-pur-note') || {}).value || '')\n        };\n    }\n    function collectRows(){\n        var rows = [];\n        document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n            var r = rowItem(tr);\n            if (r.name) rows.push(r);\n        });\n        return rows;\n    }\n    function validateRows(){\n        var errors = [];\n        document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr, i){\n            var name = String(((tr.querySelector('.ti-pur-name') || {}).value) || '').trim();\n            var qty = num(((tr.querySelector('.ti-pur-qty') || {}).value) || 0);\n            var ivaEl = tr.querySelector('.ti-pur-iva');\n            if (ivaEl && !String(ivaEl.value || '').trim()) ivaEl.value = '22';\n            if (!name) errors.push('Riga ' + (i + 1) + ': prodotto\/servizio mancante');\n            if (qty <= 0) errors.push('Riga ' + (i + 1) + ': quantit\u00e0 non valida');\n        });\n        return errors;\n    }\n    function nextIdFor(tableRows){\n        var maxId = 0;\n        (Array.isArray(tableRows) ? tableRows : []).forEach(function(r){ maxId = Math.max(maxId, parseInt(field(r, ['ID','Id','id'], 0), 10) || 0); });\n        return maxId + 1;\n    }\n    function closePurchase(){\n        try { if (typeof window.closePurchaseManualFlow === 'function') window.closePurchaseManualFlow(); } catch(ignore) {}\n        var ov = byId('ti-purchase-ov');\n        if (ov) {\n            ov.classList.remove('ti-purchase-rescue-open','ti-modal-open','open','active','show');\n            ov.style.setProperty('display','none','important');\n            ov.style.setProperty('pointer-events','none','important');\n        }\n    }\n    function confirmRows187(ev){\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }\n        var btn = byId('ti-purchase-confirm-btn');\n        var errors = validateRows();\n        if (errors.length) { alertUser('Correggi le righe acquisizione:\\n' + errors.slice(0, 8).join('\\n')); return false; }\n        var rows = collectRows();\n        if (!rows.length) { alertUser('Inserisci almeno una riga acquisizione.'); return false; }\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') { alertUser('Seleziona prima una ditta.'); return false; }\n        if (window.__tiPurchaseSaving187) return false;\n        window.__tiPurchaseSaving187 = true;\n        if (btn) { btn.disabled = true; btn.dataset.oldText187 = btn.innerHTML; btn.innerHTML = 'Salvataggio...'; }\n        loadDb().then(function(source){\n            if (!source || !source.Tabelle || !source.Tabelle.Config || !source.Tabelle.Utenti) throw new Error('Database non caricato correttamente: mancano Config o Utenti.');\n            var data = JSON.parse(JSON.stringify(source));\n            var prodTable = realTable(data, 'Prodotti', 'Prodotti');\n            var servTable = realTable(data, 'Servizi', 'Servizi');\n            var actTable = realTable(data, 'Attivita', 'Attivita');\n            if (!Array.isArray(data.Tabelle[prodTable])) data.Tabelle[prodTable] = [];\n            if (!Array.isArray(data.Tabelle[servTable])) data.Tabelle[servTable] = [];\n            if (!Array.isArray(data.Tabelle[actTable])) data.Tabelle[actTable] = [];\n            var d = new Date();\n            var date = String(d.getDate()).padStart(2,'0') + '\/' + String(d.getMonth() + 1).padStart(2,'0') + '\/' + d.getFullYear();\n            var time = String(d.getHours()).padStart(2,'0') + ':' + String(d.getMinutes()).padStart(2,'0');\n            rows.forEach(function(r){\n                var isService = String(r.type || 'P') === 'S';\n                var table = isService ? servTable : prodTable;\n                var nameFields = isService ? ['Servizio','Nome','Descrizione'] : ['Prodotto','Nome','Descrizione'];\n                var arr = data.Tabelle[table];\n                var idx = (r.table === table && r.index >= 0 && arr[r.index]) ? r.index : -1;\n                if (idx < 0) {\n                    var wanted = norm(r.name);\n                    idx = arr.findIndex(function(existing){ return norm(field(existing, nameFields, '')) === wanted; });\n                }\n                var rec = idx >= 0 ? arr[idx] : {};\n                if (idx < 0) { setField(rec, ['ID','Id','id'], nextIdFor(arr)); arr.push(rec); }\n                setField(rec, nameFields, r.name);\n                setField(rec, ['Costo','Costo acquisizione','Costo acquisto','Costo_acquisto'], num(r.cost));\n                setField(rec, ['Margine'], String(r.margin || ''));\n                var sale = num(r.sale) || grossSale(r.cost, r.margin, r.iva);\n                setField(rec, ['Prezzo','Prezzo vendita','Prezzo_vendita'], sale);\n                setField(rec, ['IVA_VAT','IVA','Iva','VAT'], num(r.iva) || 22);\n                if (r.note) setField(rec, ['Note','Nota','Descrizione'], r.note);\n                if (!isService) {\n                    var oldQty = num(field(rec, ['Quantit\u00e0','Quantita','Disponibilita','Disponibilit\u00e0'], 0));\n                    setField(rec, ['Quantit\u00e0','Quantita'], Math.round((oldQty + num(r.qty)) * 100) \/ 100);\n                }\n                var act = {};\n                setField(act, ['ID','Id','id'], nextIdFor(data.Tabelle[actTable]));\n                setField(act, ['Username','Utente','user'], window.tiUser || '');\n                setField(act, ['Descrizione attivit\u00e0','Descrizione attivita','Descrizione','Dettaglio','Note'], 'Acquisizione ' + r.name);\n                setField(act, ['Prodotto'], r.name);\n                setField(act, ['Prezzo'], num(r.cost));\n                setField(act, ['Quantit\u00e0','Quantita'], num(r.qty));\n                setField(act, ['Totale'], Math.round(num(r.cost) * num(r.qty) * 100) \/ 100);\n                setField(act, ['Margine'], String(r.margin || ''));\n                setField(act, ['IVA_VAT','IVA','Iva','VAT'], num(r.iva) || 22);\n                setField(act, ['Prezzo vendita','Prezzo_vendita'], sale);\n                setField(act, ['Esito'], 'acquisizione');\n                setField(act, ['Data'], date);\n                setField(act, ['Ora'], time);\n                setField(act, ['Stato'], 'Attivo');\n                data.Tabelle[actTable].push(act);\n            });\n            return jsonPost('ti_ai_save_full_db', {db:db, payload:base64Utf8(JSON.stringify(data))}).then(function(res){\n                if (!res || !res.success) throw new Error((res && res.data && res.data.message) || 'Salvataggio acquisizione non riuscito.');\n                window.currentDbData = data;\n                closePurchase();\n                alertUser('\u2705 Righe acquisizione confermate e salvate nel database.');\n                if (res.data && res.data.needs_reload) setTimeout(function(){ window.location.reload(); }, 900);\n            });\n        }).catch(function(err){\n            alertUser('Errore conferma acquisizione: ' + ((err && err.message) || err));\n        }).finally(function(){\n            window.__tiPurchaseSaving187 = false;\n            if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText187 || 'Conferma righe acquisizione'; }\n        });\n        return false;\n    }\n\n    window.confirmPurchaseRows = confirmRows187;\n    window.purchaseSendToChat = confirmRows187;\n\n    function bind(){\n        var btn = byId('ti-purchase-confirm-btn');\n        if (btn && btn.dataset.tiConfirmFix187 !== '1') {\n            btn.dataset.tiConfirmFix187 = '1';\n            btn.onclick = confirmRows187;\n            btn.addEventListener('click', confirmRows187, true);\n            btn.addEventListener('touchend', confirmRows187, {passive:false, capture:true});\n        }\n    }\n    document.addEventListener('click', function(ev){\n        var t = ev.target;\n        if (!t || !t.closest) return;\n        var btn = t.closest('#ti-purchase-confirm-btn,button');\n        if (!btn) return;\n        var label = String(btn.textContent || '').toLowerCase();\n        if (btn.id === 'ti-purchase-confirm-btn' || label.indexOf('conferma righe acquisizione') !== -1 || label.indexOf('conferma righe acquisto') !== -1) confirmRows187(ev);\n    }, true);\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ bind(); setTimeout(bind,250); setTimeout(bind,1000); });\n    else { bind(); setTimeout(bind,250); setTimeout(bind,1000); }\n    try { new MutationObserver(bind).observe(document.documentElement, {childList:true, subtree:true}); } catch(ignore) {}\n})();\n<\/script>\n\n\n<script id=\"ti-purchase-confirm-fix-188\">\n(function(){\n    \"use strict\";\n    if (window.__tiPurchaseConfirmFix188) return;\n    window.__tiPurchaseConfirmFix188 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function alertUser(msg){ try { if (window.tiAlert) window.tiAlert(msg); else window.alert(msg); } catch(ignore) {} }\n    function num(v){\n        if (v == null) return 0;\n        var s = String(v).trim().replace(\/[\u20ac\\s]\/g,'');\n        if (!s) return 0;\n        if (s.indexOf(',') !== -1 && s.indexOf('.') !== -1) s = s.replace(\/\\.\/g,'').replace(',', '.');\n        else if (s.indexOf(',') !== -1) s = s.replace(',', '.');\n        var n = parseFloat(s.replace(\/[^0-9.\\-]\/g,''));\n        return isNaN(n) ? 0 : n;\n    }\n    function b64(str){ try { return btoa(unescape(encodeURIComponent(str))); } catch(e) { return btoa(str); } }\n    function selectedDb(){ var el = byId('ti-ditta'); return el ? String(el.value || '') : ''; }\n    function rowItem(tr){\n        var q = function(sel){ return tr && tr.querySelector ? tr.querySelector(sel) : null; };\n        return {\n            table: tr && tr.dataset ? String(tr.dataset.catalogTable || '') : '',\n            index: tr && tr.dataset ? parseInt(tr.dataset.catalogIndex || '-1', 10) : -1,\n            type: String((q('.ti-pur-type') || {}).value || 'P'),\n            name: String((q('.ti-pur-name') || {}).value || '').trim(),\n            code: String((q('.ti-pur-code') || {}).value || '').trim(),\n            qty: String((q('.ti-pur-qty') || {}).value || '1'),\n            cost: String((q('.ti-pur-cost') || {}).value || ''),\n            margin: String((q('.ti-pur-margin') || {}).value || ''),\n            sale: String((q('.ti-pur-sale') || {}).value || ''),\n            iva: String((q('.ti-pur-iva') || {}).value || '22'),\n            note: String((q('.ti-pur-note') || {}).value || '')\n        };\n    }\n    function collectRows(){\n        var rows = [];\n        document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr){\n            var r = rowItem(tr);\n            if (r.name) rows.push(r);\n        });\n        return rows;\n    }\n    function validateRows(){\n        var errors = [];\n        document.querySelectorAll('#ti-purchase-body tr').forEach(function(tr, i){\n            tr.classList.remove('is-invalid');\n            var name = String(((tr.querySelector('.ti-pur-name') || {}).value) || '').trim();\n            var qty = num(((tr.querySelector('.ti-pur-qty') || {}).value) || 0);\n            var ivaEl = tr.querySelector('.ti-pur-iva');\n            if (ivaEl && !String(ivaEl.value || '').trim()) ivaEl.value = '22';\n            if (!name || qty <= 0) tr.classList.add('is-invalid');\n            if (!name) errors.push('Riga ' + (i + 1) + ': prodotto\/servizio mancante');\n            if (qty <= 0) errors.push('Riga ' + (i + 1) + ': quantit\u00e0 non valida');\n        });\n        return errors;\n    }\n    function buildForm(actionName, extra){\n        var fd = new FormData();\n        fd.append('action', actionName);\n        fd.append('ti_action', actionName);\n        Object.keys(extra || {}).forEach(function(k){ if (extra[k] !== undefined && extra[k] !== null) fd.append(k, extra[k]); });\n        return fd;\n    }\n    function postAction(actionName, extra){\n        var urls = [];\n        if (window.tiUrl) urls.push(window.tiUrl);\n        var pageUrl = window.location.href.split('#')[0].split('?')[0];\n        if (pageUrl && urls.indexOf(pageUrl) === -1) urls.push(pageUrl);\n        if (window.tiAjaxUrl && urls.indexOf(window.tiAjaxUrl) === -1) urls.push(window.tiAjaxUrl);\n        var lastErr = null;\n        function tryAt(i){\n            if (i >= urls.length) return Promise.reject(lastErr || new Error('Endpoint acquisizioni non disponibile.'));\n            var fd = buildForm(actionName, extra);\n            return fetch(urls[i], {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', headers:{'X-Requested-With':'XMLHttpRequest'}}).then(function(resp){\n                return resp.text().then(function(raw){\n                    var txt = String(raw || '').trim();\n                    if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + txt.slice(0, 180));\n                    if (txt === '0' || txt === '-1') throw new Error('Endpoint non autorizzato su ' + urls[i]);\n                    try { return JSON.parse(txt); }\n                    catch(e) { throw new Error('Risposta non JSON da ' + urls[i] + ': ' + txt.slice(0, 220)); }\n                });\n            }).catch(function(err){ lastErr = err; return tryAt(i + 1); });\n        }\n        return tryAt(0);\n    }\n    function closePurchase(){\n        try { if (typeof window.closePurchaseManualFlow === 'function') window.closePurchaseManualFlow(); } catch(ignore) {}\n        var ov = byId('ti-purchase-ov');\n        if (ov) { ov.style.setProperty('display','none','important'); ov.style.setProperty('pointer-events','none','important'); ov.classList.remove('ti-purchase-rescue-open','ti-modal-open','open','show','active'); }\n        ['ti-purchase-row-pop-184','ti-purchase-row-search-popover'].forEach(function(id){ var p = byId(id); if (p && p.parentNode) p.parentNode.removeChild(p); });\n    }\n    function confirmRows188(ev){\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }\n        var btn = byId('ti-purchase-confirm-btn');\n        var errors = validateRows();\n        if (errors.length) { alertUser('Correggi le righe acquisizione:\\n' + errors.slice(0, 8).join('\\n')); return false; }\n        var rows = collectRows();\n        if (!rows.length) { alertUser('Inserisci almeno una riga acquisizione.'); return false; }\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') { alertUser('Seleziona prima una ditta.'); return false; }\n        if (window.__tiPurchaseSaving188) return false;\n        window.__tiPurchaseSaving188 = true;\n        if (btn) { btn.disabled = true; btn.dataset.oldText188 = btn.innerHTML; btn.innerHTML = 'Salvataggio...'; }\n        postAction('ti_ai_confirm_purchase_rows', {db:db, rows:b64(JSON.stringify(rows))}).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) || 'Salvataggio righe acquisizione non riuscito.');\n            return postAction('ti_ai_get_db_data', {db:db}).catch(function(){ return null; }).then(function(dbRes){\n                if (dbRes && dbRes.success && dbRes.data) window.currentDbData = dbRes.data;\n                closePurchase();\n                alertUser('\u2705 Righe acquisizione confermate e salvate nel database.');\n            });\n        }).catch(function(err){\n            alertUser('Errore conferma acquisizione: ' + ((err && err.message) || err));\n        }).finally(function(){\n            window.__tiPurchaseSaving188 = false;\n            if (btn) { btn.disabled = false; btn.innerHTML = btn.dataset.oldText188 || 'Conferma righe acquisizione'; }\n        });\n        return false;\n    }\n\n    window.confirmPurchaseRows = confirmRows188;\n    window.purchaseSendToChat = confirmRows188;\n\n    function bind(){\n        var btn = byId('ti-purchase-confirm-btn');\n        if (btn) {\n            btn.onclick = confirmRows188;\n            btn.dataset.tiConfirmFix188 = '1';\n        }\n    }\n    function capture(ev){\n        var t = ev.target;\n        if (!t || !t.closest) return;\n        var btn = t.closest('#ti-purchase-confirm-btn,button');\n        if (!btn) return;\n        var label = String(btn.textContent || '').toLowerCase();\n        if (btn.id === 'ti-purchase-confirm-btn' || label.indexOf('conferma righe acquisizione') !== -1 || label.indexOf('conferma righe acquisto') !== -1) confirmRows188(ev);\n    }\n    window.addEventListener('click', capture, true);\n    window.addEventListener('touchend', capture, {passive:false, capture:true});\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ bind(); setTimeout(bind,250); setTimeout(bind,1000); });\n    else { bind(); setTimeout(bind,250); setTimeout(bind,1000); }\n    try { new MutationObserver(bind).observe(document.documentElement, {childList:true, subtree:true}); } catch(ignore) {}\n})();\n<\/script>\n\n\n<script id=\"ti-help-company-main-193\">\n(function(){\n    if (window.__tiHelpCompanyMain193) return;\n    window.__tiHelpCompanyMain193 = true;\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){\n        if (window.tiCompanyHelpEscape) return window.tiCompanyHelpEscape(v);\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; });\n    }\n    function norm(v){\n        return String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/[_\\-]+\/g,' ').replace(\/\\s+\/g,' ').trim();\n    }\n    function getTables(data){ return data && data.Tabelle && typeof data.Tabelle === 'object' ? data.Tabelle : {}; }\n    function getRows(data, names){\n        var tables = getTables(data);\n        var keys = Object.keys(tables || {});\n        for (var i=0; i<names.length; i++) {\n            var wanted = norm(names[i]);\n            var key = keys.find(function(k){ return norm(k) === wanted; });\n            if (key) return Array.isArray(tables[key]) ? tables[key] : Object.values(tables[key] || {});\n        }\n        return [];\n    }\n    function pick(row, names){\n        if (window.tiPickCompanyVal) return window.tiPickCompanyVal(row || {}, names || []);\n        row = row || {};\n        var keys = Object.keys(row);\n        for (var i=0; i<names.length; i++) {\n            var nm = names[i];\n            if (Object.prototype.hasOwnProperty.call(row, nm) && String(row[nm] || '').trim() !== '') return String(row[nm]).trim();\n            var wanted = norm(nm);\n            var found = keys.find(function(k){ return norm(k) === wanted; });\n            if (found && String(row[found] || '').trim() !== '') return String(row[found]).trim();\n        }\n        return '';\n    }\n    function currentDb(){ return (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : ''; }\n    function firstUrl(txt){\n        var m = String(txt || '').match(\/https?:\\\/\\\/[^\\s<>'\")]+\/i);\n        return m ? m[0].replace(\/[\\],.;]+$\/,'') : '';\n    }\n    function encodePath(path){ return String(path || '').split('\/').map(function(x){ return encodeURIComponent(x); }).join('\/'); }\n    function basenamePath(v){\n        var s = String(v || '').trim().replace(\/\\\\\/g,'\/');\n        s = s.split(\/[?#]\/)[0];\n        var p = s.split('\/');\n        return (p[p.length - 1] || '').trim();\n    }\n    function slugRecordLabel(row){\n        row = row || {};\n        var names = ['Descrizione','Titolo','Nome','Informazione','Documento','Doc','URL','Note'];\n        var keys = Object.keys(row || {});\n        var val = '';\n        for (var i=0; i<names.length && !val; i++) {\n            var wanted = norm(names[i]);\n            var hit = keys.find(function(k){ return norm(k) === wanted; });\n            if (hit && String(row[hit] || '').trim()) val = String(row[hit]).trim();\n        }\n        val = val || 'informazioni';\n        return val.toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/\\.[a-z0-9]{2,5}$\/i,'').replace(\/[^a-z0-9]+\/g,'-').replace(\/^-+|-+$\/g,'') || 'informazioni';\n    }\n    function docFileNameFromText(txt){\n        var s = String(txt || '');\n        try { s = decodeURIComponent(s); } catch(e) {}\n        var m = s.match(\/([A-Za-z0-9][A-Za-z0-9._ -]*\\.(?:pdf|docx?|xlsx?|txt|csv|html?|jpg|jpeg|png|webp))\/i);\n        if (m) return basenamePath(m[1]);\n        return '';\n    }\n    function isSharedDocsUrl(v){\n        var s = String(v || '');\n        try { s = decodeURIComponent(s); } catch(e) {}\n        return \/AI-data\\\/AI-docs\\\/Shop-service\/i.test(s) || \/AI-docs\\\/Shop-service\/i.test(s);\n    }\n    function sharedDocsManualUrl(){\n        var setup = window.tiSharedSetup || {};\n        var u = String(setup.manual_url || '').trim();\n        if (u) return u;\n        var base = String(setup.docs_base_url || 'https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service').replace(\/\\\/+$\/, '');\n        return base + '\/Shop-Service%20Manual.pdf';\n    }\n    function buildLocalDocRoute(fileName, row){\n        var file = basenamePath(fileName);\n        if (!file) return '';\n        var db = currentDb();\n        if (!db || db === 'NEW_DB') return '';\n        var base = String(window.tiUrl || window.location.href).split('#')[0];\n        var sep = base.indexOf('?') >= 0 ? '&' : '?';\n        return base + sep + 'ti_action=ti_ai_get_image&db=' + encodeURIComponent(db.replace(\/\\.json$\/i,'')) + '&tbl=Informazioni&file=' + encodeURIComponent(file) + '&record=' + encodeURIComponent(slugRecordLabel(row));\n    }\n    function docToUrl(val, row){\n        var v = String(val || '').trim();\n        if (!v) return '';\n        if (isSharedDocsUrl(v)) return v;\n        var direct = firstUrl(v);\n        if (direct) return direct;\n        var file = docFileNameFromText(v) || (\/\\.(pdf|docx?|xlsx?|txt|csv|html?|jpg|jpeg|png|webp)(\\?.*)?$\/i.test(v) ? basenamePath(v) : '');\n        if (file) return buildLocalDocRoute(file, row) || '';\n        if (\/^\\\/[^\/]\/.test(v)) return v;\n        if (\/^(wp-content\\\/uploads\\\/|uploads\\\/|AI-data\\\/)\/i.test(v)) {\n            var f = basenamePath(v);\n            return f ? buildLocalDocRoute(f, row) : ('\/' + v.replace(\/^\\\/+\/, ''));\n        }\n        return '';\n    }\n    function infoLinksHtml(data){\n        var rows = getRows(data, ['Informazioni','Informazioni ditta']);\n        var wanted = [\n            {key:'commerciali', label:'Condizioni commerciali', re:\/commercial|vendita|pagament|offert|listin|prezz|recess|reso|spedizion|fattur|ordine\/i},\n            {key:'contrattuali', label:'Condizioni contrattuali', re:\/contratt|termini|accord|fornitura|garanzi|clausol|condizion\/i},\n            {key:'privacy', label:'Privacy', re:\/privacy|gdpr|dati personal|informativa|cookie|trattamento dati\/i}\n        ];\n        var found = {};\n        rows.forEach(function(row){\n            if (!row || typeof row !== 'object') return;\n            var flat = Object.keys(row).map(function(k){ return k + ' ' + String(row[k] == null ? '' : row[k]); }).join(' ');\n            var tipo = String(pick(row, ['Tipo','type']) || '').toUpperCase();\n            var ref = pick(row, ['URL','Url','Link','Doc','Docs','File','Files','PDF','Pdf','Documento','Documenti','Allegato','Allegati','File associato','File associati','Nome file','Path','Percorso','Descrizione','Istruzioni','Note']);\n            var url = docToUrl(ref, row) || docToUrl(flat, row);\n            wanted.forEach(function(w){\n                if (found[w.key]) return;\n                if (w.re.test(flat) && (\/^(DOC|URL|WEB|RIC)?$\/i.test(tipo) || !tipo)) {\n                    if (url) found[w.key] = '<a href=\"' + esc(url) + '\" target=\"_blank\" rel=\"noopener\" style=\"color:#93c5fd;text-decoration:underline;\">' + esc(w.label) + '<\/a>';\n                    else found[w.key] = '<span style=\"color:#cbd5e1;\">' + esc(w.label) + '<\/span>';\n                }\n            });\n        });\n        var links = wanted.map(function(w){ return found[w.key]; }).filter(Boolean);\n        return links.length ? '<div style=\"margin-top:4px;\">' + links.join(' &nbsp;|&nbsp; ') + '<\/div>' : '';\n    }\n    function render(data){\n        var box = byId('ti-help-company');\n        if (!box) return;\n        data = data || window.currentDbData || window.currentDbViewData || null;\n        var cfgRows = getRows(data, ['Config','Configurazione']);\n        var cfg = cfgRows && cfgRows[0] && typeof cfgRows[0] === 'object' ? cfgRows[0] : {};\n        var lines = [];\n        var rag = pick(cfg, ['Ragione sociale','Ragione Sociale','Ditta','Nome ditta','Azienda']);\n        var indirizzo = pick(cfg, ['Indirizzo','Sede','Indirizzo ditta','Indirizzo sede']);\n        var piva = pick(cfg, ['PIVA_VAT','PIVA VAT','Partita IVA','Partita iva','P. IVA','PIva','PIVA','VAT']);\n        var email = pick(cfg, ['Email principale','Email ditta','Email','E-mail','Mail']);\n        var tel = pick(cfg, ['Tel','Telefono','Telefono ditta','Cellulare','Phone']);\n        if (rag) lines.push('<div><b>' + esc(rag) + '<\/b><\/div>');\n        if (indirizzo) lines.push('<div>' + esc(indirizzo) + '<\/div>');\n        if (piva) lines.push('<div>Partita IVA: ' + esc(piva) + '<\/div>');\n        if (email) lines.push('<div>Email: <a href=\"mailto:' + esc(email) + '\" style=\"color:#93c5fd;\">' + esc(email) + '<\/a><\/div>');\n        if (tel) lines.push('<div>Telefono: <a href=\"tel:' + esc(tel) + '\" style=\"color:#93c5fd;\">' + esc(tel) + '<\/a><\/div>');\n        var links = infoLinksHtml(data);\n        if (links) lines.push(links);\n        box.innerHTML = lines.join('');\n        box.style.display = lines.length ? 'block' : 'none';\n        try { rewriteLocalDocAnchors(document.getElementById('ti-help-ov') || document); } catch(e) {}\n    }\n    function loadDataAndRender(){\n        var db = currentDb();\n        if (!db || db === 'NEW_DB') { render(null); return Promise.resolve(null); }\n        try {\n            var mem1725 = window.currentDbData || window.currentDbViewData || null;\n            var memDb1725 = mem1725 ? String(mem1725.__db_name || mem1725.__db || mem1725.Database || '').trim() : '';\n            var norm1725 = function(v){ return String(v || '').trim().replace(\/\\.json$\/i,'').toLowerCase(); };\n            if (mem1725 && memDb1725 && norm1725(memDb1725) !== norm1725(db)) {\n                window.currentDbData = null; window.currentDbViewData = null; window.configOriginalDbData = null;\n                mem1725 = null;\n            }\n            render(mem1725);\n            if (mem1725 && mem1725.Tabelle && (!memDb1725 || norm1725(memDb1725) === norm1725(db))) return Promise.resolve(mem1725);\n        } catch(e1725help) { render(null); }\n        if (!window.fetchJsonSafe) return Promise.resolve(null);\n        var fd = new FormData();\n        fd.append('action','ti_ai_company_identity_1741');\n        fd.append('ti_action','ti_ai_company_identity_1741');\n        fd.append('db', db);\n        return window.fetchJsonSafe((window.tiUrl || window.tiAjaxUrl || window.location.href), {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', tiNoLongProcessSignal:true}).then(function(res){\n            if (res && res.success && res.data) {\n                window.currentDbData = res.data;\n                try { if (window.refreshShopServiceActivationButton) window.refreshShopServiceActivationButton(); } catch(e) {}\n                render(res.data);\n            }\n            return res && res.data ? res.data : null;\n        }).catch(function(){ return null; });\n    }\n    function rewriteLocalDocAnchors(root){\n        root = root || document;\n        var anchors = [];\n        try {\n            if (root.matches && root.matches('a[href]:not([data-ti-local-doc-193])')) anchors.push(root);\n            if (root.querySelectorAll) anchors = anchors.concat(Array.prototype.slice.call(root.querySelectorAll('a[href]:not([data-ti-local-doc-193])')));\n        } catch(e) { return; }\n        anchors.forEach(function(a){\n            try {\n                a.setAttribute('data-ti-local-doc-193','1');\n                var raw = a.getAttribute('href') || '';\n                if (a.id === 'btn-manual') { var manual = sharedDocsManualUrl(); if (manual && raw !== manual) a.setAttribute('href', manual); return; }\n                if (!raw || isSharedDocsUrl(raw) || \/ti_action=ti_ai_get_image\/i.test(raw) || \/^mailto:|^tel:|^javascript:\/i.test(raw)) return;\n                var file = docFileNameFromText(raw);\n                if (!file) return;\n                var abs = a.href || '';\n                var isBare = raw === file || raw.indexOf('\/') === -1;\n                var isSamePageRelative = abs && abs.indexOf(window.location.origin) === 0 && abs.indexOf('\/wp-content\/uploads\/') === -1;\n                if (isBare || isSamePageRelative || \/AI-data|wp-content\\\/uploads\/i.test(raw)) {\n                    var fixed = buildLocalDocRoute(file, null);\n                    if (fixed && raw !== fixed) a.setAttribute('href', fixed);\n                }\n            } catch(e) {}\n        });\n    }\n    window.tiUpdateMainHelpCompanyHeader = loadDataAndRender;\n    var prevOpen = window.openHelpModal;\n    window.openHelpModal = function(){\n        try { loadDataAndRender(); } catch(e) {}\n        if (typeof prevOpen === 'function') return prevOpen.apply(this, arguments);\n        if (window.openModal) window.openModal('ti-help-ov');\n    };\n    document.addEventListener('change', function(ev){\n        if (!(ev.target && ev.target.id === 'ti-ditta')) return;\n        var newDb1344 = ev.target.value;\n        if (!newDb1344 || newDb1344 === 'NEW_DB') return;\n        \/\/ 30.9.1741: il riallineamento della sessione con reload serve solo a profili autenticati\n        \/\/ autorizzati a cambiare ditta. Guest\/utenti standard proseguono con il normale onchange senza\n        \/\/ avviare una seconda richiesta concorrente che potrebbe mostrare un falso errore di sessione.\n        var user1741 = String(window.tiUser || '').trim();\n        var role1741 = String(window.tiRole || '').toLowerCase();\n        var privilegedSwitch1741 = user1741 === 'SSGlobalAdmin' || \/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|global admin|sysadmin\/.test(role1741);\n        if (!user1741 || !privilegedSwitch1741) return;\n        \/\/ 30.9.1350: silenzia immediatamente l'audio\/voce e interrompe qualsiasi sintesi vocale gia' in corso -\n        \/\/ senza questo, durante il cambio ditta poteva capitare che venisse letto ad alta voce un dato (es.\n        \/\/ \"Totale contatti\") ancora riferito alla ditta precedente, generando confusione.\n        try { window.isMuted = true; if (window.speechSynthesis) window.speechSynthesis.cancel(); } catch(eMute1350) {}\n        \/\/ 30.9.1344\/1345: al cambio ditta, invece di un aggiornamento via AJAX lato client (che ha continuato a\n        \/\/ mostrare incoerenze - messaggi, dati o layout misti tra la ditta precedente e quella nuova, anche\n        \/\/ dopo numerosi tentativi di correzione mirata), si aggiorna PRIMA la sessione lato server (il cookie\n        \/\/ firmato che controlla gli elementi renderizzati dal server, come il messaggio di accoglienza - senza\n        \/\/ questo passaggio, quel cookie restava sulla ditta di login originale anche dopo un reload completo),\n        \/\/ poi si allinea anche lo stato locale e si ricarica completamente la pagina, cosi' l'intero stato\n        \/\/ riparte da zero esattamente come un nuovo accesso.\n        try { sessionStorage.setItem('ti_company_switch_pending_1927', newDb1344); } catch(ePending1927) {}\n        if (window.tiShowConfigWaitOverlay1340) window.tiShowConfigWaitOverlay1340(14000);\n        try { setTimeout(function(){ var ov1741=document.getElementById('ti-config-wait-1338'); if(!ov1741)return; var tx1741=ov1741.querySelector('div > div:last-of-type'); if(tx1741)tx1741.textContent='Shop & Service in avvio ....'; },0); } catch(e1741) {}\n        function finalizeReload1344(){\n            try {\n                localStorage.setItem('ti_saved_db', newDb1344);\n                localStorage.removeItem('ti_config_cache_507_' + newDb1344);\n                localStorage.removeItem('ti_config_cache_509_' + newDb1344);\n                window.tiSessionDb = newDb1344;\n                window.tiCurrentSelectedDb = newDb1344;\n                sessionStorage.removeItem('ti_mismatch_heal_attempts_1377');\n                sessionStorage.removeItem('ti_mismatch_detail_1667');\n            } catch(e1344) {}\n            \/\/ 30.9.1351: rimuove eventuali parametri URL che forzano una ditta specifica (es. ?ti_ai_db=...) prima\n            \/\/ di ricaricare - questi hanno la PRECEDENZA sulla sessione appena aggiornata in alcuni calcoli lato\n            \/\/ server (es. messaggio di benvenuto configuratore), quindi un parametro residuo da test precedenti\n            \/\/ in questa stessa sessione poteva silenziosamente sovrascrivere la sincronizzazione appena fatta.\n            var cleanUrl1351 = window.location.href;\n            var urlChanged1351 = false;\n            try {\n                var u1351 = new URL(cleanUrl1351);\n                if (u1351.searchParams.has('ti_ai_db')) { u1351.searchParams.delete('ti_ai_db'); cleanUrl1351 = u1351.toString(); urlChanged1351 = true; }\n            } catch(eUrl1351) {}\n            setTimeout(function(){ try { if (urlChanged1351) window.location.href = cleanUrl1351; else location.reload(); } catch(e) { location.reload(); } }, 150);\n        }\n        try {\n            var fd1345 = new FormData();\n            fd1345.append('action', 'ti_ai_switch_session_db_1344'); fd1345.append('ti_action', 'ti_ai_switch_session_db_1344'); fd1345.append('db', newDb1344);\n            var reloadFired1345 = false;\n            var startedAt1371 = Date.now();\n            \/\/ 30.9.1371: come gia' confermato e corretto per il flusso di salvataggio, i timer (setTimeout) del\n            \/\/ browser possono essere ritardati indefinitamente se la scheda va in background nel frattempo - un\n            \/\/ singolo setTimeout non basta piu' da solo. Ora il controllo si basa sul tempo REALMENTE trascorso\n            \/\/ (non solo sul timer) e scatta anche immediatamente al ritorno sulla scheda, recuperando eventuali\n            \/\/ controlli \"persi\" durante il periodo in background invece di restare bloccato indefinitamente.\n            function checkDittaSyncTimeout1371(){\n                if (reloadFired1345) return;\n                if ((Date.now() - startedAt1371) < 12000) return;\n                reloadFired1345 = true;\n                try { var wov = document.getElementById('ti-config-wait-1338'); if (wov) wov.remove(); if (window.tiRestoreAudioAfterWait1360) window.tiRestoreAudioAfterWait1360(); } catch(e){}\n                try { sessionStorage.removeItem('ti_company_switch_pending_1927'); } catch(ePendingNet1927) {}\n                if (window.tiAlert) window.tiAlert('Problema temporaneo di connessione con il server. Riprova a selezionare la ditta.');\n                else alert('Problema temporaneo di connessione con il server. Riprova a selezionare la ditta.');\n            }\n            var safetyTimer1345 = setTimeout(checkDittaSyncTimeout1371, 12000);\n            try { document.addEventListener('visibilitychange', function onVis1371(){ if (!document.hidden) { checkDittaSyncTimeout1371(); if (reloadFired1345) document.removeEventListener('visibilitychange', onVis1371); } }); } catch(e){}\n            fetch(window.tiUrl || window.location.href, {method:'POST', body:fd1345, credentials:'same-origin'}).then(function(r){ return r.json(); }).then(function(d){\n                try { if (window.log1088) window.log1088('DIAGNOSTICA 1345: switch sessione server db=' + newDb1344 + ' esito=' + (d && d.success)); } catch(e){}\n                clearTimeout(safetyTimer1345);\n                if (!d || !d.success) {\n                    reloadFired1345 = true;\n                    try { var wov1741 = document.getElementById('ti-config-wait-1338'); if (wov1741) wov1741.remove(); if (window.tiRestoreAudioAfterWait1360) window.tiRestoreAudioAfterWait1360(); } catch(e){}\n                    try { sessionStorage.removeItem('ti_company_switch_pending_1927'); } catch(ePendingFail1927) {}\n                    var msg1741 = (d && d.data && (d.data.message || d.data.reply)) ? String(d.data.message || d.data.reply) : 'Cambio ditta non completato dal server.';\n                    if (window.tiAlert) window.tiAlert(msg1741); else alert(msg1741);\n                    return;\n                }\n                if (!reloadFired1345) { reloadFired1345 = true; finalizeReload1344(); }\n            }).catch(function(){\n                clearTimeout(safetyTimer1345);\n                if (reloadFired1345) return;\n                reloadFired1345 = true;\n                try { var wov2 = document.getElementById('ti-config-wait-1338'); if (wov2) wov2.remove(); if (window.tiRestoreAudioAfterWait1360) window.tiRestoreAudioAfterWait1360(); } catch(e){}\n                try { sessionStorage.removeItem('ti_company_switch_pending_1927'); } catch(ePendingNet1927) {}\n                if (window.tiAlert) window.tiAlert('Problema temporaneo di connessione con il server. Riprova a selezionare la ditta.');\n                else alert('Problema temporaneo di connessione con il server. Riprova a selezionare la ditta.');\n            });\n        } catch(e1345) { finalizeReload1344(); }\n    }, true);\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ render(); setTimeout(loadDataAndRender, 300); try { rewriteLocalDocAnchors(document); } catch(e) {} });\n    else { render(); setTimeout(loadDataAndRender, 300); try { rewriteLocalDocAnchors(document); } catch(e) {} }\n    try { new MutationObserver(function(muts){ muts.forEach(function(m){ (m.addedNodes || []).forEach(function(n){ if (n && n.nodeType === 1) rewriteLocalDocAnchors(n); }); }); }).observe(document.documentElement, {childList:true, subtree:true}); } catch(e) {}\n})();\n<\/script>\n\n\n\n<script id=\"ti-activity-qrcode-direct-299\">\n(function(){\n    \"use strict\";\n    if (window.__tiActivityQrDirect299) return;\n    window.__tiActivityQrDirect299 = true;\n    function tryShow(){ try { if (window.showActivityFromQrIfRequested) window.showActivityFromQrIfRequested(); } catch(e) {} }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ setTimeout(tryShow, 600); setTimeout(tryShow, 1600); });\n    else { setTimeout(tryShow, 600); setTimeout(tryShow, 1600); }\n    document.addEventListener('change', function(ev){ if (ev && ev.target && ev.target.id === 'ti-ditta') setTimeout(tryShow, 700); }, true);\n})();\n<\/script>\n\n\n<script id=\"ti-config-open-rescue-218\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigOpenRescue218) return;\n    window.__tiConfigOpenRescue218 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){\n            return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#039;'}[c];\n        });\n    }\n    function selectedDb(){\n        var sel = byId('ti-ditta');\n        return sel ? String(sel.value || '').trim() : '';\n    }\n    function currentSessionDb(){\n        var db = '';\n        try { db = String(window.tiSessionDb || window.tiForced || window.tiCurrentSelectedDb || '').trim(); } catch(e) {}\n        if (!db) db = selectedDb();\n        return db;\n    }\n    function markCurrentDbData(db){\n        try {\n            db = String(db || selectedDb() || '').trim();\n            if (db) {\n                window.__tiCurrentDbDataDb = db;\n                window.__tiConfigLoadedDb = db;\n                if (window.currentDbData && typeof window.currentDbData === 'object' && !window.currentDbData.__db_name) window.currentDbData.__db_name = db;\n            }\n        } catch(e) {}\n    }\n    function cachedConfigDataFor(db){\n        try {\n            db = String(db || '').trim();\n            var data = window.currentDbData || null;\n            if (!db || !data || !data.Tabelle) return null;\n            var known = String(data.__db_name || window.__tiCurrentDbDataDb || window.__tiConfigLoadedDb || '').trim();\n            if (known && known !== db) return null;\n            if (!known) {\n                var sel = selectedDb();\n                var sessDb = currentSessionDb();\n                if (sel && sel === db) {\n                    try { data.__db_name = db; window.__tiCurrentDbDataDb = db; window.__tiConfigLoadedDb = db; } catch(e) {}\n                    return data;\n                }\n                if (!sessDb || sessDb !== db) return null;\n            }\n            return data;\n        } catch(e) { return null; }\n    }\n    function prepareConfigStateFromData(data, db){\n        window.currentDbData = data;\n        markCurrentDbData(db);\n        try { window.configOriginalDbData = JSON.parse(JSON.stringify(data || {})); } catch(e) { window.configOriginalDbData = data || {}; }\n        window.configWasSaved = false;\n        window.tiConfigDeletedRowsManifest = [];\n        if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear();\n        try { if (window.refreshShopServiceActivationButton) window.refreshShopServiceActivationButton(); } catch(e) {}\n    }\n    function renderConfigNow(db, sourceLabel){\n        if (typeof window.renderConfig !== 'function') throw new Error('Funzione renderConfig non disponibile.');\n        window.__tiConfigOpeningFast459 = true;\n        window.renderConfig();\n        window.__tiConfigOpeningFast459 = false;\n        openConfigOverlay();\n        try { if (typeof window.updateConfigSaveButtonState === 'function') window.updateConfigSaveButtonState(); } catch(e) {}\n        try { if (sourceLabel && window.console) console.info('Shop & Service configurazione aperta: ' + sourceLabel + ' - ' + db); } catch(e) {}\n    }\n    function showConfigSoftNotice(html, type){\n        try {\n            var cnt = byId('ti-conf-cnt');\n            if (!cnt) return;\n            var old = byId('ti-config-soft-notice-459');\n            if (old && old.parentNode) old.parentNode.removeChild(old);\n            var div = document.createElement('div');\n            div.id = 'ti-config-soft-notice-459';\n            var border = type === 'error' ? '#ef4444' : '#f59e0b';\n            var bg = type === 'error' ? '#450a0a' : '#422006';\n            var color = type === 'error' ? '#fecaca' : '#fde68a';\n            div.setAttribute('style','position:sticky;top:0;z-index:5;margin:8px 8px 12px 8px;padding:10px 12px;border-radius:10px;border:1px solid '+border+';background:'+bg+';color:'+color+';font-size:12px;line-height:1.35;');\n            div.innerHTML = html;\n            cnt.insertBefore(div, cnt.firstChild || null);\n        } catch(e) {}\n    }\n    function openConfigOverlay(){\n        var ov = byId('ti-conf-ov');\n        try {\n            if (window.showPluginModal) window.showPluginModal(ov || 'ti-conf-ov');\n            else if (window.openModal) window.openModal('ti-conf-ov');\n            else if (ov) { ov.style.display = 'flex'; ov.style.position = 'fixed'; ov.style.inset = '0'; ov.style.zIndex = '2147483000'; }\n        } catch(e) {\n            if (ov) { ov.style.display = 'flex'; ov.style.position = 'fixed'; ov.style.inset = '0'; ov.style.zIndex = '2147483000'; }\n        }\n    }\n    function setConfigMessage(html, type){\n        var cnt = byId('ti-conf-cnt');\n        if (!cnt) return;\n        var border = type === 'error' ? '#ef4444' : '#22c55e';\n        var bg = type === 'error' ? '#450a0a' : '#052e16';\n        var color = type === 'error' ? '#fecaca' : '#bbf7d0';\n        cnt.innerHTML = '<div style=\"margin:14px;padding:14px;border-radius:12px;border:1px solid ' + border + ';background:' + bg + ';color:' + color + ';font-size:14px;line-height:1.45;\">' + html + '<\/div>';\n    }\n    function buildFd(action, extra){\n        var fd;\n        if (typeof window.buildAjaxFormData === 'function') fd = window.buildAjaxFormData(action, extra || {});\n        else {\n            fd = new FormData();\n            fd.append('action', action);\n            fd.append('ti_action', action);\n            Object.keys(extra || {}).forEach(function(k){ if (extra[k] !== undefined && extra[k] !== null) fd.append(k, extra[k]); });\n        }\n        if (fd instanceof FormData) {\n            if (!fd.has('action')) fd.append('action', action);\n            if (!fd.has('ti_action')) fd.append('ti_action', action);\n        }\n        return fd;\n    }\n    function postJson(fd, db, cfgOpts){\n        cfgOpts = cfgOpts || {};\n        var url = window.tiAjaxUrl || window.ajaxurl || window.tiUrl || window.location.href;\n        var form = (window.ensureAjaxActionField ? window.ensureAjaxActionField(fd) : fd);\n        var timeoutMs = cfgOpts.timeoutMs || 15000;\n        var controller = null;\n        var timer = null;\n        var opts = { method:'POST', body:form, credentials:'same-origin', cache:'no-store' };\n        try {\n            if (window.AbortController) {\n                controller = new AbortController();\n                opts.signal = controller.signal;\n            }\n        } catch(e) {}\n        return new Promise(function(resolve, reject){\n            timer = setTimeout(function(){\n                try { if (controller) controller.abort(); } catch(e) {}\n                reject(new Error('Lettura database non completata entro ' + Math.round(timeoutMs\/1000) + ' secondi. Riprova oppure ricarica la pagina.'));\n            }, timeoutMs);\n            fetch(url, opts).then(function(r){\n                return r.text().then(function(t){\n                    if(!r.ok) throw new Error('HTTP ' + r.status + ': ' + String(t || '').slice(0,180));\n                    try { return JSON.parse(t); }\n                    catch(e) { throw new Error('Risposta server non valida: ' + String(t || '').slice(0,180)); }\n                });\n            }).then(function(json){ clearTimeout(timer); resolve(json); }).catch(function(err){ clearTimeout(timer); reject(err); });\n        });\n    }\n    function withConfigTimeout(promise, ms, label){\n        var done = false;\n        return new Promise(function(resolve, reject){\n            var timer = setTimeout(function(){\n                if (done) return;\n                done = true;\n                reject(new Error((label || 'Caricamento configurazione') + ' non completato entro ' + Math.round(ms\/1000) + ' secondi. Il server potrebbe essere occupato o la risposta troppo lenta.'));\n            }, ms);\n            Promise.resolve(promise).then(function(v){\n                if (done) return;\n                done = true; clearTimeout(timer); resolve(v);\n            }).catch(function(e){\n                if (done) return;\n                done = true; clearTimeout(timer); reject(e);\n            });\n        });\n    }\n\n    window.openConfigSafe218 = function(ev){\n        if (ev && ev.preventDefault) ev.preventDefault();\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') {\n            var msg = 'Seleziona prima una ditta valida per aprire la configurazione.';\n            if (typeof window.tiAlert === 'function') window.tiAlert(msg); else alert(msg);\n            return Promise.resolve(false);\n        }\n        if (window.__tiConfigOpeningPromise459 && window.__tiConfigOpeningDb459 === db) return window.__tiConfigOpeningPromise459;\n        openConfigOverlay();\n        var cached = cachedConfigDataFor(db);\n        var usedCache = false;\n        var cachedVersion = cached && cached.__db_version ? String(cached.__db_version) : '';\n        if (cached) {\n            try {\n                usedCache = true;\n                prepareConfigStateFromData(cached, db);\n                renderConfigNow(db, 'dati gia in memoria');\n                showConfigSoftNotice('<b>Configurazione aperta subito.<\/b> Verifico in background se il database e stato modificato.', 'warn');\n            } catch(cacheErr) {\n                usedCache = false;\n                setConfigMessage('<b>Caricamento configurazione in corso...<\/b><br><span style=\"font-size:12px;\">I dati in memoria non sono utilizzabili, rileggo il database.<\/span>', 'ok');\n            }\n        } else {\n            setConfigMessage('<b>Caricamento configurazione in corso...<\/b><br><span style=\"font-size:12px;\">Lettura database in corso. Se il server non risponde, comparira automaticamente il pulsante Riprova.<\/span>', 'ok');\n        }\n        var slowTimer = setTimeout(function(){\n            try {\n                if (usedCache) showConfigSoftNotice('<b>Verifica database ancora in corso.<\/b> Puoi continuare a consultare la configurazione; se il server conferma modifiche, la form viene aggiornata automaticamente.', 'warn');\n                else setConfigMessage('<b>Caricamento configurazione ancora in corso...<\/b><br>Il server sta impiegando piu del previsto. <button type=\"button\" class=\"ti-btn\" style=\"margin-left:8px;background:#2563eb;color:#fff;\" onclick=\"window.__tiConfigOpeningPromise459=null;window.openConfigSafe218(event);return false;\">Riprova<\/button> <button type=\"button\" class=\"ti-btn\" style=\"margin-left:8px;background:#4b5563;color:#fff;\" onclick=\"window.__tiConfigOpeningPromise459=null;if(window.closeModal)window.closeModal(&quot;ti-conf-ov&quot;);return false;\">Chiudi<\/button>', 'ok');\n            } catch(e) {}\n        }, 5000);\n        var fd = buildFd('ti_ai_get_db_data', {db: db, ti_config_open: '1'});\n        if (usedCache) {\n            window.__tiConfigOpeningPromise459 = null;\n            window.__tiConfigOpeningDb459 = '';\n        }\n        var promise = withConfigTimeout(postJson(fd, db, {silentWait: true, timeoutMs: usedCache ? 9000 : 12000}), usedCache ? 10000 : 13000, 'Caricamento configurazione').then(function(res){\n            clearTimeout(slowTimer);\n            window.__tiConfigOpeningPromise459 = null;\n            if (!res || !res.success || !res.data) {\n                var serverMsg = res && res.data && res.data.message ? res.data.message : (res && res.message ? res.message : 'lettura database non riuscita');\n                throw new Error(serverMsg);\n            }\n            var freshVersion = res.data && res.data.__db_version ? String(res.data.__db_version) : '';\n            prepareConfigStateFromData(res.data, db);\n            if (usedCache && cachedVersion && freshVersion && cachedVersion === freshVersion) {\n                showConfigSoftNotice('<b>Database verificato.<\/b> La configurazione era gia aggiornata.', 'warn');\n                setTimeout(function(){ var n = byId('ti-config-soft-notice-459'); if (n && n.parentNode) n.parentNode.removeChild(n); }, 2500);\n                return true;\n            }\n            try {\n                renderConfigNow(db, usedCache ? 'refresh database completato' : 'lettura database completata');\n            } catch(renderErr) {\n                setConfigMessage('<b>Errore apertura form configurazione.<\/b><br>' + esc(renderErr && renderErr.message ? renderErr.message : renderErr), 'error');\n                throw renderErr;\n            }\n            setTimeout(function(){\n                var cnt = byId('ti-conf-cnt');\n                if (cnt && !String(cnt.innerHTML || '').trim()) {\n                    setConfigMessage('<b>Form configurazione aperto, ma nessuna tabella renderizzata.<\/b><br>Verifica che il database contenga la sezione Tabelle.', 'error');\n                }\n                if (typeof window.updateConfigSaveButtonState === 'function') window.updateConfigSaveButtonState();\n            }, 80);\n            return true;\n        }).catch(function(err){\n            clearTimeout(slowTimer);\n            window.__tiConfigOpeningPromise459 = null;\n            openConfigOverlay();\n            var m = err && err.message ? err.message : String(err || 'errore sconosciuto');\n            if (usedCache) {\n                showConfigSoftNotice('<b>Verifica database non completata.<\/b> La configurazione aperta e quella gia disponibile in memoria.<br>' + esc(m), 'error');\n                try { console.error('Shop & Service CONFIGURA background refresh error', err); } catch(e) {}\n                return true;\n            }\n            setConfigMessage('<b>Configurazione non caricata.<\/b><br>' + esc(m) + '<br><br><button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;margin-right:8px;\" onclick=\"window.__tiConfigOpeningPromise459=null;window.openConfigSafe218(event);return false;\">Riprova<\/button><button type=\"button\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\" onclick=\"window.closeModal&&window.closeModal(\\'ti-conf-ov\\');return false;\">Chiudi<\/button><br><br>La finestra resta aperta per mostrare il problema invece di chiudersi senza messaggi.', 'error');\n            try { console.error('Shop & Service CONFIGURA open error', err); } catch(e) {}\n            return false;\n        });\n        window.__tiConfigOpeningDb459 = db;\n        window.__tiConfigOpeningPromise459 = promise;\n        return promise;\n    };\n\n    function bindConfigButton(){\n        var btn = byId('ti-conf-toggle');\n        if (!btn) return;\n        btn.onclick = window.openConfigSafe218;\n        btn.setAttribute('data-ti-config-open-rescue', '218');\n        btn.style.display = 'inline-block';\n    }\n\n    document.addEventListener('click', function(ev){\n        var target = ev.target;\n        if (!target || !target.closest) return;\n        var btn = target.closest('#ti-conf-toggle');\n        if (!btn) return;\n        ev.preventDefault();\n        if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n        else ev.stopPropagation();\n        window.openConfigSafe218(ev);\n    }, true);\n\n    var prevSetAdminUI = window.setAdminUI;\n    if (typeof prevSetAdminUI === 'function' && !prevSetAdminUI.__tiConfigOpenRescue218) {\n        window.setAdminUI = function(){\n            var ret = prevSetAdminUI.apply(this, arguments);\n            try { bindConfigButton(); } catch(e) {}\n            return ret;\n        };\n        window.setAdminUI.__tiConfigOpenRescue218 = true;\n    }\n\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bindConfigButton);\n    else bindConfigButton();\n    var tries = 0;\n    var timer = setInterval(function(){\n        tries += 1;\n        bindConfigButton();\n        if (tries > 20 || byId('ti-conf-toggle')) clearInterval(timer);\n    }, 500);\n})();\n<\/script>\n\n\n\n\n\n<script id=\"ti-demo-readonly-695\">\n(function(){\n    \"use strict\";\n    if (window.__tiDemoReadonly695) return;\n    window.__tiDemoReadonly695 = true;\n    function byId(id){ return document.getElementById(id); }\n    function esc(s){ return String(s == null ? '' : s).replace(\/[&<>\"']\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];}); }\n    function alertHtml(html){ try { if (window.tiAlert) window.tiAlert(html); else window.alert(String(html || '').replace(\/<[^>]+>\/g,' ')); } catch(e) {} }\n    \/\/ 30.9.1939: il primo avviso di accesso a una ditta Demo ha una finestra dedicata,\n    \/\/ cosi nessun alert concorrente puo sostituirlo prima dei 20 secondi richiesti.\n    window.tiShowDemoFirstNotice1939 = function(html){\n        try {\n            var old = byId('ti-demo-first-notice-1939');\n            if (old) old.remove();\n            var ov = document.createElement('div');\n            ov.id = 'ti-demo-first-notice-1939';\n            ov.setAttribute('role','dialog');\n            ov.setAttribute('aria-modal','true');\n            ov.style.cssText = 'position:fixed;inset:0;z-index:2147483647;background:rgba(0,0,0,.72);display:flex;align-items:center;justify-content:center;padding:18px;box-sizing:border-box;';\n            var box = document.createElement('div');\n            box.style.cssText = 'width:min(560px,94vw);max-height:86vh;overflow:auto;background:#111827;color:#fff;border:1px solid #38bdf8;border-radius:12px;padding:18px;box-shadow:0 18px 48px rgba(0,0,0,.55);font-family:Arial,Helvetica,sans-serif;text-align:left;';\n            var body = document.createElement('div');\n            body.style.cssText = 'font-size:14px;line-height:1.5;color:#f8fafc;';\n            body.innerHTML = String(html || '');\n            var footer = document.createElement('div');\n            footer.style.cssText = 'display:flex;justify-content:flex-end;align-items:center;gap:10px;margin-top:18px;';\n            var count = document.createElement('span');\n            count.id = 'ti-demo-first-notice-countdown-1939';\n            count.style.cssText = 'font-size:12px;color:#bae6fd;font-weight:700;';\n            var btn = document.createElement('button');\n            btn.type = 'button';\n            btn.className = 'ti-btn';\n            btn.disabled = false;\n            btn.style.cssText = 'background:#0284c7;color:#fff;border:1px solid #0ea5e9;border-radius:8px;padding:8px 15px;font-weight:800;opacity:1;cursor:pointer;';\n            footer.appendChild(count); footer.appendChild(btn); box.appendChild(body); box.appendChild(footer); ov.appendChild(box); document.body.appendChild(ov);\n            var endAt = Date.now() + 20000;\n            var closed2037 = false;\n            var timer = 0;\n            var autoCloseTimer = 0;\n            var closeDemoNotice2037 = function(){\n                if (closed2037) return false;\n                closed2037 = true;\n                try { if (timer) window.clearInterval(timer); } catch(e) {}\n                try { if (autoCloseTimer) window.clearTimeout(autoCloseTimer); } catch(e) {}\n                try { if (ov && ov.parentNode) ov.parentNode.removeChild(ov); } catch(e) {}\n                return false;\n            };\n            var tick = function(){\n                if (closed2037) return;\n                var left = Math.max(0, Math.ceil((endAt - Date.now()) \/ 1000));\n                var isEn = String(window.currLang || 'it').toLowerCase().indexOf('en') === 0;\n                count.textContent = isEn ? ('Automatic close in ' + left + ' s') : ('Chiusura automatica tra ' + left + ' s');\n                btn.textContent = isEn ? 'Close' : 'Chiudi';\n                if (left <= 0) closeDemoNotice2037();\n            };\n            tick();\n            timer = window.setInterval(tick, 250);\n            autoCloseTimer = window.setTimeout(closeDemoNotice2037, 20000);\n            \/\/ Il popup dura al massimo 20 secondi, ma Chiudi e operativo subito per consentire la chiusura anticipata.\n            \/\/ Click\/tap sullo sfondo non devono invece chiuderlo accidentalmente.\n            ov.addEventListener('click', function(ev){\n                if (ev && ev.target === btn) return;\n                ev.preventDefault(); ev.stopPropagation();\n            }, true);\n            ov.addEventListener('touchend', function(ev){\n                if (ev && ev.target === btn) return;\n                ev.preventDefault(); ev.stopPropagation();\n            }, {capture:true, passive:false});\n            btn.addEventListener('click', function(ev){\n                ev.preventDefault(); ev.stopPropagation();\n                return closeDemoNotice2037();\n            }, true);\n            try { if (window.applyLayoutLanguage) window.applyLayoutLanguage(true); } catch(e) {}\n        } catch(e) { alertHtml(html); }\n    };\n    window.tiIsDemoReadonly = function(){ return !!window.tiDemoReadonly || String(window.tiUser || '').trim().toLowerCase() === 'ssdemo'; };\n    window.tiShowDemoCompanyAccessNotice695 = function(optionEl){\n        try {\n            if (!optionEl) return;\n            var isDemo = String((optionEl.dataset && (optionEl.dataset.status || optionEl.dataset.companyState || optionEl.dataset.stato)) || '').toLowerCase().indexOf('demo') !== -1 || String(optionEl.getAttribute('data-demo-login-available') || '') === '1';\n            if (!isDemo) return;\n            if (String(window.tiUser || '').trim().toLowerCase() === 'ssdemo') return;\n            var db = String(optionEl.value || '');\n            var key = 'ti_demo_login_notice_695_' + db;\n            if (sessionStorage.getItem(key) === '1') return;\n            sessionStorage.setItem(key, '1');\n            var msg = String(optionEl.getAttribute('data-demo-login-notice') || 'Ditta Demo: puoi accedere con username ssdemo e password ssdemo per visualizzare la configurazione in sola lettura.');\n            window.tiShowDemoFirstNotice1939('<b>Ditta Demo<\/b><br><br>' + esc(msg) + '<br><br><b>Username:<\/b> ssdemo<br><b>Password:<\/b> ssdemo');\n        } catch(e) {}\n    };\n    window.tiShowSsdemoAccessPopup695 = function(){\n        try {\n            if (!window.tiIsDemoReadonly || !window.tiIsDemoReadonly()) return;\n            if (window.__tiSsdemoPopupShown695) return;\n            window.__tiSsdemoPopupShown695 = true;\n            alertHtml('<b>Accesso Demo sola lettura<\/b><br><br>Sei entrato come <b>ssdemo<\/b>.<br>Puoi visualizzare la configurazione della ditta Demo e usare la chat AI come utente base. Non puoi modificare, aggiungere, cancellare o salvare dati.');\n        } catch(e) {}\n    };\n    window.tiApplyDemoReadonlyConfig695 = function(root){\n        try {\n            if (!window.tiIsDemoReadonly || !window.tiIsDemoReadonly()) return;\n            root = root || document;\n            var conf = byId('ti-conf-cnt');\n            var scope = conf && conf.contains(root) ? conf : (root === document ? conf || document : root);\n            if (!scope) return;\n            if (conf && !byId('ti-demo-readonly-banner-695')) {\n                var b = document.createElement('div');\n                b.id = 'ti-demo-readonly-banner-695';\n                b.style.cssText = 'margin:8px 0 12px 0;padding:10px 12px;border-radius:10px;background:#082f49;border:1px solid #38bdf8;color:#e0f2fe;font-size:13px;font-weight:700;line-height:1.35;';\n                b.innerHTML = 'Modalit\u00e0 Demo sola lettura: puoi consultare i dati, ma non puoi modificare, aggiungere, cancellare o salvare.';\n                conf.insertBefore(b, conf.firstChild);\n            }\n            var editable = scope.querySelectorAll ? scope.querySelectorAll('input, textarea, select') : [];\n            Array.prototype.forEach.call(editable, function(el){\n                if (!el || el.id === 'ti-cfg-tips-enabled') return;\n                if (el.id === 'ti-conf-ai-prompt') {\n                    el.readOnly = false; el.disabled = false;\n                    el.setAttribute('data-ti-demo-readonly-allow','1');\n                    el.style.removeProperty('opacity');\n                    return;\n                }\n                if (el.type === 'hidden') return;\n                if (el.type === 'checkbox' || el.type === 'radio' || el.tagName === 'SELECT') el.disabled = true;\n                else el.readOnly = true;\n                el.setAttribute('data-ti-demo-readonly','1');\n                el.style.setProperty('opacity','0.85','important');\n            });\n            function isMutatingDemoButton(btn){\n                var txt = String((btn && (btn.textContent || btn.value)) || '').replace(\/\\s+\/g,' ').trim().toLowerCase();\n                var inline = String((btn && btn.getAttribute && btn.getAttribute('onclick')) || '').toLowerCase();\n                if (txt === 'x' || txt.indexOf('chiudi') !== -1 || txt.indexOf('esci') !== -1 || txt.indexOf('?') !== -1 || txt.indexOf('info') !== -1 || txt.indexOf('copia') !== -1) return false;\n                if (inline.indexOf('close') !== -1 || inline.indexOf('openconfigtableforwarning') !== -1 || inline.indexOf('showconfiguratoroperationaltipspopup') !== -1) return false;\n                if (\/^(config|prodotti|servizi|utenti|informazioni|istruzioni|operatori|siti|dispositivi|appuntamenti|attivita|attivit\u00e0|apri tabella|elenco dati|<<|>>|pag\\s*\\d*)$\/i.test(txt)) return false;\n                var mut = \/(salva|salvataggio|aggiung|nuov|crea|elimina|cancella|rimuov|pulisci|import|carica|upload|genera|applica|modifica|sposta|ordina|associa|dissocia|backup|ripristina|attiva|disattiva|verifica istruzioni|acquisizion|globale|storage|password|email|sms)\/i;\n                return mut.test(txt) || mut.test(inline);\n            }\n            window.tiDemoReadonlyIsMutatingButton695 = isMutatingDemoButton;\n            var buttons = scope.querySelectorAll ? scope.querySelectorAll('button, [role=\"button\"]') : [];\n            Array.prototype.forEach.call(buttons, function(btn){\n                if (btn && btn.id === 'ti-conf-ai-send') { btn.disabled = false; btn.setAttribute('data-ti-demo-readonly-allow','1'); btn.style.removeProperty('opacity'); return; }\n                if (isMutatingDemoButton(btn)) {\n                    btn.disabled = true;\n                    btn.setAttribute('data-ti-demo-readonly','1');\n                    btn.style.setProperty('opacity','0.45','important');\n                    btn.title = 'Disabilitato in accesso Demo sola lettura';\n                }\n            });\n            var save = byId('ti-save-config');\n            if (save) { save.disabled = true; save.textContent = 'Sola lettura Demo'; save.title = 'Accesso ssdemo: salvataggio disabilitato'; }\n        } catch(e) {}\n    };\n    document.addEventListener('change', function(ev){\n        try { if (ev && ev.target && ev.target.id === 'ti-ditta') window.tiShowDemoCompanyAccessNotice695(ev.target.options[ev.target.selectedIndex]); } catch(e) {}\n    }, true);\n    document.addEventListener('click', function(ev){\n        try {\n            var t = ev.target;\n            if (!t || !t.closest) return;\n            if ((window.tiIsDemoReadonly && window.tiIsDemoReadonly()) && t.closest('#ti-conf-cnt button:not([data-ti-demo-readonly-allow])')) {\n                var b = t.closest('button');\n                if (!b) return;\n                if (b.disabled) return;\n                var mut = window.tiDemoReadonlyIsMutatingButton695 ? window.tiDemoReadonlyIsMutatingButton695(b) : false;\n                if (mut) {\n                    ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                    alertHtml('<b>Accesso Demo sola lettura<\/b><br><br>Con l utente <b>ssdemo<\/b> puoi solo visualizzare i dati. Modifiche, aggiunte, cancellazioni e salvataggi sono disabilitati.');\n                    return false;\n                }\n            }\n        } catch(e) {}\n    }, true);\n    if (typeof window.renderConfig === 'function' && !window.renderConfig.__tiDemoReadonly695) {\n        var prevRenderConfig695 = window.renderConfig;\n        window.renderConfig = function(){\n            var ret = prevRenderConfig695.apply(this, arguments);\n            setTimeout(function(){ window.tiApplyDemoReadonlyConfig695(document); }, 0);\n            return ret;\n        };\n        window.renderConfig.__tiDemoReadonly695 = true;\n    }\n    if (typeof window.updCtx === 'function' && !window.updCtx.__tiDemoNotice695) {\n        var prevUpdCtx695 = window.updCtx;\n        window.updCtx = function(){\n            var ret = prevUpdCtx695.apply(this, arguments);\n            try { var d = byId('ti-ditta'); if (d && d.value) window.tiShowDemoCompanyAccessNotice695(d.options[d.selectedIndex]); } catch(e) {}\n            return ret;\n        };\n        window.updCtx.__tiDemoNotice695 = true;\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ setTimeout(window.tiShowSsdemoAccessPopup695, 350); setTimeout(function(){ window.tiApplyDemoReadonlyConfig695(document); }, 700); });\n    else { setTimeout(window.tiShowSsdemoAccessPopup695, 350); setTimeout(function(){ window.tiApplyDemoReadonlyConfig695(document); }, 700); }\n    try { new MutationObserver(function(){ if (window.tiIsDemoReadonly && window.tiIsDemoReadonly()) window.tiApplyDemoReadonlyConfig695(document); }).observe(document.documentElement, {childList:true, subtree:true}); } catch(e) {}\n})();\n<\/script>\n\n<script id=\"ti-login-memory-fix-312\">\n(function(){\n    \"use strict\";\n    if (window.__tiLoginMemoryFix312) return;\n    window.__tiLoginMemoryFix312 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function safeGet(storage, key){ try { return storage.getItem(key) || ''; } catch(e) { return ''; } }\n    function safeSet(storage, key, val){ try { storage.setItem(key, String(val || '')); } catch(e) {} }\n    function safeRemove(storage, key){ try { storage.removeItem(key); } catch(e) {} }\n    function hasOption(sel, value){\n        if (!sel || !value) return false;\n        for (var i = 0; i < sel.options.length; i++) if (sel.options[i].value === value) return true;\n        return false;\n    }\n    function isBadCredentialClearActive(){\n        return safeGet(sessionStorage, 'ti_login_failed_clear') === '1';\n    }\n    function clearStableUsername(userEl){\n        try { if (userEl && userEl.dataset) delete userEl.dataset.tiStableUsername; } catch(e) {}\n    }\n\n    window.tiRememberSuccessfulLogin = function(user, db){\n        try {\n            var u = String(user || '').trim();\n            var d = String(db || '').trim();\n            if (\/^(?:SSGlobalAdmin|SSGlobelAdmin|GlobalAdmin)$\/i.test(u)) safeRemove(localStorage, 'ti_last_login_user');\n            else if (u) safeSet(localStorage, 'ti_last_login_user', u);\n            if (d) {\n                safeSet(localStorage, 'ti_last_login_db', d);\n                safeSet(localStorage, 'ti_saved_db', d);\n            }\n            safeRemove(sessionStorage, 'ti_login_failed_clear');\n        } catch(e) {}\n    };\n\n    window.tiClearLoginFieldsAfterFailure = function(clearUserToo){\n        try {\n            var currentUser1995 = String((byId('l-user')||{}).value || (byId('ti-direct-login-user')||{}).value || '').trim();\n            if (\/^SSGlobalAdmin$\/i.test(currentUser1995)) {\n                \/\/ 30.9.1995: un errore credenziali globale non crea memoria\/recovery di login fallito.\n                safeRemove(sessionStorage, 'ti_login_failed_clear');\n                safeRemove(localStorage, 'ti_last_login_user');\n                ['l-pass','ti-direct-login-pass'].forEach(function(id){ var el=byId(id); if(el) el.value=''; });\n                return;\n            }\n            safeSet(sessionStorage, 'ti_login_failed_clear', '1');\n            var ids = clearUserToo ? ['l-user','ti-direct-login-user'] : [];\n            ids.forEach(function(id){ var el = byId(id); if (el) { el.value = ''; clearStableUsername(el); } });\n            ['l-pass','ti-direct-login-pass'].forEach(function(id){ var el = byId(id); if (el) el.value = ''; });\n            var target = clearUserToo ? (byId('l-user') || byId('ti-direct-login-user')) : (byId('l-pass') || byId('ti-direct-login-pass'));\n            if (target && typeof target.focus === 'function') {\n                setTimeout(function(){ try { target.focus({preventScroll:true}); } catch(e) { try { target.focus(); } catch(ignore) {} } }, 30);\n            }\n        } catch(e) {}\n    };\n\n    window.tiApplyLastSuccessfulLoginToForm = function(force){\n        try {\n            var userEl = byId('l-user');\n            var passEl = byId('l-pass');\n            var dbEl = byId('l-db');\n            var hiddenDb = byId('l-db-hidden');\n            if (isBadCredentialClearActive() && !force) {\n                if (userEl && userEl.value) { userEl.value = ''; clearStableUsername(userEl); }\n                if (passEl && passEl.value) passEl.value = '';\n                return;\n            }\n            var lastUser = safeGet(localStorage, 'ti_last_login_user');\n            if (\/^(?:SSGlobalAdmin|SSGlobelAdmin|GlobalAdmin)$\/i.test(lastUser)) { safeRemove(localStorage, 'ti_last_login_user'); lastUser = ''; }\n            var lastDb = safeGet(localStorage, 'ti_last_login_db') || safeGet(localStorage, 'ti_saved_db');\n            if (userEl && lastUser && (!userEl.value || force)) {\n                userEl.value = lastUser;\n                try { userEl.dataset.tiStableUsername = lastUser; } catch(e) {}\n            }\n            if (dbEl && lastDb && hasOption(dbEl, lastDb) && (!dbEl.value || force)) {\n                dbEl.value = lastDb;\n                if (hiddenDb) hiddenDb.value = lastDb;\n                try { dbEl.dispatchEvent(new Event('change', {bubbles:true})); } catch(e) {}\n            } else if (hiddenDb && lastDb && (!hiddenDb.value || force)) {\n                hiddenDb.value = lastDb;\n            }\n            if (passEl) passEl.value = '';\n        } catch(e) {}\n    };\n\n    function bindManualTypingReset(){\n        try {\n            ['l-user','l-pass','ti-direct-login-user','ti-direct-login-pass'].forEach(function(id){\n                var el = byId(id);\n                if (!el || el.dataset.tiLoginMemoryResetBound312) return;\n                el.dataset.tiLoginMemoryResetBound312 = '1';\n                el.addEventListener('input', function(){ safeRemove(sessionStorage, 'ti_login_failed_clear'); }, false);\n            });\n        } catch(e) {}\n    }\n\n    function patchOpenLogin(){\n        try {\n            if (typeof window.openLoginModalSafe === 'function' && !window.openLoginModalSafe.__tiLoginMemory312) {\n                var prevOpen = window.openLoginModalSafe;\n                window.openLoginModalSafe = function(){\n                    var ret = prevOpen.apply(this, arguments);\n                    setTimeout(function(){ try { window.tiApplyLastSuccessfulLoginToForm(false); bindManualTypingReset(); } catch(e) {} }, 90);\n                    setTimeout(function(){ try { window.tiApplyLastSuccessfulLoginToForm(false); bindManualTypingReset(); } catch(e) {} }, 260);\n                    return ret;\n                };\n                window.openLoginModalSafe.__tiLoginMemory312 = true;\n            }\n            if (typeof window.syncLoginDbSelect === 'function' && !window.syncLoginDbSelect.__tiLoginMemory312) {\n                var prevSync = window.syncLoginDbSelect;\n                window.syncLoginDbSelect = function(){\n                    var ret = prevSync.apply(this, arguments);\n                    try { window.tiApplyLastSuccessfulLoginToForm(false); } catch(e) {}\n                    return ret;\n                };\n                window.syncLoginDbSelect.__tiLoginMemory312 = true;\n            }\n        } catch(e) {}\n    }\n\n    function boot(){\n        try {\n            if (String(window.tiUser || '').trim() && window.tiRememberSuccessfulLogin) {\n                window.tiRememberSuccessfulLogin(window.tiUser, window.tiSessionDb || window.tiForced || '');\n            }\n        } catch(e) {}\n        bindManualTypingReset();\n        patchOpenLogin();\n        try { window.tiApplyLastSuccessfulLoginToForm(false); } catch(e) {}\n    }\n\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ boot(); setTimeout(boot, 300); setTimeout(boot, 1200); });\n    else { boot(); setTimeout(boot, 300); setTimeout(boot, 1200); }\n    try { new MutationObserver(function(){ bindManualTypingReset(); patchOpenLogin(); }).observe(document.documentElement, {childList:true, subtree:true}); } catch(e) {}\n})();\n<\/script>\n\n\n<script id=\"ti-plugin-version-access-memory-314\">\n(function(){\n    \"use strict\";\n    if (window.__tiPluginVersionAccessMemory314) return;\n    window.__tiPluginVersionAccessMemory314 = true;\n\n    function safeGet(storage, key){ try { return storage.getItem(key) || ''; } catch(e) { return ''; } }\n    function safeSet(storage, key, val){ try { storage.setItem(key, String(val || '')); } catch(e) {} }\n    function esc(s){\n        return String(s == null ? '' : s).replace(\/[&<>\"']\/g, function(c){\n            return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c] || c;\n        });\n    }\n    function isPrivilegedVersionUser(){\n        var role = String(window.tiRole || '').toLowerCase();\n        var user = String(window.tiUser || '').toLowerCase();\n        return !!String(window.tiUser || '').trim() && (user === 'ssglobaladmin' || role.indexOf('configuratore') >= 0 || role.indexOf('configurator') >= 0 || role.indexOf('amministratore') >= 0 || role.indexOf('administrator') >= 0);\n    }\n    function selectedDbKey(){\n        var db = String(window.tiSessionDb || window.tiForced || window.tiCurrentSelectedDb || '').trim();\n        if (!db) { try { db = String((document.getElementById('ti-ditta') || {}).value || '').trim(); } catch(e) {} }\n        if (!db) { try { db = String(localStorage.getItem('ti_saved_db') || '').trim(); } catch(e) {} }\n        return db || 'no_db';\n    }\n    function storageKey(){\n        var user = String(window.tiUser || 'guest').trim() || 'guest';\n        var db = selectedDbKey();\n        return 'ti_plugin_last_version_access_' + location.host + '_' + db + '_' + user;\n    }\n    function readPrevious(key){\n        var raw = safeGet(localStorage, key);\n        if (!raw) return null;\n        try {\n            var obj = JSON.parse(raw);\n            if (obj && typeof obj === 'object') return obj;\n        } catch(e) {}\n        return {version: raw, datetime: '', ts: ''};\n    }\n    function currentPayload(){\n        return {\n            version: String(window.tiVersion || '').trim(),\n            datetime: String(window.tiVersionDateTime || '').trim(),\n            header: String(window.tiVersion || '').trim() + (window.tiVersionDateTime ? ' - ' + String(window.tiVersionDateTime).trim() : ''),\n            user: String(window.tiUser || '').trim(),\n            role: String(window.tiRole || '').trim(),\n            db: selectedDbKey(),\n            ts: new Date().toISOString()\n        };\n    }\n    window.tiCheckPluginVersionOnAccess = function(){\n        try {\n            if (!String(window.tiUser || '').trim()) return;\n            var key = storageKey();\n            var cur = currentPayload();\n            if (!cur.version) return;\n            var prev = readPrevious(key);\n            var changed = !!(prev && String(prev.version || '').trim() && String(prev.version || '').trim() !== cur.version);\n            safeSet(localStorage, key, JSON.stringify(cur));\n            safeSet(localStorage, 'ti_plugin_last_version_access_global_' + location.host, JSON.stringify(cur));\n            if (!changed || !isPrivilegedVersionUser()) return;\n            var prevHeader = String(prev.header || '').trim() || (String(prev.version || '').trim() + (prev.datetime ? ' - ' + String(prev.datetime).trim() : ''));\n            var html = '<div style=\"text-align:left;line-height:1.45;\">' +\n                '<b>Aggiornamento versione Shop &amp; Service rilevato<\/b><br><br>' +\n                'La versione del plugin e diversa da quella memorizzata al precedente accesso.<br><br>' +\n                '<b>Versione precedente:<\/b><br>' + esc(prevHeader || 'non disponibile') + '<br><br>' +\n                '<b>Versione attuale:<\/b><br>' + esc(cur.header || cur.version) + '<br><br>' +\n                '<span style=\"font-size:12px;color:#ccc;\">La nuova versione e stata ora memorizzata per i prossimi accessi.<\/span>' +\n                '<\/div>';\n            setTimeout(function(){\n                try {\n                    if (typeof window.tiAlert === 'function') window.tiAlert(html);\n                    else alert('Aggiornamento versione Shop & Service rilevato\\nVersione precedente: ' + (prevHeader || 'non disponibile') + '\\nVersione attuale: ' + (cur.header || cur.version));\n                } catch(e) {}\n            }, 900);\n        } catch(e) {}\n    };\n    function boot(){ try { window.tiCheckPluginVersionOnAccess(); } catch(e) {} }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ setTimeout(boot, 250); setTimeout(boot, 1400); });\n    else { setTimeout(boot, 250); setTimeout(boot, 1400); }\n})();\n<\/script>\n\n\n\n<script id=\"ti-plugin-server-version-check-457\">\n(function(){\n    \"use strict\";\n    if (window.__tiPluginServerVersionCheck457) return;\n    window.__tiPluginServerVersionCheck457 = true;\n\n    var pending = false;\n    var lastCheckAt = 0;\n    var lastSourceAt = {};\n    var endpoint = (function(){try{return String(window.tiUrl||window.location.href||'').split('#')[0].split('?')[0];}catch(e){return window.location.href;}})();\n    var pageVersion = String(window.tiVersion || \"30.9.2075\" || '').trim();\n    var pageDateTime = String(window.tiVersionDateTime || \"2026-10-14 11:26 CEST\" || '').trim();\n\n    function txt(v){ return String(v == null ? '' : v).trim(); }\n    function byId(id){ return document.getElementById(id); }\n    function esc(s){ return String(s == null ? '' : s).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c] || c; }); }\n    function fmt(n){\n        n = parseInt(n, 10) || 0;\n        try { return n.toLocaleString('it-IT'); } catch(e) { return String(n); }\n    }\n    function isPrivileged(){\n        var role = txt(window.tiRole).toLowerCase();\n        var user = txt(window.tiUser).toLowerCase();\n        if (!user) return false;\n        return user === 'ssglobaladmin' || role.indexOf('configuratore') >= 0 || role.indexOf('configurator') >= 0 || role.indexOf('amministratore') >= 0 || role.indexOf('administrator') >= 0;\n    }\n    function selectedDb(){\n        var db = txt(window.tiSessionDb || window.tiForced || window.tiCurrentSelectedDb || '');\n        if (!db) { var sel = byId('ti-ditta'); if (sel) db = txt(sel.value); }\n        return db || 'no_db';\n    }\n    function currentHeader(){ return pageVersion + (pageDateTime ? ' - ' + pageDateTime : ''); }\n    function disabled(){ try { return window.localStorage && localStorage.getItem('ti_disable_plugin_version_check') === '1'; } catch(e) { return false; } }\n    function warnedKey(v){ return 'ti_plugin_version_warned_457_' + location.host + '_' + selectedDb() + '_' + txt(window.tiUser || 'user') + '_' + txt(v || ''); }\n    function wasWarned(v){ try { return window.sessionStorage && sessionStorage.getItem(warnedKey(v)) === '1'; } catch(e) { return false; } }\n    function markWarned(v){ try { if (window.sessionStorage) sessionStorage.setItem(warnedKey(v), '1'); } catch(e) {} }\n    function showWarn(data, source){\n        data = data || {};\n        var serverVersion = txt(data.version);\n        if (!serverVersion || serverVersion === pageVersion) return;\n        if (wasWarned(serverVersion)) return;\n        markWarned(serverVersion);\n        var serverHeader = txt(data.header) || (serverVersion + (data.datetime ? ' - ' + txt(data.datetime) : ''));\n        var html = '<div style=\"text-align:left;line-height:1.45;\">' +\n            '<b>\u26a0\ufe0f Aggiornamento plugin rilevato<\/b><br><br>' +\n            'La pagina aperta sta usando una versione precedente di <b>Shop &amp; Service<\/b>, mentre sul server risulta attiva una versione diversa.<br><br>' +\n            '<b>Versione caricata nella pagina:<\/b><br>' + esc(currentHeader() || 'non disponibile') + '<br><br>' +\n            '<b>Versione attiva sul server:<\/b><br>' + esc(serverHeader || serverVersion) + '<br><br>' +\n            'Prima di proseguire in <b>Configurazione<\/b> o nella <b>main form<\/b>, aggiorna la pagina per usare il plugin aggiornato.' +\n            '<br><br><button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;border:0;border-radius:8px;padding:9px 12px;\" onclick=\"location.reload();return false;\">Aggiorna ora<\/button>' +\n            '<button type=\"button\" class=\"ti-btn\" style=\"margin-left:8px;background:#374151;color:#fff;border:0;border-radius:8px;padding:9px 12px;\" onclick=\"try{var m=document.querySelector(\\'.ti-modal.show,.ti-overlay.show,#ti-alert-ov\\');if(m)m.classList.remove(\\'show\\');}catch(e){} return false;\">Continua<\/button>' +\n            '<div style=\"margin-top:8px;font-size:12px;color:#cbd5e1;\">Controllo: ' + esc(source || 'accesso') + '<\/div>' +\n            '<\/div>';\n        try {\n            if (typeof window.tiAlert === 'function') window.tiAlert(html);\n            else alert('Aggiornamento plugin rilevato. Versione pagina: ' + (currentHeader() || 'non disponibile') + '\\nVersione server: ' + (serverHeader || serverVersion) + '\\nAggiorna la pagina prima di proseguire.');\n        } catch(e) {}\n    }\n    function parseJson(resp){ return resp.text().then(function(t){ try { return JSON.parse(t); } catch(e) { return null; } }); }\n    window.tiCheckPluginServerVersion457 = function(source, force){\n        try {\n            source = source || 'main form';\n            if (disabled() || !isPrivileged()) return Promise.resolve(false);\n            var now = Date.now();\n            \/\/ Anti-loop: mai piu di una chiamata globale ogni 60s; la Configurazione puo forzare ma non piu di una volta ogni 15s.\n            var minGlobal = force ? 15000 : 60000;\n            if (pending || (now - lastCheckAt < minGlobal)) return Promise.resolve(false);\n            if (lastSourceAt[source] && now - lastSourceAt[source] < 15000) return Promise.resolve(false);\n            pending = true; lastCheckAt = now; lastSourceAt[source] = now;\n            var fd = new FormData();\n            fd.append('action', 'ti_ai_plugin_version_check');\n            fd.append('ti_action', 'ti_ai_plugin_version_check');\n            fd.append('_ts', String(now));\n            fd.append('loaded_version', pageVersion);\n            fd.append('db', selectedDb());\n            var opts = {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'};\n            var ctl = null; var timer = null;\n            if (window.AbortController) {\n                ctl = new AbortController(); opts.signal = ctl.signal;\n                timer = setTimeout(function(){ try { ctl.abort(); } catch(e) {} }, 4000);\n            }\n            return fetch(endpoint, opts).then(parseJson).then(function(res){\n                pending = false; if (timer) clearTimeout(timer);\n                if (!res || res.success === false) return false;\n                showWarn(res.data || {}, source);\n                return true;\n            }).catch(function(){ pending = false; if (timer) clearTimeout(timer); return false; });\n        } catch(e) { pending = false; return Promise.resolve(false); }\n    };\n    function checkSoon(source, force, delay){ setTimeout(function(){ try { window.tiCheckPluginServerVersion457(source, !!force); } catch(e) {} }, delay == null ? 150 : delay); }\n    function patchFn(name, source){\n        try {\n            var fn = window[name];\n            if (typeof fn !== 'function' || fn.__tiVersionCheck457) return;\n            var wrapped = function(){\n                var ret = fn.apply(this, arguments);\n                checkSoon(source, true, 250);\n                return ret;\n            };\n            wrapped.__tiVersionCheck457 = true; wrapped.__tiOriginal = fn; window[name] = wrapped;\n        } catch(e) {}\n    }\n    function patchAll(){ patchFn('openConfigSafe218','Configurazione'); patchFn('setAdminUI','main form'); }\n    document.addEventListener('click', function(ev){\n        try {\n            var t = ev && ev.target; if (!t || !t.closest) return;\n            if (t.closest('#ti-conf-toggle')) checkSoon('Configurazione', true, 200);\n            else if (t.closest('#ti-send, #ti-ditta-trigger, #ti-ditta')) checkSoon('main form', false, 300);\n        } catch(e) {}\n    }, true);\n    document.addEventListener('change', function(ev){ try { if (ev && ev.target && ev.target.id === 'ti-ditta') checkSoon('main form', true, 300); } catch(e) {} }, true);\n    function boot(){ patchAll(); checkSoon('main form', false, 1200); setTimeout(patchAll, 1500); }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); else boot();\n})();\n<\/script>\n\n<script id=\"ti-login-singleton-fix-315\">\n(function(){\n    \"use strict\";\n    if (window.__tiLoginSingletonFix315) return;\n    window.__tiLoginSingletonFix315 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function all(sel){ try { return Array.prototype.slice.call(document.querySelectorAll(sel)); } catch(e) { return []; } }\n    function isVisible(el){\n        if (!el) return false;\n        try {\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            return el.style.display !== 'none' && (!cs || cs.display !== 'none') && el.getAttribute('aria-hidden') !== 'true';\n        } catch(e) { return el.style.display !== 'none'; }\n    }\n    function hideOverlay(el){\n        if (!el) return;\n        try {\n            el.classList.remove('ti-modal-open','ti-login-open-186','ti-login-open-315','open','active','show');\n            el.style.setProperty('display','none','important');\n            el.setAttribute('aria-hidden','true');\n        } catch(e) {}\n    }\n    function preferredLoginOverlay(){\n        var list = all('#ti-login-ov');\n        if (!list.length) return null;\n        var visible = list.filter(isVisible);\n        if (visible.length) return visible[0];\n        var inOuter = list.filter(function(el){ return !!(el.closest && el.closest('#ti-ai-outer')); });\n        return inOuter[0] || list[0];\n    }\n    function dedupeLoginDom(){\n        try {\n            var keep = preferredLoginOverlay();\n            all('#ti-login-ov').forEach(function(el){ if (el !== keep) hideOverlay(el); });\n            var keepForm = keep ? keep.querySelector('#ti-login-form') : null;\n            all('#ti-login-form').forEach(function(form){ if (form !== keepForm && form.closest && form.closest('#ti-login-ov')) hideOverlay(form.closest('#ti-login-ov')); });\n            var keepDirect = byId('ti-mobile-direct-login');\n            all('#ti-mobile-direct-login').forEach(function(el, idx){ if (idx > 0 || el !== keepDirect) { try { el.style.display='none'; el.setAttribute('aria-hidden','true'); } catch(e) {} } });\n            return keep;\n        } catch(e) { return byId('ti-login-ov'); }\n    }\n    function closeDirectFallbackUnlessManual(){\n        try {\n            var dl = byId('ti-mobile-direct-login');\n            if (!dl) return;\n            if (!dl.classList.contains('ti-direct-login-manual-open')) {\n                dl.classList.remove('ti-direct-login-visible');\n                dl.style.display = 'none';\n                dl.setAttribute('aria-hidden','true');\n            }\n        } catch(e) {}\n    }\n    function openLoginSingleton(ev){\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }\n        var now = Date.now();\n        if (window.__tiLoginOpenTs315 && now - window.__tiLoginOpenTs315 < 450) return false;\n        window.__tiLoginOpenTs315 = now;\n        var ov = dedupeLoginDom();\n        if (!ov) return false;\n        closeDirectFallbackUnlessManual();\n        try { if (window.syncLoginDbSelect) window.syncLoginDbSelect(); } catch(e) {}\n        try {\n            ov.style.setProperty('display','flex','important');\n            ov.style.setProperty('align-items','center','important');\n            ov.style.setProperty('justify-content','center','important');\n            ov.style.setProperty('pointer-events','auto','important');\n            ov.style.setProperty('z-index','2147483000','important');\n            ov.classList.add('ti-modal-open','ti-login-open-315');\n            ov.removeAttribute('aria-hidden');\n            var modal = ov.querySelector('.ti-modal');\n            if (modal) modal.style.setProperty('pointer-events','auto','important');\n            if (window.applyLayoutLanguage) window.applyLayoutLanguage(true);\n            if (window.tiApplyLastSuccessfulLoginToForm) window.tiApplyLastSuccessfulLoginToForm(false);\n            if (window.bindMobileLoginButton) window.bindMobileLoginButton();\n        } catch(e) {}\n        setTimeout(function(){\n            try {\n                dedupeLoginDom();\n                if (!(window.tiIsMobileLike && window.tiIsMobileLike())) {\n                    var u = byId('l-user'); if (u && typeof u.focus === 'function') u.focus({preventScroll:true});\n                }\n            } catch(e) {}\n        }, 80);\n        return false;\n    }\n    function closeLoginSingleton(ev){\n        if (ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }\n        all('#ti-login-ov').forEach(hideOverlay);\n        try {\n            document.documentElement.classList.remove('ti-no-scroll');\n            document.body.classList.remove('ti-no-scroll');\n            if (window.updatePluginScrollLock) window.updatePluginScrollLock();\n        } catch(e) {}\n        return false;\n    }\n    function markManualDirectOpen(){\n        try {\n            var dl = byId('ti-mobile-direct-login');\n            if (dl) dl.classList.add('ti-direct-login-manual-open');\n        } catch(e) {}\n    }\n    function bindLoginSingleton(){\n        try {\n            dedupeLoginDom();\n            var openBtn = byId('ti-login-btn');\n            if (openBtn && !openBtn.dataset.tiLoginSingleton315) {\n                openBtn.dataset.tiLoginSingleton315 = '1';\n                openBtn.onclick = openLoginSingleton;\n                openBtn.addEventListener('click', openLoginSingleton, true);\n                openBtn.addEventListener('touchend', openLoginSingleton, {passive:false, capture:true});\n            }\n            all('#ti-login-ov .btn-close, #ti-login-ov button[onclick*=\"closeModal\"]').forEach(function(btn){\n                if (btn.dataset.tiLoginSingletonClose315) return;\n                btn.dataset.tiLoginSingletonClose315 = '1';\n                btn.onclick = closeLoginSingleton;\n                btn.addEventListener('click', closeLoginSingleton, true);\n            });\n            var manual = byId('ti-show-direct-login-fallback');\n            if (manual && !manual.dataset.tiDirectManual315) {\n                manual.dataset.tiDirectManual315 = '1';\n                manual.addEventListener('click', markManualDirectOpen, true);\n            }\n        } catch(e) {}\n    }\n\n    var previousOpenLogin = window.openLoginModalSafe;\n    window.openLoginModalSafe = function(){ return openLoginSingleton(); };\n    window.openLoginModalSafe.__tiLoginSingleton315 = true;\n\n    if (typeof window.openModal === 'function' && !window.openModal.__tiLoginSingleton315) {\n        var prevOpenModal = window.openModal;\n        window.openModal = function(id){\n            if (id === 'ti-login-ov') return openLoginSingleton();\n            return prevOpenModal.apply(this, arguments);\n        };\n        window.openModal.__tiLoginSingleton315 = true;\n    }\n    if (typeof window.closeModal === 'function' && !window.closeModal.__tiLoginSingleton315) {\n        var prevCloseModal = window.closeModal;\n        window.closeModal = function(id){\n            if (id === 'ti-login-ov') return closeLoginSingleton();\n            return prevCloseModal.apply(this, arguments);\n        };\n        window.closeModal.__tiLoginSingleton315 = true;\n    }\n\n    function suppressRepeatedLoginErrorOpen(){\n        try {\n            var params = new URLSearchParams(window.location.search || '');\n            if (!params.has('ti_login_error')) return;\n            if (String(params.get('ti_login_scope') || '').toLowerCase() === 'global') {\n                try { sessionStorage.removeItem('ti_login_failed_clear'); localStorage.removeItem('ti_last_login_user'); } catch(e) {}\n                return;\n            }\n            var key = 'ti_login_error_open_seen_' + location.pathname + '_' + params.get('ti_login_error');\n            if (sessionStorage.getItem(key) === '1') return;\n            sessionStorage.setItem(key, '1');\n            setTimeout(function(){\n                try {\n                    var detail = params.get('ti_login_error') || 'login non riuscito';\n                    if (window.revealDirectLoginFallback) window.revealDirectLoginFallback('login-error-url', decodeURIComponent(detail));\n                    else openLoginSingleton();\n                } catch(e) { openLoginSingleton(); }\n            }, 260);\n        } catch(e) {}\n    }\n\n    function bindDelegatedLoginInterceptors(){\n        if (window.__tiLoginDelegatedInterceptors315) return;\n        window.__tiLoginDelegatedInterceptors315 = true;\n        document.addEventListener('click', function(ev){\n            var t = ev.target;\n            if (!t || !t.closest) return;\n            if (t.closest('#ti-login-btn')) { openLoginSingleton(ev); return; }\n            if (t.closest('#ti-login-ov .btn-close, #ti-login-ov button[onclick*=\\\"closeModal\\\"]')) { closeLoginSingleton(ev); return; }\n        }, true);\n        document.addEventListener('touchend', function(ev){\n            var t = ev.target;\n            if (!t || !t.closest) return;\n            if (t.closest('#ti-login-btn')) { openLoginSingleton(ev); return; }\n        }, {passive:false, capture:true});\n    }\n\n    function boot(){\n        bindDelegatedLoginInterceptors();\n        bindLoginSingleton();\n        dedupeLoginDom();\n        suppressRepeatedLoginErrorOpen();\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ boot(); setTimeout(boot, 400); setTimeout(boot, 1200); });\n    else { boot(); setTimeout(boot, 400); setTimeout(boot, 1200); }\n    \/\/ 30.9.1484: rimosso observer globale; click\/touch delegati e bootstrap iniziale mantengono un solo login.\n})();\n<\/script>\n\n\n<script id=\"ti-login-success-nonblocking-fix-318\">\n(function(){\n    \"use strict\";\n    if (window.__tiLoginSuccessNonBlocking318) return;\n    window.__tiLoginSuccessNonBlocking318 = true;\n\n    function hasLoginParam(){\n        try {\n            var p = new URLSearchParams(window.location.search || '');\n            return p.has('ti_login_error') || p.has('ti_login_ok') || p.has('ti_action') || p.has('action') || p.has('redirect') || p.has('ti_mobile_login_redirect');\n        } catch(e) { return false; }\n    }\n    function cleanLoginUrl(){\n        try {\n            var url = new URL(window.location.href);\n            ['ti_login_error','ti_login_scope','ti_login_ok','ti_action','action','redirect','ti_mobile_login_redirect','_wpnonce'].forEach(function(k){ url.searchParams.delete(k); });\n            var clean = url.pathname + (url.search ? url.search : '') + (url.hash || '');\n            if (clean !== (window.location.pathname + window.location.search + window.location.hash)) {\n                window.history.replaceState({}, document.title, clean);\n            }\n            return clean || window.location.pathname || '\/';\n        } catch(e) { return window.location.href.split('#')[0]; }\n    }\n    function hideLoginIfVisible(){\n        try {\n            document.querySelectorAll('#ti-login-ov').forEach(function(ov){\n                var cs = window.getComputedStyle ? window.getComputedStyle(ov) : null;\n                var visible = ov && ov.getAttribute('aria-hidden') !== 'true' && (!cs || cs.display !== 'none') && ov.style.display !== 'none';\n                if (!visible) return;\n                ov.classList.remove('ti-modal-open','ti-login-open-186','ti-login-open-315','open','active','show');\n                ov.style.setProperty('display','none','important');\n                ov.setAttribute('aria-hidden','true');\n            });\n            var dl = document.getElementById('ti-mobile-direct-login');\n            if (dl && !dl.classList.contains('ti-direct-login-manual-open')) {\n                dl.classList.remove('ti-direct-login-visible');\n                dl.style.display = 'none';\n                dl.setAttribute('aria-hidden','true');\n            }\n            if (window.updatePluginScrollLock) window.updatePluginScrollLock();\n        } catch(e) {}\n    }\n    function markSuccess(){\n        try {\n            sessionStorage.setItem('ti_login_success_no_autoopen_318', String(Date.now()));\n            sessionStorage.removeItem('ti_login_failed_clear');\n        } catch(e) {}\n    }\n    function recentSuccess(){\n        try {\n            var ts = parseInt(sessionStorage.getItem('ti_login_success_no_autoopen_318') || '0', 10);\n            return ts && (Date.now() - ts < 15000);\n        } catch(e) { return false; }\n    }\n\n    window.tiCleanLoginUrl = cleanLoginUrl;\n    window.tiReloadAfterSuccessfulLogin = function(){\n        markSuccess();\n        var clean = cleanLoginUrl();\n        try {\n            var target = new URL(clean, window.location.origin).href;\n            window.location.replace(target);\n        } catch(e) {\n            window.location.href = clean || window.location.href.split('#')[0];\n        }\n    };\n\n    function boot(){\n        try {\n            var logged = !!String(window.tiUser || '').trim();\n            if (logged || hasLoginParam() || recentSuccess()) cleanLoginUrl();\n            if (logged || recentSuccess()) {\n                hideLoginIfVisible();\n                setTimeout(hideLoginIfVisible, 180);\n            }\n        } catch(e) {}\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, {once:true});\n    else boot();\n})();\n<\/script>\n\n\n<script id=\"ti-login-direct-proposal-336\">\n(function(){\n    \"use strict\";\n    if (window.__tiLoginDirectProposal336) return;\n    window.__tiLoginDirectProposal336 = true;\n    function propose(detail){\n        try {\n            if (String(window.tiUser || '').trim()) return;\n            if (window.revealDirectLoginFallback) {\n                window.revealDirectLoginFallback('login-failed-336', detail || 'login non riuscito');\n            }\n        } catch(e) {}\n    }\n    function boot(){\n        try {\n            var params = new URLSearchParams(window.location.search || '');\n            if (String(params.get('ti_login_scope') || '').toLowerCase() === 'global') return;\n            if (params.has('ti_login_error')) {\n                var detail = params.get('ti_login_error') || 'login non riuscito';\n                setTimeout(function(){ propose(detail); }, 360);\n            }\n        } catch(e) {}\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, {once:true});\n    else boot();\n})();\n<\/script>\n\n\n<script id=\"ti-config-stay-open-324\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigStayOpen324Installed) return;\n    window.__tiConfigStayOpen324Installed = true;\n\n    var ensureTimer324 = 0;\n    var observerCheckTimer324 = 0;\n\n    function byId(id){ return document.getElementById(id); }\n    function getConfigOverlay(){ return byId('ti-conf-ov'); }\n    function targetId(x){ return typeof x === 'string' ? x : (x && x.id ? x.id : ''); }\n    function fastHidden(el){\n        if (!el || el.hidden) return true;\n        if (el.getAttribute && el.getAttribute('aria-hidden') === 'true') return true;\n        var s = el.style || {};\n        return s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0';\n    }\n    function actuallyHidden(el){\n        if (fastHidden(el)) return true;\n        try {\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            return !!(cs && (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0'));\n        } catch(e) { return false; }\n    }\n    function markConfigOpen(reason){\n        window.__tiConfigStayOpen324 = true;\n        window.__tiConfigExplicitClose324 = false;\n        window.__tiConfigStayOpenReason324 = reason || 'config-open';\n    }\n    function allowExplicitConfigClose(reason){\n        window.__tiConfigExplicitClose324 = true;\n        window.__tiConfigStayOpen324 = false;\n        window.__tiConfigStayOpenReason324 = reason || 'explicit-close';\n        if (ensureTimer324) { clearTimeout(ensureTimer324); ensureTimer324 = 0; }\n        if (observerCheckTimer324) { clearTimeout(observerCheckTimer324); observerCheckTimer324 = 0; }\n    }\n    function shouldKeepConfigOpen(){\n        return !!(getConfigOverlay() && !window.__tiConfigExplicitClose324 && window.__tiConfigStayOpen324);\n    }\n    function showConfigOverlay(reason){\n        var ov = getConfigOverlay();\n        if (!ov || !shouldKeepConfigOpen()) return false;\n        if (!actuallyHidden(ov)) {\n            try { if (window.keepPluginModalInFront) window.keepPluginModalInFront(ov); } catch(e0) {}\n            window.__tiConfigStayOpenReason324 = reason || window.__tiConfigStayOpenReason324 || 'visible';\n            return true;\n        }\n        if (window.__tiConfigStayOpenShowing324) return false;\n        window.__tiConfigStayOpenShowing324 = true;\n        try {\n            if (window.preparePluginModal) window.preparePluginModal(ov);\n            if (window.showPluginModal) window.showPluginModal(ov);\n            if (fastHidden(ov)) {\n                ov.style.setProperty('display', 'flex', 'important');\n                ov.style.removeProperty('visibility');\n                ov.style.removeProperty('opacity');\n                ov.removeAttribute('aria-hidden');\n            }\n            if (window.keepPluginModalInFront) window.keepPluginModalInFront(ov);\n            if (window.updatePluginScrollLock) window.updatePluginScrollLock();\n            window.__tiConfigStayOpenReason324 = reason || 'ensure';\n            return true;\n        } catch(e) {\n            try { ov.style.setProperty('display', 'flex', 'important'); ov.removeAttribute('aria-hidden'); } catch(ignore) {}\n            return false;\n        } finally {\n            window.__tiConfigStayOpenShowing324 = false;\n        }\n    }\n    function ensureConfigOpen(reason, forceCheck, delay){\n        if (!shouldKeepConfigOpen()) return;\n        var ov = getConfigOverlay();\n        if (!ov) return;\n        if (!forceCheck && !fastHidden(ov)) return;\n        window.__tiConfigStayOpenReason324 = reason || window.__tiConfigStayOpenReason324 || 'ensure';\n        if (ensureTimer324) clearTimeout(ensureTimer324);\n        ensureTimer324 = setTimeout(function(){\n            ensureTimer324 = 0;\n            if (shouldKeepConfigOpen() && actuallyHidden(ov)) showConfigOverlay(reason || 'after-process');\n        }, typeof delay === 'number' ? delay : 90);\n    }\n    window.tiEnsureConfigOpen324 = ensureConfigOpen;\n\n    function wrapOpenModal(){\n        if (typeof window.openModal === 'function' && !window.openModal.__tiConfigStayOpen324) {\n            var prevOpen = window.openModal;\n            window.openModal = function(id){\n                var tid = targetId(id);\n                if (tid === 'ti-conf-ov') markConfigOpen('openModal');\n                var ret = prevOpen.apply(this, arguments);\n                if (tid === 'ti-conf-ov') ensureConfigOpen('openModal', true, 20);\n                return ret;\n            };\n            window.openModal.__tiConfigStayOpen324 = true;\n        }\n    }\n    function wrapShowPluginModal(){\n        if (typeof window.showPluginModal === 'function' && !window.showPluginModal.__tiConfigStayOpen324) {\n            var prevShow = window.showPluginModal;\n            window.showPluginModal = function(elOrId){\n                var tid = targetId(elOrId);\n                if (tid === 'ti-conf-ov') markConfigOpen('showPluginModal');\n                var ret = prevShow.apply(this, arguments);\n                if (tid === 'ti-conf-ov' && fastHidden(getConfigOverlay())) ensureConfigOpen('showPluginModal', true, 20);\n                return ret;\n            };\n            window.showPluginModal.__tiConfigStayOpen324 = true;\n        }\n    }\n    function wrapCloseModal(){\n        if (typeof window.closeModal === 'function' && !window.closeModal.__tiConfigStayOpen324) {\n            var prevClose = window.closeModal;\n            window.closeModal = function(id){\n                var tid = targetId(id);\n                if (tid === 'ti-conf-ov' && shouldKeepConfigOpen() && !window.__tiConfigExplicitClose324) {\n                    ensureConfigOpen('blocked-closeModal', true, 20);\n                    return false;\n                }\n                var ret = prevClose.apply(this, arguments);\n                if (tid && tid !== 'ti-conf-ov' && shouldKeepConfigOpen()) ensureConfigOpen('closed-' + tid, true, 120);\n                return ret;\n            };\n            window.closeModal.__tiConfigStayOpen324 = true;\n        }\n    }\n    function wrapCloseConfigModal(){\n        if (typeof window.closeConfigModal === 'function' && !window.closeConfigModal.__tiConfigStayOpen324) {\n            var prevCloseConfig = window.closeConfigModal;\n            window.closeConfigModal = function(){ allowExplicitConfigClose('closeConfigModal'); return prevCloseConfig.apply(this, arguments); };\n            window.closeConfigModal.__tiConfigStayOpen324 = true;\n        }\n    }\n    function wrapProcessFunctions(){\n        if (typeof window.hideProgressPopup === 'function' && !window.hideProgressPopup.__tiConfigStayOpen324) {\n            var prevHideProgress = window.hideProgressPopup;\n            window.hideProgressPopup = function(){ var ret = prevHideProgress.apply(this, arguments); ensureConfigOpen('hideProgressPopup', true, 120); return ret; };\n            window.hideProgressPopup.__tiConfigStayOpen324 = true;\n        }\n        if (typeof window.tiAlert === 'function' && !window.tiAlert.__tiConfigStayOpen324) {\n            var prevAlert = window.tiAlert;\n            window.tiAlert = function(){ var ret = prevAlert.apply(this, arguments); ensureConfigOpen('tiAlert', true, 180); return ret; };\n            window.tiAlert.__tiConfigStayOpen324 = true;\n        }\n        if (typeof window.closeConfigImportPreview === 'function' && !window.closeConfigImportPreview.__tiConfigStayOpen324) {\n            var prevCloseImport = window.closeConfigImportPreview;\n            window.closeConfigImportPreview = function(){ var ret = prevCloseImport.apply(this, arguments); ensureConfigOpen('closeConfigImportPreview', true, 100); return ret; };\n            window.closeConfigImportPreview.__tiConfigStayOpen324 = true;\n        }\n    }\n    function installExplicitCloseCapture(){\n        if (window.__tiConfigExplicitCloseCapture324) return;\n        window.__tiConfigExplicitCloseCapture324 = true;\n        document.addEventListener('click', function(ev){\n            var t = ev.target;\n            if (!t || !t.closest || !t.closest('#ti-conf-ov')) return;\n            var btn = t.closest('button,a');\n            if (!btn) return;\n            var txt = String(btn.textContent || btn.value || '').trim().toLowerCase();\n            if (btn.classList.contains('ti-modal-x-red') || btn.classList.contains('btn-close') || \/^(x|\u00d7|chiudi|close)$\/i.test(txt) || \/\\bchiudi\\b\/i.test(txt)) allowExplicitConfigClose('user-button');\n        }, true);\n    }\n    function installObserver(){\n        if (window.__tiConfigStayObserver324 || typeof MutationObserver === 'undefined') return;\n        var ov = getConfigOverlay();\n        if (!ov) return;\n        window.__tiConfigStayObserver324 = new MutationObserver(function(records){\n            if (!shouldKeepConfigOpen() || window.__tiConfigStayOpenShowing324) return;\n            var needsCheck = false;\n            for (var i = 0; i < records.length; i++) {\n                var name = records[i].attributeName || '';\n                if (name === 'style' || name === 'aria-hidden') {\n                    if (fastHidden(ov)) { needsCheck = true; break; }\n                } else if (name === 'class') {\n                    needsCheck = true;\n                }\n            }\n            if (!needsCheck || observerCheckTimer324) return;\n            observerCheckTimer324 = setTimeout(function(){\n                observerCheckTimer324 = 0;\n                if (shouldKeepConfigOpen() && actuallyHidden(ov)) ensureConfigOpen('observer', true, 20);\n            }, 0);\n        });\n        try { window.__tiConfigStayObserver324.observe(ov, {attributes:true, attributeFilter:['style','class','aria-hidden']}); } catch(e) {}\n    }\n    function boot(){\n        wrapShowPluginModal(); wrapOpenModal(); wrapCloseModal(); wrapCloseConfigModal(); wrapProcessFunctions(); installExplicitCloseCapture(); installObserver();\n        var ov = getConfigOverlay();\n        if (ov && !actuallyHidden(ov)) markConfigOpen('boot-visible');\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, {once:true}); else boot();\n    setTimeout(boot, 500);\n})();\n<\/script>\n<script id=\"ti-file-manager-ateco-front-347\">\n(function(){\n})();\n<\/script>\n\n<script id=\"ti-file-manager-ateco-native-fallback-346\">\n(function(){\n    \"use strict\";\n    if (window.__tiFileManagerAtecoNativeFallback346) return;\n    window.__tiFileManagerAtecoNativeFallback346 = true;\n    function byId(id){ return document.getElementById(id); }\n    function isVisible(el){\n        if (!el) return false;\n        try { var cs = window.getComputedStyle ? window.getComputedStyle(el) : null; return !!(cs && cs.display !== 'none' && cs.visibility !== 'hidden'); }\n        catch(e) { return el.style && el.style.display !== 'none'; }\n    }\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var atecoBtn = t.closest('button[onclick*=\"openAtecoSearch\"]');\n        if (atecoBtn) {\n            setTimeout(function(){\n                if (isVisible(byId('ti-ateco-ov'))) return;\n                var oc = String(atecoBtn.getAttribute('onclick') || '');\n                var m = oc.match(\/openAtecoSearch\\((['\"])(.*?)\\1\\)\/);\n                if (m && typeof window.openAtecoSearch === 'function') window.openAtecoSearch(m[2] || '');\n            }, 80);\n            return;\n        }\n        var fmBtn = t.closest('#ti-file-manager-ov button');\n        if (!fmBtn) return;\n        var oc = String(fmBtn.getAttribute('onclick') || '');\n        if (oc.indexOf('chooseAIManager') !== -1) {\n            setTimeout(function(){ if (!isVisible(byId('ti-ai-gen-ov')) && typeof window.chooseAIManager === 'function') window.chooseAIManager(); }, 120);\n        }\n    }, false);\n})();\n<\/script>\n<script id=\"ti-operational-popups-front-350\">\n(function(){\n})();\n<\/script>\n<script id=\"ti-operational-popups-front-persistent-351\">\n(function(){\n})();\n<\/script>\n<script id=\"ti-ai-gen-interactive-front-352\">\n(function(){\n})();\n<\/script>\n\n\n<script id=\"ti-modal-front-354\">\n(function(){\n})();\n<\/script>\n\n<script id=\"ti-modal-front-355\">\n(function(){\n    \"use strict\";\n    if (window.__tiModalFront355) return;\n    window.__tiModalFront355 = true;\n    var MAIN_Z = 2147480800;\n    var CHILD_BASE_Z = 2147483000;\n    var ALERT_Z = 2147483647;\n    var LOADER_Z = 2147483646;\n    var seq = 0;\n    var order = [];\n    var mainIds = {'ti-conf-ov':true,'ti-login-ov':true,'ti-direct-login-ov':true,'ti-purchase-ov':true};\n    function byId(id){ return typeof id === 'string' ? document.getElementById(id) : id; }\n    function isEl(el){ return !!(el && el.nodeType === 1); }\n    function isOverlay(el){ return isEl(el) && ((el.classList && el.classList.contains('ti-ov')) || !!(el.id && \/^ti-.*-ov$\/.test(el.id))); }\n    function closestOverlay(node){ try { return node && node.closest ? node.closest('.ti-ov, [id^=\"ti-\"][id$=\"-ov\"]') : null; } catch(e) { return null; } }\n    function visible(el){\n        if (!isOverlay(el)) return false;\n        try {\n            if (el.hasAttribute && el.hasAttribute('hidden')) return false;\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return false;\n            return true;\n        } catch(e) { return !!(el.style && el.style.display !== 'none'); }\n    }\n    function setZ(el, z){\n        if (!isEl(el) || !el.style) return;\n        try { el.style.setProperty('z-index', String(z), 'important'); } catch(e) { try { el.style.zIndex = String(z); } catch(e2) {} }\n        try { el.style.setProperty('pointer-events', 'auto', 'important'); } catch(e) {}\n    }\n    function removeOrder(el){ order = order.filter(function(x){ return x !== el && visible(x); }); }\n    function promote(el){\n        el = byId(el);\n        if (!isOverlay(el)) return null;\n        if (el.id === 'ti-alert-ov') { setZ(el, ALERT_Z); return el; }\n        if (el.id === 'ti-ai-loader-ov') { setZ(el, LOADER_Z); return el; }\n        removeOrder(el);\n        order.push(el);\n        seq++;\n        if (seq > 20000) seq = 1;\n        if (mainIds[el.id]) {\n            setZ(el, MAIN_Z);\n        } else {\n            setZ(el, CHILD_BASE_Z + seq);\n            var conf = document.getElementById('ti-conf-ov');\n            if (visible(conf)) setZ(conf, MAIN_Z);\n        }\n        return el;\n    }\n    function promoteVisibleTop(){ order = order.filter(visible); if (order.length) promote(order[order.length - 1]); }\n    function afterOpen(id){ setTimeout(function(){ promote(id); }, 0); setTimeout(function(){ promote(id); }, 80); setTimeout(function(){ promote(id); }, 240); }\n    window.tiPromoteModalFront355 = function(id){ return promote(id); };\n    window.tiPromoteLastVisibleModal355 = promoteVisibleTop;\n    if (typeof window.openModal === 'function' && !window.openModal.__tiFront355) {\n        var prevOpen = window.openModal;\n        window.openModal = function(id){ var ret = prevOpen.apply(this, arguments); afterOpen(id); return ret; };\n        window.openModal.__tiFront355 = true;\n    }\n    if (typeof window.showPluginModal === 'function' && !window.showPluginModal.__tiFront355) {\n        var prevShow = window.showPluginModal;\n        window.showPluginModal = function(id){ var ret = prevShow.apply(this, arguments); afterOpen(id); return ret; };\n        window.showPluginModal.__tiFront355 = true;\n    }\n    if (typeof window.closeModal === 'function' && !window.closeModal.__tiFront355) {\n        var prevClose = window.closeModal;\n        window.closeModal = function(id){ var el = byId(id); var ret = prevClose.apply(this, arguments); if (el) removeOrder(el); setTimeout(promoteVisibleTop, 40); return ret; };\n        window.closeModal.__tiFront355 = true;\n    }\n    ['mousedown','focusin','touchstart'].forEach(function(evt){ document.addEventListener(evt, function(ev){ var ov = closestOverlay(ev && ev.target); if (ov) promote(ov); }, false); });\n    setTimeout(function(){ ['ti-col-help-ov','ti-ateco-ov','ti-file-manager-ov','ti-ai-gen-ov','ti-help-ov','ti-report-ov','ti-global-action-ov'].forEach(function(id){ var el=byId(id); if (visible(el)) promote(el); }); }, 300);\n})();\n<\/script>\n\n\n<script id=\"ti-modal-context-front-356\">\n(function(){\n    \"use strict\";\n    if (window.__tiModalContextFront356) return;\n    window.__tiModalContextFront356 = true;\n\n    var MAIN_Z = 2147480900;\n    var CHILD_BASE_Z = 2147483200;\n    var ALERT_Z = 2147483647;\n    var LOADER_Z = 2147483646;\n    var mainIds = {\n        'ti-conf-ov': true,\n        'ti-login-ov': true,\n        'ti-direct-login-ov': true,\n        'ti-purchase-ov': true\n    };\n    var topSystemIds = {\n        'ti-alert-ov': ALERT_Z,\n        'ti-ai-loader-ov': LOADER_Z\n    };\n    var order = [];\n    var seq = 0;\n\n    function byId(id){ return (typeof id === 'string') ? document.getElementById(id) : id; }\n    function isEl(el){ return !!(el && el.nodeType === 1); }\n    function overlayOf(el){\n        if (!el) return null;\n        if (typeof el === 'string') return document.getElementById(el);\n        try {\n            if (el.classList && el.classList.contains('ti-ov')) return el;\n            return el.closest ? el.closest('.ti-ov, [id^=\"ti-\"][id$=\"-ov\"]') : null;\n        } catch(e) { return null; }\n    }\n    function overlayId(idOrEl){ var el = byId(idOrEl); return el && el.id ? el.id : String(idOrEl || ''); }\n    function isOverlay(el){ return isEl(el) && ((el.classList && el.classList.contains('ti-ov')) || (el.id && \/^ti-.*-ov$\/.test(el.id))); }\n    function isVisible(el){\n        if (!isOverlay(el)) return false;\n        try {\n            if (el.hasAttribute && el.hasAttribute('hidden')) return false;\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')) return false;\n            if (el.style && (el.style.display === 'none' || el.style.visibility === 'hidden')) return false;\n            return true;\n        } catch(e) { return !!(el.style && el.style.display !== 'none'); }\n    }\n    function setZ(el, z){\n        if (!isEl(el) || !el.style) return;\n        try { el.style.setProperty('z-index', String(z), 'important'); } catch(e) { try { el.style.zIndex = String(z); } catch(e2) {} }\n        try { el.style.setProperty('pointer-events', 'auto', 'important'); } catch(e) {}\n        if (isVisible(el)) {\n            try { el.removeAttribute('aria-hidden'); } catch(e) {}\n        }\n    }\n    function visibleChildren(){\n        var nodes = Array.prototype.slice.call(document.querySelectorAll('.ti-ov, [id^=\"ti-\"][id$=\"-ov\"]'));\n        return nodes.filter(function(el){\n            if (!isVisible(el) || !el.id) return false;\n            if (mainIds[el.id] || topSystemIds[el.id]) return false;\n            return true;\n        });\n    }\n    function visibleMain(){\n        return Object.keys(mainIds).map(function(id){ return document.getElementById(id); }).filter(isVisible);\n    }\n    function normalizeOrder(){\n        var children = visibleChildren();\n        order = order.filter(function(id){ return children.some(function(el){ return el.id === id; }); });\n        children.forEach(function(el){ if (order.indexOf(el.id) < 0) order.push(el.id); });\n    }\n    function lowerMainIfNeeded(){\n        var children = visibleChildren();\n        if (!children.length) return;\n        visibleMain().forEach(function(el){ setZ(el, MAIN_Z); });\n    }\n    function topChild(){\n        normalizeOrder();\n        for (var i = order.length - 1; i >= 0; i--) {\n            var el = document.getElementById(order[i]);\n            if (isVisible(el) && !mainIds[el.id] && !topSystemIds[el.id]) return el;\n        }\n        var children = visibleChildren();\n        return children.length ? children[children.length - 1] : null;\n    }\n    function applyStack(){\n        normalizeOrder();\n        lowerMainIfNeeded();\n        order.forEach(function(id, idx){\n            var el = document.getElementById(id);\n            if (isVisible(el)) setZ(el, CHILD_BASE_Z + idx + 1);\n        });\n        Object.keys(topSystemIds).forEach(function(id){ var el = document.getElementById(id); if (isVisible(el)) setZ(el, topSystemIds[id]); });\n    }\n    function promote(idOrEl){\n        var el = overlayOf(idOrEl) || byId(idOrEl);\n        if (!isOverlay(el)) return null;\n        if (topSystemIds[el.id]) { setZ(el, topSystemIds[el.id]); return el; }\n        if (mainIds[el.id]) {\n            var child = topChild();\n            setZ(el, MAIN_Z);\n            if (child) promote(child);\n            else setZ(el, CHILD_BASE_Z);\n            return el;\n        }\n        order = order.filter(function(id){ return id !== el.id; });\n        order.push(el.id);\n        seq++;\n        applyStack();\n        return el;\n    }\n    function promoteSoon(idOrEl){\n        var delays = [0, 60, 180, 420, 900, 1600];\n        delays.forEach(function(ms){ setTimeout(function(){ promote(idOrEl); applyStack(); }, ms); });\n    }\n\n    \/\/ Esponi un solo punto leggero di promozione. Mantiene compatibilita con il codice gia esistente.\n    window.tiPromoteModalFront356 = function(idOrEl){ return promote(idOrEl); };\n    window.tiPromoteLastVisibleModal356 = function(){ var el = topChild(); if (el) promote(el); else applyStack(); };\n    window.tiPromoteModalFront355 = window.tiPromoteModalFront356;\n    window.tiPromoteLastVisibleModal355 = window.tiPromoteLastVisibleModal356;\n\n    if (typeof window.bringPluginModalToFront === 'function' && !window.bringPluginModalToFront.__tiFront356) {\n        var prevBring = window.bringPluginModalToFront;\n        window.bringPluginModalToFront = function(elOrId){\n            var el = overlayOf(elOrId) || byId(elOrId);\n            if (el && mainIds[el.id] && topChild()) { setZ(el, MAIN_Z); promote(topChild()); return el; }\n            var ret = prevBring.apply(this, arguments);\n            var target = overlayOf(ret) || el;\n            if (target) promote(target);\n            return ret;\n        };\n        window.bringPluginModalToFront.__tiFront356 = true;\n    }\n    if (typeof window.keepPluginModalInFront === 'function' && !window.keepPluginModalInFront.__tiFront356) {\n        var prevKeep = window.keepPluginModalInFront;\n        window.keepPluginModalInFront = function(idOrEl){\n            var el = overlayOf(idOrEl) || byId(idOrEl);\n            var ret = prevKeep.apply(this, arguments);\n            if (el && mainIds[el.id]) {\n                setZ(el, MAIN_Z);\n                var child = topChild();\n                if (child) promoteSoon(child);\n            } else if (el) {\n                promoteSoon(el);\n            }\n            return ret;\n        };\n        window.keepPluginModalInFront.__tiFront356 = true;\n    }\n    if (typeof window.showPluginModal === 'function' && !window.showPluginModal.__tiFront356) {\n        var prevShow = window.showPluginModal;\n        window.showPluginModal = function(idOrEl){\n            var ret = prevShow.apply(this, arguments);\n            var el = overlayOf(idOrEl) || overlayOf(ret) || byId(idOrEl);\n            if (el) promoteSoon(el);\n            return ret;\n        };\n        window.showPluginModal.__tiFront356 = true;\n    }\n    if (typeof window.openModal === 'function' && !window.openModal.__tiFront356) {\n        var prevOpen = window.openModal;\n        window.openModal = function(id){\n            var ret = prevOpen.apply(this, arguments);\n            var el = byId(id);\n            if (el) promoteSoon(el);\n            return ret;\n        };\n        window.openModal.__tiFront356 = true;\n    }\n    if (typeof window.closeModal === 'function' && !window.closeModal.__tiFront356) {\n        var prevClose = window.closeModal;\n        window.closeModal = function(id){\n            var tid = overlayId(id);\n            var ret = prevClose.apply(this, arguments);\n            if (tid) order = order.filter(function(x){ return x !== tid; });\n            setTimeout(function(){ var child = topChild(); if (child) promote(child); else applyStack(); }, 60);\n            return ret;\n        };\n        window.closeModal.__tiFront356 = true;\n    }\n    ['mousedown','mouseup','click','focusin','touchstart'].forEach(function(evt){\n        document.addEventListener(evt, function(ev){\n            var ov = overlayOf(ev && ev.target);\n            if (!ov) return;\n            if (mainIds[ov.id] && topChild()) { setTimeout(function(){ var child = topChild(); if (child) promote(child); }, 0); return; }\n            if (!mainIds[ov.id]) promote(ov);\n        }, false);\n    });\n\n    function cloneCtx(ctx){\n        if (!ctx || typeof ctx !== 'object') return null;\n        return {tbl: ctx.tbl, idx: ctx.idx, key: ctx.key, val: ctx.val};\n    }\n    function validCtx(ctx){ return !!(ctx && typeof ctx === 'object' && ctx.tbl && ctx.idx !== undefined && ctx.idx !== null && ctx.key); }\n    function saveUploadCtx(ctx){\n        if (!validCtx(ctx)) return null;\n        var c = cloneCtx(ctx);\n        window.tiLastUploadContext356 = c;\n        try { sessionStorage.setItem('tiLastUploadContext356', JSON.stringify(c)); } catch(e) {}\n        return c;\n    }\n    function restoreUploadCtx(){\n        if (validCtx(window.targetUploadContext)) return window.targetUploadContext;\n        if (validCtx(window.tiLastUploadContext356)) { window.targetUploadContext = cloneCtx(window.tiLastUploadContext356); return window.targetUploadContext; }\n        try {\n            var raw = sessionStorage.getItem('tiLastUploadContext356');\n            if (raw) {\n                var parsed = JSON.parse(raw);\n                if (validCtx(parsed)) { window.targetUploadContext = cloneCtx(parsed); window.tiLastUploadContext356 = cloneCtx(parsed); return window.targetUploadContext; }\n            }\n        } catch(e) {}\n        return window.targetUploadContext;\n    }\n    function stampOverlayCtx(id, ctx){\n        var el = document.getElementById(id);\n        if (!el || !validCtx(ctx)) return;\n        try {\n            el.setAttribute('data-ti-context-table', ctx.tbl || '');\n            el.setAttribute('data-ti-context-row', String(ctx.idx));\n            el.setAttribute('data-ti-context-field', ctx.key || '');\n        } catch(e) {}\n    }\n\n    if (typeof window.openFileManager === 'function' && !window.openFileManager.__tiCtx356) {\n        var prevOpenFM = window.openFileManager;\n        window.openFileManager = function(tbl, idx, key){\n            var ret = prevOpenFM.apply(this, arguments);\n            var ctx = saveUploadCtx(window.targetUploadContext || {tbl:tbl, idx:idx, key:key});\n            stampOverlayCtx('ti-file-manager-ov', ctx);\n            promoteSoon('ti-file-manager-ov');\n            return ret;\n        };\n        window.openFileManager.__tiCtx356 = true;\n    }\n    if (typeof window.chooseAIManager === 'function' && !window.chooseAIManager.__tiCtx356) {\n        var prevChooseAIManager = window.chooseAIManager;\n        window.chooseAIManager = function(){\n            var ctx = restoreUploadCtx();\n            if (validCtx(ctx)) saveUploadCtx(ctx);\n            var ret = prevChooseAIManager.apply(this, arguments);\n            ctx = restoreUploadCtx();\n            if (validCtx(ctx)) {\n                window.targetUploadContext = cloneCtx(ctx);\n                stampOverlayCtx('ti-ai-gen-ov', ctx);\n                stampOverlayCtx('ti-file-manager-ov', ctx);\n            }\n            \/\/ La form AI e l'ultima operativa: deve stare sopra Gestione File Associati.\n            promoteSoon('ti-ai-gen-ov');\n            return ret;\n        };\n        window.chooseAIManager.__tiCtx356 = true;\n    }\n    if (typeof window.chooseAI === 'function' && !window.chooseAI.__tiCtx356) {\n        var prevChooseAI = window.chooseAI;\n        window.chooseAI = function(){\n            if (validCtx(window.targetUploadContext)) saveUploadCtx(window.targetUploadContext);\n            var ret = prevChooseAI.apply(this, arguments);\n            var ctx = restoreUploadCtx();\n            if (validCtx(ctx)) stampOverlayCtx('ti-ai-gen-ov', ctx);\n            promoteSoon('ti-ai-gen-ov');\n            return ret;\n        };\n        window.chooseAI.__tiCtx356 = true;\n    }\n    if (typeof window.useAIGen === 'function' && !window.useAIGen.__tiCtx356) {\n        var prevUseAI = window.useAIGen;\n        window.useAIGen = function(){\n            var ctx = restoreUploadCtx();\n            if (validCtx(ctx)) window.targetUploadContext = cloneCtx(ctx);\n            var ret = prevUseAI.apply(this, arguments);\n            setTimeout(function(){ if (validCtx(ctx)) { window.targetUploadContext = cloneCtx(ctx); promote('ti-file-manager-ov'); } }, 160);\n            return ret;\n        };\n        window.useAIGen.__tiCtx356 = true;\n    }\n    if (typeof window.handleFileSelect === 'function' && !window.handleFileSelect.__tiCtx356) {\n        var prevHandleFileSelect = window.handleFileSelect;\n        window.handleFileSelect = function(e){\n            try {\n                if (e && e.target && e.target.dataset && e.target.dataset.target === 'manager') {\n                    var ctx = restoreUploadCtx();\n                    if (validCtx(ctx)) window.targetUploadContext = cloneCtx(ctx);\n                }\n            } catch(ignore) {}\n            return prevHandleFileSelect.apply(this, arguments);\n        };\n        window.handleFileSelect.__tiCtx356 = true;\n    }\n\n    if (typeof window.openAtecoSearch === 'function' && !window.openAtecoSearch.__tiCtx356) {\n        var prevAteco = window.openAtecoSearch;\n        window.openAtecoSearch = function(targetId){\n            window.tiAtecoTargetId356 = targetId || window.tiAtecoTargetId356 || '';\n            var ret = prevAteco.apply(this, arguments);\n            try { var hidden = document.getElementById('ateco-target-id'); if (hidden && targetId) hidden.value = targetId; } catch(e) {}\n            promoteSoon('ti-ateco-ov');\n            return ret;\n        };\n        window.openAtecoSearch.__tiCtx356 = true;\n    }\n    if (typeof window.searchAteco === 'function' && !window.searchAteco.__tiFront356) {\n        var prevSearchAteco = window.searchAteco;\n        window.searchAteco = function(){ var ret = prevSearchAteco.apply(this, arguments); promoteSoon('ti-ateco-ov'); return ret; };\n        window.searchAteco.__tiFront356 = true;\n    }\n    if (typeof window.selectAteco === 'function' && !window.selectAteco.__tiCtx356) {\n        var prevSelectAteco = window.selectAteco;\n        window.selectAteco = function(codice, desc){\n            try { var hidden = document.getElementById('ateco-target-id'); if (hidden && !hidden.value && window.tiAtecoTargetId356) hidden.value = window.tiAtecoTargetId356; } catch(e) {}\n            return prevSelectAteco.apply(this, arguments);\n        };\n        window.selectAteco.__tiCtx356 = true;\n    }\n\n    if (typeof window.askColumnHelp === 'function' && !window.askColumnHelp.__tiCtx356) {\n        var prevAskColumnHelp = window.askColumnHelp;\n        window.askColumnHelp = function(tbl, col){\n            var ctx = {tbl:String(tbl || ''), col:String(col || ''), ts:Date.now()};\n            window.tiColumnHelpContext356 = ctx;\n            var ret = prevAskColumnHelp.apply(this, arguments);\n            var ov = document.getElementById('ti-col-help-ov');\n            if (ov) {\n                try {\n                    ov.setAttribute('data-ti-help-table', ctx.tbl);\n                    ov.setAttribute('data-ti-help-column', ctx.col);\n                    ov.setAttribute('data-ti-help-context-ts', String(ctx.ts));\n                } catch(e) {}\n            }\n            promoteSoon('ti-col-help-ov');\n            return ret;\n        };\n        window.askColumnHelp.__tiCtx356 = true;\n    }\n\n    \/\/ Primo riallineamento non invasivo per form gia aperte al caricamento dello script.\n    setTimeout(function(){ var child = topChild(); if (child) promote(child); else applyStack(); }, 300);\n})();\n<\/script>\n\n\n\n<script id=\"ti-help-copy-loader-close-357\">\n(function(){\n    \"use strict\";\n    if (window.__tiHelpCopyLoaderClose357Installed) return;\n    window.__tiHelpCopyLoaderClose357Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function textOf(el){ return el ? String(el.innerText || el.textContent || '') : ''; }\n    function clearLoaderTimers(){\n        try {\n            var st = window.tiLoaderState || (window.tiLoaderState = {});\n            st.active = false;\n            ['timer','watchdog327','stallGuard338'].forEach(function(k){ if (st[k]) { clearInterval(st[k]); st[k] = null; } });\n            ['closeTimer338','closeTimer357'].forEach(function(k){ if (st[k]) { clearTimeout(st[k]); st[k] = null; } });\n        } catch(e) {}\n    }\n    function hardCloseLoader(reason){\n        clearLoaderTimers();\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        var ov = byId('ti-ai-loader-ov');\n        if (ov) {\n            try {\n                ov.style.setProperty('display','none','important');\n                ov.style.setProperty('visibility','hidden','important');\n                ov.style.setProperty('opacity','0','important');\n                ov.style.setProperty('pointer-events','none','important');\n                ov.setAttribute('aria-hidden','true');\n            } catch(e) {}\n        }\n        try { if (typeof window.updatePluginScrollLock === 'function') window.updatePluginScrollLock(); } catch(e) {}\n        return true;\n    }\n    function looksCompleted(title, sub){\n        var s = String(title || '') + ' ' + String(sub || '') + ' ' + textOf(byId('ti-loader-title')) + ' ' + textOf(byId('ti-loader-sub')) + ' ' + textOf(byId('ti-loader-percent'));\n        s = s.toLowerCase();\n        if (\/errore|fallito|interrotto|annulla|chiarimento|specifiche|record aggiornati\\s*0\/.test(s)) return false;\n        return \/100\\s*%|completamento confermato|configurazione salvata|immagine generata|attivit[a\u00e0] ai conclusa|operazione completata\/.test(s);\n    }\n    function scheduleHardClose(reason, delay){\n        try {\n            var st = window.tiLoaderState || (window.tiLoaderState = {});\n            if (st.closeTimer357) clearTimeout(st.closeTimer357);\n            st.closeTimer357 = setTimeout(function(){ hardCloseLoader(reason); }, Math.max(80, delay || 700));\n        } catch(e) { setTimeout(function(){ hardCloseLoader(reason); }, Math.max(80, delay || 700)); }\n    }\n    window.tiHardCloseCompletedLoader357 = function(reason){\n        if (looksCompleted('', '')) return hardCloseLoader(reason || 'manual');\n        return false;\n    };\n\n    if (typeof window.hideProgressPopup === 'function' && !window.hideProgressPopup.__tiClose357) {\n        var prevHide357 = window.hideProgressPopup;\n        window.hideProgressPopup = function(success, finalText, opts){\n            var ret = prevHide357.apply(this, arguments);\n            if (success !== false) {\n                scheduleHardClose('hideProgressPopup-success', 650);\n                scheduleHardClose('hideProgressPopup-success-late', 1600);\n            }\n            return ret;\n        };\n        window.hideProgressPopup.__tiClose357 = true;\n    }\n    if (typeof window.updateProgressPopup === 'function' && !window.updateProgressPopup.__tiClose357) {\n        var prevUpdate357 = window.updateProgressPopup;\n        window.updateProgressPopup = function(percent, title, subtitle, currentItem){\n            var ret = prevUpdate357.apply(this, arguments);\n            if ((parseInt(percent,10) || 0) >= 100 && looksCompleted(title, subtitle)) {\n                scheduleHardClose('updateProgressPopup-100', 650);\n                scheduleHardClose('updateProgressPopup-100-late', 1600);\n            }\n            return ret;\n        };\n        window.updateProgressPopup.__tiClose357 = true;\n    }\n    if (!window.__tiVisibilityCloseGuard1039) {\n        window.__tiVisibilityCloseGuard1039 = true;\n        var visCheckClose1039 = function(){\n            try {\n                if (document.visibilityState !== 'visible') return;\n                if (looksCompleted('', '')) hardCloseLoader('visibilitychange-catchup-1039');\n            } catch (e1039) {}\n        };\n        document.addEventListener('visibilitychange', visCheckClose1039);\n        window.addEventListener('focus', visCheckClose1039);\n        \/\/ 30.9.1426: rete di sicurezza complementare basata sul tempo (non solo sul cambio scheda) - se\n        \/\/ l'utente resta a guardare il popup senza mai cambiare finestra\/scheda, il controllo precedente\n        \/\/ (visibilitychange\/focus) non scatterebbe mai, lasciando il popup bloccato al 100% indefinitamente\n        \/\/ anche a operazione gia' conclusa con successo.\n        setInterval(function(){\n            try { if (looksCompleted('', '')) hardCloseLoader('periodic-catchup-1426'); } catch(e1426) {}\n        }, 2000);\n    }\n\n    \/\/ Garanzia non invasiva: se la risposta help viene aggiornata da vecchi handler, ripulisci solo # e * e mantieni il pulsante copia.\n    function sanitizeHelpNow(){\n        try {\n            var title = byId('col-help-title');\n            var box = byId('col-help-content');\n            if (title && \/[#*]\/.test(title.innerText || title.textContent || '')) title.innerText = String(title.innerText || title.textContent || '').replace(\/[#*]+\/g,'').trim();\n            if (box && \/[#*]\/.test(box.innerHTML || '')) {\n                box.innerHTML = String(box.innerHTML || '').replace(\/[#*]+\/g,'').replace(\/(<br\\s*\\\/?>(\\s*)){3,}\/gi,'<br><br>');\n            }\n        } catch(e) {}\n    }\n    if (typeof MutationObserver !== 'undefined') {\n        var box = byId('col-help-content');\n        if (box) {\n            try {\n                var busy = false;\n                var mo = new MutationObserver(function(){ if (busy) return; busy = true; setTimeout(function(){ sanitizeHelpNow(); busy = false; }, 20); });\n                mo.observe(box, {childList:true, subtree:true});\n            } catch(e) {}\n        }\n    }\n    setTimeout(sanitizeHelpNow, 300);\n})();\n<\/script>\n\n\n\n\n\n<script id=\"ti-plugin-audio-mic-internal-363\">\n(function(){\n    \"use strict\";\n    if (window.__tiPluginAudioMic363Installed) return;\n    window.__tiPluginAudioMic363Installed = true;\n\n    var audioCtx = null;\n    var audioUnlocked = false;\n    var speechPrimed = false;\n    var lastUnlockError = '';\n    var micRecognition = null;\n    var micStoppingTimer = null;\n\n    function byId(id){ return document.getElementById(id); }\n    function root(){ return byId('ti-ai-outer') || document.querySelector('.ti-ai-shop-service,[data-ti-shop-service]'); }\n    function isMuted(){ return !!(window.isMuted || window.muteState === 1 || window.muteState === 2); }\n    function safeAlert(msg){ try { if (window.tiAlert) window.tiAlert(msg); else alert(msg); } catch(e) { try { alert(msg); } catch(ignore) {} } }\n    function setMicUi(active){\n        var btn = byId('ti-mic');\n        if (!btn) return;\n        try {\n            btn.style.background = active ? '#b91c1c' : '#222';\n            btn.style.color = active ? '#fff' : '#ccc';\n            btn.textContent = active ? 'Mic...' : ((window.currLang === 'en') ? 'Mic' : 'Mic');\n            btn.disabled = false;\n        } catch(e) {}\n    }\n    function secureContextOk(){\n        try { return window.isSecureContext || location.protocol === 'https:' || location.hostname === 'localhost' || location.hostname === '127.0.0.1'; } catch(e) { return false; }\n    }\n    function unlockAudioInternal(){\n        var ok = false;\n        lastUnlockError = '';\n        try {\n            var AC = window.AudioContext || window.webkitAudioContext;\n            if (AC) {\n                audioCtx = audioCtx || new AC();\n                if (audioCtx.state === 'suspended' && audioCtx.resume) {\n                    var r = audioCtx.resume();\n                    if (r && typeof r.catch === 'function') r.catch(function(e){ lastUnlockError = e && e.message ? e.message : String(e || ''); });\n                }\n                try {\n                    var osc = audioCtx.createOscillator();\n                    var gain = audioCtx.createGain();\n                    gain.gain.value = 0.00001;\n                    osc.connect(gain);\n                    gain.connect(audioCtx.destination);\n                    osc.start(0);\n                    osc.stop(audioCtx.currentTime + 0.04);\n                } catch(ignore) {}\n                ok = true;\n            }\n        } catch(e) {\n            lastUnlockError = e && e.message ? e.message : String(e || 'AudioContext non disponibile');\n        }\n        try {\n            if ('speechSynthesis' in window) {\n                window.speechSynthesis.resume();\n                if (!speechPrimed) {\n                    var u = new SpeechSynthesisUtterance(' ');\n                    u.volume = 0;\n                    u.rate = 1;\n                    u.pitch = 1;\n                    u.lang = (window.currLang === 'en') ? 'en-US' : 'it-IT';\n                    window.speechSynthesis.speak(u);\n                    speechPrimed = true;\n                }\n                ok = true;\n            }\n        } catch(e) {\n            lastUnlockError = e && e.message ? e.message : String(e || 'speechSynthesis non disponibile');\n        }\n        try {\n            var r = root();\n            (r ? r.querySelectorAll('audio,video') : document.querySelectorAll('#ti-ai-outer audio,#ti-ai-outer video')).forEach(function(el){\n                try { el.muted = false; el.volume = 1; } catch(ignore) {}\n            });\n        } catch(e) {}\n        if (ok) audioUnlocked = true;\n        window.tiPluginAudioUnlocked363 = audioUnlocked;\n        return ok;\n    }\n    window.tiEnsurePluginAudioUnlocked = function(){ return unlockAudioInternal(); };\n    window.tiPluginAudioStatus = function(){\n        return {\n            audioUnlocked: audioUnlocked,\n            audioContextState: audioCtx ? audioCtx.state : 'not-created',\n            speechSynthesis: ('speechSynthesis' in window),\n            speechPrimed: speechPrimed,\n            muted: isMuted(),\n            secureContext: secureContextOk(),\n            mediaDevices: !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia),\n            speechRecognition: !!(window.SpeechRecognition || window.webkitSpeechRecognition),\n            rootFound: !!root(),\n            lastUnlockError: lastUnlockError\n        };\n    };\n\n    var oldPrime = window.primeSpeech;\n    window.primeSpeech = function(){\n        if (audioUnlocked && speechPrimed) return true;\n        return unlockAudioInternal() || (typeof oldPrime === 'function' ? oldPrime.apply(this, arguments) : false);\n    };\n\n    if (typeof window.speakText === 'function' && !window.speakText.__tiAudio363) {\n        var oldSpeakText = window.speakText;\n        window.speakText = function(text){\n            if (!isMuted()) unlockAudioInternal();\n            return oldSpeakText.apply(this, arguments);\n        };\n        window.speakText.__tiAudio363 = true;\n    }\n\n    function startMic(){\n        unlockAudioInternal();\n        var btn = byId('ti-mic');\n        var msg = byId('ti-msg');\n        var send = byId('ti-send');\n        if (!secureContextOk()) {\n            safeAlert('Microfono non disponibile. Apri la pagina in HTTPS e autorizza il microfono per questo sito.');\n            return false;\n        }\n        if (!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)) {\n            safeAlert('Microfono non disponibile nel browser. Verifica permessi sito oppure usa Chrome, Edge o Safari aggiornato.');\n            return false;\n        }\n        var SR = window.SpeechRecognition || window.webkitSpeechRecognition;\n        if (!SR) {\n            safeAlert('Riconoscimento vocale non supportato dal browser. Il microfono esiste, ma questo browser non supporta SpeechRecognition. Usa Chrome o Edge quando possibile.');\n            return false;\n        }\n        if (micRecognition) {\n            try { micRecognition.stop(); } catch(e) {}\n            micRecognition = null;\n            setMicUi(false);\n            return false;\n        }\n        setMicUi(true);\n        try { if (window.log1088) window.log1088('DIAGNOSTICA 1265: mic getUserMedia chiamata (riga 1)'); } catch(e0) {}\n        navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1265: mic getUserMedia RISOLTA con successo'); } catch(e1) {}\n            try { stream.getTracks().forEach(function(t){ t.stop(); }); } catch(e) {}\n            var r = new SR();\n            micRecognition = r;\n            r.lang = (window.currLang === 'en') ? 'en-US' : 'it-IT';\n            r.continuous = false;\n            r.interimResults = false;\n            r.maxAlternatives = 1;\n            r.onresult = function(e){\n                try {\n                    var transcript = e && e.results && e.results[0] && e.results[0][0] ? e.results[0][0].transcript : '';\n                    if (transcript && msg) {\n                        msg.value = transcript;\n                        msg.dispatchEvent(new Event('input', {bubbles:true}));\n                        msg.dispatchEvent(new Event('change', {bubbles:true}));\n                    }\n                    if (transcript && send) setTimeout(function(){ try { send.click(); } catch(ignore) {} }, 80);\n                } catch(err) {}\n            };\n            r.onerror = function(e){\n                var code = e && e.error ? e.error : 'errore';\n                var detail = 'Microfono non disponibile o non autorizzato.';\n                if (code === 'not-allowed' || code === 'service-not-allowed') detail = 'Microfono non autorizzato. Abilita il permesso microfono nelle impostazioni del browser per questo sito.';\n                else if (code === 'no-speech') detail = 'Non ho rilevato voce. Riprova parlando dopo aver premuto Mic.';\n                else if (code === 'audio-capture') detail = 'Nessun microfono rilevato dal browser.';\n                safeAlert(detail + ' Codice: ' + code);\n            };\n            r.onend = function(){\n                micRecognition = null;\n                if (micStoppingTimer) { clearTimeout(micStoppingTimer); micStoppingTimer = null; }\n                setMicUi(false);\n            };\n            try { r.start(); } catch(e) { micRecognition = null; setMicUi(false); safeAlert('Impossibile avviare il microfono: ' + (e && e.message ? e.message : 'errore browser')); return; }\n            micStoppingTimer = setTimeout(function(){\n                try { if (micRecognition) micRecognition.stop(); } catch(e) {}\n                setMicUi(false);\n            }, 10000);\n        }).catch(function(e){\n            setMicUi(false);\n            var msgErr = e && e.name ? e.name : '';\n            safeAlert('Microfono non autorizzato o non disponibile. Verifica i permessi del browser per questo sito. ' + (msgErr ? 'Dettaglio: ' + msgErr : ''));\n        });\n        return false;\n    }\n    window.tiStartPluginMic = startMic;\n\n    function installMicButton(){\n        var btn = byId('ti-mic');\n        if (!btn || btn.__tiMic363) return;\n        btn.__tiMic363 = true;\n        btn.onclick = function(ev){\n            if (ev) { try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {} }\n            return startMic();\n        };\n    }\n    function installGestureUnlock(){\n        var r = root();\n        if (!r || r.__tiAudioGesture363) return;\n        r.__tiAudioGesture363 = true;\n        ['pointerdown','touchstart','mousedown','click','keydown'].forEach(function(evt){\n            r.addEventListener(evt, function(){ unlockAudioInternal(); }, {capture:true, passive:true});\n        });\n    }\n    function installAll(){ installGestureUnlock(); installMicButton(); }\n\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', installAll);\n    installAll();\n    setTimeout(installAll, 300);\n    setTimeout(installAll, 1200);\n})();\n<\/script>\n\n\n\n<script id=\"ti-ateco-config-field-restore-364\">\n(function(){\n    \"use strict\";\n    if (window.__tiAtecoConfigFieldRestore364Installed) return;\n    window.__tiAtecoConfigFieldRestore364Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function norm(s){\n        try { s = String(s || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,''); } catch(e) { s = String(s || ''); }\n        return s.toLowerCase().replace(\/[^a-z0-9]+\/g,'');\n    }\n    function isAtecoFieldName(key){\n        var n = norm(key);\n        return n === 'attivita' || n === 'attivitaditta' || n === 'codiceateco' || n === 'codateco' || n.indexOf('ateco') !== -1;\n    }\n    function visible(el){\n        if (!el) return false;\n        try {\n            var st = window.getComputedStyle ? getComputedStyle(el) : null;\n            if (st && (st.display === 'none' || st.visibility === 'hidden' || st.opacity === '0')) return false;\n            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n        } catch(e) { return false; }\n    }\n    function css(el, prop, val){ try { if (el) el.style.setProperty(prop, val, 'important'); } catch(e) {} }\n    function ensureId(el){\n        if (!el) return '';\n        if (el.id) return el.id;\n        var tbl = el.getAttribute('data-tbl') || 'Config';\n        var idx = el.getAttribute('data-idx') || '0';\n        var key = el.getAttribute('data-key') || 'Attivita';\n        var id = 'ti-ateco-target-' + norm(tbl) + '-' + String(idx).replace(\/[^0-9a-z_-]\/gi,'') + '-' + norm(key) + '-' + Math.random().toString(36).slice(2,7);\n        el.id = id;\n        return id;\n    }\n    function frontAteco(){\n        var ov = byId('ti-ateco-ov');\n        if (!ov) return;\n        try { if (window.preparePluginModal) window.preparePluginModal(ov); } catch(e) {}\n        css(ov, 'display', 'flex');\n        css(ov, 'visibility', 'visible');\n        css(ov, 'opacity', '1');\n        css(ov, 'pointer-events', 'auto');\n        css(ov, 'z-index', '2147483647');\n        try { ov.removeAttribute('aria-hidden'); ov.setAttribute('data-ti-config-child-modal','1'); ov.setAttribute('data-ti-force-front','1'); } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n        setTimeout(function(){\n            try {\n                var input = byId('ateco-in');\n                if (input) input.focus({preventScroll:true});\n            } catch(e) {}\n        }, 80);\n    }\n    function openForTarget(el){\n        if (!el) return false;\n        var id = ensureId(el);\n        window.__tiAtecoTargetElement364 = el;\n        window.__tiAtecoTargetId364 = id;\n        try {\n            var h = byId('ateco-target-id');\n            if (h) h.value = id;\n        } catch(e) {}\n        try {\n            if (typeof window.__tiNativeOpenAtecoSearch364 === 'function') {\n                window.__tiNativeOpenAtecoSearch364(id);\n            } else if (typeof window.openAtecoSearch === 'function') {\n                window.openAtecoSearch(id);\n            }\n        } catch(e) {\n            try { if (window.tiAlert) window.tiAlert('Ricerca ATECO non disponibile: ' + (e && e.message ? e.message : 'errore')); } catch(ignore) {}\n        }\n        try {\n            var h2 = byId('ateco-target-id');\n            if (h2) h2.value = id;\n            var q = byId('ateco-in');\n            if (q && !q.value && el.value) q.value = String(el.value || '').trim();\n            var res = byId('ateco-res');\n            if (res && !String(res.innerHTML || '').trim()) res.innerHTML = '<i>Scrivi l\\'attivit\u00e0 da cercare...<\/i>';\n        } catch(e) {}\n        frontAteco();\n        return false;\n    }\n    function findFieldFromButton(btn){\n        if (!btn) return null;\n        var wrap = btn.parentElement || btn.closest('td');\n        var field = wrap ? wrap.querySelector('input[data-key], textarea[data-key], select[data-key]') : null;\n        if (field) return field;\n        var oc = String(btn.getAttribute('onclick') || '');\n        var m = oc.match(\/openAtecoSearch\\((['\"])(.*?)\\1\\)\/);\n        if (m && m[2]) return byId(m[2]);\n        var targetId = btn.getAttribute('data-ti-ateco-target');\n        return targetId ? byId(targetId) : null;\n    }\n    function addButtonForField(el){\n        if (!el || !isAtecoFieldName(el.getAttribute('data-key') || '')) return;\n        var parent = el.parentElement;\n        if (!parent) return;\n        if (parent.querySelector('[data-ti-ateco-btn=\"364\"], button[onclick*=\"openAtecoSearch\"]')) return;\n        var btn = document.createElement('button');\n        btn.type = 'button';\n        btn.className = 'ti-btn ti-ateco-restore-btn';\n        btn.setAttribute('data-ti-ateco-btn', '364');\n        btn.setAttribute('data-ti-ateco-target', ensureId(el));\n        btn.title = 'Ricerca ATECO';\n        btn.textContent = '\ud83d\udd0d';\n        btn.style.cssText = 'padding:4px 6px;font-size:10px;background:#2563eb;color:#fff;white-space:nowrap;';\n        parent.appendChild(btn);\n    }\n    function ensureAtecoButtons(root){\n        try {\n            var scope = root && root.querySelectorAll ? root : (byId('ti-conf-ov') || document);\n            if (scope.matches && scope.matches('input[data-key], textarea[data-key], select[data-key]')) addButtonForField(scope);\n            var fields = scope.querySelectorAll('input[data-key], textarea[data-key], select[data-key]');\n            Array.prototype.forEach.call(fields, addButtonForField);\n        } catch(e) {}\n    }\n\n    if (typeof window.openAtecoSearch === 'function' && !window.openAtecoSearch.__tiAteco364) {\n        window.__tiNativeOpenAtecoSearch364 = window.openAtecoSearch;\n        window.openAtecoSearch = function(targetId){\n            var el = targetId ? byId(targetId) : null;\n            if (el) {\n                window.__tiAtecoTargetElement364 = el;\n                window.__tiAtecoTargetId364 = targetId;\n            }\n            var ret = window.__tiNativeOpenAtecoSearch364.apply(this, arguments);\n            try { var h = byId('ateco-target-id'); if (h && targetId) h.value = targetId; } catch(e) {}\n            frontAteco();\n            return ret;\n        };\n        window.openAtecoSearch.__tiAteco364 = true;\n    }\n    if (typeof window.selectAteco === 'function' && !window.selectAteco.__tiAteco364) {\n        var prevSelect364 = window.selectAteco;\n        window.selectAteco = function(codice, desc){\n            try {\n                var h = byId('ateco-target-id');\n                var id = (h && h.value) || window.__tiAtecoTargetId364 || '';\n                var el = id ? byId(id) : null;\n                if (!el && window.__tiAtecoTargetElement364) el = window.__tiAtecoTargetElement364;\n                if (el) {\n                    el.value = desc || codice || '';\n                    try { el.dispatchEvent(new Event('input', {bubbles:true})); } catch(e) {}\n                    try { el.dispatchEvent(new Event('change', {bubbles:true})); } catch(e) {}\n                }\n            } catch(e) {}\n            return prevSelect364.apply(this, arguments);\n        };\n        window.selectAteco.__tiAteco364 = true;\n    }\n    document.addEventListener('click', function(ev){\n        var btn = ev.target && ev.target.closest ? ev.target.closest('[data-ti-ateco-btn=\"364\"], button[onclick*=\"openAtecoSearch\"]') : null;\n        if (!btn) return;\n        var field = findFieldFromButton(btn);\n        if (!field) return;\n        if (!isAtecoFieldName(field.getAttribute('data-key') || '')) return;\n        ev.preventDefault();\n        ev.stopPropagation();\n        openForTarget(field);\n        return false;\n    }, true);\n\n    if (typeof window.renderConfig === 'function' && !window.renderConfig.__tiAteco364) {\n        var prevRender364 = window.renderConfig;\n        window.renderConfig = function(){\n            var ret = prevRender364.apply(this, arguments);\n            setTimeout(ensureAtecoButtons, 80);\n            setTimeout(ensureAtecoButtons, 350);\n            return ret;\n        };\n        window.renderConfig.__tiAteco364 = true;\n    }\n    if (typeof MutationObserver !== 'undefined') {\n        try {\n            var cfg = byId('ti-conf-ov');\n            if (cfg) {\n                var mo = new MutationObserver(function(muts){\n                    for (var i=0; i<muts.length; i++) {\n                        var added = muts[i].addedNodes || [];\n                        for (var j=0; j<added.length; j++) if (added[j] && added[j].nodeType === 1) ensureAtecoButtons(added[j]);\n                    }\n                });\n                mo.observe(cfg, {childList:true, subtree:true});\n            }\n        } catch(e) {}\n    }\n    setTimeout(ensureAtecoButtons, 400);\n})();\n<\/script>\n\n\n<script id=\"ti-global-template-quick-button-368\">\n(function(){\n    \"use strict\";\n    if (window.__tiGlobalTemplateQuickButton368Installed) return;\n    window.__tiGlobalTemplateQuickButton368Installed = true;\n\n    var CMD = \"Adegua struttura database a template shopservicemain.json\";\n\n    function byId(id){ return document.getElementById(id); }\n\n    function fillGlobalTemplateCommand(){\n        var prompt = byId('global-action-prompt');\n        if (!prompt) return false;\n        prompt.value = CMD;\n        try { prompt.dispatchEvent(new Event('input', {bubbles:true})); } catch(e) {}\n        try { prompt.dispatchEvent(new Event('change', {bubbles:true})); } catch(e) {}\n        try { prompt.focus({preventScroll:true}); } catch(e) { try { prompt.focus(); } catch(ignore) {} }\n        return false;\n    }\n\n    window.tiFillGlobalTemplateCommand368 = fillGlobalTemplateCommand;\n\n    function ensureButton(){\n        var prompt = byId('global-action-prompt');\n        if (!prompt) return;\n\n        var btn = byId('global-action-template-btn');\n        if (!btn) {\n            btn = document.createElement('button');\n            btn.type = 'button';\n            btn.id = 'global-action-template-btn';\n            btn.className = 'ti-btn';\n            btn.textContent = 'Template';\n            btn.title = 'Scrivi comando: ' + CMD;\n            btn.onclick = fillGlobalTemplateCommand;\n\n            var parent = prompt.parentNode;\n            if (parent) {\n                try {\n                    parent.style.display = 'flex';\n                    parent.style.gap = parent.style.gap || '6px';\n                    parent.style.alignItems = 'stretch';\n                } catch(e) {}\n                parent.appendChild(btn);\n            }\n        } else {\n            btn.onclick = fillGlobalTemplateCommand;\n            btn.textContent = 'Template';\n            btn.title = 'Scrivi comando: ' + CMD;\n        }\n\n        try {\n            btn.style.setProperty('display', 'inline-flex', 'important');\n            btn.style.setProperty('align-items', 'center', 'important');\n            btn.style.setProperty('justify-content', 'center', 'important');\n            btn.style.setProperty('width', '58px', 'important');\n            btn.style.setProperty('min-width', '58px', 'important');\n            btn.style.setProperty('padding', '6px 4px', 'important');\n            btn.style.setProperty('background', '#0f766e', 'important');\n            btn.style.setProperty('color', '#fff', 'important');\n            btn.style.setProperty('font-size', '10px', 'important');\n            btn.style.setProperty('line-height', '1.1', 'important');\n            btn.style.setProperty('font-weight', '800', 'important');\n            btn.style.setProperty('white-space', 'normal', 'important');\n            btn.style.setProperty('cursor', 'pointer', 'important');\n            prompt.style.setProperty('flex', '1 1 auto', 'important');\n            prompt.style.setProperty('min-width', '0', 'important');\n        } catch(e) {}\n    }\n\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', ensureButton);\n    else ensureButton();\n\n    if (typeof window.openModal === 'function' && !window.openModal.__tiGlobalTpl368) {\n        var prevOpen = window.openModal;\n        window.openModal = function(id){\n            var ret = prevOpen.apply(this, arguments);\n            if (id === 'ti-global-action-ov') setTimeout(ensureButton, 40);\n            return ret;\n        };\n        window.openModal.__tiGlobalTpl368 = true;\n    }\n\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t) return;\n        if (t.id === 'global-action-template-btn' || (t.closest && t.closest('#global-action-template-btn'))) {\n            ev.preventDefault();\n            ev.stopPropagation();\n            fillGlobalTemplateCommand();\n        }\n    }, true);\n\n    setTimeout(ensureButton, 300);\n})();\n<\/script>\n\n\n<script id=\"ti-contact-num-main-access-375\">\n(function(){\n    \"use strict\";\n    if (window.__tiContactNumMainAccess375Installed) return;\n    window.__tiContactNumMainAccess375Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function selectedDb(){\n        try {\n            var d = byId('ti-ditta');\n            var v = d && d.value ? String(d.value).trim() : '';\n            if (!v || v === 'NEW_DB') {\n                try { v = String(window.tiForced || localStorage.getItem('ti_saved_db') || '').trim(); } catch(e) {}\n            }\n            return (!v || v === 'NEW_DB') ? '' : v;\n        } catch(e) { return ''; }\n    }\n    function fmt(n){\n        n = parseInt(n, 10) || 0;\n        try { return n.toLocaleString('it-IT'); } catch(e) { return String(n).replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, '.'); }\n    }\n    function escHtml(s){ return String(s == null ? '' : s).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c] || c; }); }\n    function clientContactId584(){\n        var k = 'ti_contact_client_id_584';\n        var id = '';\n        try { id = sessionStorage.getItem(k) || ''; } catch(e) {}\n        if (!id) {\n            id = 'cc_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 12);\n            try { sessionStorage.setItem(k, id); } catch(e) {}\n        }\n        return id;\n    }\n    function isPrivilegedClient(){\n        var role = String(window.tiRole || '').toLowerCase();\n        var user = String(window.tiUser || '').toLowerCase();\n        return user === 'ssglobaladmin' || user === 'targetai' || \/amministratore|administrator|configuratore|configurator|responsabile|responsible|operatore|operator|globaladmin|sysadmin\/.test(role);\n    }\n    function canReadContactLog1572(){\n        if (window.tiStrictAdminLog1488 === true) return true;\n        var role = String(window.tiRole || '').toLowerCase();\n        var user = String(window.tiUser || '').trim();\n        if (!user) return false;\n        return \/configuratore|configurator\/.test(role);\n    }\n    function isAdminClient1874(){\n        var role = String(window.tiRole || '').toLowerCase();\n        var user = String(window.tiUser || '').toLowerCase();\n        return window.tiStrictAdminLog1488 === true || user === 'ssglobaladmin' || user === 'targetai' || \/amministratore|administrator|globaladmin|global admin|sysadmin\/.test(role);\n    }\n    function isAiActsPrivileged1552(){\n        var role = String(window.tiRole || '').toLowerCase();\n        var user = String(window.tiUser || '').toLowerCase();\n        return user === 'ssglobaladmin' || user === 'targetai' || \/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|global admin|sysadmin\/.test(role);\n    }\n    function getConfigRow(){\n        try {\n            var data = window.currentDbData || {};\n            var t = data && data.Tabelle ? data.Tabelle : null;\n            if (!t) return null;\n            var cfgName = Object.keys(t).find(function(k){ return String(k).toLowerCase() === 'config'; }) || 'Config';\n            var rows = t[cfgName];\n            if (Array.isArray(rows)) return rows[0] || null;\n            if (rows && typeof rows === 'object') return Object.values(rows)[0] || null;\n        } catch(e) {}\n        return null;\n    }\n    function setLocalContactsNum(n, field){\n        n = parseInt(n, 10) || 0;\n        try {\n            if (!window.currentDbData) window.currentDbData = {};\n            window.currentDbData.__contacts_num = n;\n            var row = getConfigRow();\n            if (row) {\n                var k = Object.keys(row).find(function(x){\n                    var s = String(x || '').toLowerCase().replace(\/[^a-z0-9]\/g,'');\n                    return s === 'contactsnum' || s === 'contactnum';\n                }) || field || 'Contacts_num';\n                row[k] = n;\n            }\n        } catch(e) {}\n        return n;\n    }\n    function currentContactsNum(){\n        try {\n            if (window.currentDbData && typeof window.currentDbData.__contacts_num !== 'undefined') return parseInt(window.currentDbData.__contacts_num, 10) || 0;\n            var row = getConfigRow();\n            if (!row) return 0;\n            var k = Object.keys(row).find(function(x){\n                var s = String(x || '').toLowerCase().replace(\/[^a-z0-9]\/g,'');\n                return s === 'contactsnum' || s === 'contactnum';\n            });\n            return k ? (parseInt(String(row[k] || '0').replace(\/[^0-9\\-]\/g,''), 10) || 0) : 0;\n        } catch(e) { return 0; }\n    }\n    function setLocalAiActs1552(payload){\n        if (!payload || !payload.ai_acts_visible || !isAiActsPrivileged1552()) return;\n        try {\n            if (!window.currentDbData) window.currentDbData = {};\n            var tot = parseInt(payload.tot_ai_acts,10) || 0;\n            var used = parseInt(payload.ai_acts,10) || 0;\n            var rem = Math.max(0, (typeof payload.ai_acts_remaining !== 'undefined') ? (parseInt(payload.ai_acts_remaining,10) || 0) : (tot-used));\n            window.currentDbData.__tot_ai_acts = tot;\n            window.currentDbData.__ai_acts = used;\n            window.currentDbData.__ai_acts_remaining = rem;\n            window.currentDbData.__ai_acts_usage_percent = (typeof payload.ai_acts_usage_percent !== 'undefined') ? Number(payload.ai_acts_usage_percent || 0) : (tot > 0 ? ((used \/ tot) * 100) : (used > 0 ? 100 : 0));\n            window.currentDbData.__ai_acts_threshold_90 = (typeof payload.ai_acts_threshold_90 !== 'undefined') ? (parseInt(payload.ai_acts_threshold_90,10) || 0) : (tot > 0 ? Math.ceil(tot * 0.90) : 0);\n            window.currentDbData.__ai_acts_near_limit = payload.ai_acts_near_limit ? 1 : 0;\n            window.currentDbData.__ai_acts_extra_active = payload.ai_acts_extra_active ? 1 : 0;\n            window.currentDbData.__ai_acts_month = String(payload.ai_acts_month || '');\n            var row = getConfigRow();\n            if (row) {\n                Object.keys(row).forEach(function(k){\n                    var nk = String(k || '').toLowerCase().replace(\/[^a-z0-9]\/g,'');\n                    if (nk === 'totaiacts') row[k] = String(tot);\n                    if (nk === 'aiacts') row[k] = String(used);\n                });\n            }\n        } catch(e) {}\n    }\n    \/\/ 30.9.1568: il riepilogo accesso\/attivit\u00e0 AI deve esistere una sola volta per la ditta corrente.\n    \/\/ Le richieste iniziali possono arrivare prima e dopo il riallineamento mensile; per evitare il doppio\n    \/\/ blocco (es. AIActs 0 seguito da AIActs 7) si fa debounce e si aggiorna in-place la stessa bubble.\n    function renderAdminInfo1568(db, n, payload){\n        if (!isPrivilegedClient()) return;\n        db = String(db || selectedDb() || '').trim();\n        if (!db || db === 'NEW_DB') return;\n        var key = db;\n        var isNewCompany1772=false;\n        try{isNewCompany1772=(new URLSearchParams(window.location.search||'')).get('ti_new_company')==='1';}catch(e1772){}\n        var trialActive1772=!!(payload&&payload.trial_period_active);\n        var active1874 = payload && typeof payload.active_contacts_current !== 'undefined' ? (parseInt(payload.active_contacts_current,10) || 0) : 0;\n        var showActive1874 = isAdminClient1874() && !(isNewCompany1772 && trialActive1772);\n        var plain = isNewCompany1772 && trialActive1772 ? '' : ((showActive1874 ? ('Contatti attualmente attivi : ' + fmt(active1874) + '\\n') : '') + 'Totale contatti : ' + fmt(n || 0));\n        var totalLabel1488 = canReadContactLog1572()\n            ? ('<a href=\"#\" class=\"ti-contact-log-link\" data-ti-db=\"' + escHtml(db) + '\" style=\"color:#93c5fd;text-decoration:underline;font-weight:700;\">Totale contatti<\/a>')\n            : '<span style=\"font-weight:700;\">Totale contatti<\/span>';\n        var activeHtml1874 = showActive1874 ? ('<a href=\"#\" class=\"ti-contact-log-active-link\" data-ti-db=\"' + escHtml(db) + '\" style=\"color:#93c5fd;text-decoration:underline;font-weight:700;\">Contatti attualmente attivi<\/a> : <b>' + fmt(active1874) + '<\/b><br>') : '';\n        var html = '<span data-ti-company-summary-content-1568=\"1\">' + (isNewCompany1772 && trialActive1772 ? '' : (activeHtml1874 + totalLabel1488 + ' : <b>' + fmt(n || 0) + '<\/b>'));\n        var sigParts = [String(parseInt(n,10)||0),String(active1874),trialActive1772?'trial':''];\n        if(trialActive1772){\n            var trialEnd1772=parseInt(payload.trial_period_end,10)||0;\n            var trialDays1772=Math.max(0,parseInt(payload.trial_period_days_remaining,10)||0);\n            var trialDate1772='';\n            try{trialDate1772=new Date(trialEnd1772*1000).toLocaleDateString('it-IT',{day:'2-digit',month:'2-digit',year:'numeric'});}catch(e1772d){}\n            var prefix1772=(plain?'\\n':'');\n            plain += prefix1772+'Periodo iniziale gratuito di attivit\u00e0 in corso valido fino al '+trialDate1772+'\\nGiorni ancora disponibili '+trialDays1772;\n            html += (html.slice(-1)==='>'&&html.indexOf('Totale contatti')>=0?'<br>':'')+'Periodo iniziale gratuito di attivit\u00e0 in corso valido fino al <b>'+escHtml(trialDate1772)+'<\/b><br>Giorni ancora disponibili <b>'+trialDays1772+'<\/b>';\n            sigParts.push(String(trialEnd1772),String(trialDays1772));\n        }\n        if (payload && payload.ai_acts_visible && isAiActsPrivileged1552()) {\n            var tot1552 = parseInt(payload.tot_ai_acts,10) || 0;\n            var used1552 = parseInt(payload.ai_acts,10) || 0;\n            var rem1552 = Math.max(0, (typeof payload.ai_acts_remaining !== 'undefined') ? (parseInt(payload.ai_acts_remaining,10) || 0) : (tot1552-used1552));\n            var extra1552 = !!payload.ai_acts_extra_active;\n            var threshold1552 = (typeof payload.ai_acts_threshold_90 !== 'undefined') ? (parseInt(payload.ai_acts_threshold_90,10) || 0) : (tot1552 > 0 ? Math.ceil(tot1552 * 0.90) : 0);\n            var usagePct1552 = (typeof payload.ai_acts_usage_percent !== 'undefined') ? Number(payload.ai_acts_usage_percent || 0) : (tot1552 > 0 ? ((used1552 \/ tot1552) * 100) : (used1552 > 0 ? 100 : 0));\n            var nearLimit1552 = (typeof payload.ai_acts_near_limit !== 'undefined') ? !!payload.ai_acts_near_limit : (rem1552 <= 0 || (tot1552 > 0 && used1552 >= threshold1552));\n            sigParts.push(String(tot1552), String(used1552), String(rem1552), String(Math.round(usagePct1552*10)\/10), extra1552?'1':'0', nearLimit1552?'1':'0');\n            plain += '\\nTotale attivit\u00e0 AI abilitate : ' + fmt(tot1552) + '\\nAttivit\u00e0 AI eseguite : ' + fmt(used1552) + '\\nAttivit\u00e0 AI disponibili : ' + fmt(rem1552) + '\\nUtilizzo attivit\u00e0 AI : ' + usagePct1552.toLocaleString('it-IT', {maximumFractionDigits:1}) + '%';\n            var usagePctHtml1660 = usagePct1552.toLocaleString('it-IT', {maximumFractionDigits:1}) + '%';\n            if (usagePct1552 > 95) usagePctHtml1660 = '<span style=\"color:#ef4444;font-weight:900;\">' + usagePctHtml1660 + '<\/span>';\n            html += '<br><b>Totale attivit\u00e0 AI abilitate<\/b> : ' + fmt(tot1552) +\n                '<br><b>Attivit\u00e0 AI eseguite<\/b> : ' + fmt(used1552) +\n                '<br><b>Attivit\u00e0 AI disponibili<\/b> : ' + fmt(rem1552) +\n                '<br><b>Utilizzo attivit\u00e0 AI<\/b> : ' + usagePctHtml1660;\n            if (isNewCompany1772 && trialActive1772 && tot1552===200 && used1552===0 && rem1552===200) {\n                plain += '\\nAttivit\u00e0 AI disponibili esaurite: 0. Puoi avviare la ditta in ogni momento ed acquistare ulteriori attivit\u00e0 AI.';\n                html += '<br><span style=\"display:inline-block;margin-top:7px;\"><b>Attivit\u00e0 AI disponibili esaurite: 0.<\/b> Puoi avviare la ditta in ogni momento ed acquistare ulteriori attivit\u00e0 AI.<\/span>';\n                try{var u1772=new URL(window.location.href);u1772.searchParams.delete('ti_new_company');u1772.searchParams.delete('ti_v');history.replaceState(history.state,'',u1772.toString());}catch(e1772u){}\n            }\n            if (rem1552 <= 0) {\n                plain += '\\nAttivit\u00e0 AI disponibili esaurite. Come utente privilegiato puoi acquistare ulteriori attivit\u00e0 AI.';\n                html += '<br><span style=\"display:inline-block;margin-top:7px;color:#fecaca;\"><b>Attivit\u00e0 AI disponibili esaurite: 0.<\/b> Puoi acquistare ulteriori attivit\u00e0 AI.<\/span> ' +\n                    '<button type=\"button\" class=\"ti-btn\" data-ti-ai-acts-buy-1552=\"1\" style=\"margin-left:6px;padding:4px 9px;font-size:12px;background:#a3e635;color:#1a2e05;border:1px solid #65a30d;border-radius:7px;font-weight:800;\">Acquista attivit\u00e0 AI<\/button>';\n            } else if (nearLimit1552 && !extra1552) {\n                plain += '\\nHai raggiunto almeno il 90% delle attivit\u00e0 AI abilitate. Puoi acquistare SHOP-SERVICE-2 (+200 attivit\u00e0 AI \/ 30 giorni) tramite Attiva Shop & Service.';\n                html += '<br><span style=\"display:inline-block;margin-top:7px;color:#fde68a;\"><b>Soglia 90% raggiunta.<\/b> Puoi aggiungere <b>200 attivit\u00e0 AI per 30 giorni<\/b> con SHOP-SERVICE-2.<\/span> ' +\n                    '<button type=\"button\" class=\"ti-btn\" data-ti-ai-acts-buy-1552=\"1\" style=\"margin-left:6px;padding:4px 9px;font-size:12px;background:#a3e635;color:#1a2e05;border:1px solid #65a30d;border-radius:7px;font-weight:800;\">Attiva \/ acquista attivit\u00e0 AI<\/button>';\n            } else if (extra1552) {\n                html += '<br><span style=\"display:inline-block;margin-top:7px;color:#bbf7d0;\">Pacchetto attivit\u00e0 AI aggiuntive: <b>attivo (+200 \/ 30 giorni)<\/b>.<\/span>';\n            }\n        }\n        if (payload && typeof payload.activation_coverage_days_remaining !== 'undefined') {\n            var d1659 = parseInt(payload.activation_coverage_days_remaining,10);\n            var r1659 = Math.max(0, parseInt(payload.activation_ai_remaining,10)||0);\n            if (Number.isFinite(d1659) && d1659 >= 0 && d1659 <= 7) {\n                plain += '\\nAVVISO SHOP-SERVICE-1: copertura in scadenza tra ' + d1659 + ' giorni. Le attivit\u00e0 AI una tantum residue resteranno disponibili fino a esaurimento.';\n                html += '<br><span style=\"display:inline-block;margin-top:8px;padding:7px 9px;border-radius:8px;background:#422006;color:#fde68a;border:1px solid #f59e0b;\"><b>Scadenza SHOP-SERVICE-1:<\/b> ' + d1659 + ' giorni. Attivit\u00e0 AI una tantum residue: <b>' + fmt(r1659) + '<\/b>; restano utilizzabili fino a esaurimento.<\/span>';\n            } else if (Number.isFinite(d1659) && d1659 < 0 && r1659 > 0) {\n                plain += '\\nSHOP-SERVICE-1: copertura scaduta; attivit\u00e0 AI una tantum residue disponibili fino a esaurimento: ' + r1659;\n                html += '<br><span style=\"display:inline-block;margin-top:8px;padding:7px 9px;border-radius:8px;background:#172554;color:#dbeafe;border:1px solid #3b82f6;\"><b>Il periodo di attivazione Shop & Service \u00e8 esaurito:<\/b> restano <b>' + fmt(r1659) + '<\/b> attivit\u00e0 AI una tantum utilizzabili fino a esaurimento. Attivare l\\'abbonamento mensile per avviare definitivamente il servizio.<\/span>';\n            }\n        }\n        html += '<\/span>';\n        var signature = sigParts.join('|');\n        window.__tiContactInfoShown375 = window.__tiContactInfoShown375 || {};\n        var existing = null;\n        try {\n            var nodes = document.querySelectorAll('.ti-bubble.ai[data-ti-company-summary-1568=\"1\"]');\n            for (var i=0;i<nodes.length;i++) {\n                if (String(nodes[i].getAttribute('data-ti-company-summary-db') || '') === key) {\n                    if (!existing) existing = nodes[i]; else nodes[i].remove();\n                }\n            }\n            \/\/ Rimuove anche eventuali vecchi riepiloghi 1552\/1567 non marcati, limitandosi alle bubble che\n            \/\/ contengono contemporaneamente Totale contatti e Totale attivit\u00e0 AI.\n            document.querySelectorAll('.ti-bubble.ai').forEach(function(b){\n                if (b === existing) return;\n                var tx = String(b.innerText || b.textContent || '');\n                if (\/Totale\\s+contatti\/i.test(tx) && \/Totale\\s+attivit[a\u00e0]\\s+AI\\s+(?:mensili|abilitate)\/i.test(tx)) {\n                    try { b.remove(); } catch(e) {}\n                }\n            });\n        } catch(e) {}\n        if (existing) {\n            if (existing.getAttribute('data-ti-company-summary-signature') === signature) {\n                window.__tiContactInfoShown375[key] = signature;\n                return existing;\n            }\n            existing.innerHTML = html;\n            existing.setAttribute('data-ti-company-summary-signature', signature);\n            existing.setAttribute('data-ti-it-html', html);\n            existing.setAttribute('data-raw-source', plain);\n            existing.__tiChatHtmlByLang = existing.__tiChatHtmlByLang || {};\n            existing.__tiChatHtmlByLang.it = html;\n            try { if (window.tiCleanEscapedUiInSubtree) window.tiCleanEscapedUiInSubtree(existing); if (window.tiI18nTranslateSubtree) window.tiI18nTranslateSubtree(existing); } catch(e) {}\n            window.__tiContactInfoShown375[key] = signature;\n            return existing;\n        }\n        var bubble = null;\n        try {\n            if (window.tiAddAiMessageTranslatedIfNeeded) bubble = window.tiAddAiMessageTranslatedIfNeeded(html, plain, db);\n            else if (window.addMsg) bubble = window.addMsg('ai', html, plain);\n        } catch(e) {}\n        if (bubble) {\n            bubble.setAttribute('data-ti-company-summary-1568','1');\n            bubble.setAttribute('data-ti-company-summary-db',key);\n            bubble.setAttribute('data-ti-company-summary-signature',signature);\n        }\n        window.__tiContactInfoShown375[key] = signature;\n        return bubble;\n    }\n    function addAdminInfoOnce(db, n, payload){\n        if (!isPrivilegedClient()) return;\n        db = String(db || selectedDb() || '').trim();\n        if (!db || db === 'NEW_DB') return;\n        window.__tiContactInfoPending1568 = window.__tiContactInfoPending1568 || {};\n        var key = db;\n        try { if (window.__tiContactInfoPending1568[key]) clearTimeout(window.__tiContactInfoPending1568[key]); } catch(e) {}\n        \/\/ Copia semplice del payload per non dipendere da mutazioni successive della risposta AJAX.\n        var snap = {};\n        try { Object.keys(payload || {}).forEach(function(k){ snap[k] = payload[k]; }); } catch(e) { snap = payload || {}; }\n        window.__tiContactInfoPending1568[key] = setTimeout(function(){\n            try { delete window.__tiContactInfoPending1568[key]; } catch(e) {}\n            \/\/ Se nel frattempo e cambiata ditta, non mostrare dati appartenenti alla precedente.\n            if (String(selectedDb() || '').trim() !== key) return;\n            renderAdminInfo1568(key, n, snap);\n        }, 900);\n    }\n    function updateReportTitle(n){\n        try {\n            var title = byId('ti-report-title');\n            if (!title) return;\n            if (typeof n === 'undefined' || n === null) n = currentContactsNum();\n            var txt = String(title.innerText || title.textContent || '').replace(\/\\s*[\\-\u2013\u2014]?\\s*(?:Contatti(?: main form)?|Totale contatti)\\s*:\\s*[0-9.]+\\s*$\/i, '').trim();\n            var totalTitle1488 = canReadContactLog1572()\n                ? ('<a href=\"#\" class=\"ti-contact-log-link\" data-ti-db=\"' + escHtml(selectedDb() || '') + '\" style=\"color:#93c5fd;text-decoration:underline;font-weight:700;\">Totale contatti<\/a>')\n                : '<span style=\"font-weight:700;\">Totale contatti<\/span>';\n            title.innerHTML = escHtml(txt) + ' - ' + totalTitle1488 + ' : <b>' + fmt(n || 0) + '<\/b>';\n        } catch(e) {}\n    }\n    function requestContacts(db, mode, opts){\n        opts = opts || {};\n        db = String(db || selectedDb() || '').trim();\n        if (!db || db === 'NEW_DB') return Promise.resolve({contacts_num: currentContactsNum(), skipped:true});\n        mode = mode || 'read';\n        window.__tiContactReq1693 = window.__tiContactReq1693 || {pending:Object.create(null),cache:Object.create(null)};\n        var reqKey1693 = db + '|' + mode;\n        var now1693 = Date.now ? Date.now() : (new Date()).getTime();\n        if (mode === 'read') {\n            var c1693 = window.__tiContactReq1693.cache[reqKey1693];\n            if (c1693 && (now1693 - c1693.at) < 12000) return Promise.resolve(c1693.payload);\n        }\n        if (window.__tiContactReq1693.pending[reqKey1693]) return window.__tiContactReq1693.pending[reqKey1693];\n        try {\n            var fd = new FormData();\n            fd.append('action', 'ti_ai_track_contact_access');\n            fd.append('ti_action', 'ti_ai_track_contact_access');\n            fd.append('db', db);\n            fd.append('mode', mode);\n            fd.append('client_contact_id', clientContactId584());\n            var url = window.tiUrl || window.location.href; \/\/ 30.9.1692: evita admin-ajax per contatti\n            var p = window.fetchJsonSafe\n                ? window.fetchJsonSafe(url, {method:'POST', body:fd, credentials:'same-origin', tiNoLongProcessSignal:true})\n                : fetch(url, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ return r.json(); });\n            var tracked1693 = p.then(function(res){\n                var payload = res && res.success ? (res.data || {}) : {};\n                \/\/ 30.9.1734: una risposta Contatti\/AI della ditta precedente non puo mai\n                \/\/ modificare currentDbData della ditta appena selezionata ne renderizzare riepiloghi obsoleti.\n                var selectedNow1734 = String(selectedDb() || '').trim();\n                var currentMatches1734 = false;\n                try {\n                    var cur1734 = window.currentDbData || null;\n                    if (cur1734 && window.tiDbPayloadMatches1657) currentMatches1734 = !!window.tiDbPayloadMatches1657(cur1734, db);\n                    else if (cur1734) {\n                        var got1734 = String(cur1734.__db_name || cur1734.__db || cur1734.Database || '').trim().replace(\/\\.json$\/i,'').toLowerCase();\n                        var exp1734 = String(db || '').trim().replace(\/\\.json$\/i,'').toLowerCase();\n                        currentMatches1734 = !!got1734 && got1734 === exp1734;\n                    }\n                } catch(e1734) { currentMatches1734 = false; }\n                var selectedMismatch1741 = String(selectedNow1734).replace(\/\\.json$\/i,'').toLowerCase() !== String(db||'').replace(\/\\.json$\/i,'').toLowerCase();\n                var explicitMemDb1741 = '';\n                try { var cur1741 = window.currentDbData || null; explicitMemDb1741 = cur1741 ? String(cur1741.__db_name || cur1741.__db || cur1741.Database || '').trim() : ''; } catch(e1741) {}\n                var explicitMismatch1741 = !!explicitMemDb1741 && String(explicitMemDb1741).replace(\/\\.json$\/i,'').toLowerCase() !== String(db||'').replace(\/\\.json$\/i,'').toLowerCase();\n                if (selectedMismatch1741 || explicitMismatch1741) {\n                    payload.discarded_company_mismatch_1734 = true;\n                    payload.request_db_1734 = db;\n                    payload.selected_db_1734 = selectedNow1734;\n                    try { console.warn('[Shop-Service] risposta contatti\/AI scartata per cambio ditta 1741',{requestDb:db,selectedDb:selectedNow1734,memoryDb:explicitMemDb1741}); } catch(e) {}\n                    return payload;\n                }\n                if (!window.currentDbData || !explicitMemDb1741) {\n                    window.currentDbData = window.currentDbData || {};\n                    window.currentDbData.__db_name = db;\n                    window.currentDbData.Database = String(db||'').replace(\/\\.json$\/i,'');\n                    window.currentDbData.Tabelle = window.currentDbData.Tabelle || {};\n                }\n                var n = typeof payload.contacts_num !== 'undefined' ? (parseInt(payload.contacts_num, 10) || 0) : currentContactsNum();\n                setLocalContactsNum(n, payload.field || 'Contacts_num');\n                setLocalAiActs1552(payload);\n                try {\n                    var flagKey = 'ti_contact_counted_before_role_login_' + String(db || '');\n                    if (payload.incremented) sessionStorage.setItem(flagKey, '1');\n                    if (payload.decremented) sessionStorage.removeItem(flagKey);\n                } catch(ignore) {}\n                if (mode === 'read') window.__tiContactReq1693.cache[reqKey1693] = {at:(Date.now?Date.now():(new Date()).getTime()),payload:payload};\n                if (opts.showChat) addAdminInfoOnce(db, n, payload);\n                if (opts.updateReport) updateReportTitle(n);\n                return payload;\n            }).catch(function(){\n                if (opts.updateReport) updateReportTitle(currentContactsNum());\n                return {contacts_num: currentContactsNum(), error:true};\n            }).finally(function(){ try{delete window.__tiContactReq1693.pending[reqKey1693];}catch(e){} });\n            window.__tiContactReq1693.pending[reqKey1693] = tracked1693;\n            return tracked1693;\n        } catch(e) {\n            if (opts.updateReport) updateReportTitle(currentContactsNum());\n            return Promise.resolve({contacts_num: currentContactsNum(), error:true});\n        }\n    }\n    if (!window.__tiAiActsBuyDelegated1552) {\n        window.__tiAiActsBuyDelegated1552 = true;\n        document.addEventListener('click', function(ev){\n            var b = ev.target && ev.target.closest ? ev.target.closest('[data-ti-ai-acts-buy-1552=\"1\"]') : null;\n            if (!b) return;\n            ev.preventDefault(); ev.stopPropagation();\n            if (typeof window.openShopServiceActivationPopup === 'function') window.openShopServiceActivationPopup();\n        }, false);\n    }\n    function trackMainAccess(db){\n        db = String(db || selectedDb() || '').trim();\n        if (!db || db === 'NEW_DB') return;\n        window.__tiContactMainAccessDone375 = window.__tiContactMainAccessDone375 || {};\n        if (window.__tiContactMainAccessDone375[db]) {\n            requestContacts(db, 'read', {showChat:true, updateReport:true});\n            return;\n        }\n        window.__tiContactMainAccessDone375[db] = true;\n        requestContacts(db, 'access', {showChat:true, updateReport:true});\n        \/\/ 30.9.1368: al primo accesso alla main form con i dati della ditta caricati, cita e pronuncia il nome\n        \/\/ della ditta - richiesto esplicitamente; le voci in \"Istruzioni\" da sole non bastavano perche'\n        \/\/ guidano l'AI solo quando genera una risposta a un messaggio, non al semplice caricamento pagina.\n        \/\/ 30.9.1375: ora condizionato alla presenza effettiva, nella tabella \"Istruzioni\" di QUESTA ditta, di una\n        \/\/ riga che richieda esplicitamente questo comportamento - prima scattava sempre per tutte le ditte,\n        \/\/ indipendentemente da cosa fosse configurato, il che non rifletteva correttamente l'intento dell'utente.\n        (function announceDittaName1368(attempt){\n            try {\n                \/\/ 30.9.1369: non pronuncia nulla mentre uno dei popup di attesa e' visibile - riprova piu' tardi\n                \/\/ invece di parlare subito, cosi' non si sovrappone mai audibilmente a quelle fasi.\n                if (document.getElementById('ti-config-wait-1338') || document.getElementById('ti-save-wait-1356')) {\n                    if ((attempt || 0) < 20) setTimeout(function(){ announceDittaName1368((attempt||0)+1); }, 500);\n                    return;\n                }\n                var t = window.currentDbData && window.currentDbData.Tabelle;\n                var cfgName = t ? Object.keys(t).find(function(k){ return String(k).toLowerCase() === 'config'; }) : null;\n                var rows = cfgName ? t[cfgName] : null;\n                var row = Array.isArray(rows) ? rows[0] : (rows && typeof rows === 'object' ? Object.values(rows)[0] : null);\n                var key = row ? Object.keys(row).find(function(k){ return String(k).toLowerCase() === 'ditta'; }) : null;\n                var name = key ? String(row[key] || '').trim() : '';\n                if (!name) {\n                    if ((attempt || 0) < 8) setTimeout(function(){ announceDittaName1368((attempt||0)+1); }, 400);\n                    return;\n                }\n                \/\/ 30.9.1375: verifica se la ditta ha configurato questa specifica istruzione nella propria\n                \/\/ tabella \"Istruzioni\" - ricerca per parole chiave (accesso + cita\/pronuncia\/nome), senza\n                \/\/ richiedere una corrispondenza esatta del testo, cosi' l'utente puo' formularla liberamente.\n                var instrName = t ? Object.keys(t).find(function(k){ return String(k).toLowerCase() === 'istruzioni'; }) : null;\n                var instrRows = instrName ? t[instrName] : null;\n                var instrList = Array.isArray(instrRows) ? instrRows : (instrRows && typeof instrRows === 'object' ? Object.values(instrRows) : []);\n                var configured = instrList.some(function(r){\n                    if (!r || typeof r !== 'object') return false;\n                    var iKey = Object.keys(r).find(function(k){ return String(k).toLowerCase() === 'istruzione'; });\n                    var txt = iKey ? String(r[iKey] || '').toLowerCase() : '';\n                    return \/accesso\/.test(txt) && \/(cita|pronuncia|nome)\/.test(txt);\n                });\n                if (!configured) return;\n                \/\/ 30.9.1374: attende che le voci del motore vocale siano davvero pronte prima di mostrare\n                \/\/ testo+audio insieme - la sola \"sveglia anticipata\" (1370) non bastava sempre, causando un\n                \/\/ audio udibile solo molto piu' tardi (es. al successivo messaggio scritto), scollegato dal\n                \/\/ testo gia' mostrato. Cosi' testo e voce restano sincronizzati, con un limite di attesa breve.\n                function speakWhenReady1374(waited){\n                    var voicesReady = ('speechSynthesis' in window) && window.speechSynthesis.getVoices().length > 0;\n                    if (!voicesReady && (waited || 0) < 2500) {\n                        setTimeout(function(){ speakWhenReady1374((waited||0)+100); }, 100);\n                        return;\n                    }\n                    var msg = 'Hai effettuato l\\'accesso alla ditta ' + name + '.';\n                    if (typeof window.addMsg === 'function') window.addMsg('ai', msg);\n                    if (window.speakText) window.speakText(msg);\n                }\n                speakWhenReady1374(0);\n            } catch(e) {}\n        })(0);\n    }\n    function compensateAfterRoleLogin(db){\n        db = String(db || selectedDb() || '').trim();\n        if (!db || db === 'NEW_DB') return Promise.resolve(false);\n        var flagKey = 'ti_contact_counted_before_role_login_' + db;\n        var hadCount = false;\n        try { hadCount = sessionStorage.getItem(flagKey) === '1'; } catch(e) {}\n        if (!hadCount) return Promise.resolve(false);\n        return requestContacts(db, 'role_login_compensate', {showChat:false, updateReport:true}).then(function(payload){\n            try { if (payload && payload.decremented) sessionStorage.removeItem(flagKey); } catch(e) {}\n            return !!(payload && payload.decremented);\n        });\n    }\n\n    function refreshForReport(){\n        requestContacts(selectedDb(), 'report', {showChat:false, updateReport:true});\n        setTimeout(function(){ requestContacts(selectedDb(), 'report', {showChat:false, updateReport:true}); }, 600);\n    }\n    function scheduleTrack(){\n        var tries = 0;\n        var tm = setInterval(function(){\n            tries++;\n            var db = selectedDb();\n            if (db) { clearInterval(tm); trackMainAccess(db); }\n            if (tries > 60) clearInterval(tm);\n        }, 300);\n    }\n    function installContactHeartbeat1874(){\n        if (window.__tiContactHeartbeat1874Installed) return;\n        window.__tiContactHeartbeat1874Installed = true;\n        function beat(){\n            try {\n                if (document.visibilityState && document.visibilityState !== 'visible') return;\n                if (isPrivilegedClient()) return;\n                var db = selectedDb();\n                if (!db || db === 'NEW_DB') return;\n                requestContacts(db, 'contact_touch', {showChat:false, updateReport:false});\n            } catch(e) {}\n        }\n        window.__tiContactHeartbeat1874Timer = setInterval(beat, 60000);\n        setTimeout(beat, 15000);\n        document.addEventListener('visibilitychange', function(){ if (!document.hidden) setTimeout(beat, 500); }, false);\n    }\n    function install(){\n        if (typeof window.updCtx === 'function' && !window.updCtx.__tiContact375) {\n            var oldUpd = window.updCtx;\n            window.updCtx = function(){\n                var ret = oldUpd.apply(this, arguments);\n                setTimeout(function(){ trackMainAccess(selectedDb()); }, 700);\n                return ret;\n            };\n            window.updCtx.__tiContact375 = true;\n        }\n        if (typeof window.renderActivityReport === 'function' && !window.renderActivityReport.__tiContact375) {\n            var oldRender = window.renderActivityReport;\n            window.renderActivityReport = function(){ var ret = oldRender.apply(this, arguments); updateReportTitle(); return ret; };\n            window.renderActivityReport.__tiContact375 = true;\n        }\n        if (typeof window.openActivityReport === 'function' && !window.openActivityReport.__tiContact375) {\n            var oldOpen = window.openActivityReport;\n            window.openActivityReport = function(){\n                var ret = oldOpen.apply(this, arguments);\n                refreshForReport();\n                return ret;\n            };\n            window.openActivityReport.__tiContact375 = true;\n        }\n        try {\n            var d = byId('ti-ditta');\n            if (d && !d.__tiContact375Change) {\n                d.__tiContact375Change = true;\n                d.addEventListener('change', function(){\n                    var db = selectedDb();\n                    if (db) {\n                        window.__tiContactInfoShown375 = {};\n                        setTimeout(function(){ trackMainAccess(db); }, 900);\n                    }\n                }, false);\n            }\n        } catch(e) {}\n    }\n    document.addEventListener('DOMContentLoaded', function(){ install(); scheduleTrack(); installContactHeartbeat1874(); }, false);\n    setTimeout(function(){ install(); scheduleTrack(); installContactHeartbeat1874(); }, 800);\n    window.tiTrackCompanyContactAccess375 = trackMainAccess;\n    window.tiReadCompanyContactAccess375 = function(db){ return requestContacts(db || selectedDb(), 'read', {showChat:false, updateReport:true}); };\n    window.tiForceCompanyContactsNum375 = function(n, field){\n        n = setLocalContactsNum(n, field || 'Contacts_num');\n        updateReportTitle(n);\n        return n;\n    };\n    window.tiCompensateContactAfterRoleLogin377 = compensateAfterRoleLogin;\n    window.tiUpdateActivityReportContactsTitle375 = function(){ refreshForReport(); };\n    function touchContactOnExit584(){\n        try {\n            var db = selectedDb();\n            if (!db || isPrivilegedClient()) return;\n            var fd = new FormData();\n            fd.append('action', 'ti_ai_track_contact_access');\n            fd.append('ti_action', 'ti_ai_track_contact_access');\n            fd.append('db', db);\n            fd.append('mode', 'contact_touch');\n            fd.append('client_contact_id', clientContactId584());\n            var url = window.tiUrl || window.location.href; \/\/ 30.9.1692: evita admin-ajax per contatti\n            if (navigator.sendBeacon) navigator.sendBeacon(url, fd);\n            else fetch(url, {method:'POST', body:fd, credentials:'same-origin', keepalive:true});\n        } catch(e) {}\n    }\n    if (!window.__tiContactTouchExit584Installed) {\n        window.__tiContactTouchExit584Installed = true;\n        window.addEventListener('pagehide', touchContactOnExit584, false);\n        window.addEventListener('beforeunload', touchContactOnExit584, false);\n    }\n    try {\n        if (!window.__tiContactLoginCompensate377Installed) {\n            window.__tiContactLoginCompensate377Installed = true;\n            var prevReload = window.tiReloadAfterSuccessfulLogin;\n            window.tiReloadAfterSuccessfulLogin = function(){\n                var db = selectedDb();\n                var done = false;\n                function go(){ if (done) return; done = true; if (typeof prevReload === 'function') prevReload(); else window.location.reload(); }\n                try {\n                    compensateAfterRoleLogin(db).then(go).catch(go);\n                    setTimeout(go, 900);\n                } catch(e) { go(); }\n            };\n        }\n    } catch(e) {}\n})();\n<\/script>\n\n<script id=\"ti-contact-log-popup-584\">\n(function(){\n    \"use strict\";\n    if (window.__tiContactLogPopup584Installed) return;\n    window.__tiContactLogPopup584Installed = true;\n\n    function esc(s){ return String(s == null ? '' : s).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c] || c; }); }\n    function ipLookupHtml1885(ip){\n        ip = String(ip == null ? '' : ip).trim();\n        if (!ip) return '';\n        var href = 'https:\/\/www.whatismyip.com\/ip-address-lookup\/?ip=' + encodeURIComponent(ip);\n        return '<span class=\"ti-contact-ip-wrap-1886\" style=\"display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap;\">'\n            + '<a class=\"ti-contact-ip-lookup-1886\" href=\"' + esc(href) + '\" target=\"_blank\" rel=\"noopener noreferrer\" title=\"Verifica informazioni IP\" style=\"color:#93c5fd;text-decoration:underline;font-weight:700;\">' + esc(ip) + '<\/a>'\n            + '<\/span>';\n    }\n    function fmt(n){\n        n = parseInt(n, 10) || 0;\n        try { return n.toLocaleString('it-IT'); } catch(e) { return String(n).replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, '.'); }\n    }\n    function selectedDb(){\n        try {\n            var d = document.getElementById('ti-ditta');\n            var v = d && d.value ? String(d.value).trim() : '';\n            if (!v || v === 'NEW_DB') v = String(window.tiForced || localStorage.getItem('ti_saved_db') || '').trim();\n            return (!v || v === 'NEW_DB') ? '' : v;\n        } catch(e) { return ''; }\n    }\n    function ajaxLog(db, mode){\n        var fd = new FormData();\n        fd.append('action', 'ti_ai_contact_log');\n        fd.append('ti_action', 'ti_ai_contact_log');\n        fd.append('db', db || selectedDb());\n        fd.append('mode', mode || 'read');\n        var url = window.tiUrl || window.location.href; \/\/ 30.9.1692: evita admin-ajax per contatti\n        var p = window.fetchJsonSafe\n            ? window.fetchJsonSafe(url, {method:'POST', body:fd, credentials:'same-origin', tiNoLongProcessSignal:true})\n            : fetch(url, {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ return r.json(); });\n        return p.then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && (res.data.message || res.data.error)) || 'Errore log contatti');\n            return res.data || {};\n        });\n    }\n    function plainRows(rows, total, activeOnly){\n        rows = Array.isArray(rows) ? rows : [];\n        var out = [activeOnly ? 'Contatti attualmente attivi' : 'Lista contatti', (activeOnly ? 'Contatti attualmente attivi: ' : 'Totale contatti: ') + fmt(total || rows.length), 'Righe dettaglio log: ' + fmt(rows.length), 'Data e ora\\tIP\\tPosizione IP stimata\\tUsername\\tDurata hh.mm'];\n        rows.forEach(function(r){ out.push([r.datetime || '', r.ip || '', r.location || 'Non disponibile', r.username || '', r.duration || '00.00'].join('\\t')); });\n        return out.join('\\n');\n    }\n    function copyText(text, btn){\n        text = String(text || '');\n        if (window.tiAiSafeCopyText459) return window.tiAiSafeCopyText459(text, btn || null);\n        function done(ok){ if (btn) { var old = btn.getAttribute('data-old') || btn.textContent || 'Copia testo'; btn.setAttribute('data-old', old); btn.textContent = ok ? 'Copiato' : 'Copia manuale'; setTimeout(function(){ btn.textContent = old; }, 1200); } }\n        try { if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){ done(false); }); return true; } } catch(e) {}\n        try { var ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.left='-9999px'; document.body.appendChild(ta); ta.select(); var ok=document.execCommand('copy'); ta.remove(); done(ok); return ok; } catch(e) { done(false); }\n        return false;\n    }\n    function ensureModal(){\n        var old = document.getElementById('ti-contact-log-modal-584');\n        if (old) return old;\n        var div = document.createElement('div');\n        div.id = 'ti-contact-log-modal-584';\n        div.style.cssText = 'position:fixed;inset:0;z-index:1000002;background:rgba(15,23,42,.74);display:none;align-items:center;justify-content:center;padding:14px;box-sizing:border-box;';\n        div.innerHTML = '<div style=\"width:min(860px,96vw);max-height:88vh;overflow:auto;background:#111827;color:#e5e7eb;border:1px solid #334155;border-radius:14px;box-shadow:0 18px 50px rgba(0,0,0,.45);padding:14px;font-family:Arial,sans-serif;\">'\n            + '<div style=\"display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;\">'\n            + '<div id=\"ti-contact-log-title-584\" style=\"font-size:16px;font-weight:700;\">Lista contatti<\/div>'\n            + '<button type=\"button\" data-ti-contact-close=\"1\" data-ti-no-global-exit=\"1\" style=\"background:#374151;color:#fff;border:0;border-radius:8px;padding:7px 10px;cursor:pointer;\">Chiudi lista<\/button>'\n            + '<\/div>'\n            + '<div id=\"ti-contact-log-status-584\" aria-hidden=\"true\" style=\"display:none!important;\"><\/div>'\n            + '<div id=\"ti-contact-log-summary-584\" style=\"font-size:12px;color:#cbd5e1;margin:0 0 8px 2px;\"><\/div>'\n            + '<div style=\"overflow:auto;border:1px solid #334155;border-radius:10px;\">'\n            + '<table style=\"width:100%;border-collapse:collapse;font-size:12px;min-width:760px;\">'\n            + '<thead><tr style=\"background:#1f2937;\"><th style=\"text-align:left;padding:7px;border-bottom:1px solid #334155;\">Data e ora<\/th><th style=\"text-align:left;padding:7px;border-bottom:1px solid #334155;\">IP<\/th><th style=\"text-align:left;padding:7px;border-bottom:1px solid #334155;\">Posizione IP (stimata)<\/th><th style=\"text-align:left;padding:7px;border-bottom:1px solid #334155;\">Username<\/th><th style=\"text-align:left;padding:7px;border-bottom:1px solid #334155;\">Durata hh.mm<\/th><\/tr><\/thead>'\n            + '<tbody id=\"ti-contact-log-body-584\"><\/tbody>'\n            + '<\/table><\/div>'\n            + '<div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;justify-content:flex-end;\">'\n            + '<button type=\"button\" id=\"ti-contact-log-copy-584\" style=\"background:#2563eb;color:#fff;border:0;border-radius:8px;padding:8px 10px;cursor:pointer;font-size:12px;\">Copia testo<\/button>'\n            + '<button type=\"button\" id=\"ti-contact-log-clear-584\" style=\"background:#b91c1c;color:#fff;border:0;border-radius:8px;padding:8px 10px;cursor:pointer;font-size:12px;\">Cancella lista \/ Azzera totale<\/button>'\n            + '<button type=\"button\" data-ti-contact-close=\"1\" data-ti-no-global-exit=\"1\" style=\"background:#374151;color:#fff;border:0;border-radius:8px;padding:8px 10px;cursor:pointer;font-size:12px;\">Chiudi lista<\/button>'\n            + '<\/div><\/div>';\n        document.body.appendChild(div);\n        div.addEventListener('click', function(ev){\n            var ipLink1886 = ev.target && ev.target.closest ? ev.target.closest('.ti-contact-ip-lookup-1886') : null;\n            if (ipLink1886) {\n                try {\n                    ev.preventDefault();\n                    ev.stopPropagation();\n                    if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                    var ipHref1886 = String(ipLink1886.getAttribute('href') || '');\n                    if (ipHref1886) {\n                        var ipWin1886 = window.open(ipHref1886, '_blank', 'noopener,noreferrer');\n                        if (ipWin1886) try { ipWin1886.opener = null; } catch(e) {}\n                    }\n                } catch(e) {}\n                return false;\n            }\n            if (ev.target === div || (ev.target && ev.target.getAttribute && ev.target.getAttribute('data-ti-contact-close') === '1')) {\n                try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n                div.style.display = 'none';\n                try {\n                    document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked','ti-no-scroll');\n                    document.documentElement.classList.remove('ti-no-scroll');\n                } catch(e) {}\n                return false;\n            }\n        }, true);\n        return div;\n    }\n    function renderRows(rows, total, activeOnly){\n        var body = document.getElementById('ti-contact-log-body-584');\n        if (!body) return;\n        rows = Array.isArray(rows) ? rows : [];\n        total = parseInt(total, 10) || 0;\n        var summary1576 = document.getElementById('ti-contact-log-summary-584');\n        if (summary1576) summary1576.textContent = (activeOnly ? 'Contatti attualmente attivi: ' : 'Totale contatti: ') + fmt(total) + ' \u00b7 Righe dettaglio disponibili: ' + fmt(rows.length) + ' \u00b7 Posizione IP: stima rete (non GPS)';\n        if (!rows.length) {\n            body.innerHTML = '<tr><td colspan=\"5\" style=\"padding:12px;color:#94a3b8;text-align:center;\">Nessun dettaglio contatto disponibile per il totale registrato.<\/td><\/tr>';\n            return;\n        }\n        body.innerHTML = rows.map(function(r){\n            return '<tr>'\n                + '<td style=\"padding:7px;border-top:1px solid #334155;\">' + esc(r.datetime || '') + '<\/td>'\n                + '<td style=\"padding:7px;border-top:1px solid #334155;\">' + ipLookupHtml1885(r.ip || '') + '<\/td>'\n                + '<td style=\"padding:7px;border-top:1px solid #334155;\">' + esc(r.location || 'Non disponibile') + '<\/td>'\n                + '<td style=\"padding:7px;border-top:1px solid #334155;\">' + esc(r.username || '') + '<\/td>'\n                + '<td style=\"padding:7px;border-top:1px solid #334155;\">' + esc(r.duration || '00.00') + '<\/td>'\n                + '<\/tr>';\n        }).join('');\n    }\n    function openContactLog(db, activeOnly){\n        activeOnly = !!activeOnly;\n        db = String(db || selectedDb() || '').trim();\n        if (!db) { try { if (window.tiAlert) window.tiAlert('Ditta non selezionata.'); else alert('Ditta non selezionata.'); } catch(e) {} return; }\n        var modal = ensureModal();\n        var status = document.getElementById('ti-contact-log-status-584');\n        var copyBtn = document.getElementById('ti-contact-log-copy-584');\n        var clearBtn = document.getElementById('ti-contact-log-clear-584');\n        var titleEl1876 = document.getElementById('ti-contact-log-title-584');\n        if (titleEl1876) titleEl1876.textContent = activeOnly ? 'Contatti attualmente attivi' : 'Lista contatti';\n        if (clearBtn) clearBtn.style.display = (!activeOnly && window.tiStrictAdminLog1488 === true) ? '' : 'none';\n        var currentRows = [];\n        var currentTotal = 0;\n        modal.style.display = 'flex';\n        if (status) { status.textContent = ''; status.style.display = 'none'; status.setAttribute('aria-hidden','true'); }\n        renderRows([], 0, activeOnly);\n        function refresh(){\n            return ajaxLog(db, activeOnly ? 'active' : 'read').then(function(data){\n                currentRows = Array.isArray(data.rows) ? data.rows : [];\n                currentTotal = parseInt(data.total_contacts || data.contacts_num || currentRows.length, 10) || 0;\n                renderRows(currentRows, currentTotal, activeOnly);\n                if (status) { status.textContent = ''; status.style.display = 'none'; }\n                try { if (window.tiForceCompanyContactsNum375) window.tiForceCompanyContactsNum375(currentTotal, data.field || 'Contacts_num'); } catch(e) {}\n                return data;\n            }).catch(function(err){\n                if (status) { status.textContent = ''; status.style.display = 'none'; }\n                renderRows([], currentTotal, false);\n            });\n        }\n        if (copyBtn) {\n            copyBtn.onclick = function(){ copyText(plainRows(currentRows, currentTotal, activeOnly), copyBtn); };\n        }\n        if (clearBtn && !activeOnly && window.tiStrictAdminLog1488 === true) {\n            clearBtn.onclick = function(){\n                var ok = false;\n                try { ok = confirm('Cancellare la lista log contatti e azzerare anche il totale contatti della ditta corrente?'); } catch(e) { ok = true; }\n                if (!ok) return;\n                if (status) { status.textContent = ''; status.style.display = 'none'; }\n                ajaxLog(db, 'clear').then(function(data){\n                    currentRows = [];\n                    currentTotal = parseInt(data && (data.total_contacts || data.contacts_num), 10) || 0;\n                    renderRows([], currentTotal);\n                    if (status) { status.textContent = ''; status.style.display = 'none'; }\n                    try { if (window.tiForceCompanyContactsNum375) window.tiForceCompanyContactsNum375(currentTotal, (data && data.field) || 'Contacts_num'); } catch(e) {}\n                    try { if (window.tiReadCompanyContactAccess375) setTimeout(function(){ window.tiReadCompanyContactAccess375(db); }, 350); } catch(e) {}\n                }).catch(function(err){ if (status) { status.textContent = ''; status.style.display = 'none'; } });\n            };\n        } else if (clearBtn) {\n            clearBtn.onclick = null;\n        }\n        refresh();\n    }\n    document.addEventListener('click', function(ev){\n        var aa = ev.target && ev.target.closest ? ev.target.closest('.ti-contact-log-active-link') : null;\n        if (aa) {\n            ev.preventDefault(); ev.stopPropagation();\n            openContactLog(aa.getAttribute('data-ti-db') || selectedDb(), true);\n            return;\n        }\n        var a = ev.target && ev.target.closest ? ev.target.closest('.ti-contact-log-link') : null;\n        if (!a) return;\n        ev.preventDefault();\n        ev.stopPropagation();\n        openContactLog(a.getAttribute('data-ti-db') || selectedDb(), false);\n    }, true);\n    window.tiOpenContactLogPopup584 = openContactLog;\n})();\n<\/script>\n\n\n\n\n<script id=\"ti-contact-log-close-isolation-586\">\n(function(){\n    \"use strict\";\n    if (window.__tiContactLogCloseIsolation586Installed) return;\n    window.__tiContactLogCloseIsolation586Installed = true;\n    function closeOnly(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var modal = t.closest('#ti-contact-log-modal-584');\n        if (!modal) return;\n        var isClose = (t === modal) || (t.closest && t.closest('[data-ti-contact-close=\"1\"]'));\n        if (!isClose) return;\n        try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        try { modal.style.display = 'none'; } catch(e) {}\n        try {\n            document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked','ti-no-scroll');\n            document.documentElement.classList.remove('ti-no-scroll');\n        } catch(e) {}\n        return false;\n    }\n    try { window.addEventListener('click', closeOnly, true); } catch(e) {}\n    try { window.addEventListener('touchend', closeOnly, true); } catch(e) {}\n})();\n<\/script>\n\n\n<script id=\"ti-plugin-audio-mic-fix-380\">\n(function(){\n    \"use strict\";\n    if (window.__tiPluginAudioMicFix380Installed) return;\n    window.__tiPluginAudioMicFix380Installed = true;\n\n    var audioCtx380 = null;\n    var audioUnlocked380 = false;\n    var speechPrimed380 = false;\n    var micRecognition380 = null;\n    var micTimer380 = null;\n    var lastError380 = '';\n\n    function byId(id){ return document.getElementById(id); }\n    function root(){ return byId('ti-ai-outer') || document.querySelector('.ti-ai-shop-service,[data-ti-shop-service]'); }\n    function muted(){ return !!(window.isMuted || window.muteState === 1 || window.muteState === 2); }\n    function alertSafe(msg){ try { if (window.tiAlert) window.tiAlert(msg); else alert(msg); } catch(e) { try { alert(msg); } catch(ignore){} } }\n    function secureOk(){ try { return !!(window.isSecureContext || location.protocol === 'https:' || location.hostname === 'localhost' || location.hostname === '127.0.0.1'); } catch(e) { return false; } }\n\n    function unlockAudio380(){\n        var ok = false;\n        lastError380 = '';\n        try {\n            var AC = window.AudioContext || window.webkitAudioContext;\n            if (AC) {\n                audioCtx380 = audioCtx380 || new AC();\n                if (audioCtx380.state === 'suspended' && audioCtx380.resume) {\n                    try {\n                        var pr = audioCtx380.resume();\n                        if (pr && typeof pr.catch === 'function') pr.catch(function(e){ lastError380 = e && e.message ? e.message : String(e || ''); });\n                    } catch(e) { lastError380 = e && e.message ? e.message : String(e || ''); }\n                }\n                try {\n                    var osc = audioCtx380.createOscillator();\n                    var gain = audioCtx380.createGain();\n                    gain.gain.value = 0.00001;\n                    osc.frequency.value = 880;\n                    osc.connect(gain);\n                    gain.connect(audioCtx380.destination);\n                    osc.start(0);\n                    osc.stop(audioCtx380.currentTime + 0.04);\n                } catch(ignore) {}\n                ok = true;\n            }\n        } catch(e) { lastError380 = e && e.message ? e.message : String(e || 'AudioContext non disponibile'); }\n        try {\n            if ('speechSynthesis' in window) {\n                window.speechSynthesis.resume();\n                if (!speechPrimed380) {\n                    var u = new SpeechSynthesisUtterance(' ');\n                    u.lang = (window.currLang === 'en') ? 'en-US' : 'it-IT';\n                    u.volume = 0.01;\n                    u.rate = 1;\n                    u.pitch = 1;\n                    window.speechSynthesis.speak(u);\n                    speechPrimed380 = true;\n                }\n                ok = true;\n            }\n        } catch(e) { lastError380 = e && e.message ? e.message : String(e || 'speechSynthesis non disponibile'); }\n        try {\n            var rr = root();\n            (rr ? rr.querySelectorAll('audio,video') : document.querySelectorAll('#ti-ai-outer audio,#ti-ai-outer video')).forEach(function(el){\n                try { el.muted = false; el.volume = 1; } catch(ignore) {}\n            });\n        } catch(e) {}\n        if (ok) audioUnlocked380 = true;\n        window.tiPluginAudioUnlocked380 = audioUnlocked380;\n        return ok;\n    }\n\n    window.tiEnsurePluginAudioUnlocked = unlockAudio380;\n    window.tiPluginAudioStatus = function(){\n        return {\n            version: '30.9.664',\n            audioUnlocked: audioUnlocked380,\n            audioContextState: audioCtx380 ? audioCtx380.state : 'not-created',\n            speechSynthesis: ('speechSynthesis' in window),\n            speechPrimed: speechPrimed380,\n            muted: muted(),\n            secureContext: secureOk(),\n            mediaDevices: !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia),\n            speechRecognition: !!(window.SpeechRecognition || window.webkitSpeechRecognition),\n            rootFound: !!root(),\n            micBound: !!(byId('ti-mic') && byId('ti-mic').__tiMic380),\n            lastUnlockError: lastError380\n        };\n    };\n\n    if (typeof window.speakText === 'function' && !window.speakText.__tiAudio380) {\n        var prevSpeakText380 = window.speakText;\n        window.speakText = function(text){\n            if (!muted()) unlockAudio380();\n            return prevSpeakText380.apply(this, arguments);\n        };\n        window.speakText.__tiAudio380 = true;\n    }\n    var prevPrime380 = window.primeSpeech;\n    window.primeSpeech = function(){\n        return unlockAudio380() || (typeof prevPrime380 === 'function' ? prevPrime380.apply(this, arguments) : false);\n    };\n\n    function setMicUi(active){\n        var btn = byId('ti-mic');\n        if (!btn) return;\n        try {\n            btn.disabled = false;\n            btn.style.background = active ? '#b91c1c' : '#222';\n            btn.style.color = active ? '#fff' : '#ccc';\n            btn.textContent = active ? 'Mic...' : 'Mic';\n        } catch(e) {}\n    }\n    function startMic380(ev){\n        if (ev) { try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {} }\n        unlockAudio380();\n        var msg = byId('ti-msg');\n        var send = byId('ti-send');\n        if (!secureOk()) { alertSafe('Microfono non disponibile. Apri la pagina in HTTPS e autorizza il microfono per questo sito.'); return false; }\n        if (!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)) { alertSafe('Microfono non disponibile nel browser. Verifica i permessi del sito oppure usa Chrome, Edge o Safari aggiornato.'); return false; }\n        var SR = window.SpeechRecognition || window.webkitSpeechRecognition;\n        if (!SR) { alertSafe('Riconoscimento vocale non supportato dal browser. Usa Chrome o Edge quando possibile.'); return false; }\n        if (micRecognition380) {\n            try { micRecognition380.stop(); } catch(e) {}\n            micRecognition380 = null;\n            if (micTimer380) { clearTimeout(micTimer380); micTimer380 = null; }\n            setMicUi(false);\n            return false;\n        }\n        setMicUi(true);\n        var micT0_1285 = performance.now();\n        var micHungTimer1286 = setTimeout(function(){\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1286: getUserMedia mic non risolta dopo 15s, reset di sicurezza del pulsante'); } catch(eL286){}\n            setMicUi(false);\n        }, 15000);\n        try { if (window.log1088) window.log1088('DIAGNOSTICA 1285: mic getUserMedia chiamata (riga 2)'); } catch(e0) {}\n        navigator.mediaDevices.getUserMedia({audio:true}).then(function(stream){\n            clearTimeout(micHungTimer1286);\n            var micElapsed1285 = Math.round(performance.now() - micT0_1285);\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1285: mic getUserMedia RISOLTA dopo ' + micElapsed1285 + 'ms (' + (micElapsed1285\/1000).toFixed(1) + ' secondi)'); } catch(e1) {}\n            try { stream.getTracks().forEach(function(t){ t.stop(); }); } catch(e) {}\n            var r = new SR();\n            micRecognition380 = r;\n            r.lang = (window.currLang === 'en') ? 'en-US' : 'it-IT';\n            r.continuous = false;\n            r.interimResults = false;\n            r.maxAlternatives = 1;\n            r.onresult = function(e){\n                try {\n                    var transcript = e && e.results && e.results[0] && e.results[0][0] ? e.results[0][0].transcript : '';\n                    if (transcript && msg) {\n                        msg.value = transcript;\n                        msg.dispatchEvent(new Event('input', {bubbles:true}));\n                        msg.dispatchEvent(new Event('change', {bubbles:true}));\n                    }\n                    if (transcript && send) setTimeout(function(){ try { send.click(); } catch(ignore){} }, 80);\n                } catch(ignore) {}\n            };\n            r.onerror = function(e){\n                var code = e && e.error ? e.error : 'errore';\n                var detail = 'Microfono non disponibile o non autorizzato.';\n                if (code === 'not-allowed' || code === 'service-not-allowed') detail = 'Microfono non autorizzato. Abilita il permesso microfono nelle impostazioni del browser per questo sito.';\n                else if (code === 'no-speech') detail = 'Non ho rilevato voce. Riprova parlando dopo aver premuto Mic.';\n                else if (code === 'audio-capture') detail = 'Nessun microfono rilevato dal browser.';\n                alertSafe(detail + ' Codice: ' + code);\n            };\n            r.onend = function(){ micRecognition380 = null; if (micTimer380) { clearTimeout(micTimer380); micTimer380 = null; } setMicUi(false); };\n            try { r.start(); } catch(e) { micRecognition380 = null; setMicUi(false); alertSafe('Impossibile avviare il microfono: ' + (e && e.message ? e.message : 'errore browser')); }\n            micTimer380 = setTimeout(function(){ try { if (micRecognition380) micRecognition380.stop(); } catch(e) {} setMicUi(false); }, 10000);\n        }).catch(function(e){\n            clearTimeout(micHungTimer1286);\n            var micElapsedFail1285 = Math.round(performance.now() - micT0_1285);\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1285: mic getUserMedia FALLITA dopo ' + micElapsedFail1285 + 'ms (' + (micElapsedFail1285\/1000).toFixed(1) + ' secondi) - nome=' + (e && e.name)); } catch(eTF){}\n            setMicUi(false);\n            alertSafe('Microfono non autorizzato o non disponibile. Verifica i permessi del browser per questo sito.' + (e && e.name ? ' Dettaglio: ' + e.name : ''));\n        });\n        return false;\n    }\n    window.tiStartPluginMic = startMic380;\n\n    function bindMic380(){\n        var btn = byId('ti-mic');\n        if (!btn) return;\n        btn.__tiMic380 = true;\n        btn.disabled = false;\n        btn.onclick = startMic380;\n    }\n    function bindMute380(){\n        var btn = byId('ti-mute-btn');\n        if (!btn || btn.__tiMuteUnlock380) return;\n        btn.__tiMuteUnlock380 = true;\n        btn.addEventListener('click', function(){ setTimeout(function(){ if (!muted()) unlockAudio380(); }, 30); }, false);\n    }\n    function bindGestures380(){\n        var rr = root();\n        if (!rr || rr.__tiAudioGesture380) return;\n        rr.__tiAudioGesture380 = true;\n        ['pointerdown','touchstart','mousedown','click','keydown'].forEach(function(evt){\n            rr.addEventListener(evt, function(){ if (!muted()) unlockAudio380(); }, {capture:true, passive:true});\n        });\n    }\n    function install380(){ bindGestures380(); bindMic380(); bindMute380(); }\n\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', install380);\n    install380();\n    setTimeout(install380, 100);\n    setTimeout(install380, 400);\n    setTimeout(install380, 1200);\n    setInterval(bindMic380, 2500);\n})();\n<\/script>\n\n\n<script id=\"ti-profile-batch-ai-fix-381\">\n(function(){\n    \"use strict\";\n    if (window.__tiProfileBatchAiFix381Installed) return;\n    window.__tiProfileBatchAiFix381Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return (window.escapeHtml ? window.escapeHtml(String(v == null ? '' : v)) : String(v == null ? '' : v).replace(\/[&<>'\"]\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;',\"'\":'&#39;','\"':'&quot;'}[c];})); }\n    function resetNewProfileOnce(){\n        var ids = ['p-utente','p-user','p-pass','p-ragione_sociale','p-email','p-tel','p-ind','p-piva_vat','p-cod_fisc','p-ade','p-sesso','p-dato_1','p-dato_2','p-dato_3','p-nota','p-foto'];\n        ids.forEach(function(id){\n            var el = byId(id); if (!el) return;\n            try {\n                if (el.type === 'checkbox' || el.type === 'radio') el.checked = false;\n                else el.value = '';\n                el.disabled = false;\n                el.readOnly = false;\n                el.removeAttribute('readonly');\n                el.removeAttribute('disabled');\n                el.setAttribute('autocomplete', id === 'p-pass' ? 'new-password' : 'off');\n                if (window.forceWhiteEditStyle) window.forceWhiteEditStyle(el);\n            } catch(e) {}\n        });\n        ['p-com_mail','p-com_email','p-com_sms','p-com_tel'].forEach(function(id){ var el = byId(id); if (el) el.checked = true; });\n        var eta = byId('p-eta'); if (eta) { eta.value = ''; eta.disabled = false; eta.readOnly = false; }\n        var pass = byId('p-pass'); if (pass) { pass.required = true; pass.disabled = false; pass.readOnly = false; }\n        var user = byId('p-user'); if (user) {\n            user.required = true;\n            user.disabled = false;\n            user.readOnly = false;\n            user.removeAttribute('readonly');\n            user.removeAttribute('disabled');\n            user.style.setProperty('pointer-events','auto','important');\n            user.style.setProperty('user-select','text','important');\n            user.style.setProperty('-webkit-user-select','text','important');\n        }\n        var prev = byId('p-foto-preview'); if (prev) { prev.removeAttribute('src'); prev.style.display = 'none'; }\n    }\n\n    var legacyOpenProfile381 = window.openProfileModal;\n    window.openProfileModal = function(isNew){\n        var ditta = byId('ti-ditta');\n        if (!ditta || !ditta.value || ditta.value === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona una ditta prima di registrarti.'); return false; }\n        if (isNew === true) {\n            var title = byId('lbl-profile-title'); if (title) title.innerText = 'Crea Profilo';\n            var lbl = byId('lbl-p-pass'); if (lbl) lbl.innerText = 'Password*';\n            var cancelBtn = byId('ti-profile-cancel-btn'); if (cancelBtn) cancelBtn.style.display = 'none';\n            resetNewProfileOnce();\n            if (window.openModal) window.openModal('ti-profile-ov');\n            setTimeout(function(){\n                var u = byId('p-user');\n                if (u) { u.readOnly = false; u.disabled = false; try { u.focus({preventScroll:true}); } catch(e) { try { u.focus(); } catch(e2) {} } }\n                if (window.bindProfileUsernameDuplicatePopup) window.bindProfileUsernameDuplicatePopup();\n            }, 80);\n            return false;\n        }\n        if (!window.tiUser) {\n            if (window.openLoginModalSafe) window.openLoginModalSafe();\n            else if (window.openModal) window.openModal('ti-login-ov');\n            return false;\n        }\n        if (typeof legacyOpenProfile381 === 'function') return legacyOpenProfile381.apply(this, arguments);\n        return false;\n    };\n\n    function bindUserArea381(){\n        var area = byId('ti-user-area');\n        if (!area || area.__tiUserArea381) return;\n        area.__tiUserArea381 = true;\n        area.onclick = function(ev){\n            if (ev) { ev.preventDefault(); ev.stopPropagation(); }\n            if (window.tiUser) window.openProfileModal(false);\n            else if (window.openLoginModalSafe) window.openLoginModalSafe();\n            else if (window.openModal) window.openModal('ti-login-ov');\n            return false;\n        };\n    }\n    bindUserArea381();\n    setTimeout(bindUserArea381, 500);\n\n    document.addEventListener('focusin', function(ev){\n        var el = ev.target;\n        if (!el || el.id !== 'p-user') return;\n        if (byId('ti-profile-ov') && !window.tiUser) {\n            try { el.readOnly = false; el.disabled = false; el.removeAttribute('readonly'); el.removeAttribute('disabled'); } catch(e) {}\n        }\n    }, true);\n\n    function ajaxConfig381(fd){\n        if (window.postFormDataJsonSafe) return window.postFormDataJsonSafe(window.tiUrl, fd, {tiNoLongProcessSignal:true, cache:'no-store'});\n        if (window.fetchJsonSafe) return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true, cache:'no-store'});\n        return fetch(window.tiUrl, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'}).then(function(r){ return r.json(); });\n    }\n    function withTimeout381(promise, ms, label){\n        var tid;\n        var timeout = new Promise(function(_, reject){ tid = setTimeout(function(){ reject(new Error(label || 'Richiesta non completata nei tempi previsti.')); }, ms || 45000); });\n        return Promise.race([promise, timeout]).finally(function(){ clearTimeout(tid); });\n    }\n\n    window.runBatchAIGen = function(tableName) {\n        var dbSel = byId('ti-ditta');\n        var replyBox = byId('ti-conf-ai-reply');\n        if (!dbSel || !dbSel.value || dbSel.value === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona prima una ditta.'); return; }\n        if (!replyBox) { if (window.tiAlert) window.tiAlert('Area risposta configurazione non disponibile.'); return; }\n        var photoDetail = ((byId('ti-conf-ai-photo-detail') && byId('ti-conf-ai-photo-detail').value) ? byId('ti-conf-ai-photo-detail').value : '').trim();\n        replyBox.style.display = 'block';\n        replyBox.innerHTML = 'Preparazione elenco record. Priorita a prodotti e servizi senza associazioni file o immagini.<br>Prompt base: attivita ditta + descrizione prodotto\/servizio.';\n        var initFd = window.buildAjaxFormData ? window.buildAjaxFormData('ti_ai_config_action', {db: dbSel.value, mode: 'batch_ai_images', tables: tableName, detail_prompt: photoDetail}) : new FormData();\n        if (!initFd.has('ti_action')) initFd.append('ti_action','ti_ai_config_action');\n        if (!initFd.has('action')) initFd.append('action','ti_ai_config_action');\n        initFd.set('db', dbSel.value); initFd.set('mode','batch_ai_images'); initFd.set('tables', tableName); initFd.set('detail_prompt', photoDetail);\n        if (window.clearLongAIProcess) window.clearLongAIProcess();\n        if (window.showProgressPopup) window.showProgressPopup('Generazione foto AI', 'Sto preparando l elenco dei record. Prompt base: attivita ditta e descrizione prodotto o servizio.', {startPercent:2, targetPercent:18, stepMs:350, cancellable:false});\n        withTimeout381(ajaxConfig381(initFd), 45000, 'Preparazione elenco record non completata: verifica connessione o riprova.').then(function(d){\n            if (!d || !d.success) {\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                if (window.hideProgressPopup) window.hideProgressPopup(false, 'Errore preparazione batch');\n                replyBox.innerHTML = 'Errore: ' + esc(d && d.data && d.data.message ? d.data.message : 'Errore sconosciuto');\n                return;\n            }\n            var targets = (d.data && Array.isArray(d.data.targets)) ? d.data.targets : [];\n            if (!targets.length) {\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                if (window.hideProgressPopup) window.hideProgressPopup(true, 'Nessun elemento da elaborare', {notifyUser:false, remindSave:false});\n                replyBox.innerHTML = 'Nessun record trovato nella tabella selezionata.';\n                return;\n            }\n            var index = 0, okCount = 0, logs = [], total = targets.length;\n            window.tiBatchAIGenState = {active:true, pendingConfirm:false, generated:[], db:dbSel.value, tableName:tableName, total:total, startedAt:Date.now()};\n            var withoutAssoc = (d.data && typeof d.data.without_associations !== 'undefined') ? parseInt(d.data.without_associations,10) : targets.filter(function(x){return !x.has_associations;}).length;\n            var withAssoc = (d.data && typeof d.data.with_associations !== 'undefined') ? parseInt(d.data.with_associations,10) : Math.max(0,total-withoutAssoc);\n            var detailMode = (d.data && d.data.detail_prompt_mode) ? String(d.data.detail_prompt_mode) : '';\n            var detailInfo = (photoDetail && detailMode === 'leaflet') ? '<br>Istruzione aggiuntiva riconosciuta: <b>foglietto illustrativo \/ materiale informativo<\/b>.' : (photoDetail ? '<br>Istruzione aggiuntiva: <b>' + esc(photoDetail) + '<\/b>.' : '');\n            replyBox.innerHTML = 'Generazione immagini AI pronta.<br>Prompt base: <b>attivita ditta + descrizione prodotto\/servizio<\/b>.' + detailInfo + '<br>Priorita: <b>' + withoutAssoc + '<\/b> prodotti\/servizi senza associazioni.<br>Successivi: <b>' + withAssoc + '<\/b> prodotti\/servizi gia con associazioni.';\n            var refreshDb = function(){\n                if (window.refreshCurrentConfigDb) return window.refreshCurrentConfigDb(dbSel.value);\n                var fdDb = window.buildAjaxFormData ? window.buildAjaxFormData('ti_ai_get_db_data', {db: dbSel.value}) : new FormData();\n                if (!fdDb.has('ti_action')) fdDb.append('ti_action','ti_ai_get_db_data');\n                if (!fdDb.has('action')) fdDb.append('action','ti_ai_get_db_data');\n                fdDb.set('db', dbSel.value);\n                return ajaxConfig381(fdDb).then(function(dbRes){ if (dbRes && dbRes.success && dbRes.data) { window.currentDbData = dbRes.data; if (window.renderConfig) window.renderConfig(); } }).catch(function(){});\n            };\n            var runNext = function(){\n                if (index >= total) {\n                    if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                    if (window.updateProgressPopup) window.updateProgressPopup(100, 'Generazione foto AI', 'Completamento e verifica salvataggio associazioni.');\n                    Promise.resolve(refreshDb()).finally(function(){\n                        if (window.hideProgressPopup) window.hideProgressPopup(true, 'Generazione foto AI completata', {remindSave:false, successMessage:'Attivita AI completata. Immagini associate e verificate: ' + okCount + ' su ' + total + '.'});\n                        replyBox.innerHTML = '\u2705 Generazione immagini AI completata.<br>Immagini associate e verificate: <b>' + okCount + '<\/b> \/ ' + total + '<br><br>' + logs.slice(0,40).join('<br>');\n                    });\n                    return;\n                }\n                var item = targets[index];\n                var currentStep = index + 1;\n                var pct = Math.max(5, Math.min(98, Math.round((index \/ total) * 100)));\n                var priorityText = item.has_associations ? 'Elemento gia con associazioni' : 'Priorita senza associazioni';\n                if (window.updateProgressPopup) window.updateProgressPopup(pct, 'Generazione foto AI', priorityText + '. Elaborazione ' + currentStep + ' \/ ' + total + ': ' + (item.name || 'Elemento'), (item.name || 'Elemento'));\n                replyBox.innerHTML = 'Generazione immagini AI in corso...<br>' + priorityText + '<br>Elaborazione ' + currentStep + ' \/ ' + total + ': <b>' + esc(item.name || 'Elemento') + '<\/b>';\n                var fd = window.buildAjaxFormData ? window.buildAjaxFormData('ti_ai_config_action', {db: dbSel.value, mode:'batch_ai_image_one', table:item.table || tableName, row_index:item.row_index, detail_prompt:photoDetail}) : new FormData();\n                if (!fd.has('ti_action')) fd.append('ti_action','ti_ai_config_action');\n                if (!fd.has('action')) fd.append('action','ti_ai_config_action');\n                fd.set('db', dbSel.value); fd.set('mode','batch_ai_image_one'); fd.set('table', item.table || tableName); fd.set('row_index', item.row_index); fd.set('detail_prompt', photoDetail);\n                ajaxConfig381(fd).then(function(one){\n                    var data = one && one.data ? one.data : {};\n                    if (one && one.success && data.generated) {\n                        okCount++;\n                        if (window.tiBatchAIGenState && Array.isArray(window.tiBatchAIGenState.generated) && (data.added_value || data.filename || data.url)) {\n                            window.tiBatchAIGenState.generated.push({table:data.table || item.table || tableName, row_index:(typeof data.row_index !== 'undefined') ? data.row_index : item.row_index, field:data.image_field || 'Immagine', value:data.added_value || data.filename || data.url, name:data.name || item.name || 'Elemento'});\n                        }\n                        logs.push('\u2705 ' + esc(data.name || item.name || 'Elemento') + ': ' + (data.fallback_logo ? 'foto non disponibile, usato logo ditta' : 'immagine generata, associata e salvata'));\n                    } else if (one && one.success && data.skipped) {\n                        logs.push('\u23ed\ufe0f ' + esc(data.name || item.name || 'Elemento') + ': immagine gia presente');\n                    } else {\n                        logs.push('\u274c ' + esc(data.name || item.name || 'Elemento') + ': ' + esc(data.message || 'errore'));\n                    }\n                    index++;\n                    setTimeout(runNext, 350);\n                }).catch(function(err){\n                    logs.push('\u274c ' + esc(item.name || 'Elemento') + ': ' + esc(err && err.message ? err.message : 'errore rete'));\n                    index++;\n                    setTimeout(runNext, 700);\n                });\n            };\n            runNext();\n        }).catch(function(err){\n            if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n            if (window.hideProgressPopup) window.hideProgressPopup(false, 'Errore batch immagini');\n            replyBox.innerHTML = 'Errore preparazione generazione foto AI: ' + esc(err && err.message ? err.message : 'errore rete');\n        });\n    };\n})();\n<\/script>\n\n\n<script id=\"ti-report-controls-charts-fields-382\">\n(function(){\n    \"use strict\";\n    if (window.__tiReportControlsChartsFields382Installed) return;\n    window.__tiReportControlsChartsFields382Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){\n            return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];\n        });\n    }\n    function safeCols(){\n        var cols = Array.isArray(window.activityReportCols) ? window.activityReportCols.slice() : [];\n        if (!cols.length) cols = ['Username','Descrizione','Prezzo','Quantit\u00e0','Esito','Data','Ora','Stato','Totale'];\n        return cols;\n    }\n    function ensureStyle(){\n        if (byId('ti-report-controls-charts-fields-382-css')) return;\n        var st = document.createElement('style');\n        st.id = 'ti-report-controls-charts-fields-382-css';\n        st.textContent = ''+\n        '#ti-report-cnt .ti-report-toolbar{display:flex!important;visibility:visible!important;opacity:1!important;gap:8px!important;align-items:center!important;flex-wrap:wrap!important;overflow-x:auto!important;margin-bottom:8px!important;}'+\n        '#ti-report-cnt .ti-report-382-panel{display:block!important;visibility:visible!important;opacity:1!important;background:#0f172a!important;border:1px solid #334155!important;border-radius:10px!important;padding:8px!important;margin:8px 0!important;color:#e5e7eb!important;}'+\n        '#ti-report-cnt .ti-report-382-row{display:flex!important;gap:8px!important;align-items:center!important;flex-wrap:wrap!important;margin:5px 0!important;}'+\n        '#ti-report-cnt .ti-report-382-row label{display:inline-flex!important;gap:5px!important;align-items:center!important;font-size:12px!important;background:#111827!important;border:1px solid #334155!important;border-radius:999px!important;padding:4px 8px!important;}'+\n        '#ti-report-cnt .ti-report-382-btn{border:1px solid #475569!important;border-radius:8px!important;background:#1f2937!important;color:#fff!important;padding:6px 9px!important;font-weight:800!important;cursor:pointer!important;}'+\n        '#ti-report-cnt .ti-report-382-btn.is-active{background:#1d4ed8!important;border-color:#60a5fa!important;}'+\n        '#ti-report-cnt .ti-report-382-select{background:#111827!important;color:#fff!important;border:1px solid #475569!important;border-radius:8px!important;padding:5px 8px!important;}'+\n        '#ti-report-cnt .ti-chart-wrap{display:block!important;visibility:visible!important;opacity:1!important;min-height:360px!important;}'+\n        '#ti-report-cnt .ti-chart-wrap canvas{display:block!important;visibility:visible!important;opacity:1!important;background:#020617!important;max-width:100%!important;}';\n        document.head.appendChild(st);\n    }\n    function ensureState(){\n        if (!window.activityReportState) window.activityReportState = {};\n        if (!window.activityReportState.colFlags) window.activityReportState.colFlags = {};\n        if (!window.activityReportState.metricFlags) {\n            window.activityReportState.metricFlags = (typeof window.getDefaultActivityMetricFlags === 'function') ? window.getDefaultActivityMetricFlags() : {Prezzo:false, Quantit\u00e0:false, Totale:true};\n        }\n        if (!window.activityReportState.view) window.activityReportState.view = 'table';\n        if (!window.activityReportState.groupField) window.activityReportState.groupField = 'Username';\n    }\n    function setView(view){\n        ensureState();\n        window.activityReportState.view = view || 'table';\n        if (typeof window.saveActivityReportPrefs === 'function') window.saveActivityReportPrefs();\n        if (typeof window.renderActivityReport === 'function') window.renderActivityReport();\n    }\n    function setColumnVisible(col, checked){\n        ensureState();\n        window.activityReportState.colFlags[col] = !checked;\n        if (typeof window.saveActivityReportPrefs === 'function') window.saveActivityReportPrefs();\n        if (typeof window.renderActivityReport === 'function') window.renderActivityReport();\n    }\n    function setMetric(metric, checked){\n        ensureState();\n        window.activityReportState.metricFlags[metric] = !!checked;\n        var metrics = ['Prezzo','Quantit\u00e0','Totale'];\n        var has = metrics.some(function(m){ return !!window.activityReportState.metricFlags[m]; });\n        if (!has) window.activityReportState.metricFlags[metric] = true;\n        if (typeof window.saveActivityReportPrefs === 'function') window.saveActivityReportPrefs();\n        if (typeof window.renderActivityReport === 'function') window.renderActivityReport();\n    }\n    function setGroup(field){\n        ensureState();\n        window.activityReportState.groupField = field || 'Username';\n        if (typeof window.saveActivityReportPrefs === 'function') window.saveActivityReportPrefs();\n        if (typeof window.renderActivityReport === 'function') window.renderActivityReport();\n    }\n    window.tiReport382SetView = setView;\n    window.tiReport382SetColumnVisible = setColumnVisible;\n    window.tiReport382SetMetric = setMetric;\n    window.tiReport382SetGroup = setGroup;\n\n    function addControls(){\n        var box = byId('ti-report-cnt');\n        if (!box) return;\n        ensureStyle();\n        ensureState();\n        \/\/ 30.9.1538: i controlli del Report sono gia presenti nel renderer principale.\n        \/\/ Rimuove il pannello legacy 382 senza duplicare Vista report\/Campi\/Grafico.\n        var old = byId('ti-report-controls-382');\n        if (old) old.remove();\n    }\n    function ensureChart(){\n        var box = byId('ti-report-cnt');\n        if (!box || !window.activityReportState) return;\n        var view = window.activityReportState.view || 'table';\n        if (view !== 'pie' && view !== 'bar' && view !== 'trend') return;\n        var id = view === 'pie' ? 'ti-report-pie' : (view === 'bar' ? 'ti-report-bar' : 'ti-report-trend');\n        if (!byId(id)) {\n            box.insertAdjacentHTML('beforeend', '<div class=\"ti-chart-wrap\"><canvas id=\"'+id+'\" width=\"980\" height=\"380\"><\/canvas><\/div>');\n        }\n        var rows = (typeof window.getFilteredActivityRows === 'function') ? window.getFilteredActivityRows(false) : [];\n        setTimeout(function(){\n            try {\n                if (view === 'pie' && typeof window.drawPie3D === 'function') window.drawPie3D(id, rows);\n                if (view === 'bar' && typeof window.drawBar3D === 'function') window.drawBar3D(id, rows);\n                if (view === 'trend' && typeof window.drawTrend3D === 'function') window.drawTrend3D(id, rows);\n            } catch(e) {\n                try {\n                    var cv = byId(id), ctx = cv && cv.getContext ? cv.getContext('2d') : null;\n                    if (ctx) { ctx.fillStyle='#fff'; ctx.font='14px Arial'; ctx.fillText('Grafico non disponibile: '+(e && e.message ? e.message : 'errore'), 20, 30); }\n                } catch(ignore) {}\n            }\n        }, 80);\n    }\n    function enhance(){ addControls(); ensureChart(); }\n\n    if (typeof window.renderActivityReport === 'function' && !window.renderActivityReport.__ti382) {\n        var oldRender = window.renderActivityReport;\n        window.renderActivityReport = function(){\n            var ret = oldRender.apply(this, arguments);\n            setTimeout(enhance, 0);\n            setTimeout(enhance, 160);\n            return ret;\n        };\n        window.renderActivityReport.__ti382 = true;\n    }\n    if (typeof window.openActivityReport === 'function' && !window.openActivityReport.__ti382) {\n        var oldOpen = window.openActivityReport;\n        window.openActivityReport = function(){\n            var ret = oldOpen.apply(this, arguments);\n            setTimeout(enhance, 120);\n            setTimeout(enhance, 450);\n            return ret;\n        };\n        window.openActivityReport.__ti382 = true;\n    }\n    setTimeout(enhance, 500);\n})();\n<\/script>\n\n\n\n\n<script id=\"ti-auto-audio-unlock-383\">\n(function(){\n    \"use strict\";\n    if (window.__tiAutoAudioUnlock383Installed) return;\n    window.__tiAutoAudioUnlock383Installed = true;\n\n    var audioCtx = null;\n    var speechPrimed = false;\n    var unlocked = false;\n    var lastError = \"\";\n    var gestureCount = 0;\n\n    function byId(id){ return document.getElementById(id); }\n    function hasPluginRoot(){ return !!(byId('ti-ai-outer') || document.querySelector('.ti-ai-shop-service,[data-ti-shop-service]')); }\n    function isPluginPage(){\n        try {\n            return hasPluginRoot() || (document.body && document.body.classList && document.body.classList.contains('page-id-1165'));\n        } catch(e) { return false; }\n    }\n    function isMuted(){ return !!(window.isMuted || window.muteState === 1 || window.muteState === 2); }\n    function mediaEls(){\n        var root = byId('ti-ai-outer');\n        try { return root ? root.querySelectorAll('audio,video') : document.querySelectorAll('#ti-ai-outer audio,#ti-ai-outer video'); }\n        catch(e) { return []; }\n    }\n    function unlockAudio383(force){\n        if (!force && !isPluginPage()) return false;\n        var ok = false;\n        lastError = \"\";\n        try {\n            var AC = window.AudioContext || window.webkitAudioContext;\n            if (AC) {\n                audioCtx = audioCtx || new AC();\n                if (audioCtx.state === 'suspended' && audioCtx.resume) {\n                    try {\n                        var pr = audioCtx.resume();\n                        if (pr && typeof pr.catch === 'function') pr.catch(function(e){ lastError = e && e.message ? e.message : String(e || ''); });\n                    } catch(e) { lastError = e && e.message ? e.message : String(e || ''); }\n                }\n                try {\n                    var osc = audioCtx.createOscillator();\n                    var gain = audioCtx.createGain();\n                    gain.gain.value = 0.00001;\n                    osc.frequency.value = 880;\n                    osc.connect(gain);\n                    gain.connect(audioCtx.destination);\n                    osc.start(0);\n                    osc.stop(audioCtx.currentTime + 0.04);\n                } catch(ignore) {}\n                ok = true;\n            }\n        } catch(e) { lastError = e && e.message ? e.message : String(e || 'AudioContext non disponibile'); }\n        try {\n            if ('speechSynthesis' in window) {\n                window.speechSynthesis.resume();\n                if (!speechPrimed && !isMuted()) {\n                    var u = new SpeechSynthesisUtterance(' ');\n                    u.lang = (window.currLang === 'en') ? 'en-US' : 'it-IT';\n                    u.volume = 0;\n                    u.rate = 1;\n                    u.pitch = 1;\n                    window.speechSynthesis.speak(u);\n                    speechPrimed = true;\n                }\n                ok = true;\n            }\n        } catch(e) { lastError = e && e.message ? e.message : String(e || 'speechSynthesis non disponibile'); }\n        try { mediaEls().forEach(function(el){ try { el.muted = false; el.volume = 1; } catch(ignore) {} }); } catch(e) {}\n        if (ok) unlocked = true;\n        window.tiAudioAutoUnlocked383 = unlocked;\n        return ok;\n    }\n\n    window.tiEnsurePluginAudioUnlocked = function(){ return unlockAudio383(true); };\n    window.tiPluginAudioStatus = function(){\n        var prev = {};\n        try { if (typeof window.__tiPreviousPluginAudioStatus383 === 'function') prev = window.__tiPreviousPluginAudioStatus383() || {}; } catch(e) {}\n        return Object.assign({}, prev, {\n            version: '30.9.664',\n            audioUnlocked: unlocked,\n            audioAutoUnlock383: unlocked,\n            gestureCount383: gestureCount,\n            audioContextState383: audioCtx ? audioCtx.state : 'not-created',\n            speechSynthesis: ('speechSynthesis' in window),\n            speechPrimed383: speechPrimed,\n            muted: isMuted(),\n            pluginRootFound: hasPluginRoot(),\n            pageId1165: !!(document.body && document.body.classList && document.body.classList.contains('page-id-1165')),\n            lastUnlockError383: lastError\n        });\n    };\n\n    \/\/ Conserva eventuale diagnostica esistente, ma sovrascrive lo sblocco con il nuovo fallback.\n    try {\n        if (typeof window.tiPluginAudioStatus === 'function' && !window.__tiPreviousPluginAudioStatus383) {\n            window.__tiPreviousPluginAudioStatus383 = window.tiPluginAudioStatus;\n        }\n    } catch(e) {}\n\n    function onRealGesture(){\n        if (!isPluginPage()) return;\n        gestureCount++;\n        unlockAudio383(true);\n    }\n    function bindDocumentGestures(){\n        if (document.__tiAudioAutoGestures383) return;\n        document.__tiAudioAutoGestures383 = true;\n        ['pointerdown','touchstart','mousedown','click','keydown'].forEach(function(evt){\n            document.addEventListener(evt, onRealGesture, {capture:true, passive:true});\n        });\n    }\n    function wrapSpeakText(){\n        if (typeof window.speakText === 'function' && !window.speakText.__tiAutoAudio383) {\n            var prevSpeakText = window.speakText;\n            window.speakText = function(text){\n                if (!isMuted()) unlockAudio383(true);\n                return prevSpeakText.apply(this, arguments);\n            };\n            window.speakText.__tiAutoAudio383 = true;\n        }\n        if (typeof window.primeSpeech === 'function' && !window.primeSpeech.__tiAutoAudio383) {\n            var prevPrime = window.primeSpeech;\n            window.primeSpeech = function(){\n                return unlockAudio383(true) || prevPrime.apply(this, arguments);\n            };\n            window.primeSpeech.__tiAutoAudio383 = true;\n        }\n    }\n    function wrapNativeSpeak(){\n        try {\n            if (!('speechSynthesis' in window) || !window.speechSynthesis || !window.speechSynthesis.speak || window.speechSynthesis.speak.__tiAutoAudio383) return;\n            var nativeSpeak = window.speechSynthesis.speak.bind(window.speechSynthesis);\n            var wrappedSpeak = function(utterance){\n                if (!isMuted()) unlockAudio383(true);\n                return nativeSpeak(utterance);\n            };\n            wrappedSpeak.__tiAutoAudio383 = true;\n            window.speechSynthesis.speak = wrappedSpeak;\n        } catch(e) {}\n    }\n    function wrapMediaPlay(){\n        try {\n            if (!window.HTMLMediaElement || !HTMLMediaElement.prototype || !HTMLMediaElement.prototype.play || HTMLMediaElement.prototype.play.__tiAutoAudio383) return;\n            var nativePlay = HTMLMediaElement.prototype.play;\n            var wrappedPlay = function(){\n                unlockAudio383(true);\n                try { this.muted = false; this.volume = 1; } catch(e) {}\n                return nativePlay.apply(this, arguments);\n            };\n            wrappedPlay.__tiAutoAudio383 = true;\n            HTMLMediaElement.prototype.play = wrappedPlay;\n        } catch(e) {}\n    }\n    function bindMute(){\n        var btn = byId('ti-mute-btn');\n        if (!btn || btn.__tiAutoAudio383) return;\n        btn.__tiAutoAudio383 = true;\n        btn.addEventListener('click', function(){ setTimeout(function(){ if (!isMuted()) unlockAudio383(true); }, 40); }, false);\n    }\n    function install(){\n        if (!isPluginPage()) return;\n        bindDocumentGestures();\n        wrapSpeakText();\n        wrapNativeSpeak();\n        wrapMediaPlay();\n        bindMute();\n        \/\/ Tentativo non sonoro: se il browser lo permette, lo sblocco avviene subito; altrimenti avverra al primo gesto reale.\n        if (!isMuted()) unlockAudio383(false);\n    }\n\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', install);\n    install();\n    setTimeout(install, 250);\n    setTimeout(install, 900);\n    setTimeout(install, 1800);\n    \/\/ 30.9.1484: rimosso observer globale; i wrapper sono installati all'avvio e ai tre tentativi temporizzati.\n})();\n<\/script>\n\n\n\n<script id=\"ti-profile-registration-384\">\n(function(){\n    \"use strict\";\n    if (window.__tiProfileRegistration384Installed) return;\n    window.__tiProfileRegistration384Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function visible(el){\n        if (!el) return false;\n        try {\n            var st = window.getComputedStyle ? getComputedStyle(el) : null;\n            return !(st && (st.display === 'none' || st.visibility === 'hidden' || st.opacity === '0')) && !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n        } catch(e) { return false; }\n    }\n    function inRegistration(){ return window.__tiProfileRegistrationMode384 === true; }\n    function setUserAreaVisibility384(){\n        var area = byId('ti-user-area');\n        if (!area) return;\n        var allow = !!window.tiUser || inRegistration();\n        area.style.setProperty('display', allow ? 'flex' : 'none', 'important');\n        if (!window.tiUser && !inRegistration()) {\n            var name = byId('ti-user-name');\n            var role = byId('ti-user-role');\n            if (name) name.textContent = 'Cliente\/Utente';\n            if (role) role.textContent = '';\n        }\n    }\n    function setEditableRegistrationFields384(){\n        ['p-utente','p-user','p-pass','p-email','p-ragione_sociale','p-ind','p-piva_vat','p-cod_fisc','p-ade','p-tel','p-sesso','p-eta','p-dato_1','p-dato_2','p-dato_3','p-nota'].forEach(function(id){\n            var el = byId(id); if (!el) return;\n            try {\n                el.disabled = false;\n                el.readOnly = false;\n                el.removeAttribute('disabled');\n                el.removeAttribute('readonly');\n                el.style.setProperty('pointer-events','auto','important');\n                el.style.setProperty('user-select','text','important');\n                el.style.setProperty('-webkit-user-select','text','important');\n                el.setAttribute('autocomplete', id === 'p-pass' ? 'new-password' : 'off');\n                if (id === 'p-user') {\n                    el.required = true;\n                    el.setAttribute('inputmode','text');\n                    el.setAttribute('autocapitalize','none');\n                    el.setAttribute('autocorrect','off');\n                    el.setAttribute('spellcheck','false');\n                }\n            } catch(e) {}\n        });\n        var pass = byId('p-pass'); if (pass) pass.required = true;\n        var title = byId('lbl-profile-title'); if (title) title.innerText = 'Crea Profilo Cliente\/Utente';\n        var lbl = byId('lbl-p-pass'); if (lbl) lbl.innerText = 'Password*';\n        var cancelBtn = byId('ti-profile-cancel-btn'); if (cancelBtn) cancelBtn.style.display = 'none';\n    }\n    function clearRegistrationFields384(){\n        ['p-utente','p-user','p-pass','p-email','p-ragione_sociale','p-ind','p-piva_vat','p-cod_fisc','p-ade','p-tel','p-sesso','p-eta','p-dato_1','p-dato_2','p-dato_3','p-nota','p-foto'].forEach(function(id){\n            var el = byId(id); if (!el) return;\n            try { if (el.type === 'checkbox' || el.type === 'radio') el.checked = false; else el.value = ''; } catch(e) {}\n        });\n        ['p-com_mail','p-com_email','p-com_sms','p-com_tel'].forEach(function(id){ var el = byId(id); if (el) el.checked = true; });\n        var prev = byId('p-foto-preview'); if (prev) { prev.removeAttribute('src'); prev.style.display = 'none'; }\n        setEditableRegistrationFields384();\n    }\n\n    var prevOpen384 = window.openProfileModal;\n    window.openProfileModal = function(isNew){\n        if (isNew === true) {\n            var ditta = byId('ti-ditta');\n            if (!ditta || !ditta.value || ditta.value === 'NEW_DB' || ditta.value === '') { if (window.tiAlert) window.tiAlert('Seleziona una ditta prima di registrarti.'); return false; }\n            window.__tiProfileRegistrationMode384 = true;\n            clearRegistrationFields384();\n            if (typeof prevOpen384 === 'function') prevOpen384.call(this, true);\n            else if (window.openModal) window.openModal('ti-profile-ov');\n            setTimeout(function(){ window.__tiProfileRegistrationMode384 = true; setEditableRegistrationFields384(); setUserAreaVisibility384(); var u = byId('p-user'); if (u) { try { u.focus({preventScroll:true}); } catch(e) { try { u.focus(); } catch(e2) {} } } }, 60);\n            setTimeout(function(){ setEditableRegistrationFields384(); setUserAreaVisibility384(); }, 250);\n            return false;\n        }\n        if (!window.tiUser) {\n            window.__tiProfileRegistrationMode384 = false;\n            setUserAreaVisibility384();\n            if (window.openLoginModalSafe) window.openLoginModalSafe();\n            else if (window.openModal) window.openModal('ti-login-ov');\n            return false;\n        }\n        window.__tiProfileRegistrationMode384 = false;\n        return (typeof prevOpen384 === 'function') ? prevOpen384.apply(this, arguments) : false;\n    };\n\n    var prevClose384 = window.closeModal;\n    if (typeof prevClose384 === 'function' && !prevClose384.__tiProfile384) {\n        window.closeModal = function(id){\n            var ret = prevClose384.apply(this, arguments);\n            if (id === 'ti-profile-ov') {\n                window.__tiProfileRegistrationMode384 = false;\n                setTimeout(setUserAreaVisibility384, 40);\n            }\n            return ret;\n        };\n        window.closeModal.__tiProfile384 = true;\n    }\n\n    function bindRegistrationButton384(){\n        try {\n            document.querySelectorAll('button').forEach(function(btn){\n                var txt = String(btn.textContent || '').trim().toLowerCase();\n                if (txt.indexOf('registrati') === -1) return;\n                if (btn.__tiReg384) return;\n                btn.__tiReg384 = true;\n                btn.addEventListener('click', function(ev){\n                    window.__tiProfileRegistrationMode384 = true;\n                    setTimeout(function(){ setEditableRegistrationFields384(); setUserAreaVisibility384(); }, 80);\n                }, true);\n            });\n        } catch(e) {}\n    }\n    function bindUserArea384(){\n        var area = byId('ti-user-area');\n        if (!area) return;\n        area.onclick = function(ev){\n            if (ev) { ev.preventDefault(); ev.stopPropagation(); }\n            if (window.tiUser) return window.openProfileModal(false);\n            if (inRegistration() && visible(byId('ti-profile-ov'))) return window.openProfileModal(true);\n            return false;\n        };\n    }\n    document.addEventListener('focusin', function(ev){\n        var el = ev && ev.target;\n        if (!el) return;\n        if (inRegistration() && \/^p-\/.test(el.id || '')) setEditableRegistrationFields384();\n    }, true);\n    document.addEventListener('input', function(ev){\n        var el = ev && ev.target;\n        if (el && el.id === 'p-user' && inRegistration()) setEditableRegistrationFields384();\n    }, true);\n\n    function tick384(){ bindRegistrationButton384(); bindUserArea384(); setUserAreaVisibility384(); }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', tick384);\n    tick384();\n    setTimeout(tick384, 200);\n    setTimeout(tick384, 800);\n    setTimeout(tick384, 1600);\n})();\n<\/script>\n\n\n\n<script id=\"ti-registration-start-385\">\n(function(){\n    \"use strict\";\n    if (window.__tiRegistrationStart385Installed) return;\n    window.__tiRegistrationStart385Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function setImp(el, prop, val){ try { if (el) el.style.setProperty(prop, val, 'important'); } catch(e) {} }\n    function selectedDb(){ var d = byId('ti-ditta') || byId('l-db') || byId('l-db-hidden'); return d ? String(d.value || '').trim() : ''; }\n    function hideLogin(){\n        var ov = byId('ti-login-ov');\n        if (!ov) return;\n        setImp(ov, 'display', 'none');\n        setImp(ov, 'visibility', 'hidden');\n        setImp(ov, 'opacity', '0');\n        setImp(ov, 'pointer-events', 'none');\n        try { ov.setAttribute('aria-hidden','true'); } catch(e) {}\n    }\n    function showProfile(){\n        var ov = byId('ti-profile-ov');\n        if (!ov) return;\n        setImp(ov, 'display', 'flex');\n        setImp(ov, 'visibility', 'visible');\n        setImp(ov, 'opacity', '1');\n        setImp(ov, 'pointer-events', 'auto');\n        setImp(ov, 'z-index', '2147483647');\n        try { ov.removeAttribute('aria-hidden'); ov.classList.add('ti-modal-active','ti-ov-active','is-active','show'); } catch(e) {}\n        try { if (window.preparePluginModal) window.preparePluginModal(ov); } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n    }\n    function enableProfileInputs(){\n        var ids = ['p-utente','p-user','p-pass','p-email','p-ragione_sociale','p-ind','p-piva_vat','p-cod_fisc','p-ade','p-tel','p-sesso','p-eta','p-dato_1','p-dato_2','p-dato_3','p-nota','p-foto'];\n        ids.forEach(function(id){\n            var el = byId(id); if (!el) return;\n            try {\n                el.disabled = false;\n                el.readOnly = false;\n                el.removeAttribute('disabled');\n                el.removeAttribute('readonly');\n                el.style.setProperty('pointer-events','auto','important');\n                el.style.setProperty('user-select','text','important');\n                el.style.setProperty('-webkit-user-select','text','important');\n                el.setAttribute('autocomplete', id === 'p-pass' ? 'new-password' : 'off');\n                el.setAttribute('autocorrect','off');\n                el.setAttribute('spellcheck','false');\n                if (id === 'p-user') {\n                    el.required = true;\n                    el.setAttribute('inputmode','text');\n                    el.setAttribute('autocapitalize','none');\n                }\n                if (window.forceWhiteEditStyle) window.forceWhiteEditStyle(el);\n            } catch(e) {}\n        });\n        var pass = byId('p-pass'); if (pass) pass.required = true;\n        var user = byId('p-user'); if (user) user.required = true;\n    }\n    function clearProfileFields(){\n        var ids = ['p-utente','p-user','p-pass','p-email','p-ragione_sociale','p-ind','p-piva_vat','p-cod_fisc','p-ade','p-tel','p-sesso','p-eta','p-dato_1','p-dato_2','p-dato_3','p-nota','p-foto'];\n        ids.forEach(function(id){\n            var el = byId(id); if (!el) return;\n            try { if (el.type === 'checkbox' || el.type === 'radio') el.checked = false; else el.value = ''; } catch(e) {}\n        });\n        ['p-com_mail','p-com_email','p-com_sms','p-com_tel'].forEach(function(id){ var el = byId(id); if (el) el.checked = true; });\n        var prev = byId('p-foto-preview'); if (prev) { try { prev.removeAttribute('src'); prev.style.display = 'none'; } catch(e) {} }\n    }\n    function setProfileRegistrationLayout(){\n        window.__tiProfileRegistrationMode384 = true;\n        window.__tiProfileRegistrationMode385 = true;\n        var title = byId('lbl-profile-title'); if (title) title.innerText = 'Crea Profilo Cliente\/Utente';\n        var passLbl = byId('lbl-p-pass'); if (passLbl) passLbl.innerText = 'Password*';\n        var cancelBtn = byId('ti-profile-cancel-btn'); if (cancelBtn) cancelBtn.style.display = 'none';\n        var area = byId('ti-user-area'); if (area) area.style.setProperty('display','flex','important');\n        var name = byId('ti-user-name'); if (name) name.textContent = 'Cliente\/Utente';\n        var role = byId('ti-user-role'); if (role) role.textContent = 'Registrazione';\n        enableProfileInputs();\n    }\n\n    window.tiStartUserRegistration385 = function(ev){\n        if (ev) {\n            try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        }\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona una ditta prima di registrarti.'); return false; }\n        window.__tiProfileRegistrationMode384 = true;\n        window.__tiProfileRegistrationMode385 = true;\n        hideLogin();\n        clearProfileFields();\n        setProfileRegistrationLayout();\n        try { if (window.openModal) window.openModal('ti-profile-ov'); } catch(e) {}\n        showProfile();\n        setTimeout(function(){ setProfileRegistrationLayout(); showProfile(); var u = byId('p-user'); if (u) { try { u.focus({preventScroll:true}); } catch(e) { try { u.focus(); } catch(e2) {} } } }, 40);\n        setTimeout(function(){ setProfileRegistrationLayout(); showProfile(); }, 180);\n        setTimeout(function(){ setProfileRegistrationLayout(); showProfile(); }, 500);\n        try { if (window.bindProfileUsernameDuplicatePopup) window.bindProfileUsernameDuplicatePopup(); } catch(e) {}\n        return false;\n    };\n\n    function isRegisterButton(el){\n        if (!el) return false;\n        var btn = el.closest ? el.closest('button,a,input[type=\"button\"],input[type=\"submit\"]') : null;\n        if (!btn) return false;\n        if (btn.getAttribute && btn.getAttribute('data-ti-order-register-1765') === '1') return false;\n        var txt = String(btn.textContent || btn.value || '').toLowerCase();\n        return txt.indexOf('registrati') !== -1 || txt.indexOf('register') !== -1 || btn.id === 'ti-register-user-btn';\n    }\n    document.addEventListener('click', function(ev){\n        if (!isRegisterButton(ev.target)) return;\n        window.tiStartUserRegistration385(ev);\n    }, true);\n\n    function bindButtons(){\n        try {\n            document.querySelectorAll('button,a,input[type=\"button\"],input[type=\"submit\"]').forEach(function(btn){\n                var txt = String(btn.textContent || btn.value || '').toLowerCase();\n                if (txt.indexOf('registrati') === -1 && txt.indexOf('register') === -1 && btn.id !== 'ti-register-user-btn') return;\n                btn.setAttribute('data-ti-registration-button','1');\n                btn.onclick = function(ev){ return window.tiStartUserRegistration385(ev || window.event); };\n            });\n        } catch(e) {}\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bindButtons, {once:true});\n    else bindButtons();\n    \/\/ 30.9.1483: i nuovi pulsanti sono intercettati dal listener click delegato; nessuna scansione globale ripetuta.\n})();\n<\/script>\n\n\n<script id=\"ti-batch-ai-timeout-386\">\n(function(){\n    \"use strict\";\n    if (window.__tiBatchAiTimeout386Installed) return;\n    window.__tiBatchAiTimeout386Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){\n        return (window.escapeHtml ? window.escapeHtml(String(v == null ? '' : v)) : String(v == null ? '' : v).replace(\/[&<>'\"]\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;',\"'\":'&#39;','\"':'&quot;'}[c];}));\n    }\n    function buildFd(action, data){\n        var fd = window.buildAjaxFormData ? window.buildAjaxFormData(action, data || {}) : new FormData();\n        if (!fd.has('ti_action')) fd.append('ti_action', action);\n        if (!fd.has('action')) fd.append('action', action);\n        Object.keys(data || {}).forEach(function(k){ fd.set(k, data[k]); });\n        return fd;\n    }\n    function ajaxWithTimeout(fd, ms, label){\n        ms = ms || 90000;\n        var controller = null;\n        var timer = null;\n        var opts = {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'};\n        try {\n            if (window.AbortController) {\n                controller = new AbortController();\n                opts.signal = controller.signal;\n            }\n        } catch(e) {}\n        return new Promise(function(resolve, reject){\n            var settled = false;\n            var startedAt1382 = Date.now();\n            function doTimeout1382(){\n                if (settled) return;\n                settled = true;\n                try { if (controller) controller.abort(); } catch(e) {}\n                reject(new Error(label || 'Richiesta non completata nei tempi previsti.'));\n            }\n            timer = setTimeout(doTimeout1382, ms);\n            \/\/ 30.9.1382: come gia' confermato e corretto altrove in questa sessione, un singolo setTimeout puo'\n            \/\/ essere ritardato indefinitamente se la scheda va in background - dato che questo timeout viene\n            \/\/ usato fino a decine di volte in sequenza (una per ogni prodotto\/servizio), l'effetto cumulativo\n            \/\/ di ritardi anche modesti puo' facilmente sommarsi a ore. Il controllo su tempo REALMENTE\n            \/\/ trascorso, attivato anche al ritorno sulla scheda, recupera immediatamente.\n            function onVis1382(){\n                if (settled) { document.removeEventListener('visibilitychange', onVis1382); return; }\n                if (!document.hidden && (Date.now() - startedAt1382) >= ms) doTimeout1382();\n            }\n            try { document.addEventListener('visibilitychange', onVis1382); } catch(e) {}\n            fetch(window.tiUrl, opts).then(function(r){\n                if (!r.ok) throw new Error('HTTP ' + r.status);\n                return r.json();\n            }).then(function(d){ if (!settled) { settled = true; resolve(d); } }).catch(function(err){\n                if (settled) return;\n                settled = true;\n                if (err && err.name === 'AbortError') reject(new Error(label || 'Richiesta interrotta per timeout.'));\n                else reject(err);\n            }).finally(function(){ clearTimeout(timer); try { document.removeEventListener('visibilitychange', onVis1382); } catch(e){} });\n        });\n    }\n    function shouldCancel(){\n        try { return !!(window.isLongAIProcessCancelled && window.isLongAIProcessCancelled()); } catch(e) { return false; }\n    }\n    function clearCancel(){ try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {} }\n\n    window.runBatchAIGen = function(tableName) {\n        var dbSel = byId('ti-ditta');\n        var replyBox = byId('ti-conf-ai-reply');\n        if (!dbSel || !dbSel.value || dbSel.value === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona prima una ditta.'); return; }\n        if (!replyBox) { if (window.tiAlert) window.tiAlert('Area risposta configurazione non disponibile.'); return; }\n        var photoDetail = ((byId('ti-conf-ai-photo-detail') && byId('ti-conf-ai-photo-detail').value) ? byId('ti-conf-ai-photo-detail').value : '').trim();\n        replyBox.style.display = 'block';\n        replyBox.innerHTML = 'Preparazione elenco record. Priorita a prodotti e servizi senza associazioni file o immagini.<br>Prompt base: attivita ditta + descrizione prodotto\/servizio.';\n        clearCancel();\n        if (window.showProgressPopup) window.showProgressPopup('Generazione foto AI', 'Sto preparando l elenco dei record. Prompt base: attivita ditta e descrizione prodotto o servizio.', {startPercent:2, targetPercent:18, stepMs:350, cancellable:true});\n\n        var initFd = buildFd('ti_ai_config_action', {db:dbSel.value, mode:'batch_ai_images', tables:tableName, detail_prompt:photoDetail});\n        ajaxWithTimeout(initFd, 45000, 'Preparazione elenco record non completata entro 45 secondi. Riprova o riduci il numero di record.').then(function(d){\n            if (!d || !d.success) {\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                if (window.hideProgressPopup) window.hideProgressPopup(false, 'Errore preparazione batch');\n                replyBox.innerHTML = 'Errore preparazione generazione foto AI: ' + esc(d && d.data && d.data.message ? d.data.message : 'Errore sconosciuto');\n                return;\n            }\n            var targets = (d.data && Array.isArray(d.data.targets)) ? d.data.targets : [];\n            if (!targets.length) {\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                if (window.hideProgressPopup) window.hideProgressPopup(true, 'Nessun elemento da elaborare', {notifyUser:false, remindSave:false});\n                replyBox.innerHTML = 'Nessun record trovato nella tabella selezionata.';\n                return;\n            }\n            var index = 0;\n            var okCount = 0;\n            var skipCount = 0;\n            var failCount = 0;\n            var logs = [];\n            var total = targets.length;\n            var itemTimeoutMs = 90000;\n            window.tiBatchAIGenState = {active:true, pendingConfirm:false, generated:[], db:dbSel.value, tableName:tableName, total:total, startedAt:Date.now(), timeout_ms:itemTimeoutMs};\n            var withoutAssoc = (d.data && typeof d.data.without_associations !== 'undefined') ? parseInt(d.data.without_associations,10) : targets.filter(function(x){return !x.has_associations;}).length;\n            var withAssoc = (d.data && typeof d.data.with_associations !== 'undefined') ? parseInt(d.data.with_associations,10) : Math.max(0,total-withoutAssoc);\n            var detailMode = (d.data && d.data.detail_prompt_mode) ? String(d.data.detail_prompt_mode) : '';\n            var detailInfo = (photoDetail && detailMode === 'leaflet') ? '<br>Istruzione aggiuntiva riconosciuta: <b>foglietto illustrativo \/ materiale informativo<\/b>.' : (photoDetail ? '<br>Istruzione aggiuntiva: <b>' + esc(photoDetail) + '<\/b>.' : '');\n            replyBox.innerHTML = 'Generazione immagini AI pronta.<br>Prompt base: <b>attivita ditta + descrizione prodotto\/servizio<\/b>.' + detailInfo + '<br>Priorita: <b>' + withoutAssoc + '<\/b> prodotti\/servizi senza associazioni.<br>Successivi: <b>' + withAssoc + '<\/b> prodotti\/servizi gia con associazioni.<br><span style=\"color:#facc15;\">Ogni record ha timeout controllato: se un elemento si blocca viene saltato e il batch prosegue.<\/span>';\n\n            function refreshDb(){\n                if (window.refreshCurrentConfigDb) return Promise.resolve(window.refreshCurrentConfigDb(dbSel.value)).catch(function(){});\n                var fdDb = buildFd('ti_ai_get_db_data', {db:dbSel.value});\n                return ajaxWithTimeout(fdDb, 30000, 'Rilettura database non completata').then(function(dbRes){\n                    if (dbRes && dbRes.success && dbRes.data) { window.currentDbData = dbRes.data; if (window.renderConfig) window.renderConfig(); }\n                }).catch(function(){});\n            }\n            function finish(){\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                if (window.updateProgressPopup) window.updateProgressPopup(100, 'Generazione foto AI', 'Completamento e verifica salvataggio associazioni.');\n                Promise.resolve(refreshDb()).finally(function(){\n                    if (window.hideProgressPopup) window.hideProgressPopup(true, 'Generazione foto AI completata', {remindSave:false, successMessage:'Attivita AI completata. Immagini associate e verificate: ' + okCount + ' su ' + total + '. Errori\/saltati: ' + failCount + '.'});\n                    replyBox.innerHTML = '\u2705 Generazione immagini AI completata.<br>Immagini associate e verificate: <b>' + okCount + '<\/b> \/ ' + total + '<br>Elementi gia presenti\/saltati: <b>' + skipCount + '<\/b><br>Errori o timeout: <b>' + failCount + '<\/b><br><br>' + logs.slice(0,80).join('<br>');\n                });\n            }\n            function runNext(){\n                if (shouldCancel()) {\n                    if (window.tiBatchAIGenState && window.tiBatchAIGenState.pendingConfirm) return;\n                    replyBox.innerHTML = 'Generazione foto AI interrotta dall utente. Immagini gia generate mantenute: ' + okCount + '. Errori\/saltati: ' + failCount + '.';\n                    if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                    clearCancel();\n                    return;\n                }\n                if (index >= total) { finish(); return; }\n                var item = targets[index] || {};\n                var currentStep = index + 1;\n                var pct = Math.max(5, Math.min(98, Math.round(((index + 0.1) \/ total) * 100)));\n                var itemName = item.name || 'Elemento';\n                var priorityText = item.has_associations ? 'Elemento gia con associazioni' : 'Priorita senza associazioni';\n                if (window.updateProgressPopup) window.updateProgressPopup(pct, 'Generazione foto AI', priorityText + '. Elaborazione ' + currentStep + ' \/ ' + total + ': ' + itemName, itemName);\n                replyBox.innerHTML = 'Generazione immagini AI in corso...<br>' + priorityText + '<br>Elaborazione ' + currentStep + ' \/ ' + total + ': <b>' + esc(itemName) + '<\/b><br><span style=\"color:#94a3b8;\">Timeout massimo per questo record: ' + Math.round(itemTimeoutMs\/1000) + ' secondi.<\/span>';\n                var fd = buildFd('ti_ai_config_action', {db:dbSel.value, mode:'batch_ai_image_one', table:item.table || tableName, row_index:item.row_index, detail_prompt:photoDetail});\n                ajaxWithTimeout(fd, itemTimeoutMs, 'Timeout su record: ' + itemName).then(function(one){\n                    var data = one && one.data ? one.data : {};\n                    if (one && one.success && data.generated) {\n                        okCount++;\n                        if (window.tiBatchAIGenState && Array.isArray(window.tiBatchAIGenState.generated) && (data.added_value || data.filename || data.url)) {\n                            window.tiBatchAIGenState.generated.push({table:data.table || item.table || tableName, row_index:(typeof data.row_index !== 'undefined') ? data.row_index : item.row_index, field:data.image_field || 'Immagine', value:data.added_value || data.filename || data.url, name:data.name || itemName});\n                        }\n                        logs.push('\u2705 ' + esc(data.name || itemName) + ': ' + (data.fallback_logo ? 'foto non disponibile, usato logo ditta' : 'immagine generata e associazione salvata'));\n                    } else if (one && one.success && data.skipped) {\n                        skipCount++;\n                        logs.push('\u23ed\ufe0f ' + esc(data.name || itemName) + ': immagine gia presente');\n                    } else {\n                        failCount++;\n                        logs.push('\u274c ' + esc(data.name || itemName) + ': ' + esc(data.message || 'errore generazione'));\n                    }\n                }).catch(function(err){\n                    failCount++;\n                    logs.push('\u23f1\ufe0f ' + esc(itemName) + ': ' + esc(err && err.message ? err.message : 'timeout o errore rete') + '. Record saltato, proseguo con il successivo.');\n                }).finally(function(){\n                    index++;\n                    setTimeout(runNext, 250);\n                });\n            }\n            runNext();\n        }).catch(function(err){\n            if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n            if (window.hideProgressPopup) window.hideProgressPopup(false, 'Errore batch immagini');\n            replyBox.innerHTML = 'Errore preparazione generazione foto AI: ' + esc(err && err.message ? err.message : 'errore rete');\n        });\n    };\n})();\n<\/script>\n\n\n<script id=\"ti-help-ai-answer-copy-440\">\n(function(){\n    \"use strict\";\n    if (window.__tiHelpAiAnswerCopy440Installed) return;\n    window.__tiHelpAiAnswerCopy440Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function visibleText(node){\n        if (!node) return '';\n        try {\n            var clone = node.cloneNode(true);\n            var removeSel = 'button,.ti-btn,script,style,noscript,input,textarea,select';\n            clone.querySelectorAll(removeSel).forEach(function(el){ el.remove(); });\n            var txt = String(clone.innerText || clone.textContent || '');\n            return clean(txt);\n        } catch(e) { return clean(String(node.innerText || node.textContent || '')); }\n    }\n    function clean(txt){\n        txt = String(txt || '')\n            .replace(\/\\r\/g, '')\n            .replace(\/^\\s*AI_MANUAL_HELP\\s*:\\s*\/gim, '')\n            .replace(\/^\\s*(Istruzione\\s+(?:inviata|ricevuta)[^\\n]*|Help\\s+instruction[^\\n]*)\\s*$\/gim, '')\n            .replace(\/(?:<br\\s*\\\/?>)+\/gi, '\\n')\n            .replace(\/[ \\t]+\\n\/g, '\\n')\n            .replace(\/\\n{3,}\/g, '\\n\\n')\n            .trim();\n        return txt;\n    }\n    function sanitizeHelpBox(){\n        var box = byId('col-help-content');\n        if (!box) return;\n        try {\n            var html = String(box.innerHTML || '');\n            html = html\n                .replace(\/(?:^|<br\\s*\\\/?\\s*>)\\s*AI_MANUAL_HELP\\s*:\\s*\/gi, '')\n                .replace(\/(?:^|<br\\s*\\\/?\\s*>)\\s*(Istruzione\\s+(?:inviata|ricevuta)[^<\\n\\r]*|Help\\s+instruction[^<\\n\\r]*)\\s*(?=<br\\s*\\\/?\\s*>|$)\/gi, '')\n                .replace(\/(<br\\s*\\\/?>(\\s*)){3,}\/gi, '<br><br>');\n            if (html !== String(box.innerHTML || '')) box.innerHTML = html;\n        } catch(e) {}\n    }\n    window.tiSanitizeColumnHelpText357 = function(text){ return clean(text).replace(\/[#*]+\/g, '').trim(); };\n    window.copyColumnHelpText357 = function(){\n        sanitizeHelpBox();\n        var modal = document.querySelector('#ti-col-help-ov .ti-modal');\n        var title = byId('col-help-title');\n        var company = byId('col-help-company');\n        var box = byId('col-help-content');\n        var btn = byId('ti-col-help-copy');\n        var parts = [];\n        var t = visibleText(title); if (t) parts.push(t);\n        var c = visibleText(company); if (c) parts.push(c);\n        var b = visibleText(box); if (b) parts.push(b);\n        var text = clean(parts.join('\\n\\n'));\n        if (!text && modal) text = visibleText(modal);\n        function done(ok){\n            if (!btn) return;\n            var old = btn.getAttribute('data-old-label') || btn.innerText || 'Copia testo';\n            if (!btn.getAttribute('data-old-label')) btn.setAttribute('data-old-label', old);\n            btn.innerText = ok ? 'Testo copiato' : 'Copia manuale';\n            setTimeout(function(){ btn.innerText = old; }, 1400);\n        }\n        function copyTextarea(value){\n            try {\n                var ta = document.createElement('textarea');\n                ta.value = value;\n                ta.setAttribute('readonly','readonly');\n                ta.style.position = 'fixed';\n                ta.style.top = '0';\n                ta.style.left = '0';\n                ta.style.width = '1px';\n                ta.style.height = '1px';\n                ta.style.opacity = '0';\n                ta.style.zIndex = '-1';\n                document.body.appendChild(ta);\n                ta.focus();\n                ta.select();\n                ta.setSelectionRange(0, ta.value.length);\n                var ok = false;\n                try { ok = document.execCommand('copy'); } catch(e) { ok = false; }\n                document.body.removeChild(ta);\n                return !!ok;\n            } catch(e) { return false; }\n        }\n        if (!text) { done(false); return false; }\n        if (copyTextarea(text)) { done(true); return true; }\n        if (navigator.clipboard && navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){\n                try { window.prompt('Copia il testo:', text); } catch(e) {}\n                done(false);\n            });\n            return true;\n        }\n        try { window.prompt('Copia il testo:', text); } catch(e) {}\n        done(false);\n        return false;\n    };\n    if (typeof MutationObserver !== 'undefined') {\n        var box = byId('col-help-content');\n        if (box) {\n            try { new MutationObserver(function(){ setTimeout(sanitizeHelpBox, 20); }).observe(box, {childList:true, subtree:true}); } catch(e) {}\n        }\n    }\n    setTimeout(sanitizeHelpBox, 250);\n})();\n<\/script>\n\n\n\n\n\n<script id=\"ti-ai-media-safe-fix-455\">\n(function(){\n    \"use strict\";\n    if (window.__tiAIMediaSafeFix455Installed) return;\n    window.__tiAIMediaSafeFix455Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function setImp(el, prop, val){ try { if (el) el.style.setProperty(prop, String(val), 'important'); } catch(e) {} }\n    function isVisible(el){\n        if (!el) return false;\n        try {\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')) return false;\n            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n        } catch(e) { return false; }\n    }\n    function validCtx(ctx){ return !!(ctx && typeof ctx === 'object' && ctx.tbl && ctx.key && ctx.idx !== undefined && ctx.idx !== null && ctx.idx !== ''); }\n    function cloneCtx(ctx){ return validCtx(ctx) ? {tbl:String(ctx.tbl), idx:ctx.idx, key:String(ctx.key)} : null; }\n    function saveCtx(ctx){\n        var c = cloneCtx(ctx);\n        if (!c) return null;\n        window.targetUploadContext = c;\n        window.__tiLastFileManagerCtx455 = c;\n        try { sessionStorage.setItem('tiLastFileManagerCtx455', JSON.stringify(c)); } catch(e) {}\n        return c;\n    }\n    function readCtx(){\n        var c = cloneCtx(window.targetUploadContext);\n        if (c) return saveCtx(c);\n        var fm = byId('ti-file-manager-ov');\n        if (fm) {\n            c = cloneCtx({tbl:fm.dataset ? fm.dataset.tbl : '', idx:fm.dataset ? fm.dataset.idx : '', key:fm.dataset ? fm.dataset.key : ''});\n            if (c) return saveCtx(c);\n            c = cloneCtx({tbl:fm.getAttribute('data-ti-context-table') || '', idx:fm.getAttribute('data-ti-context-row') || '', key:fm.getAttribute('data-ti-context-field') || ''});\n            if (c) return saveCtx(c);\n        }\n        c = cloneCtx(window.__tiLastFileManagerCtx455 || window.__tiLastFileManagerCtx360 || window.__tiLastFileAiCtx358 || window.__tiLastUploadContext356);\n        if (c) return saveCtx(c);\n        try {\n            var keys = ['tiLastFileManagerCtx455','tiLastFileManagerCtx360','tiLastFileAiCtx358','tiLastUploadContext356'];\n            for (var i=0;i<keys.length;i++) {\n                var raw = sessionStorage.getItem(keys[i]);\n                if (!raw) continue;\n                c = cloneCtx(JSON.parse(raw));\n                if (c) return saveCtx(c);\n            }\n        } catch(e) {}\n        return null;\n    }\n    function rowFor(ctx){\n        try {\n            if (ctx && window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[ctx.tbl]) return window.currentDbData.Tabelle[ctx.tbl][ctx.idx] || null;\n        } catch(e) {}\n        return null;\n    }\n    function recordLabel(ctx){\n        try { if (window.getRecordLabelForUpload) return window.getRecordLabelForUpload(ctx.tbl, rowFor(ctx), ctx.tbl); } catch(e) {}\n        return ctx && ctx.tbl ? ctx.tbl : '';\n    }\n    function resetAIGen(row){\n        try {\n            if (typeof window.populateAIGenPrompt === 'function') window.populateAIGenPrompt(row);\n            else {\n                var prompt = byId('ai-gen-prompt');\n                if (prompt) {\n                    var label = row ? (row.Descrizione || row.Prodotto || row.Servizio || row.Nome || row.Titolo || '') : '';\n                    prompt.value = (typeof window.buildAIGenPrompt === 'function') ? window.buildAIGenPrompt(label) : String(label || '');\n                }\n            }\n        } catch(e) {}\n        try { var detail = byId('ai-gen-detail'); if (detail) detail.value = ''; } catch(e) {}\n        try { var res = byId('ai-gen-res'); if (res) res.style.display = 'none'; } catch(e) {}\n        try { var img = byId('ai-gen-img'); if (img) img.src = ''; } catch(e) {}\n        try { var btn = byId('ai-gen-btn'); if (btn) { btn.disabled = false; btn.innerText = 'Genera Immagine'; btn.style.display = 'block'; } } catch(e) {}\n        window.currentGenFilename = null;\n    }\n    function activateAI(){\n        var ai = byId('ti-ai-gen-ov');\n        if (!ai) return false;\n        setImp(ai, 'display', 'flex');\n        setImp(ai, 'visibility', 'visible');\n        setImp(ai, 'opacity', '1');\n        setImp(ai, 'pointer-events', 'auto');\n        setImp(ai, 'z-index', '2147483647');\n        try { ai.removeAttribute('aria-hidden'); ai.setAttribute('data-ti-force-front','1'); ai.setAttribute('data-ti-config-child-modal','1'); } catch(e) {}\n        try { if (window.preparePluginModal) window.preparePluginModal(ai); } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n        return true;\n    }\n    function demoteFileManager(){\n        var fm = byId('ti-file-manager-ov');\n        if (!fm) return;\n        try { fm.setAttribute('data-ti-demoted-by-aigen455','1'); } catch(e) {}\n        setImp(fm, 'display', 'flex');\n        setImp(fm, 'visibility', 'visible');\n        setImp(fm, 'opacity', '1');\n        setImp(fm, 'pointer-events', 'none');\n        setImp(fm, 'z-index', '2147483400');\n        try { fm.removeAttribute('aria-hidden'); } catch(e) {}\n    }\n    function restoreFileManager(){\n        var fm = byId('ti-file-manager-ov');\n        if (!fm) return;\n        try {\n            if (Date.now && Date.now() < (window.tiSuppressFileManagerUntil || 0)) {\n                setImp(fm, 'display', 'none');\n                setImp(fm, 'visibility', 'hidden');\n                setImp(fm, 'opacity', '0');\n                setImp(fm, 'pointer-events', 'none');\n                try { fm.setAttribute('aria-hidden','true'); fm.removeAttribute('data-ti-demoted-by-aigen455'); } catch(e) {}\n                return;\n            }\n            if (fm.getAttribute('data-ti-demoted-by-aigen455') !== '1' && window.__tiAIGenReturnToFileManager455 !== true) {\n                return;\n            }\n        } catch(e) {}\n        try { fm.removeAttribute('data-ti-demoted-by-aigen455'); } catch(e) {}\n        setImp(fm, 'display', 'flex');\n        setImp(fm, 'visibility', 'visible');\n        setImp(fm, 'opacity', '1');\n        setImp(fm, 'pointer-events', 'auto');\n        setImp(fm, 'z-index', '2147483500');\n        try { fm.removeAttribute('aria-hidden'); if (window.preparePluginModal) window.preparePluginModal(fm); } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n    }\n    function releaseBlockedUI(){\n        try {\n            var btn = byId('ai-gen-btn');\n            if (btn) { btn.disabled = false; btn.innerText = 'Genera Immagine'; btn.style.display = 'block'; }\n        } catch(e) {}\n        try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n        try {\n            var loader = byId('ti-ai-loader-ov');\n            if (loader) { setImp(loader,'display','none'); setImp(loader,'visibility','hidden'); setImp(loader,'opacity','0'); setImp(loader,'pointer-events','none'); loader.setAttribute('aria-hidden','true'); }\n        } catch(e) {}\n        if (!isVisible(byId('ti-ai-gen-ov'))) restoreFileManager();\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n    }\n    function makeFd(action, data){\n        var form = new FormData();\n        form.append('action', action);\n        form.append('ti_action', action);\n        Object.keys(data || {}).forEach(function(k){ form.append(k, data[k] == null ? '' : data[k]); });\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(form); } catch(e) {}\n        return form;\n    }\n    function parseResponse(resp){\n        return resp.text().then(function(raw){\n            if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + String(raw || '').slice(0, 240));\n            try { return JSON.parse(raw); }\n            catch(e) { throw new Error('Risposta server non JSON: ' + String(raw || '').slice(0, 240)); }\n        });\n    }\n    function postJson(action, data, timeoutMs, preferAjax){\n        var urls = [];\n        if (preferAjax && window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl) urls.push(window.tiUrl);\n        if (window.tiAjaxUrl && urls.indexOf(window.tiAjaxUrl) === -1) urls.push(window.tiAjaxUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            var controller = null, timer = null, done = false;\n            var opts = {method:'POST', body:makeFd(action, data || {}), credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller = new AbortController(); opts.signal = controller.signal; } } catch(e) {}\n            return new Promise(function(resolve, reject){\n                timer = setTimeout(function(){\n                    if (done) return;\n                    done = true;\n                    try { if (controller) controller.abort(); } catch(e) {}\n                    reject(new Error('Timeout: il server non ha risposto nei tempi previsti. Interfaccia sbloccata.'));\n                }, timeoutMs || 120000);\n                fetch(urls[i], opts).then(parseResponse).then(function(d){ if (done) return; done = true; resolve(d); }).catch(function(err){\n                    if (done) return;\n                    done = true;\n                    if (i + 1 < urls.length) attempt(i + 1).then(resolve).catch(reject);\n                    else reject(err);\n                }).finally(function(){ clearTimeout(timer); });\n            });\n        }\n        return attempt(0);\n    }\n    function openAIGenFromManager(){\n        var ctx = readCtx();\n        var row = rowFor(ctx);\n        resetAIGen(row);\n        window.__tiAIGenReturnToFileManager455 = !!ctx;\n        try { if (typeof window.openModal === 'function') window.openModal('ti-ai-gen-ov'); } catch(e) {}\n        demoteFileManager();\n        activateAI();\n        setTimeout(function(){\n            if (!activateAI()) {\n                restoreFileManager();\n                if (window.tiAlert) window.tiAlert('Form AI non disponibile. Riapri Gestione File Associati e riprova.');\n            } else {\n                try { var p = byId('ai-gen-prompt'); if (p) p.focus({preventScroll:true}); } catch(e) {}\n            }\n        }, 120);\n        setTimeout(function(){ if (!isVisible(byId('ti-ai-gen-ov'))) restoreFileManager(); }, 1200);\n        if (!ctx && window.tiAlert) setTimeout(function(){ window.tiAlert('Generatore AI aperto, ma contesto record non rilevato. Dopo la generazione potrai associare manualmente il file.'); }, 180);\n        return false;\n    }\n    window.tiOpenAIGeneratorFromFileManager455 = openAIGenFromManager;\n    window.chooseAIManager = function(){ return openAIGenFromManager(); };\n    window.chooseAI = function(){\n        try { if (window.closeModal) window.closeModal('ti-up-choice-ov'); } catch(e) {}\n        var target = window.targetUploadContext;\n        var row = validCtx(target) ? rowFor(target) : null;\n        if (validCtx(target)) saveCtx(target);\n        resetAIGen(row);\n        window.__tiAIGenReturnToFileManager455 = false;\n        try { if (typeof window.openModal === 'function') window.openModal('ti-ai-gen-ov'); } catch(e) {}\n        activateAI();\n        setTimeout(function(){ activateAI(); }, 80);\n        return false;\n    };\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var btn = t.closest('#ti-file-manager-ov button');\n        if (!btn) return;\n        var oc = String(btn.getAttribute('onclick') || '');\n        var txt = String(btn.textContent || btn.value || '').toLowerCase();\n        if (oc.indexOf('chooseAIManager') === -1 && txt.indexOf('genera con ai') === -1) return;\n        try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        openAIGenFromManager();\n    }, true);\n    setTimeout(function(){\n        try {\n            document.querySelectorAll('#ti-file-manager-ov button').forEach(function(btn){\n                var oc = String(btn.getAttribute('onclick') || ''), txt = String(btn.textContent || '').toLowerCase();\n                if (oc.indexOf('chooseAIManager') !== -1 || txt.indexOf('genera con ai') !== -1) {\n                    btn.onclick = function(e){ if (e) { e.preventDefault(); e.stopPropagation(); } return openAIGenFromManager(); };\n                    btn.setAttribute('data-ti-ai-safe-455','1');\n                }\n            });\n        } catch(e) {}\n    }, 250);\n    function isImageDiagAdmin(){\n        var role = String(window.tiRole || '').toLowerCase();\n        var user = String(window.tiUser || '');\n        return user === 'SSGlobalAdmin' || \/amministratore|administrator|admin\/i.test(role);\n    }\n    window.doAIGen = function(){\n        var promptEl = byId('ai-gen-prompt'), detailEl = byId('ai-gen-detail'), btn = byId('ai-gen-btn'), res = byId('ai-gen-res'), img = byId('ai-gen-img');\n        var prompt = promptEl ? String(promptEl.value || '').trim() : '';\n        var detail = detailEl ? String(detailEl.value || '').trim() : '';\n        if (!prompt && !detail) { if (window.tiAlert) window.tiAlert('Inserisci una descrizione!'); return false; }\n        if (!prompt && detail) prompt = detail;\n        try {\n            if (!\/^Attivit[a\u00e0]\\s+ditta:\/i.test(prompt) && !\/^Verifica anzitutto\/i.test(prompt) && typeof window.buildAIGenPrompt === 'function') {\n                prompt = window.buildAIGenPrompt(prompt);\n                if (promptEl) promptEl.value = prompt;\n            }\n        } catch(e) {}\n        if (detail && prompt.indexOf(detail) === -1) prompt += ' Istruzioni di dettaglio per la generazione foto: ' + detail + '.';\n        var db = (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : 'Global';\n        var jobId = 'img_' + Date.now() + '_' + Math.random().toString(36).slice(2,8);\n        var allowDiag = isImageDiagAdmin();\n        var finished = false;\n        var watchdog = null;\n        var diagTimer = null;\n        var firstDiagSeen = false;\n        function setDiagText(txt){\n            if (!allowDiag) return;\n            try {\n                var cur = byId('ti-loader-current-item');\n                if (cur) { cur.style.display = 'block'; cur.textContent = txt; }\n            } catch(e) {}\n        }\n        function finish(){\n            finished = true;\n            if (watchdog) { try { clearTimeout(watchdog); } catch(e) {} watchdog = null; }\n            if (diagTimer) { try { clearInterval(diagTimer); } catch(e) {} diagTimer = null; }\n            if (btn) { btn.disabled = false; btn.innerText = 'Genera Immagine'; }\n        }\n        function startDiagPolling(){\n            if (!allowDiag) return;\n            setDiagText('Diagnostica generazione: avvio richiesta... ID ' + jobId);\n            diagTimer = setInterval(function(){\n                if (finished) return;\n                postJson('ti_ai_image_diag_status', {job:jobId}, 20000, true).then(function(s){\n                    if (finished || !s || !s.success || !s.data) return;\n                    if (s.data.found && s.data.diag) {\n                        firstDiagSeen = true;\n                        var dg = s.data.diag;\n                        setDiagText('Diagnostica: ' + (dg.step || '') + ' - ' + (dg.message || '') + (dg.time ? ' (' + dg.time + ')' : ''));\n                    } else if (!firstDiagSeen) {\n                        setDiagText('Diagnostica: richiesta inviata, ma il server non ha ancora scritto il primo stato. Se resta cos\u00ec, controllare Network\/AJAX, firewall o 503 hosting.');\n                    }\n                }).catch(function(){\n                    if (!finished && !firstDiagSeen) setDiagText('Diagnostica: endpoint stato non raggiungibile. Possibile blocco AJAX\/server.');\n                });\n            }, 8000);\n        }\n        if (btn) { btn.disabled = true; btn.innerText = 'Generazione in corso...'; }\n        if (res) res.style.display = 'none';\n        try { if (window.showProgressPopup) window.showProgressPopup('AI Image Generator', 'Generazione immagine in corso. In caso di attesa lunga, errore o timeout la form viene sbloccata automaticamente.', {startPercent:6, targetPercent:93, stepMs:900, cancellable:true}); } catch(e) {}\n        startDiagPolling();\n        setTimeout(function(){ if (allowDiag && !finished && !firstDiagSeen) setDiagText('Diagnostica: nessun segnale dal server generazione. Verifica in Console\/Network la richiesta ti_ai_generate_media.'); }, 18000);\n        watchdog = setTimeout(function(){\n            if (finished) return;\n            finish();\n            releaseBlockedUI();\n            try { if (window.hideProgressPopup) window.hideProgressPopup(false, 'Timeout generazione immagine'); } catch(e) {}\n            if (window.tiAlert) window.tiAlert(allowDiag ? (\"La generazione dell'immagine sta impiegando troppo tempo. Ho sbloccato la form. Ultimo stato diagnostico visibile nel popup\/log: \" + jobId) : \"La generazione dell'immagine sta impiegando troppo tempo. Ho sbloccato la form. Riprova tra poco o contatta la ditta.\");\n        }, 210000);\n        postJson('ti_ai_generate_media', {db:db, prompt:prompt, job:jobId}, 300000, true).then(function(d){\n            finish();\n            if (!d || !d.success) throw new Error(d && d.data && d.data.message ? d.data.message : 'Errore generazione immagine.');\n            window.currentGenFilename = d.data && d.data.filename ? d.data.filename : null;\n            if (img && d.data && d.data.url) img.src = d.data.url;\n            if (btn) btn.style.display = 'none';\n            if (res) res.style.display = 'block';\n            try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'Immagine generata', {remindSave:true, notifyUser:false, successMessage:'Attivita AI completata. Immagine generata correttamente.'}); } catch(e) {}\n            activateAI();\n        }).catch(function(err){\n            finish();\n            releaseBlockedUI();\n            try { if (window.hideProgressPopup) window.hideProgressPopup(false, 'Errore generazione immagine'); } catch(e) {}\n            if (window.tiAlert) window.tiAlert(allowDiag ? ('Errore generazione immagine: ' + (err && err.message ? err.message : 'errore rete')) : 'Non \u00e8 stato possibile completare la generazione immagine. Riprova tra poco o contatta la ditta.');\n        });\n        return false;\n    };\n    function uploadTemp(db, tbl, tempFile, label){ return postJson('ti_ai_media_upload', {db:db, tbl:tbl, temp_file:tempFile, record_label:label || ''}, 120000, true); }\n    window.useAIGen = function(){\n        var filename = window.currentGenFilename;\n        if (!filename) { if (window.tiAlert) window.tiAlert('Nessuna immagine generata da associare.'); return false; }\n        var db = (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : 'Global';\n        var tgt = window.targetUploadContext;\n        try { if (window.closeModal) window.closeModal('ti-ai-gen-ov'); } catch(e) {}\n        if (validCtx(tgt)) {\n            var ctx = saveCtx(tgt);\n            uploadTemp(db, ctx.tbl, filename, recordLabel(ctx)).then(function(d){\n                if (!d || !d.success) throw new Error(d && d.data && d.data.message ? d.data.message : 'errore associazione');\n                try {\n                    if (!window.currentDbData) window.currentDbData = {Tabelle:{}};\n                    if (!window.currentDbData.Tabelle) window.currentDbData.Tabelle = {};\n                    if (!window.currentDbData.Tabelle[ctx.tbl]) window.currentDbData.Tabelle[ctx.tbl] = [];\n                    if (!window.currentDbData.Tabelle[ctx.tbl][ctx.idx]) window.currentDbData.Tabelle[ctx.tbl][ctx.idx] = {};\n                    var oldVal = String(window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] || '');\n                    var arr = oldVal.split(\/[,;\\r\\n]+\/).map(function(x){ return x.trim(); }).filter(Boolean);\n                    var name = (d.data && (d.data.name || d.data.filename)) ? (d.data.name || d.data.filename) : filename;\n                    if (arr.map(function(x){ return x.toLowerCase(); }).indexOf(String(name).toLowerCase()) === -1) arr.push(name);\n                    window.currentDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] = arr.join(', ');\n                    if (!window.modifiedFields) window.modifiedFields = new Set();\n                    window.modifiedFields.add(ctx.tbl + '-' + ctx.idx + '-' + ctx.key);\n                    if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n                    if (window.renderConfig) window.renderConfig();\n                    if (window.openFileManager) window.openFileManager(ctx.tbl, ctx.idx, ctx.key);\n                } catch(e) { restoreFileManager(); }\n            }).catch(function(err){ restoreFileManager(); if (window.tiAlert) window.tiAlert('Errore salvataggio immagine AI: ' + (err && err.message ? err.message : 'errore rete')); });\n            return false;\n        }\n        if (tgt === 'chat') {\n            uploadTemp(db, 'Chat', filename, '').then(function(d){\n                if (!d || !d.success) throw new Error(d && d.data && d.data.message ? d.data.message : 'errore salvataggio chat');\n                window.lastUploadedFile = d.data.url;\n                if (window.rememberLastFileContext) window.rememberLastFileContext(window.lastUploadedFile, 'Ho generato questa immagine. Analizzala.', false);\n                var msg = byId('ti-msg'); if (msg) msg.value = 'Ho generato questa immagine. Analizzala.';\n                var send = byId('ti-send'); if (send) send.click();\n            }).catch(function(err){ if (window.tiAlert) window.tiAlert('Errore salvataggio immagine AI: ' + (err && err.message ? err.message : 'errore rete')); });\n            return false;\n        }\n        var tblName = 'Config';\n        if (typeof tgt === 'string' && tgt.indexOf('cfg-img-') === 0) { var m = tgt.match(\/cfg-img-([^-]+)-\/); if (m) tblName = m[1]; }\n        else if (tgt === 'p-foto') tblName = 'Utenti';\n        var label = (tgt === 'p-foto') ? ((byId('p-user') && byId('p-user').value) || (byId('p-utente') && byId('p-utente').value) || 'utente') : tblName;\n        uploadTemp(db, tblName, filename, label).then(function(d){\n            if (!d || !d.success) throw new Error(d && d.data && d.data.message ? d.data.message : 'errore salvataggio');\n            if (typeof tgt === 'string') {\n                var inp = byId(tgt);\n                if (inp) { inp.value = d.data.name || d.data.filename || filename; inp.dispatchEvent(new Event('change')); if (tgt.indexOf('cfg-') === 0 && window.renderConfig) window.renderConfig(); }\n            }\n            \/\/ 30.9.1487: associazione completata senza popup finale.\n        }).catch(function(err){ if (window.tiAlert) window.tiAlert('Errore salvataggio immagine AI: ' + (err && err.message ? err.message : 'errore rete')); });\n        return false;\n    };\n    var prevCloseModal455 = window.closeModal;\n    if (typeof prevCloseModal455 === 'function') {\n        window.closeModal = function(id){\n            var ret = prevCloseModal455.apply(this, arguments);\n            if (id === 'ti-ai-gen-ov') setTimeout(function(){ if (window.__tiAIGenReturnToFileManager455) restoreFileManager(); else releaseBlockedUI(); }, 60);\n            return ret;\n        };\n    }\n    setInterval(function(){\n        var ai = byId('ti-ai-gen-ov');\n        var fm = byId('ti-file-manager-ov');\n        if (fm && fm.getAttribute('data-ti-demoted-by-aigen455') === '1' && !isVisible(ai)) restoreFileManager();\n    }, 2500);\n})();\n<\/script>\n\n\n<script id=\"ti-ai-generator-visual-fix-464\">\n(function(){\n    \"use strict\";\n    if (window.__tiAIGeneratorVisualFix464Installed) return;\n    window.__tiAIGeneratorVisualFix464Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function setImp(el, prop, val){ try { if (el && el.style) el.style.setProperty(prop, String(val), 'important'); } catch(e) {} }\n    function visible(el){\n        if (!el) return false;\n        try {\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')) return false;\n            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n        } catch(e) { return false; }\n    }\n    function ensureStyle(){\n        if (byId('ti-ai-generator-visual-fix-464-style')) return;\n        var st = document.createElement('style');\n        st.id = 'ti-ai-generator-visual-fix-464-style';\n        st.textContent = ''\n        + '#ti-ai-gen-ov.ti-ai-gen-visible-464{background:rgba(0,0,0,.22)!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important;align-items:flex-start!important;justify-content:center!important;padding:16px 8px 26px 8px!important;overflow-y:auto!important;}'\n        + '#ti-ai-gen-ov.ti-ai-gen-visible-464>.ti-modal{margin:12px auto 26px auto!important;box-shadow:0 18px 46px rgba(0,0,0,.55)!important;max-height:calc(100vh - 44px)!important;}'\n        + '#ti-file-manager-ov.ti-hidden-under-aigen-464{display:none!important;visibility:hidden!important;opacity:0!important;pointer-events:none!important;}'\n        + '#ti-ai-outer.ti-mainform-blocked-464 .ti-header,#ti-ai-outer.ti-mainform-blocked-464 #ti-chat-box,#ti-ai-outer.ti-mainform-blocked-464 .ti-input-wrap,#ti-ai-outer.ti-mainform-blocked-464 #ti-order-confirm-host{user-select:none!important;-webkit-user-select:none!important;}'\n        + '#ti-ai-outer.ti-mainform-blocked-464 #ti-chat-box,#ti-ai-outer.ti-mainform-blocked-464 .ti-input-wrap,#ti-ai-outer.ti-mainform-blocked-464 .ti-header,#ti-ai-outer.ti-mainform-blocked-464 #ti-order-confirm-host{filter:grayscale(.06) opacity(.92)!important;}'\n        + '#ti-ai-loader-ov.ti-ai-center-progress-464{position:fixed!important;inset:0!important;width:100vw!important;height:100vh!important;min-height:100vh!important;background:rgba(0,0,0,.42)!important;display:flex!important;align-items:center!important;justify-content:center!important;overflow:hidden!important;pointer-events:auto!important;border-radius:0!important;z-index:2147483647!important;}'\n        + '#ti-ai-loader-ov.ti-ai-center-progress-464 .ti-loader-box{width:min(460px,calc(100vw - 28px))!important;max-width:460px!important;margin:0 auto!important;padding:18px 18px!important;border-radius:16px!important;border:1px solid #38bdf8!important;background:rgba(15,23,42,.985)!important;box-shadow:0 18px 56px rgba(0,0,0,.62)!important;pointer-events:auto!important;position:relative!important;z-index:2147483647!important;}'\n        + '#ti-ai-loader-ov.ti-ai-center-progress-464 .ti-loader-spinner{font-size:22px!important;margin-bottom:6px!important;}'\n        + '#ti-ai-loader-ov.ti-ai-center-progress-464 #ti-loader-title{font-size:15px!important;line-height:1.3!important;}'\n        + '#ti-ai-loader-ov.ti-ai-center-progress-464 #ti-loader-sub{font-size:12px!important;line-height:1.35!important;color:#cbd5e1!important;}'\n        + '#ti-ai-loader-ov.ti-ai-center-progress-464 #ti-loader-progress-wrap{display:block!important;}'\n        + '#ti-ai-loader-ov.ti-ai-center-progress-464 #ti-loader-actions{display:block!important;max-width:240px!important;margin:12px auto 0 auto!important;}'\n        + '@media (max-width:767px){#ti-ai-loader-ov.ti-ai-center-progress-464 .ti-loader-box{width:min(94vw,420px)!important;padding:16px 14px!important;}#ti-ai-gen-ov.ti-ai-gen-visible-464{padding:8px 6px 24px 6px!important;}#ti-ai-gen-ov.ti-ai-gen-visible-464>.ti-modal{width:min(96vw,820px)!important;max-height:calc(100vh - 40px)!important;margin:4px auto 12px auto!important;}}';\n        (document.head || document.documentElement).appendChild(st);\n    }\n    function setMainFormBlocked(blocked){\n        var root = byId('ti-ai-outer');\n        if (!root) return;\n        try { root.classList.remove('ti-mainform-blocked-463'); root.classList[blocked ? 'add' : 'remove']('ti-mainform-blocked-464'); } catch(e) {}\n        try { root.setAttribute('aria-busy', blocked ? 'true' : 'false'); } catch(e) {}\n    }\n    function isProgressVisible(){\n        var loader = byId('ti-ai-loader-ov');\n        return !!(loader && visible(loader));\n    }\n\n    function markAIVisible(){\n        ensureStyle();\n        var ai = byId('ti-ai-gen-ov');\n        if (!ai || !visible(ai)) return false;\n        try { ai.classList.add('ti-ai-gen-visible-464'); } catch(e) {}\n        setImp(ai, 'background', 'rgba(0,0,0,.22)');\n        setImp(ai, 'backdrop-filter', 'none');\n        setImp(ai, '-webkit-backdrop-filter', 'none');\n        setImp(ai, 'align-items', 'flex-start');\n        setImp(ai, 'justify-content', 'center');\n        setImp(ai, 'overflow-y', 'auto');\n        var fm = byId('ti-file-manager-ov');\n        if (fm && fm.getAttribute('data-ti-demoted-by-aigen455') === '1') {\n            try { fm.classList.add('ti-hidden-under-aigen-464'); } catch(e) {}\n            setImp(fm, 'display', 'none');\n            setImp(fm, 'visibility', 'hidden');\n            setImp(fm, 'opacity', '0');\n            setImp(fm, 'pointer-events', 'none');\n        }\n        return true;\n    }\n    function clearVisualState(){\n        var ai = byId('ti-ai-gen-ov');\n        if (ai && !visible(ai)) { try { ai.classList.remove('ti-ai-gen-visible-464'); } catch(e) {} }\n        var fm = byId('ti-file-manager-ov');\n        if (fm && (!visible(ai) || fm.getAttribute('data-ti-demoted-by-aigen455') !== '1')) {\n            try { fm.classList.remove('ti-hidden-under-aigen-464'); } catch(e) {}\n        }\n        var loader = byId('ti-ai-loader-ov');\n        if (loader && !visible(loader)) { try { loader.classList.remove('ti-ai-center-progress-464'); } catch(e) {} }\n        if (!isProgressVisible()) setMainFormBlocked(false);\n    }\n    function centerLoader(){\n        ensureStyle();\n        setMainFormBlocked(true);\n        var loader = byId('ti-ai-loader-ov');\n        if (!loader) return;\n        try { loader.classList.add('ti-ai-center-progress-464'); } catch(e) {}\n        setImp(loader, 'background', 'rgba(0,0,0,.42)');\n        setImp(loader, 'inset', '0');\n        setImp(loader, 'width', '100vw');\n        setImp(loader, 'height', '100vh');\n        setImp(loader, 'display', 'flex');\n        setImp(loader, 'align-items', 'center');\n        setImp(loader, 'justify-content', 'center');\n        setImp(loader, 'pointer-events', 'auto');\n        setImp(loader, 'z-index', '2147483647');\n        var box = loader.querySelector ? loader.querySelector('.ti-loader-box') : null;\n        if (box) {\n            setImp(box, 'pointer-events', 'auto');\n            setImp(box, 'margin', '0 auto');\n            setImp(box, 'max-width', '460px');\n        }\n    }\n    function isImageGenerationTitle(title, subtitle){\n        var s = String(title || '') + ' ' + String(subtitle || '');\n        return \/AI Image Generator|Generazione immagine|immagine in corso|foto AI|batch immagini\/i.test(s);\n    }\n    function installWrappers(){\n        if (typeof window.openModal === 'function' && !window.openModal.__tiVisual464) {\n            var prevOpen = window.openModal;\n            window.openModal = function(id){\n                var ret = prevOpen.apply(this, arguments);\n                if (id === 'ti-ai-gen-ov') { setTimeout(markAIVisible, 0); setTimeout(markAIVisible, 80); setTimeout(markAIVisible, 260); }\n                return ret;\n            };\n            window.openModal.__tiVisual464 = true;\n        }\n        if (typeof window.showPluginModal === 'function' && !window.showPluginModal.__tiVisual464) {\n            var prevShow = window.showPluginModal;\n            window.showPluginModal = function(id){\n                var ret = prevShow.apply(this, arguments);\n                if (id === 'ti-ai-gen-ov') { setTimeout(markAIVisible, 0); setTimeout(markAIVisible, 80); setTimeout(markAIVisible, 260); }\n                if (id === 'ti-ai-loader-ov' && window.__tiCenterAILoader464) { setTimeout(centerLoader, 0); setTimeout(centerLoader, 80); }\n                return ret;\n            };\n            window.showPluginModal.__tiVisual464 = true;\n        }\n        if (typeof window.closeModal === 'function' && !window.closeModal.__tiVisual464) {\n            var prevClose = window.closeModal;\n            window.closeModal = function(id){\n                var ret = prevClose.apply(this, arguments);\n                if (id === 'ti-ai-gen-ov' || id === 'ti-ai-loader-ov') setTimeout(clearVisualState, 80);\n                return ret;\n            };\n            window.closeModal.__tiVisual464 = true;\n        }\n        if (typeof window.showProgressPopup === 'function' && !window.showProgressPopup.__tiVisual464) {\n            var prevProgress = window.showProgressPopup;\n            window.showProgressPopup = function(title, subtitle, opts){\n                var centered = isImageGenerationTitle(title, subtitle) || (opts && opts.centered === true);\n                window.__tiCenterAILoader464 = !!centered;\n                var ret = prevProgress.apply(this, arguments);\n                if (centered) { centerLoader(); setTimeout(centerLoader, 80); setTimeout(centerLoader, 250); }\n                return ret;\n            };\n            window.showProgressPopup.__tiVisual464 = true;\n        }\n        if (typeof window.hideProgressPopup === 'function' && !window.hideProgressPopup.__tiVisual464) {\n            var prevHide = window.hideProgressPopup;\n            window.hideProgressPopup = function(){\n                var ret = prevHide.apply(this, arguments);\n                setTimeout(function(){ window.__tiCenterAILoader464 = false; clearVisualState(); setMainFormBlocked(false); }, 700);\n                return ret;\n            };\n            window.hideProgressPopup.__tiVisual464 = true;\n        }\n    }\n    function boot(){\n        ensureStyle();\n        installWrappers();\n        markAIVisible();\n        clearVisualState();\n        setMainFormBlocked(isProgressVisible());\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, {once:true}); else boot();\n    setTimeout(boot, 250);\n    setTimeout(boot, 1200);\n    setInterval(function(){ if (visible(byId('ti-ai-gen-ov'))) markAIVisible(); else clearVisualState(); }, 1200);\n})();\n<\/script>\n\n\n<script id=\"ti-ai-generator-cancel-diag-fix-469\">\n(function(){\n    \"use strict\";\n    if (window.__tiAIGeneratorCancelDiagFix469Installed) return;\n    window.__tiAIGeneratorCancelDiagFix469Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function setImp(el, prop, val){ try { if (el && el.style) el.style.setProperty(prop, String(val), 'important'); } catch(e) {} }\n    function txt(v){ return String(v == null ? '' : v); }\n    function isAdmin(){\n        var role = txt(window.tiRole || '').toLowerCase();\n        var user = txt(window.tiUser || '');\n        return user === 'SSGlobalAdmin' || \/amministratore|administrator|admin\/i.test(role);\n    }\n    function resetBtn(){\n        try { var btn = byId('ai-gen-btn'); if (btn) { btn.disabled = false; btn.innerText = 'Genera Immagine'; btn.style.display = 'block'; } } catch(e) {}\n    }\n    function hideLoaderHard(){\n        try { window.__tiCenterAILoader464 = false; window.__tiCenterAILoader463 = false; window.__tiCenterAILoader462 = false; } catch(e) {}\n        try {\n            var loader = byId('ti-ai-loader-ov');\n            if (loader) {\n                ['ti-ai-center-progress-464','ti-ai-center-progress-463','ti-ai-center-progress-462','ti-ai-compact-progress-458'].forEach(function(c){ try { loader.classList.remove(c); } catch(e) {} });\n                setImp(loader, 'display', 'none'); setImp(loader, 'visibility', 'hidden'); setImp(loader, 'opacity', '0'); setImp(loader, 'pointer-events', 'none');\n                loader.setAttribute('aria-hidden','true');\n            }\n        } catch(e) {}\n        try {\n            var root = byId('ti-ai-outer');\n            if (root) {\n                ['ti-mainform-blocked-469','ti-mainform-blocked-464','ti-mainform-blocked-463'].forEach(function(c){ try { root.classList.remove(c); } catch(e) {} });\n                root.setAttribute('aria-busy','false');\n            }\n        } catch(e) {}\n        try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n        resetBtn();\n    }\n    function hasGeneratedPreview(){\n        try {\n            var res = byId('ai-gen-res'), img = byId('ai-gen-img');\n            return !!(window.currentGenFilename && img && String(img.src || '').trim() !== '' && (!res || res.style.display !== 'none'));\n        } catch(e) { return false; }\n    }\n    function hideLoaderKeepPreview(){\n        try { window.__tiCenterAILoader464 = false; window.__tiCenterAILoader463 = false; window.__tiCenterAILoader462 = false; } catch(e) {}\n        try {\n            var loader = byId('ti-ai-loader-ov');\n            if (loader) {\n                ['ti-ai-center-progress-464','ti-ai-center-progress-463','ti-ai-center-progress-462','ti-ai-compact-progress-458'].forEach(function(c){ try { loader.classList.remove(c); } catch(e) {} });\n                setImp(loader, 'display', 'none'); setImp(loader, 'visibility', 'hidden'); setImp(loader, 'opacity', '0'); setImp(loader, 'pointer-events', 'none');\n                loader.setAttribute('aria-hidden','true');\n            }\n        } catch(e) {}\n        try {\n            var root = byId('ti-ai-outer');\n            if (root) {\n                ['ti-mainform-blocked-469','ti-mainform-blocked-464','ti-mainform-blocked-463'].forEach(function(c){ try { root.classList.remove(c); } catch(e) {} });\n                root.setAttribute('aria-busy','false');\n            }\n        } catch(e) {}\n        try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n        try { var btn = byId('ai-gen-btn'); if (btn && window.currentGenFilename) { btn.disabled = false; btn.style.display = 'none'; } } catch(e) {}\n        return false;\n    }\n\n    function showDiag(op, message){\n        if (!op || !op.allowDiag) return;\n        \/\/ 30.9.1402: oltre al tentativo originale (elemento ti-loader-current-item, che potrebbe non\n        \/\/ funzionare per motivi non ancora chiariti), scrive anche direttamente nel testo del pulsante stesso\n        \/\/ (gia' confermato visibile con il marcatore [v1396]), cosi' da confermare con certezza se showDiag()\n        \/\/ viene davvero invocata, indipendentemente da problemi specifici del primo elemento target.\n        try { var btnDiag1402 = byId('ai-gen-btn'); if (btnDiag1402) btnDiag1402.innerText = message; } catch(e){}\n        try { var cur = byId('ti-loader-current-item'); if (cur) { cur.style.display = 'block'; cur.textContent = message; } } catch(e) {}\n    }\n    function abortOp(op, silent){\n        op = op || window.__tiCurrentAIGenOp469;\n        if (op) {\n            op.cancelled = true;\n            try { (op.timers || []).forEach(function(t){ clearTimeout(t); clearInterval(t); }); } catch(e) {}\n            try { (op.controllers || []).forEach(function(c){ try { c.abort(); } catch(e) {} }); } catch(e) {}\n        }\n        try { (window.__tiAIGenControllers469 || []).forEach(function(c){ try { c.abort(); } catch(e) {} }); } catch(e) {}\n        window.__tiAIGenControllers469 = [];\n        hideLoaderHard();\n        if (!silent && window.tiAlert) window.tiAlert('Processo AI interrotto. La form e stata sbloccata. Per completare l operazione devi ripeterla.');\n        return false;\n    }\n    window.tiAbortAIGen469 = abortOp;\n    window.cancelLongAIProcess = function(){\n        try { if (hasGeneratedPreview()) return hideLoaderKeepPreview(); } catch(e) {}\n        try { if (typeof window.confirmCancelBatchAIGen === 'function' && window.confirmCancelBatchAIGen()) return false; } catch(e) {}\n        return abortOp(window.__tiCurrentAIGenOp469, false);\n    };\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (t && t.closest && t.closest('#ti-loader-close')) {\n            try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n            window.cancelLongAIProcess();\n            return false;\n        }\n    }, true);\n\n    function makeFd(action, data){\n        var fd = new FormData();\n        fd.append('action', action);\n        fd.append('ti_action', action);\n        Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k] == null ? '' : data[k]); });\n        try { fd.append('upload_cleanup_token', currentUploadCleanupToken859(true)); fd.append('guided_upload_target', state.target || ''); } catch(e859fd) {}\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        return fd;\n    }\n    function parseResponse(resp){\n        return resp.text().then(function(raw){\n            if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + String(raw || '').slice(0, 220));\n            try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non JSON: ' + String(raw || '').slice(0, 220)); }\n        });\n    }\n    function postJson469(action, data, timeoutMs, op, preferAjax){\n        var urls = [];\n        if (preferAjax && window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (window.tiAjaxUrl && urls.indexOf(window.tiAjaxUrl) === -1) urls.push(window.tiAjaxUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            if (op && op.cancelled) return Promise.reject(new Error('Operazione interrotta dall utente.'));\n            var controller = null, timer = null, done = false;\n            var opts = {method:'POST', body:makeFd(action, data || {}), credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller = new AbortController(); opts.signal = controller.signal; } } catch(e) {}\n            if (controller) {\n                window.__tiAIGenControllers469 = window.__tiAIGenControllers469 || [];\n                window.__tiAIGenControllers469.push(controller);\n                if (op) { op.controllers = op.controllers || []; op.controllers.push(controller); }\n            }\n            return new Promise(function(resolve, reject){\n                timer = setTimeout(function(){\n                    if (done) return;\n                    done = true;\n                    try { if (controller) controller.abort(); } catch(e) {}\n                    reject(new Error('Timeout: il server non ha risposto.'));\n                }, timeoutMs || 120000);\n                fetch(urls[i], opts).then(parseResponse).then(function(d){\n                    if (done) return; done = true;\n                    if (op && op.cancelled) reject(new Error('Operazione interrotta dall utente.')); else resolve(d);\n                }).catch(function(err){\n                    if (done) return; done = true;\n                    if (op && op.cancelled) { reject(new Error('Operazione interrotta dall utente.')); return; }\n                    if (i + 1 < urls.length) attempt(i + 1).then(resolve).catch(reject); else reject(err);\n                }).finally(function(){ try { clearTimeout(timer); } catch(e) {} });\n            });\n        }\n        return attempt(0);\n    }\n    function buildPrompt(prompt, detail, promptEl){\n        try {\n            if (!\/^Attivit[a\u00e0]\\s+ditta:\/i.test(prompt) && !\/^Verifica anzitutto\/i.test(prompt) && typeof window.buildAIGenPrompt === 'function') {\n                prompt = window.buildAIGenPrompt(prompt);\n                if (promptEl) promptEl.value = prompt;\n            }\n        } catch(e) {}\n        if (detail && prompt.indexOf(detail) === -1) prompt += ' Istruzioni di dettaglio per la generazione foto: ' + detail + '.';\n        return prompt;\n    }\n    window.doAIGen = function(){\n        try { var btnMark1396 = byId(\"ai-gen-btn\"); if (btnMark1396) btnMark1396.setAttribute(\"data-ti-reached-1396\", \"si\"); } catch(e){}\n        var promptEl = byId('ai-gen-prompt'), detailEl = byId('ai-gen-detail'), btn = byId('ai-gen-btn'), res = byId('ai-gen-res'), img = byId('ai-gen-img');\n        var prompt = promptEl ? txt(promptEl.value).trim() : '';\n        var detail = detailEl ? txt(detailEl.value).trim() : '';\n        if (!prompt && !detail) { if (window.tiAlert) window.tiAlert('Inserisci una descrizione.'); return false; }\n        if (!prompt && detail) prompt = detail;\n        prompt = buildPrompt(prompt, detail, promptEl);\n        var db = (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : 'Global';\n        var op = {id:'img_' + Date.now() + '_' + Math.random().toString(36).slice(2,8), cancelled:false, timers:[], controllers:[], allowDiag:isAdmin()};\n        window.__tiCurrentAIGenOp469 = op;\n        if (btn) { btn.disabled = true; btn.innerText = 'Generazione in corso... [v1396]'; }\n        if (res) res.style.display = 'none';\n        try { if (window.showProgressPopup) window.showProgressPopup('AI Image Generator', 'Generazione immagine in corso. Premi Esci per interrompere e sbloccare subito la form.', {startPercent:6, targetPercent:93, stepMs:900, cancellable:true}); } catch(e) {}\n        \/\/ 30.9.1469: gestione centralizzata e riutilizzabile del completamento con successo - richiesta\n        \/\/ esplicitamente dall'utente dopo aver confermato con un caso reale che il server aveva generato e\n        \/\/ salvato correttamente l'immagine (in soli 42 secondi), ma il client non ha mai ricevuto\/elaborato\n        \/\/ quella risposta, lasciando la form bloccata per diversi minuti fino alla chiusura manuale. Puo' ora\n        \/\/ essere invocata sia dalla richiesta principale, sia dal canale di rilevamento di riserva sottostante.\n        function completeOp469(d){\n            if (op.cancelled || window.__tiCurrentAIGenOp469 !== op) return;\n            op.cancelled = true;\n            try { (op.timers || []).forEach(function(t){ clearTimeout(t); clearInterval(t); }); } catch(e) {}\n            try { if (window.__tiSingleImgWorker469) { window.__tiSingleImgWorker469.terminate(); window.__tiSingleImgWorker469 = null; } } catch(e) {}\n            if (btn) { btn.disabled = false; btn.innerText = 'Genera Immagine'; }\n            if (!d || !d.filename) { if (window.tiAlert) window.tiAlert('Errore generazione immagine.'); return; }\n            window.currentGenFilename = d.filename;\n            if (img && d.url) img.src = d.url;\n            if (btn) btn.style.display = 'none';\n            if (res) res.style.display = 'block';\n            try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'Immagine generata', {remindSave:true, notifyUser:false, successMessage:'Attivita AI completata. Immagine generata correttamente.'}); } catch(e) {}\n            setTimeout(hideLoaderKeepPreview, 120);\n            setTimeout(hideLoaderKeepPreview, 700);\n        }\n        op.timers.push(setTimeout(function(){\n            if (op.cancelled || window.__tiCurrentAIGenOp469 !== op) return;\n            showDiag(op, 'Diagnostica: se resta al 6%, la risposta server non e ancora arrivata. Controllo endpoint in corso...');\n        }, 8000));\n        \/\/ 30.9.1469: canale di rilevamento di riserva su thread separato (web worker) - MAI legato al solo\n        \/\/ profilo amministratore (a differenza del testo diagnostico visibile, che resta admin-only), dato che\n        \/\/ questa e' una correzione di affidabilita' di base per TUTTI gli utenti. Se il server ha gia'\n        \/\/ completato con successo (rilevabile tramite l'endpoint diagnostico esistente) ma la risposta\n        \/\/ principale non e' ancora arrivata al client, completa comunque l'operazione usando il nome del file\n        \/\/ trovato in questo canale alternativo.\n        try {\n            var workerCode469 = 'setInterval(function(){ postMessage(1); }, 4000);';\n            var blob469 = new Blob([workerCode469], {type: 'application\/javascript'});\n            window.__tiSingleImgWorker469 = new Worker(URL.createObjectURL(blob469));\n            window.__tiSingleImgWorker469.onmessage = function(){\n                if (op.cancelled || window.__tiCurrentAIGenOp469 !== op) return;\n                postJson469('ti_ai_image_diag_status', {job:op.id}, 15000, op, true).then(function(s){\n                    if (op.cancelled || window.__tiCurrentAIGenOp469 !== op || !s || !s.success || !s.data) return;\n                    if (op.allowDiag) {\n                        if (s.data.found && s.data.diag) showDiag(op, 'Diagnostica: ' + (s.data.diag.step || '') + ' - ' + (s.data.diag.message || ''));\n                        else showDiag(op, 'Diagnostica: nessun log server ancora scritto. Possibile blocco prima della funzione PHP: AJAX\/firewall\/hosting.');\n                    }\n                    if (s.data.found && s.data.diag && s.data.diag.step === 'success' && s.data.diag.extra && s.data.diag.extra.file) {\n                        completeOp469({filename: s.data.diag.extra.file, url: s.data.diag.extra.url || null});\n                    }\n                }).catch(function(){ if (!op.cancelled && op.allowDiag) showDiag(op, 'Diagnostica: endpoint stato non raggiungibile. Controllare Network\/AJAX o errore server.'); });\n            };\n        } catch(eWorker469) { window.__tiSingleImgWorker469 = null; }\n        if (op.allowDiag) showDiag(op, 'Diagnostica: invio richiesta al server. ID ' + op.id);\n        op.timers.push(setTimeout(function(){\n            if (op.cancelled || window.__tiCurrentAIGenOp469 !== op) return;\n            abortOp(op, true);\n            if (window.tiAlert) window.tiAlert(op.allowDiag ? ('Timeout generazione immagine. Form sbloccata. Se non e comparso nessun log server, il blocco e prima del PHP: AJAX, firewall, hosting o 503. ID: ' + op.id) : 'La generazione immagine sta impiegando troppo tempo. La form e stata sbloccata. Riprova tra poco.');\n        }, 180000));\n        postJson469('ti_ai_generate_media', {db:db, prompt:prompt, job:op.id}, 240000, op, true).then(function(d){\n            if (op.cancelled || window.__tiCurrentAIGenOp469 !== op) return;\n            if (!d || !d.success) { op.cancelled = true; try { (op.timers || []).forEach(function(t){ clearTimeout(t); clearInterval(t); }); } catch(e) {} if (btn) { btn.disabled = false; btn.innerText = 'Genera Immagine'; } throw new Error(d && d.data && d.data.message ? d.data.message : 'Errore generazione immagine.'); }\n            completeOp469({filename: d.data && d.data.filename ? d.data.filename : null, url: d.data && d.data.url ? d.data.url : null});\n        }).catch(function(err){\n            if (op.cancelled || window.__tiCurrentAIGenOp469 !== op) return;\n            abortOp(op, true);\n            if (window.tiAlert) window.tiAlert(op.allowDiag ? ('Errore generazione immagine: ' + (err && err.message ? err.message : 'errore rete')) : 'Non e stato possibile completare la generazione immagine. Riprova tra poco.');\n        });\n        return false;\n    };\n})();\n<\/script>\n\n\n<script id=\"ti-file-ai-save-pc-fix-471\">\n(function(){\n    \"use strict\";\n    if (window.__tiFileAiSavePcFix471Installed) return;\n    window.__tiFileAiSavePcFix471Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function val(v){ return String(v == null ? '' : v); }\n    function validCtx(ctx){ return !!(ctx && typeof ctx === 'object' && ctx.tbl && ctx.key && ctx.idx !== undefined && ctx.idx !== null && ctx.idx !== ''); }\n    function cloneCtx(ctx){ return validCtx(ctx) ? {tbl:String(ctx.tbl), idx:ctx.idx, key:String(ctx.key), id:ctx.id || ''} : null; }\n    function saveCtx(ctx){\n        var c = cloneCtx(ctx);\n        if (!c) return null;\n        window.targetUploadContext = c;\n        window.__tiLastFileManagerCtx471 = c;\n        window.__tiLastFileManagerCtx455 = c;\n        try { sessionStorage.setItem('tiLastFileManagerCtx471', JSON.stringify(c)); } catch(e) {}\n        return c;\n    }\n    function readCtx(){\n        var c = cloneCtx(window.targetUploadContext || window.__tiLastFileManagerCtx471 || window.__tiLastFileManagerCtx455 || window.__tiLastFileManagerCtx360 || window.__tiLastFileAiCtx358 || window.__tiLastUploadContext356);\n        if (c) return saveCtx(c);\n        var fm = byId('ti-file-manager-ov');\n        if (fm) {\n            c = cloneCtx({tbl:fm.dataset ? (fm.dataset.tbl || fm.dataset.table || '') : '', idx:fm.dataset ? (fm.dataset.idx || fm.dataset.row || '') : '', key:fm.dataset ? (fm.dataset.key || fm.dataset.field || '') : ''});\n            if (c) return saveCtx(c);\n            c = cloneCtx({tbl:fm.getAttribute('data-ti-context-table') || '', idx:fm.getAttribute('data-ti-context-row') || '', key:fm.getAttribute('data-ti-context-field') || ''});\n            if (c) return saveCtx(c);\n        }\n        try {\n            var keys = ['tiLastFileManagerCtx471','tiLastFileManagerCtx455','tiLastFileManagerCtx360','tiLastFileAiCtx358','tiLastUploadContext356'];\n            for (var i=0;i<keys.length;i++) {\n                var raw = sessionStorage.getItem(keys[i]);\n                if (!raw) continue;\n                c = cloneCtx(JSON.parse(raw));\n                if (c) return saveCtx(c);\n            }\n        } catch(e) {}\n        return null;\n    }\n    function rowFor(ctx){\n        try { return (ctx && window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[ctx.tbl]) ? (window.currentDbData.Tabelle[ctx.tbl][ctx.idx] || null) : null; } catch(e) { return null; }\n    }\n    function recordLabel(ctx){\n        try { if (window.getRecordLabelForUpload) return window.getRecordLabelForUpload(ctx.tbl, rowFor(ctx), ctx.tbl); } catch(e) {}\n        return ctx && ctx.tbl ? ctx.tbl : '';\n    }\n    function dbName(){ return (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : 'Global'; }\n    function makeFd(action, data, file){\n        var fd = new FormData();\n        fd.append('action', action); fd.append('ti_action', action);\n        Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k] == null ? '' : data[k]); });\n        if (file) fd.append('file', file);\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        return fd;\n    }\n    function post(action, data, file, timeoutMs){\n        var urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            var controller = null, timer = null, done = false;\n            var opts = {method:'POST', body:makeFd(action, data || {}, file || null), credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller = new AbortController(); opts.signal = controller.signal; } } catch(e) {}\n            return new Promise(function(resolve, reject){\n                timer = setTimeout(function(){ if (done) return; done = true; try { if (controller) controller.abort(); } catch(e) {} reject(new Error('Timeout server.')); }, timeoutMs || 120000);\n                fetch(urls[i], opts).then(function(r){ return r.text().then(function(raw){ if (!r.ok) throw new Error('HTTP ' + r.status + ': ' + raw.slice(0,160)); try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non JSON: ' + raw.slice(0,160)); } }); }).then(function(d){ if (done) return; done = true; resolve(d); }).catch(function(err){ if (done) return; done = true; if (i + 1 < urls.length) attempt(i+1).then(resolve).catch(reject); else reject(err); }).finally(function(){ try { clearTimeout(timer); } catch(e) {} });\n            });\n        }\n        return attempt(0);\n    }\n    function setBusy(on, label){\n        try {\n            var b = byId('ai-gen-res') ? byId('ai-gen-res').querySelector('button[onclick*=\"useAIGen\"]') : null;\n            if (b) { b.disabled = !!on; b.innerText = on ? (label || 'Salvataggio...') : '\u2705 Usa questa Immagine'; }\n        } catch(e) {}\n    }\n    function applyLocal(ctx, name, value, dbVersion){\n        ctx = saveCtx(ctx);\n        if (!ctx || !name) return;\n        try {\n            if (!window.currentDbData) window.currentDbData = {Tabelle:{}};\n            if (!window.currentDbData.Tabelle) window.currentDbData.Tabelle = {};\n            if (!window.currentDbData.Tabelle[ctx.tbl]) window.currentDbData.Tabelle[ctx.tbl] = [];\n            if (!window.currentDbData.Tabelle[ctx.tbl][ctx.idx]) window.currentDbData.Tabelle[ctx.tbl][ctx.idx] = {};\n            var row = window.currentDbData.Tabelle[ctx.tbl][ctx.idx];\n            row[ctx.key] = value || (function(){\n                var oldVal = val(row[ctx.key] || '');\n                var arr = oldVal.split(\/[,;\\r\\n]+\/).map(function(x){ return x.trim(); }).filter(Boolean);\n                if (arr.map(function(x){ return x.toLowerCase(); }).indexOf(val(name).toLowerCase()) === -1) arr.push(name);\n                return arr.join(', ');\n            })();\n            if (dbVersion && window.currentDbData) window.currentDbData.__db_version = dbVersion;\n            if (window.configOriginalDbData) {\n                try {\n                    if (!window.configOriginalDbData.Tabelle) window.configOriginalDbData.Tabelle = {};\n                    if (!window.configOriginalDbData.Tabelle[ctx.tbl]) window.configOriginalDbData.Tabelle[ctx.tbl] = [];\n                    if (!window.configOriginalDbData.Tabelle[ctx.tbl][ctx.idx]) window.configOriginalDbData.Tabelle[ctx.tbl][ctx.idx] = {};\n                    window.configOriginalDbData.Tabelle[ctx.tbl][ctx.idx][ctx.key] = row[ctx.key];\n                    if (dbVersion) window.configOriginalDbData.__db_version = dbVersion;\n                } catch(e) {}\n            }\n            if (!window.modifiedFields) window.modifiedFields = new Set();\n            try { window.modifiedFields.delete(ctx.tbl + '-' + ctx.idx + '-' + ctx.key); } catch(e) {}\n            if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            \/\/ 30.9.1527: nessun render completo; conserva scroll, details aperti e riga corrente.\n            try {\n                var root1527 = document.getElementById('ti-conf-ov');\n                if (root1527) root1527.querySelectorAll('[data-tbl][data-idx][data-key]').forEach(function(inp){\n                    if (String(inp.getAttribute('data-tbl') || '') !== String(ctx.tbl) || String(inp.getAttribute('data-idx') || '') !== String(ctx.idx) || String(inp.getAttribute('data-key') || '') !== String(ctx.key)) return;\n                    inp.value = row[ctx.key];\n                    try { inp.dispatchEvent(new Event('input',{bubbles:true})); } catch(e1527input) {}\n                });\n                window.currentDbViewData = null;\n                if (window.syncConfigTableAfterRowMutation) window.syncConfigTableAfterRowMutation(ctx.tbl);\n            } catch(e1527layout) {}\n        } catch(e) {}\n    }\n    function attachField(db, ctx, filename, stagedMeta1596){\n        ctx = saveCtx(ctx);\n        if (!ctx) return Promise.reject(new Error('Contesto riga\/campo non disponibile.'));\n        if (stagedMeta1596 && stagedMeta1596.association_pending_1596 === true && typeof window.tiFileManagerStageUploaded1596 === 'function') {\n            window.tiFileManagerStageUploaded1596(ctx, stagedMeta1596);\n            return Promise.resolve(stagedMeta1596);\n        }\n        return post('ti_ai_media_attach_field', {db:db, tbl:ctx.tbl, idx:ctx.idx, id:ctx.id || ((rowFor(ctx) && rowFor(ctx).ID) || ''), key:ctx.key, file:filename}, null, 120000).then(function(d){\n            if (!d || !d.success) throw new Error(d && d.data && d.data.message ? d.data.message : 'Associazione non riuscita.');\n            var data = d.data || {};\n            applyLocal(ctx, data.name || filename, data.value || '', data.db_version || '');\n            return data;\n        });\n    }\n    function finishManagerSuccess(ctx, name){\n        try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'File pronto in bozza', {notifyUser:false}); } catch(e) {}\n        try { if (window.closeModal) window.closeModal('ti-ai-gen-ov'); } catch(e) {}\n        try { if (window.openFileManager) setTimeout(function(){ window.openFileManager(ctx.tbl, ctx.idx, ctx.key); }, 150); } catch(e) {}\n    }\n\n    var prevOpenFM = window.openFileManager;\n    if (typeof prevOpenFM === 'function' && !prevOpenFM.__tiSavePc471) {\n        window.openFileManager = function(tbl, idx, key){\n            var ctx = saveCtx({tbl:tbl, idx:idx, key:key});\n            var ret = prevOpenFM.apply(this, arguments);\n            try {\n                var fm = byId('ti-file-manager-ov');\n                if (fm && ctx) { fm.dataset.tbl = ctx.tbl; fm.dataset.idx = ctx.idx; fm.dataset.key = ctx.key; fm.setAttribute('data-ti-context-table', ctx.tbl); fm.setAttribute('data-ti-context-row', ctx.idx); fm.setAttribute('data-ti-context-field', ctx.key); }\n            } catch(e) {}\n            return ret;\n        };\n        window.openFileManager.__tiSavePc471 = true;\n    }\n\n\n    var prevUseAI = window.useAIGen;\n    window.useAIGen = function(){\n        var filename = window.currentGenFilename;\n        if (!filename) { if (window.tiAlert) window.tiAlert('Nessuna immagine generata da associare.'); return false; }\n        var ctx = readCtx();\n        if (!validCtx(ctx)) {\n            if (window.tiAlert) window.tiAlert('Immagine generata, ma contesto riga\/campo non disponibile. Non chiudo la preview: riapri Gestione File Associati dalla riga corretta oppure scarica\/rigenera.');\n            return false;\n        }\n        var db = dbName();\n        setBusy(true, 'Preparazione immagine...');\n        try { if (window.showProgressPopup) window.showProgressPopup('Preparazione immagine', 'Carico l immagine nello storage. L associazione verra salvata solo con il tasto Salva della Gestione File Associati.', {startPercent:15, targetPercent:88, stepMs:500, cancellable:false}); } catch(e) {}\n        var cleanupToken1596 = (typeof window.tiFileManagerCreateToken1596 === 'function') ? window.tiFileManagerCreateToken1596() : ('fm1596_' + Date.now() + '_' + Math.random().toString(36).slice(2,10));\n        post('ti_ai_media_upload', {db:db, tbl:ctx.tbl, temp_file:filename, record_label:recordLabel(ctx), mode:'attach', defer_association:'1', guided_upload_target:'manager', upload_cleanup_token:cleanupToken1596}, null, 180000).then(function(d){\n            if (!d || !d.success) throw new Error(d && d.data && d.data.message ? d.data.message : 'Salvataggio file AI non riuscito.');\n            var data1596 = d.data || {};\n            var name = (data1596.name || data1596.filename) ? (data1596.name || data1596.filename) : filename;\n            data1596.upload_cleanup_token = data1596.upload_cleanup_token || cleanupToken1596;\n            data1596.association_pending_1596 = true;\n            data1596.mode = 'attach_pending_1596';\n            return attachField(db, ctx, name, data1596).then(function(){ return name; });\n        }).then(function(name){\n            setBusy(false);\n            finishManagerSuccess(ctx, name);\n        }).catch(function(err){\n            setBusy(false);\n            try { if (window.hideProgressPopup) window.hideProgressPopup(false, 'Errore salvataggio immagine'); } catch(e) {}\n            if (window.tiAlert) window.tiAlert('Errore salvataggio immagine AI: ' + (err && err.message ? err.message : 'errore rete') + '. La preview resta aperta: puoi riprovare senza perdere l immagine.');\n        });\n        return false;\n    };\n})();\n<\/script>\n\n\n<script id=\"ti-config-email-sms-flow-479\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigEmailSmsFlow479Installed) return;\n    window.__tiConfigEmailSmsFlow479Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function clean(v){ return String(v == null ? '' : v).replace(\/\\r\/g, '').trim(); }\n    function setReply(html){\n        var rb = byId('ti-conf-ai-reply');\n        if (rb) { rb.style.display = 'block'; rb.innerHTML = html; }\n    }\n    function clearPrompt(){\n        var p = byId('ti-conf-ai-prompt');\n        if (p) { p.value = ''; try { p.focus({preventScroll:true}); } catch(e) {} }\n    }\n    function dbName(){ return (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : 'NEW_DB'; }\n    function makeFd(action, data){\n        var fd = new FormData();\n        fd.append('action', action);\n        fd.append('ti_action', action);\n        Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k] == null ? '' : data[k]); });\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        return fd;\n    }\n    function post(action, data){\n        var urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (window.ajaxurl && urls.indexOf(window.ajaxurl) === -1) urls.push(window.ajaxurl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            var controller = null, timer = null, done = false;\n            var opts = {method:'POST', body:makeFd(action, data || {}), credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller = new AbortController(); opts.signal = controller.signal; } } catch(e) {}\n            return new Promise(function(resolve, reject){\n                timer = setTimeout(function(){\n                    if (done) return;\n                    done = true;\n                    try { if (controller) controller.abort(); } catch(e) {}\n                    reject(new Error('Timeout invio: il server non ha risposto. Verifica API Key Infobip, endpoint, firewall\/hosting e, per utenti non amministratori, stato ditta non Demo.'));\n                }, 70000);\n                fetch(urls[i], opts).then(function(r){\n                    return r.text().then(function(raw){\n                        if (!r.ok) throw new Error('HTTP ' + r.status + ': ' + raw.slice(0, 240));\n                        try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non JSON: ' + raw.slice(0, 240)); }\n                    });\n                }).then(function(res){ done = true; resolve(res); }).catch(function(err){\n                    if (done) return;\n                    done = true;\n                    if (i + 1 < urls.length) attempt(i + 1).then(resolve).catch(reject);\n                    else reject(err);\n                }).finally(function(){ try { clearTimeout(timer); } catch(e) {} });\n            });\n        }\n        return attempt(0);\n    }\n    function validEmail(v){ return \/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(clean(v)); }\n    function extractEmail(v){ var m = clean(v).match(\/[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\/i); return m ? m[0] : ''; }\n    function normalizePhone(v){\n        var s = clean(v).replace(\/[^0-9+]\/g, '');\n        if (s.indexOf('00') === 0) s = '+' + s.slice(2);\n        return s;\n    }\n    function validPhone(v){ var s = normalizePhone(v); return \/^\\+?[0-9]{8,15}$\/.test(s); }\n    function wantsConfigSend(text){\n        var t = clean(text).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'');\n        if (!t) return false;\n        var action = \/\\b(invia|manda|mandare|spedisc|inoltra|trasmetti|scrivi)\\b\/.test(t);\n        var channel = \/\\b(email|e-mail|mail|sms|messaggio|telefono|telefonico)\\b\/.test(t);\n        return action && channel;\n    }\n    function channelsFrom(text){\n        var t = clean(text).toLowerCase();\n        var ch = [];\n        if (\/email|e-mail|mail\/.test(t)) ch.push('email');\n        if (\/sms|telefono|telefonico\/.test(t)) ch.push('sms');\n        if (!ch.length && \/messaggio\/.test(t)) ch.push('sms');\n        return ch.length ? ch : ['email'];\n    }\n    function askNext(flow){\n        window.__tiConfigCommFlow479 = flow;\n        if (flow.channels.indexOf('email') !== -1 && !flow.email) {\n            flow.stage = 'ask_email';\n            setReply('<b>Invio email da Configurazione<\/b><br><br>Indica l\\'indirizzo email del destinatario.<br><small>Scrivi NO per annullare.<\/small>');\n            clearPrompt();\n            return true;\n        }\n        if (flow.channels.indexOf('sms') !== -1 && !flow.phone) {\n            if (window.tiIsDemoCompany1702 && window.tiIsDemoCompany1702() && !(window.tiDemoAdminFullAccess1709&&window.tiDemoAdminFullAccess1709())) {\n                flow.channels = flow.channels.filter(function(c){return c!=='sms';});\n                flow.phone = '';\n                if (flow.channels.indexOf('email') === -1) {\n                    window.__tiConfigCommFlow479 = null;\n                    setReply('<b>\u26a0\ufe0f Ditta Demo<\/b><br><br>SMS e invio al telefono non sono gestiti in modalit\u00e0 Demo. Usa il canale Email.');\n                    clearPrompt();\n                    return true;\n                }\n                setReply('<b>\u26a0\ufe0f Ditta Demo<\/b><br><br>SMS e invio al telefono non sono disponibili. Procedo con il canale Email.');\n                clearPrompt();\n                return askNext(flow);\n            }\n            flow.stage = 'ask_phone';\n            setReply('<b>Invio SMS da Configurazione<\/b><br><br>Indica il numero telefonico del destinatario.<br><small>Scrivi NO per annullare.<\/small>');\n            clearPrompt();\n            return true;\n        }\n        if (!flow.text) {\n            flow.stage = 'ask_text';\n            var dest = [];\n            if (flow.email) dest.push('email: <b>' + esc(flow.email) + '<\/b>');\n            if (flow.phone) dest.push('SMS: <b>' + esc(flow.phone) + '<\/b>');\n            setReply('<b>Testo da inviare<\/b><br><br>Destinatario: ' + dest.join(' + ') + '.<br>Scrivi ora il testo del messaggio da inviare.<br><small>Scrivi NO per annullare.<\/small>');\n            clearPrompt();\n            return true;\n        }\n        return sendFlow(flow);\n    }\n    function startFlow(text){\n        var flow = {stage:'start', channels:channelsFrom(text), email:'', phone:'', text:''};\n        window.__tiConfigCommFlow479 = flow;\n        return askNext(flow);\n    }\n    function cancelFlow(){\n        window.__tiConfigCommFlow479 = null;\n        setReply('Invio email\/SMS annullato.');\n        clearPrompt();\n        return true;\n    }\n    function handleFlowInput(text){\n        var flow = window.__tiConfigCommFlow479;\n        if (!flow) return false;\n        var raw = clean(text);\n        if (\/^(no|annulla|annullare|x|stop|esci)$\/i.test(raw)) return cancelFlow();\n        if (flow.stage === 'ask_email') {\n            var email = extractEmail(raw);\n            if (!email || !validEmail(email)) { setReply('Email non valida. Indica solo un indirizzo email valido, oppure scrivi NO per annullare.'); clearPrompt(); return true; }\n            flow.email = email;\n            return askNext(flow);\n        }\n        if (flow.stage === 'ask_phone') {\n            var phone = normalizePhone(raw);\n            if (!validPhone(phone)) { setReply('Numero telefonico non valido. Indica solo il numero per SMS, anche con prefisso internazionale, oppure scrivi NO per annullare.'); clearPrompt(); return true; }\n            flow.phone = phone;\n            return askNext(flow);\n        }\n        if (flow.stage === 'ask_text') {\n            if (raw.length < 2) { setReply('Testo troppo breve. Scrivi il testo da inviare, oppure NO per annullare.'); clearPrompt(); return true; }\n            flow.text = raw;\n            return askNext(flow);\n        }\n        return false;\n    }\n    function sendOne(flow, channel){\n        var data = {db:dbName(), subject:'Comunicazione Configurazione', history:flow.text, admin_copy:'0'};\n        if (channel === 'email') {\n            data.email = flow.email;\n            data.send_email_opt = '1';\n            data.send_sms_opt = '0';\n        } else {\n            data.email = flow.phone;\n            data.send_email_opt = '0';\n            data.send_sms_opt = '1';\n        }\n        return post('ti_ai_send_email', data).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) || (res && res.message) || 'Invio non riuscito');\n            return res.data && res.data.reply ? String(res.data.reply) : 'Invio completato.';\n        });\n    }\n    function sendFlow(flow){\n        var btn = byId('ti-conf-ai-send');\n        var old = btn ? btn.innerHTML : '';\n        if (btn) { btn.disabled = true; btn.innerHTML = 'Invio in corso...'; }\n        setReply(flow.channels.indexOf('sms') !== -1 && flow.channels.indexOf('email') === -1 ? 'Invio SMS in corso...' : 'Invio in corso...');\n        var tasks = [];\n        if (flow.channels.indexOf('email') !== -1 && flow.email) tasks.push(sendOne(flow, 'email').then(function(r){ return 'Email: ' + r; }));\n        if (flow.channels.indexOf('sms') !== -1 && flow.phone) tasks.push(sendOne(flow, 'sms').then(function(r){ return 'SMS: ' + r; }));\n        return Promise.all(tasks).then(function(results){\n            if (btn) { btn.disabled = false; btn.innerHTML = old || 'Invia'; }\n            window.__tiConfigCommFlow479 = null;\n            setReply('<b>Invio effettuato.<\/b><br><br>' + esc(results.join('\\n')).replace(\/\\n\/g,'<br>'));\n            clearPrompt();\n        }).catch(function(err){\n            if (btn) { btn.disabled = false; btn.innerHTML = old || 'Invia'; }\n            setReply('<b>Invio non riuscito.<\/b><br><br>' + esc(err && err.message ? err.message : 'Errore sconosciuto') + '<br><br>Controlla anche: API Key Infobip, sender ServiceSMS abilitato, numero con prefisso internazionale, stato ditta non Demo per utenti non amministratori, connessione server verso https:\/\/6zgm1d.api.infobip.com.<br><br>Il testo non \u00e8 stato perso: puoi correggere il destinatario o riprovare.');\n            clearPrompt();\n        });\n    }\n    function install(){\n        if (typeof window.runConfigBot !== 'function' || window.runConfigBot.__tiConfigEmailSms479) return;\n        var prev = window.runConfigBot;\n        window.runConfigBot = function(){\n            var box = byId('ti-conf-ai-prompt');\n            var text = box ? box.value : '';\n            if (window.__tiConfigCommFlow479) return handleFlowInput(text);\n            if (wantsConfigSend(text)) return startFlow(text);\n            return prev.apply(this, arguments);\n        };\n        window.runConfigBot.__tiConfigEmailSms479 = true;\n        var btn = byId('ti-conf-ai-send');\n        if (btn) btn.onclick = window.runConfigBot;\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', install);\n    install();\n    setTimeout(install, 300);\n    setTimeout(install, 1200);\n})();\n<\/script>\n\n\n\n<script id=\"ti-config-ai-order-sms-final-fix-483\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigAiOrderSmsFinalFix483) return;\n    window.__tiConfigAiOrderSmsFinalFix483 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function htmlToText(html){\n        try { var d=document.createElement('div'); d.innerHTML=String(html||'').replace(\/<br\\s*\\\/?\\s*>\/gi,'\\n'); return String(d.innerText||d.textContent||'').trim(); }\n        catch(e){ return String(html||'').replace(\/<br\\s*\\\/?\\s*>\/gi,'\\n').replace(\/<[^>]+>\/g,'').trim(); }\n    }\n    function normalizeFileKey(v){\n        var s = String(v == null ? '' : v).trim();\n        try { s = decodeURIComponent(s); } catch(e) {}\n        s = s.replace(\/^https?:\\\/\\\/[^\\\/]+\/i,'');\n        s = s.replace(\/[?#].*$\/,'');\n        s = s.replace(\/\\\\\/g,'\/').replace(\/\\\/+\/g,'\/').toLowerCase().trim();\n        return s;\n    }\n    window.tiDedupeOrderFileValues483 = function(values){\n        var seen = {}, out = [];\n        (values || []).forEach(function(v){\n            var raw = String(v == null ? '' : v).trim();\n            if (!raw) return;\n            var key = normalizeFileKey(raw);\n            if (!key || seen[key]) return;\n            seen[key] = true; out.push(raw);\n        });\n        return out;\n    };\n    window.tiDedupeOrderLinkedFiles483 = function(files){\n        var seen = {}, out = [];\n        (files || []).forEach(function(f){\n            if (!f) return;\n            var key = normalizeFileKey(f.raw || f.url || f.name || '');\n            if (!key || seen[key]) return;\n            seen[key] = true; out.push(f);\n        });\n        return out;\n    };\n\n    function appendConfigChat(speaker, text){\n        var p = byId('ti-conf-ai-prompt');\n        if (!p) return false;\n        var msg = String(text || '').replace(\/\\[NO_VOICE\\]\/g,'').trim();\n        if (!msg) return false;\n        var cur = String(p.value || '').trim();\n        var label = speaker || 'AI';\n        var chunk = label + ':\\n' + msg;\n        if (cur.slice(-chunk.length) === chunk || cur.indexOf(chunk) !== -1) return true;\n        if (cur && !\/(^|\\n)(Utente|AI):\/i.test(cur)) cur = 'Utente:\\n' + cur;\n        p.value = (cur ? cur + '\\n\\n' : '') + chunk + (label === 'AI' ? '\\n\\nUtente:\\n' : '\\n\\n');\n        try { p.dispatchEvent(new Event('input', {bubbles:true})); } catch(e) {}\n        setTimeout(function(){ try { p.focus({preventScroll:true}); p.selectionStart = p.selectionEnd = p.value.length; } catch(e){} }, 30);\n        return true;\n    }\n    window.tiAppendConfigAiToUnifiedChat483 = function(text){ return appendConfigChat('AI', text); };\n\n    function forceConfigAiUi(){\n        var p = byId('ti-conf-ai-prompt');\n        if (p) {\n            p.setAttribute('placeholder','Scrivi una domanda o una istruzione di configurazione. La risposta AI resta visibile sotto il campo.');\n            p.style.minHeight = '150px';\n            p.style.lineHeight = '1.45';\n        }\n        \/\/ 30.9.2031: non cancellare la risposta. Il vecchio hotfix 483 la nascondeva a ogni MutationObserver,\n        \/\/ producendo il flash visto dal Configuratore.\n        var rb = byId('ti-conf-ai-reply');\n        if (rb && rb.getAttribute('data-ti-config-ai-persistent-2031') === '1') { rb.style.display = 'block'; rb.removeAttribute('aria-hidden'); }\n        var buttons = Array.prototype.slice.call(document.querySelectorAll('button'));\n        buttons.forEach(function(btn){\n            var t = String(btn.textContent || '').trim().toLowerCase();\n            var near = btn.closest && btn.closest('#ti-conf-ai-chat-actions, [id*=\"conf-ai\"], div');\n            if ((t === 'istruzioni & indicazioni' || t === 'invia istruzione' || t === 'invia') && (btn.id === 'ti-conf-ai-send' || (near && (near.id === 'ti-conf-ai-chat-actions' || (near.innerHTML || '').indexOf('ti-conf-ai-prompt') !== -1)))) {\n                btn.id = 'ti-conf-ai-send';\n                btn.textContent = 'Invia';\n                btn.style.setProperty('background','#10b981','important');\n                btn.style.setProperty('color','#fff','important');\n                btn.style.setProperty('font-weight','800','important');\n                btn.onclick = function(ev){ if (ev) ev.preventDefault(); if (window.runConfigBot) return window.runConfigBot(); return false; };\n            }\n        });\n    }\n\n    var prevSet = window.setConfigAiReplyHtml;\n    window.setConfigAiReplyHtml = function(replyBox, html, plainText){\n        var text = plainText != null ? String(plainText) : htmlToText(html);\n        if (replyBox) {\n            replyBox.style.display='block';\n            replyBox.removeAttribute('aria-hidden');\n            replyBox.setAttribute('data-ti-config-ai-persistent-2031','1');\n            replyBox.innerHTML = String(html || '').trim() ? String(html) : esc(text).replace(\/\\n\/g,'<br>');\n        }\n        forceConfigAiUi();\n        return true;\n    };\n    if (prevSet && !prevSet.__tiReplacedBy483) window.setConfigAiReplyHtml.__prev = prevSet;\n    window.setConfigAiReplyHtml.__tiReplacedBy483 = true;\n\n    var prevRender = window.renderConfig;\n    if (typeof prevRender === 'function' && !prevRender.__tiFinalFix483) {\n        window.renderConfig = function(){\n            var ret = prevRender.apply(this, arguments);\n            setTimeout(forceConfigAiUi, 0); setTimeout(forceConfigAiUi, 120); setTimeout(forceConfigAiUi, 500);\n            return ret;\n        };\n        window.renderConfig.__tiFinalFix483 = true;\n    }\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var b = t.closest('button');\n        if (!b) return;\n        var label = String(b.textContent || '').trim().toLowerCase();\n        if (label === 'istruzioni & indicazioni' || (b.id === 'ti-conf-ai-send' && label === 'invia')) {\n            try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {}\n            if (window.runConfigBot) return window.runConfigBot();\n        }\n    }, true);\n    if (typeof MutationObserver !== 'undefined') {\n        try { new MutationObserver(function(){ setTimeout(forceConfigAiUi, 20); }).observe(document.documentElement, {childList:true, subtree:true}); } catch(e) {}\n    }\n\n    function extractLatestUnifiedUserPrompt(raw){\n        raw = String(raw || '').replace(\/\\r\/g, '').trim();\n        if (!raw) return '';\n        if (!\/(^|\\n)(Utente|AI):\/i.test(raw)) return raw;\n        var last = '';\n        var re = \/Utente:\\s*\\n?([\\s\\S]*?)(?=(?:\\nAI:\\s*\\n?)|$)\/gi, m;\n        while ((m = re.exec(raw)) !== null) {\n            var chunk = String(m[1] || '').trim();\n            if (chunk) last = chunk;\n        }\n        if (last) return last;\n        return raw.replace(\/^[\\s\\S]*Utente:\\s*\\n?\/i, '').trim();\n    }\n\n    function ensureShopServiceIcon(el, size){\n        if (!el || !el.insertBefore || el.querySelector('.ti-shop-service-logo-icon')) return;\n        var src = \"data:image\\\/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAIAAAD2HxkiAACAAElEQVR42pT9d5Bl2XkfCH6\\\/c81zaasyKyursryv7q6q9mg0PNDwoABIICmSIEWRM2KENLuamJg\\\/JmJnJ2J3R7E7sSNp5HaW4oxEkSMStABBEQJAgN1Ao72rNmW7bFZVevf8u\\\/ee8+0f55pz7r0vqxeo7s7KfPnMveecz\\\/0MaPQhYiIwSP8v+W\\\/xb2x+BULyHRR+izh7MHI\\\/in+L0x9y7jEofAnrdZOnZtY\\\/AAMg\\\/f\\\/kmdl6JAHZX5myxxXeGpV8eFgfkDn7gMb3kL1D\\\/QOYr5NdBs5dE86eqeQyWhe9\\\/PowW49KPikz67ee3KLk7UC\\\/Yc6uV\\\/rd9K9K5V6H2bpeKLmt9gXXr0HmXWGCeaGGLA\\\/rpnD+I8fvI1mr5XfQXFnZUtEvhOyaM9LFkr2UviwYcguY7EdnuwCIn5Bzt4jz9xDJcjG+6dp3ObcDWb+rkpWQfUAk95g4fjAbrzd0RcH8jv4VxNeJOVs5ADEz9AsQzCdB4an06xOXvDaMfYls+cNYV\\\/alyt9gtg8LmLsMw3dwycYCbbMDQcRDrrh5EZFbDMMeEH9tHQDZ2rEPwvSF9X2I70LyhoqHI3N2PWDfT4qPgCE3vbDhYLwSW5eY073B2T4ZdmXNBWmFDH0smVfeCDkMNo4oDD8B2To6rNvEhSOUt7l7+bUmjIuI7CS13ypQ3Dfm3SCOD5t4LxHS6IEhgTQLM4TkV3QcYS6elZzu1fRSIndQc8lOsU9l87jOFgnnNjXK7615WBR3GWDtz5KFEX9OQrrKrDPMvri5VylZdTxsqRjvMLtp+rxA8ur50z+L4cmdNC5FyQmDYixkIk5fm83XZ+tcy++U9AODjSzC2EXpjorfN3Cf7EUvBs5tgnRJljzYvLDYLjvKngLMSK5W8QKw8U1sd1wkjxK58MvpWjHPaza2e7JvCmEz9x2UvziMBA\\\/3O9CSfWcHXhByuyD\\\/blF8a8m248LNAJekidbq5PItYa9B3u5Kp0ssjcpMhXWy7cHJw4\\\/X+y3LIaGaMHRtFuOVvUo5WXPMua1c\\\/vZgfoV4qVjPyuYyh51pcnbXkdxGDL0XxXCH0lzVWLRZwOBtY5l5Bm8b6ZAPedveaohtKrb7Fij2m+f7BGPYRZa5gbj4G+DSRWMl3bDrRravVvpiYM4ibfl14HzBGMfnknvI2Y7iZCFut0XsC8LldwT5G8zWrwDZGceFD8D32ZCII40VxoygAgzLaGEHtPSvMPckl4W77OKbsShLGZiIYZYDyF4p3qhsl1YMLkttiyWcUZ4U7zcKNS2SzBelV+J+i3LYMYBh15WLtawoT31gZ+cYfouZ7ns6F7\\\/OLfjSQ61sB7BRXg9bP+YFQ66rkmyi+AplSWKSpZqbAcM+oZWWo+wGYOiNGbpHUbgPMK+MuZZRSI\\\/K3pgZCFHS9onfKYBiY6wQ38xTwLxmabbLxvVA8d3BXpVxbhz30+xqMw5ObKY9yTMi\\\/scquJnLz\\\/vk0cWlxLmohny7YUgEgRHLUZqHJQ9hpG0F3HfbsDAqeOasD1ZWoAKcT1StFZSe1bh\\\/RMj\\\/rfBW40SH7UWcxN0hLVdjtcT\\\/ZSM34azJhuxDp\\\/2RwrUZ1j9lNp93aOf3AxxYGLKPUShS7UiKYqfFKsHsFYZ8fZYvBLhYbyJXSxWPMuPXYa+1fDoRbx4uidn5pzWTgPRATLYic0lLL9dDZ7pfTmKkAYUCE4WgaWRZbBwt+sCONxynx1namtZNPyYryxvSRmMWTAxm69As9iCGnCC5O212\\\/Mz+Cm9bUfF2MZWLRz0P706nPwbbgYoLmUS+FZ4WObkXLXud7RKD\\\/GonI7MorN60TY6SDD95x1yWVeQ+nJXPc66pRcU0LjvNrKMOhTTKOg24\\\/AaiUPgVjyZQ6ZYzNl3pX1GeeJt1F9sxA1SoJ7cZYsQ5EQ9LJEoCGZc1aoyKjNODi+9\\\/GgytCcv3Sb4WTkN9cWqBrBeC8vr2fkHCKojYTErYOH7ZbFfZaV16SsXvCcb6QnGWidLPe5\\\/DFEbmuW2nwMqdkOvCouycS898mOfOkEQC+ZzLTAiHZOz57W38CuvNhlzLd1j8zr0q7PoO6fFTPADKFgKXtR3YOLqQFY1DVmlap27fsbJPLdyvf7nNDDc+tdJQxvmiumTmaYXgeESBfJVdfsSzLvCz3YeSojd+\\\/TQgDR1SsDn7KC+u08kp4krdOsbSQiHbnCjZKiW91OR7Rk2Yb90WZkYo22plqzzX+rPLHgzNOs3IBipLE\\\/Nz+XzX0r75923lF1qfQFn0AcqWLoqTK+tw2r6nh+EtJKM+S7v+WcxLcz97XIHyrKE0\\\/ber29JO2JDqgIfWEekELC55mJOdzeXTpfhOJj91OX8DYQ5ZkBQh6aQOiP+VtpWyyJvb9zEKx8oQuPz0sgfUMHtRhU2M3N+y9qLdY4YxnUdJ69YKibhv77nkTCJ7mp1NSnMftnRCSsWurj7gstInl\\\/7jA\\\/TFkJujY7vmaXadczAQ+37kU6skt2AjcWcqy+XKB5nIYkt+8Fpa0jEXG3R2VgoiFuWRFeXf42H3oLDUrJOPGUg2CLIGSrq5YL493qZUYWMwABe5\\\/Hl46QQUWjFGgz3tPCMbD+efgVn3gmEWdmVVqznGMd67AWrgYu2K8vduJbFA7qIO23M87CTlYhHK+Sab+c0MdFTat7CODqP5AAyd83D6bDxsg0Ekr8zlqyyPdEneOptHVjJeLRkCpTkOrOY9l4+400Oa80A73HeYBi7cpOTFOVtKJq7LuHTg4ekl3+\\\/OcvmRZCxLLtvRXLhV2x7iAJHIdanYSrjsA9DouOj+T4xQJLaRGMUGRTqIoTJoKJX2wc03YcU3mNcSw6fNQDFC53ee1e0HUFbwlA0RtpvCmAWBOZ8s7lUuiZNGBx5Wzz6dJmRVFgjbjMaz383NOmDl1WyUz0xgZOAxZto2RRiGzbBS\\\/HjZoGSbMuVnsmUbhoFc3g1YZW1ZSQ8My\\\/nzZ2wugUdpD4zJbjIMWRJlg\\\/RhiZzxP9e825wfnCDtiHN2gCBX3dtzhhjJaqAceJvWQtkpbsU14xhNR6zgQsMDhe3PeeR11kSBkQexkf+V4R1zaRBKU7\\\/7tba2BdHmfo2HIwrIBFnSfZLMoe3jbTpwyGNVrBiI+2BazZhhVZlcGo9hn6dDEbMAl5RVheKGt7m+GDqizl0loKQyskET5VmX+RQp+BkYkmgZRUeyCS2oKLM9ujSSx4SzUHJJQWBwbrZjZA+8\\\/RFhlERGDWlOluykyT42E5g5mwsp36ouaZ8w2z\\\/CfQpALpsXGmsU5dkt0\\\/2ab2XnNMjEl5ttfyM8lSRQyGVt1taCXRFt00KEkYqyVWrGaOqh6UURZ0PmtYHVZcpnc8ixa8zZkvHmk6CKXKIMa70CxlHMJSUNEqZHcrjGubiBQExWO5A1rWFf3eRotlKBBAGPXGJbPNqIiIR5wbisOM7NqTjJNLLcCRmVgq2sP9lFjCEN6HzbjTltC4Hvs1jNsRU4bUiVPK\\\/ZJQeVZDLYpvNhDLy374swbxPfymfytN3kbWihVbiXyCWfKB\\\/5D4mOBpLKTFOZrO9YIxMUh4Fm14aHTfZwnzY\\\/kpl3SmLJZg3gfFyzqyZrKmP1j0p7vrn2vNXOhAU\\\/hXUC5nLUktZhllYB2yOCs0gIO7YxzMZw\\\/o6nIOi0FcM5zAInJ1QuhHLpSZCvlmGcLen5wsZJw7nKuzBnNnpWGLYZMlYGrNmVfQPYBvuitNItOeTYyBZKW008ZOo\\\/7LcwvLk8FDYAsmKFHX+GnBRcfndQ3DFM9x\\\/DsUnxLPaG2SpAeNjZxSbBCMy6O2ncDR7SQuMC7zJduFROdsu\\\/vFmk2PvNRtOWNLyRrNnyM7RwE0Q+V+TyK29EVmOfmdveOIw5JSXlBjDYhtshEoiuwbQZksZuFyR52Pzd5Jwg1zyzo5gxvAS2mb\\\/aOCuDzMK56XS+q4CSM5LzDRoMqephNuh425iLYQX30LCdm3tRKc9rCIfGnu\\\/jvpU\\\/LNwQcjGK7LF\\\/liQbqG8ur91z1JMUmAk2CIt59EaxRkQRHVjoJ1lQsW2aeGWNNDZqwvy6yRXmRbSAQbAsOSTZ2EPmlK6s2IdR8PKQCMDlw2MupShbTSa2ome+8wUTrWdRxrMDk6yZG3LlOZOVaW+TNsd32xyRZVxoM00oQXrAqkSsKSQY5UlOoUfF9iXNpaf5cQiyji4+wBlo9uvL2z9cWrNaeQEKV1NHPSptlLF1ENmRMS1ak4hsoIrzobIA\\\/0YJ5JBQNqrMBfdhoBrrOUvRyEzkFnp8Zg+E2Q6fKUM5zjez3kGR0Y5CR75wWjFsrYuSTnNyRuT6MTBCPoZkVsnIBSZydAjRwMLDFeCXhY9l7CUewmE1GOs2kdBo\\\/7IFLjV6GkzDBA9QsviHBxyzm51yKouMSh46r+PS5CtrRfEwEML92uFU1tmOCfRGH6nkyprpi7GTNWgkrWPSbLYEsIUEUZtLKXibrDgntYBthrTD92EiWZAn\\\/gs78MOYHrGB\\\/bNiNGIOHXNhKlbG9E1\\\/rfieLZhuMb8p58kjxwne\\\/uNznr1vvdUirBPleHOg8InyZ5YVcWGSl4tho4h3Q5YbZXh842Gcz5NRKl+wTRcom\\\/LATgqRB7WW9cxiiATSRZ9\\\/3vsNYEqHmSg7VswDBoUjyR4kMRuDKzMlHs4dK+3eZcQjY4rKQweifJ9WS2m\\\/eejIVeSvzJB6BpYyS\\\/qEdiLMZYm8OQmCPU\\\/FNoAJNvSSigVQToIJOcBknqCmB5gAD1uupR0OtquXRB4inp2gJMG2V1I6KdlmRAG7kAZTKXe1VIUAhRdHnugD+66ymVTArg7LeQtWycqpKg4KvA1sewJsJx3CxeaQge7g3H5gsxjKpjZcwlkrOVqQv3YWy5GNdrrd5TUovyUFCBcbxMQlokWlZH1AD+utgRZgy0qZfHbr+purkIszQ+RG5\\\/m5Uf5JUrSABduzPngaqTCk1i3cy3wf34bbWP1PlFakVvsurSQBFBqzZRV4Ou60Xo+HDucoVbcyYYglQZjZ4qwMzYiSLQMmU\\\/oMbOAMyQKAWW1t4xhPRmpkiW7ZeS8ska\\\/7Iga2+YLzyQzMI2Q4TNsCKFp9cv0RuJRuwGaXgssHv1wcrzKs8ah1GnHZkJmH9LfdQkcHbGdyuayuBHcEW8iqZIaM7b9j7xxzcFogEtgpbjnQFXlcf\\\/oDtict5fgYMNl9pcJCYR7epId5ZOgSIIdD3D6NNroR9qGbpQ1civMYnhMx58mqnNarWdVtJyEFWEJaY5sILrsmLPbJUL6XP1gVUQZ8twmFGNoRS9cy8nkr2xD\\\/Qv3LhVdJpi1FDCsNabSUAWPT\\\/gTbRyQTwSUaBtOhYZl+3B4FD23CZrKFJfpHDNwnSS+b9aCQ1xVaF6J8\\\/IUMZG4MGrfJ5MFDUDRmPEyfKbeq2JzJITem2r55lp72uVcvqGzm4Ei5Riuo5NTdTmoVhTnSfYocHoqa5OJyyEanMDrDzFS6h4xVmoVfUInqiJUHcdn01VK3LG1B5W8BD515WscgZ7Pyoqgo3XcGaR4jDE4jYalkEnNp1Q1LuQ9WRGIaEpaRF7oyv5FW11zSjrZCMQ9J4oYMo4yuSZFxmKmklmM9UYBeMedp6PZ80fgIZVpbsBKNIYd8cQfBzorz2nAWbKpUu9QuCQzG8FCuDYacE6UzwPtAmxJWGw8ZTgwbsmj4GGwtXxSiENu5Yk6AV0sOD4+YuWk758ZgXDY8xzbn6Pa9ay4NdromZE77tiXPygW1gCQJRVqoF5L0QgGcL95QlADlXJJZqLXY2jM2rxSlqoXbYnSG4Fc5xu7kwBDgcjRDvgmOuNguJC9MJjK3XG6Gh1PbShKdJDnnYfvCLntyDL6hos\\\/ljdViv6v03g\\\/v1Oag0ObToFCUgGzJ8JJsLvvgnIdkmUGPPwjk3J4I5md2yE9soTVhhit9lc9J4x1jILbin7tmXYec8EG6oLKMolj7FTsrKOXdFeMAlw++yqaFpV042D3SsgFJkbNkD7vYJjzlRq5l05HsIpbPb5kS+Hy+FcuczGm4kL\\\/mWKpDsG9DThaUVgUwRl\\\/Y\\\/tQuSUJhs1hQtrFz8kvI37PyXDMXqxklUIQ8bNKqzswCO3siDCPzb5ddlxDvUJq\\\/JX0AIF9lfKCwaHWms8WTLE83uxYld4qL6VtWFJQ00RK58iInqmQpIDfILLsuwyQ0QNtOUpJVAGSSfAasILt9sGwZzFEv0xAIX+6Wo5zwXxCGN9qdBaYyU8lL3F\\\/od5vKo8DwN+tKbCPXxeUKuDwkphWXf7JVOB+fYPUmyxt29lMW60CwvduRJUdDGxucn+5ZhduwJiLbCXB69HIJ3clu7TMNfcrS4EQmn9BMvQ0YiIGKyapp5FYX2EaAGEWVSXPOYK3GjmAu7cIUi+9yKRcmaJ4rrD4\\\/EYGElfTYKAyT9GaVIjk8LOfyFQzzwmAqkqktwZSc4UT58hv+LZQMeTIjkvvNxs1xFYbNQy24H3IhGeVxE6XvlwuJy3Da5dB+8TYnXR6CwGU\\\/RwmO22j1bqtANgz6iiENGI7zRBSZeyYAqLz\\\/4+beJ5cg9sGlOXuZvw\\\/n2lwmCbVULCIfN3KDB+RRb\\\/kJYSpemyalKP1FlIhaFyLPMBeJIYAN+2PEQTU3SYuPJuQHCkNTmfyBfZ90ffgORGFzwJKIzY3UiMrcoTJiTdnuxRCsMnLaqCgZKvC2VdSQj2MwZnNZB5fOvEqRvSbZj4pqz5wPAJaTkJFHwPpEnE\\\/YhtmWcH5YHaejJU3GErol5fV5soQvY\\\/XafPMhczGUtBbNBIPKisB8Xgpbq02km5BTTWnLacCYACTWYciYGsp4SGFiUKTKcq63n6PLFvW\\\/koIIJREzz4cBlye0242Ncu1rprIU0VqUhv4OW1NZzg4SlE7Ht425KJbxtq1TQaSykF\\\/bbyD\\\/gUEFGAPT9t1cKvDQOUN\\\/2135klIWJZMfDC\\\/Z718sIKd\\\/lI0o4saM6UdVqtZKFskAsBRsY2JuTt2Yi6uhtEE8DHdSwi4x4x4IIgENCiIAgpGYGcDQaNHdkhjFzMyKmJkVWGXSWUkjqpCUprUijMVWFNy11k5Bz8E4zgwkHhMX6jQMHboUqjTOU8u5JH7C3t48LGBSmQL1B8l02VKNyilc8P3WKuj+Pe38LrBr1txSRZ6yaAdjk+nPqQ4wl6VsXKitE01dmNZ2WboALp\\\/S5XD\\\/VjqaRW7Ol71pT49KAQuF0xz59IhLW+flIz9YuhooEyPPeehAy4qBIEg4BJBwCA5BkHD1zgQECxCJ+PkUMzFYsVIgRUpBSVKSWBIzsdKGSUgcLcm0QSiZFZQOFIBh6USRXAAD5TkUJWHXSDAfHwcxttUfcnkXcijCUmQLF0ED208Ay+Z+QzyBABtZkOuMWGM5FGT+c\\\/116w5Y5p\\\/52QYPS3uzGoHtyFgOITDbcZwEKwNIkK2HWFEOQxpftgJfVse6ObhfgZmDoUAC5DYdcsQyHtYZh11Zwmhpozh7SI4iwI6ESegDSLgkHIJLwmHHI8cj4ZLjQgAQgCCRVGmsSClWTKyYFViSjEiGpCTJiFiSkmBmKJ2jgu2qL42N+W1oHW+8XSFchvYoiyDDMivjBVHUm+ESoKk5H+Ihg3K2WwDbSpVyWZjnYekYSlj75qfKtW0\\\/ED8IZguTh04q05kaclzxzAIAmdRXpj7LKK1a4wMONoVqm9qPttU7NH7XNQ6WfC8xD7ZAnuhlvqCdqGNYfl3ARRg9R2DIPCzbgZyZCYk09OmNB8djx4frk+O51drk\\\/tmpQ7smd0+MTk\\\/4o1UFUszRIOqstTrLWxt319au3+tuNFlFFIUcBYgCkiGriJQES2KlRR2RNqbNS2JqyoHLGzZUHB9zyWh\\\/O40ZS3eraEGUgcO5HCqRcuesHhmbU6H7avkYFUradiqO\\\/u9z0KCM8MvbYrip4MduKlVZwlVl4mlMOS0c2MaVRgJRMhUrEXtku0jk+3gpW20YHjK8TG\\\/E2Jny5kki+GhrriHRic4rW6MIDcvnZYYhMgrIiUIAtD3uwCnvLS75BIRDjsuOT44Pt0Jexa03po7s3XPm6M4jc\\\/XxURVE7eXN1nq33+kH\\\/ZAEudVKdbQ6MTXSmB6VYdRdby5eurXwzo3mnSUOBxwNKAxIBVARKUlKMiswEyvjXnCh517UfvwA5Trfb3Sen3OUN9YxLMu1\\\/8PmAAapAgzlO788pFZnKqZEhqEMSkYRdpBCuSghtlnHKMo05Tr5bJwzZqZNVH6PzEwlc9Xl8jKJy01t2IplXCqkmh0ORQkc8x1yStUbPZPftABt72sDID+9KGuRFclpjO1see1mpp1MJT1PCAIYDhwdAH24VfKq3ujozOlDRz9+bmL\\\/7MrN1ZuvXl+7sRQOBioIWEpWOrIxCQcCQjiOX6mO1\\\/efO3TwkUP10erN165c\\\/en5rflFHvQ47JMMoEKWIdJfTCRkmFMadtrCYev68vb9sSSucFnvjobBFEtYGFwyfygOj4ev8NxByWznJqb\\\/OBWmOHnaz\\\/Z9Gy6ZW2\\\/3G5xfZShrwA79TIUtZPOI8ttv6K7L7bHCcJ+zqVT+9DKkFHIHJNvpcNzF15uwrCl7vzQDJSVenjiQa8galCIubTygoG6W7UACCA4JQcKF47FbJa8iKrXJA3sf+vondhzc896P3p1\\\/81pvq0NRyCoiKUkGSbGnCKR\\\/HXDIcUi45HpOtTq5Z\\\/qhz56dPLTrwg9eu\\\/7cW4ONTYr6CPssB5ChLhQ5sydhpCCmTMCEy7PNkgWHIQMGDFlN1mCTP4BOWGETDpNjz2Mmh2FOSkgTPHR+vv0+HAJCYFMLnLNmI+KuZep8UKBGDUfusO12bm48U0eM8wN0tp2ghoRELnm8nR2g7J1QmWUL5zYhaBjuIN8HQynsAjbwBiizdkHOlM8C2pgNGE7rQMSTQMFCkOPGAdCveY2RU888fuyzH7r44vUbL17qbWxwMKAoiHstSpKScW4ZVwRgIQgi3syOS04FXtWp1Sf3737kq486vvvy735\\\/\\\/cpNDnoIexT1WYZJiajvWfqFga\\\/Zpl3KXDJgKEsrjcuQOGBZ9Dsu9jS4bELOBewRsoYcWxpW93fyK\\\/vR0FJ2+B41lCp46HCi6KGeL1JQVrkMl1jihPuskOUy5lY0vmkYDCb5jbVvcz6teULLUOQFZ09V3qpjInJQmaG8JMX9VGtKrFsNmQBDXsUgOlldVOacagtyFWDW+aRUT8Uh4ZDjkVshr0aVem1i\\\/KO\\\/+XOTx468\\\/Cev3HrtatDcpH6HBl0K+4gGFA0gA0Qh6XRUSVKKWIH1WCIiJaEklGQllZS9zc78u\\\/PCcc587SkpaeveRmJczLD9Y0z+e6oqAEtjpyCYC+T1YIv6MsX2b8nJiCImpRjW8u8h11QtEQQyxXnvq56P4b5mOaBS9lkSlALKGjGGOkl601NDbaMTDkAfxIBg4ZBwIFwIlxyXhEvCJTjkuAQXwmHhgASJ+LeoABgwYoQ1UAXA5bXSkLzZbsqVKktRIUibDROHKjMFgzxbMB33Q0XkPcSRmfKhTLwFZi2N8spQCMMdPJkEOi7cCrw6qvWR6emP\\\/dZXA1V58Y9f3Li9yP02BV0KehT2SQYkQ5IRKalHf8ZyYGKOx4N6TM96WhixilQQrt1a6zb7Z770mNdorF5fYqVIn6MFhzLkHBKNlVg2dIYt32SurVIweqLAg1IkGsqADcisHPMMC\\\/PlilA3NkLNMK1xlKMIkChmw3KWL0LqYepW5c9fu\\\/in1Jg+lbQSEHrU5BAcEi4cl4RHuifn+HAqcHxyfNIDKseH45Fw4LhJ\\\/SKoqJ2FHEAPZGoZ5aXPClJlBdg9AAyFpFusF9i8iDgS5jcSoVSB2z5OULI4kOHYgKHgC5QcmdnwnZHlnwRBJEgIFi65FfLrqI7Wp3d94h98tdmSr\\\/75S921Neq3EHQR9igKoEId5Yhl\\\/ErCIeGT40E4yRmokj+sv0DybyZqrXa2Vjpnv\\\/hIFPLmnVVWiogpSWmKok7WGDO\\\/GYsbJveRsa0OkjkULU9VYOydTAOyzO8aQwExVtQ1DNJQuN0lkKayQaax4beDtlojX07MW2GioEgAgiAYjm6Gk+OR65NbgVclrwavRn6N3Bo7VXL1JvTJrcL34fokfHJcEh4jfh77CDDPPRQF9Qhl79beBciBKFIdfzPZZwxlr8ZzwhjrwPYAlG1PgjKr9dL6fhhEwH4EF4eH1rKCbbEg4jTD8cmrVcbHH\\\/n5T\\\/cC8dp3XhtsblG\\\/TWGXwwAyTIYKiohIOAwB4ThetdoY9fxqFPZ7na4MB0wBqSjZfvHgPgmbxISlC7de+pb66K99oru+de+Ni8xMLIkVM6cNDAOrl8zv88x9LkCWyw62Eqt3lJEnCgxXygBNedsWq2gsXHPw8J5KjAc29FZS+SkuQxNTifIZcL8uFNncAhhD\\\/dRNOstCGYLgsOPC8Vl45LgQnnB9f7TRmJoYnR6v7hivjNZ8zxHMkZKDftDf6nTWmq2l9d5mU\\\/YDyIhlQHIAnSVBT4MVkWJStrp\\\/0XUAQxz\\\/EHc\\\/7RF3XoUkryLFBbRKSuolEA+p0GGKpRWn8Pme+TZqHSXkapRYT2dROBkJkoh3oPCrxz79aGPv7mf\\\/1x8EmxvUb9Ggg2hAMmQlwSq2KxAuOb7renP7Z7\\\/wc08\\\/ee7QeKPWGwRvX1789refv3blRjTocRQg3opJmhon7JJUtPiefOmPX3ry1555rtldv3KdVcRKklIAx7ct23rM1g6z13ieoG3fRgvewFQmJDlko5iaF0DWTjAgqRiGgyvOLwzAefG45kQ5EUzliEh7EMfMRRn\\\/kvQWhZFDDhElWOgWmqcDILtV+BV\\\/pDF1aM+JZx4d2TslgNZSa+XaUndtq93pEZGo+u5ofeLE7ImDU\\\/URT3Z6l1+6cvvli53ldTnocdSjqE9RQAihIo3bZ9KjYOS7ThaPaxs4Wt70quTCMg9pdOpzbuxsyc4vQ7iwlToX2MhkuwuAywHZnFUfeV8kLdYU+w0AujKEIOGyTkQro3sePvnYr37xJ7\\\/z7Obtu9xv06BN0QBpL1Q\\\/u+OSU\\\/XrI9\\\/4xid+\\\/uc\\\/6o\\\/WLlxeWJ5f2zE9fvr0XCSjv\\\/zzl37\\\/P3x\\\/0GlS1CMVJaMbQcIh4bLrkVulyogzMn7u558eGan87F\\\/\\\/edTeoqBN4YBUEA8P42mt\\\/ofBZeEf23Y4hg3ccyiPbQbzRR175g8ii4xiv7wwWLdmXNhu1nifHh6XA0kLR3AyiIqzIQHhsND5Z1Xnn9WJ8VOfeWTuiZO9ZnD3rRvL15a6qxtBuyuDkJSMP7sQJAQcx6tV6jtGdx7YNXtybteJ3ZsLa29\\\/+4W1KzfVoEdRj6IByTR70shhhmkokpttkE73mY2jjkvUtGAYrBonk2WsnRv5sIPKbL4AsaoNyusRolhwlPU581oveftZLkHJJKQksyGm+zGOT36jOrnzyW9+\\\/sbrt+68dZX7bRp0EA4gA46BZhzjSN2qW61\\\/\\\/Ruf\\\/C9+83NvvnPnX\\\/yr7\\\/3xHz737LPnf\\\/LT91559Uq1Xv\\\/qlx4leO+9d1tJmYBIrWQteaNidX5j\\\/9OnQdi8tUSsdFKaQZW3Mz8p9lQKTjKFqhi5yoqGN2LSe8GFZY3tdx+GYsRKt9A2L122gYc8idWOYsPwVV9nJmGUoCLpw3nkVcmrk9\\\/wRsePfPLRx37xU8KpXPzRuxf+8+tLF250l1fC1pYadCiObwOSA1IDivoc9dWg39tqbcwvz799c+HiXadWP\\\/KZh3ed3Ndc2go6AeXY2WwJGxlOmZagEUqKxmF2D7gP09P4u4PK7ryRMsxwx5ZKMYSNS0SujwQT5Zy2FJDr+5jiC8jzkpLGDDRAVDgkPPaq8Osnnnli4uDe1\\\/7kBdltY9ChsJfM4hWxnsULCI\\\/8xrETh\\\/+7\\\/\\\/Zv\\\/+yV6\\\/\\\/8X\\\/zFzet3w84WhW056K5tdM6\\\/uzA+1vjqzz325pu3V5a3iCMolRAMzTYIEUFGHIXy+KfO3nnzuhwEcSHBaggFpCRBp0LbhvMa+SAM2auUs7ZGjo1+n6xvG3X8nFy8vUWNpnapGdMH7AigxIYJyBZzVviZRaCI57euT16NvDoq9cmDex\\\/+hU9PnTr03vfPX\\\/j+G5vzi7LT4qBLod57aT88IBWSDKF0bzwkFVIUcBQOttrL7y8uXVqaOTZ37JmHo5CbS81MlNN2MODCVNKu3Ysq3hgieDvsNuRvpd6EOfc+k0MBzkzPBOVcWSysWYmXQBo587Wt6aOQWk8aPpEJPcJh4ZLrw697o+MP\\\/fynLz53afPGXdI7MBro\\\/gpYISb4CziuV63\\\/yi985tEH9v2Tf\\\/ad+Zt3VdClqE8q1Hl\\\/JMXicufLz5wZGW28\\\/PKlKOjHHRfTryh7+05nvbfn7KHqaH316l1SITT4ZjvDUxQ6yCjrUlqN8iFqK9uUU+CSBh74fqEwaaTDOv7y1qKMD7KWzPMAVNiupRWg\\\/alTgZJ0GYgkBrpV8uuiUt\\\/70OFHf\\\/nzzdXeq7\\\/\\\/3MbNe6rfpqCLqEdhHzKAPoVlRCnyXulet0b\\\/xhhgPZeKuv277853toJzP\\\/dEbcfY+q1VGaoYgGH0xGAia3NbMYs7xQmSoddicJpL5UcAaz2IXLM102mybZ45SU6GdVyQn3+QDVLY\\\/k4azjOZhJ8eTjgkPHIrs+dO9Ad8982rHPQp1LCYeP6umzF6dEtCjDS8D3\\\/oyKXbm7cX2nHfRLd2hEsEUtHC0tbPXr528tTe+kiVHI819UkTgolJKZaSZEgypChQQXT7tevHnz7l1WvkeAyXhcNmC9fQj8+x6ZFr2eeHE0bRvT0OjUtRZyWsE8A2zyi75kzbiUghdm4axmDaJgBiyHlfTIARrz3oRFSwHqabO7DSEJXGoScffOJXvnDl2ctvfusng40NHrQp6FDQ5aBP0YCjgOPtF5GKoEKSIamQdWCMQopCkgHJgMIegg4Pmqq7tfDahWf\\\/1X+aPjL3xK9\\\/sTIxQV6N3Co5XkxJTSb7mcGzPVllyzSUSxrdOR\\\/50vtpN3h0JDQYIyjMngHkfaqy2GUe5jaeHiXutgkcCeYkNC0CjamRZsdDz4W8mlMbfervfX7h4r2VS7f0UB5ZIsoEQHjwqvDrwquwcHoT08\\\/95PL87WV9VYXjCLcivKrwasKtMPP71++9+vrVhXurrCEXcYsl7pQmObSAcBhuvxvtf+LY+o3F7lqTVAQVQROdsngXQ4CQFTtlXtwlcWKbuqu87jZ2F9tDnZyep\\\/miJXZF+a9A5Rp2sQ1O6lNkyPkMrTNLR8xmTQLLW0r\\\/R+j6X8fAEVEbOfTU2bM\\\/95EX\\\/+DF+beuqH6bwi6FPcSYRN2JyWa8KbYJzNA3kRlIT3dFSiXTYxX2woWLd2cfOjT3+PGFt2+qMErnxsimPoy8TiDKsDEo3EkU7bYK8\\\/DcnNBOLDhvB4bMUaToDJF8zqJEbkmFhBzABGX2o8bH0QekcOE49cmR8V2TK5df5ZiDG7HUdHgVl\\\/KO59XGP\\\/LRh5947IjjO+xXTuwa\\\/fiTBxGP+JKNT0ISRYqZpVD0pc8+HEX8yqvvv\\\/yzt4KuFryIOMYcMikdDweDza07794+\\\/pmHV67OU+hmM9\\\/Y0TwmVMT\\\/QWmKkoNLZioEeeVMLiJ9DeKc2QrHMIUklOGz85MPtlWWDRRlcSZJ5SgBTp\\\/J1KTJwRjy740TXSYTCMqxBoIDR9f\\\/td2nDp35+kde\\\/P2fLV66xYMOwi5HA5IRpzIImRiFrbZkiHYnH1CxYkJKSSMm6q2pN771k0d+9dOn\\\/tbH3vvjH8kEHsyKIYiU4kzywk4GUGT92qzbTK+kIMyU19uPod9u\\\/gUyU7Ksj2fKkXNenxtmuC7veVveDqCCiHnpVEPHIhaChTu2e+fGcmvz3qrGoyFuK6fsJNf3\\\/V\\\/71c\\\/+2q98otOPWv0wYI6YQeQmh69KXi5ilkyC4ANgrvjOZz9\\\/7lvfmvm93\\\/lOqOvGRHuGWJGK9CuuXls49AtPe4160G9xUlMhCxHMuQCFgpLgkISch+GhUYJpNkAdTNvmi\\\/ZIkXJmS5ofzqVjkRJ4ky2Gy7nNiJz5dhHvyPH7RYolhpWQg0gwHBIeOxW4tfG56Ud+5Zk3v\\\/vW0sVbHHQo6rEMdemRnFYOIAyWGZVOCzhNTZAogOl7GvaYVW8N5\\\/\\\/wp5\\\/6R1\\\/sL61d\\\/dEr8R0nRYoZ0MJlifOoWYPz9nMf2xjaVi7NRopZlYZM\\\/De+vpweH0Z9jhwVkYfyo0vXRC4JMYa6lmkzF5FBDBBcOO7EvpmVG8tRr0dRGDMkWMWcAAhy\\\/Nl9s1\\\/9+lPff+7i737rhU5nQEqyDIgVwFqILSF+cTzYgwvhKuZqRfziL3z0S3\\\/ryR9+76X5mwNmBRkQkdah4aS4by61hO\\\/VxhvButD5c\\\/6exOW0gavOk1rLrg8KbIISbOcQqOd9mqEoSUNQLGUK0JyCS3HeTAgGZt3UJE3kHoBMnGiYtqcBeQf09oiL\\\/6o\\\/OnrmKx9eurR455WLqt+ioEsyJMWAww4ydCtbCqcx7Mue1lqZc2KTyyxJamtfp7288fq3X33o555cubGwce0WWGr5LyRg+8QPo+BYbMXIbfjcKBVczEGMXFNyvHS2nJ4Fw7sGpfpiZTR52\\\/a9zLEpBYBxPDMUjvCrO04fmj9\\\/lxTHsGzdj9HLAwKOv2NqanSk9txPL965cVuFeqNGWb6aU0GgpBUOB271hecvff0Lj+w+sPfOnUWSIUmw\\\/i1WmmPBSgXtfr8XVSZGNCBYB0PO6xzCEGW7b5ezTFHGmlVxqnlaPgCh7cmx+ECnZf6OlbnEFMRLTKn+Eqi6TaZh4xNwlhiAC8hEOD65\\\/oEPnRrbP\\\/vK\\\/\\\/u7Ub9DQZeiATFDuPCqnu\\\/5vh8TI8yQYCLsmTiFUtgsKBmFg06Ho0FcTMqQw\\\/6989enT8898PWPvfgv\\\/0xKqZMssMp06XMiGNYVs+RChsQjDNOPSl3qXDszMs+uUiOkITLsxorJ1LVzurnAsJSVhzm+A4BwK5Ude3de+ZvLWqApq6GZY6CKfpgGZktJQZuiAWe4FrbxxgZRw6mwWyFyKqCK7xOcFEbIMc6biRUpKXuD5dtrbqOWNFFhluIpNqmg8zjMIKEwDSpuDAzxmkgs2m1RCTKMQmwh96GDD84Dx0rKemvzlOSswDZTQuua53sYyDrMQsMSPXYqjcnxIx87e\\\/7bbwyaGp8UD5aE6+07sO8bX3vqkQdmhSvMfkWW3yQvo+KhLxvyViDg7krzT\\\/\\\/shTdfvRgOeqxFvcKBgrj0n17\\\/6D\\\/6wuzZ43dfeYfkgBAQZApkKxU+QAaZQWnvv1SYlE3vW8PE1M11ezJV77ynDSiP0OXymzrM\\\/I\\\/Tub\\\/p5cxljgQJPxGCSTiuI1wnbHfSvRcrC1ACp2ZmxVHcTVEsI4oGBriM2Ww7JW0AYpfgatRSxCSVsj6t1nhKnlNFYXtl06t5evVwwhKJi22jL1OOAStmiUNjJYbNcjJ7hBLrG1sFHcPbM5ahgXGco6Tey1Nu7M\\\/DwwbToG3lG8EWcCPegeTW4FePf+aR7lawcP4aB12SASmlZ79z+3b9k\\\/\\\/bz++cHH397VuDMCSBuAsKEkKkkqGat6wTGY17ZE2NARiYndv5P\\\/w\\\/fvmf\\\/k\\\/f+fEPX+ewyyokHhDQX9u8\\\/vzlB7\\\/29NK7NyLZJzkgFREJIs7A+Wnine18WzzZ2Kiw5HryMRR5GzZ2iyvFgvei+B0MZUxgm5iZo46U1DBMZQAOEARYQEaRKffCFqgcTJBErCLiJAtVkdG5TptLCU8KTCSYFThSKoqYlS4W80qPnMoEq37gVryEgGvqoCSaZyjRQ78Pkr30opXLCtrG4fcZ5g8ZNtr7uaShWk57MOy7851wHgLPsrujabmY6tVnMypNkfHJq1XGxmfPHnv7L96SYR8yYBkSKwgXTuWRR0\\\/s3T353\\\/2T7732+mUV9uNbzCrPyYyvqjJaYnpI5UKI6V3j\\\/6\\\/\\\/8e9+9atPvvzy5fZ6jzUOMRLsBHfeuLbvqeOTR\\\/asvL1FwmU4gIzn9nGoZUvJnbmk9WVtzTIv4zzLhEwF7oKVYVGvg82CeJhUtuEPPnRxsK0MmT9nU463eShzBg7i\\\/OeNJzNJnRBHyyRr1ZcvhdQaYBFmBaWS8pIsxq1Ja0msUiEEG3O5+PE2uqhMAZm3w9Uw55L\\\/fNM75xppao2WmStZiO4h4\\\/UC82bI9i2jiFOp3c2Q7V6g94ish4W0Y6lxFB4cf+rwnl4zWLw4zykIhhUTkXCnpyeDTnDr7noYhjzokUzIaCUJO1uOWtDprkeuv7aC1krr6L6dIw2\\\/vc4xkQ0RR4PB+ubd168d+fxjqxevc+gRAoaIpdkzW1wuVHq5LnSabxp+CuV9GVPjlN0Pphtk+fAg6xqA+QPirUpGnJyl9jBBH2zr5ylFYHY8P9a3p5JaJsZ9pys7\\\/ZPq3ueXpqYdKjP5Tf8pTrgghDc+Mlhfz5uApywiSyDYVv4jo6uBkvZjIeewm9qFh5T1XLNMkk1dyrJ+Kcrcp7mUPGPJfJdqn1kYEGxnu56RXjmxDIFujwmHHE+4ztGPP7h8ZUEOBokqQnrRhGLEbBeh73oyJdZ3QuWOpNxucXTlxU4FJJw4S2JiZqUACRmyDFcv3zv+zEPVyfHuoENCQCEz7ykknJSPdOXmFCizqi62ZtztkyfkPVGY0kIoTdiAXPmfKoRnfXsqUcsqv5tG00F\\\/LaWiUHq1KkEgy1rN\\\/qFililqCxZmjkvMX0uPbqMlgzywQ8BxRnaNr74TUsbf3QbYyeXSZshRa616q0zRncrlP0rTDJSqJhU2g\\\/H0dnWfqsqXUu8pr7BUIiem7HQsp\\\/RkHzXZCog5E36jPn5o5sJfX2SpQdiR0W2BZBroVaGB3QRK9LvKxh+28Yvm1jgVuL4kRIpitQT9iZVkFUGG7aX1sDUY37Ozt7TIcAyxaUNbtdTn2PIFst7GfQzsE99715paAakYnE31toVAORsIcWmsQ04pF3nqMaziBJmLreHtGddjrIJwc6lZHa+lba4UgcUZri7bg0wljl0mM9JsoRhhmTN6OqdIjpjQ6FT86ZnR99sdbWeRwUXt5EebFXAxXTER3VkWkebhJrXcxkHR9rh8A8iUoo45Nwoqs+6Gje2B7dllqsLlf0tXcQnaM\\\/6Bxo6BWBGUjTsG2y8Ua96lKD49nBBOY3rccZzOypYGgrLW4EoG+kLA95zZmbGqB4pCjsIYtEgpsz1m+hmqxtkcn4UQXqVSHx2peiRSBSMdLhQpyUqGnf6t19+fOLZ38e3LsSxD1vcuzdxhdWXMO27Rrnl7UHBSE+bs2JGLuBi6CGKwb+mMuLQ9aFpvZjVVkkMbPZ+ky0wsZRgtXrjVmBoFEQuHIECCIYy3KywonAl\\\/heFRnBz7gCgBQsOGCugJsm4bQFQaVQgEmy1dajJnhGnLgrFwx8pUagEbcW2hYPIAGhghC6WQlHjXC7I1SUy9Lsv2DJRaaVsuWVYSbFgisCl8ZFZxwiEI1vg+FbCKoDILznxqlKq227NEACwECbexc3R9sT1oD0hKyIg1KIpELAooMDs79k\\\/\\\/+6+wUnFfLlkhKiEPcKGbASLFFDExkSvgCjG2o3Hv7ga0a1AaxVlqaFRzfvXAZ86K7z4vB4ISjY8Ef8r2WKko3limh8BUUO0v2dJuacltkYQ5myrmNcdgBNGhvuDpoNw0qrVqwmLPXf887q9IuTm\\\/cvAzj4tKVQZdEi6JkJQgw59X2\\\/KilEeLYTMAmIWKMPzeMhC5EFq0a2x2MgzC3lZH85j0mMSargxJ5FEc3aAsQMOMweCc0Edi2wgzniSjMC4O8+z2qt1TT8fBKCBEYeW1mQRSgliM0bwOOVV4DXLr5HqQIYc9DttE\\\/cRYRVFZ+84uapFKKGi6TGNqcv36sgwGWigongMbKq\\\/Njd7v\\\/9n5VqutopClVEqlewgEbfnDSpl6+IDQPCUIF67nOOLnvny25juslKHjrFhju5Xsbvb8nSNOtSJbCSmIzTecmS1yPu+lcjFZ5JyebNXY5Ca4ZsBLdrQpZWR0MrkIEc5FAtq2W81lom0oI9QxKD2oJKmotbg2sWdidO\\\/U5tUOiT4jIBFBCS7pVOSw\\\/0XfYZNbFH\\\/ivIoroEWikhGWt+vI7Ma1RdkfGKjx3FgbOQSv5URoRiiy3FTJVhlM4QRsss7SJQArVCVHNec+CAouT6YvIWc2M2wGVi7B1Gu4lEihvInYT51qO2ePHTl47uDq\\\/NK1l9+T3UTDTqrYw5vzw5b0LTDyVTcc0di9Y\\\/PWRsqN0CLLiEFITMytZu+vfvDWwsISBT2SUTwMJGVhP5J0JG4Yihh0Ra4Pt+p6\\\/mOP7D9yYGeqp86s4mOJFbMMuwN2HKfia3EjS0DesHa5H0atxNBie+0Fl\\\/KofTMlNDD+hRtkA1VtawKUNuRzhvXYtl3CccNFKZJhf70VrG\\\/tOrF368YCuz5FA1IhW+ieROoYArE+lyBhVEkw25XgWEk2XsOKE9BFTCcj0vKyjkdetTYxOvvgvlf\\\/w4\\\/Srh0nEmvmteDM28vupyFtSQJW4zKnD5pX4MwCICyOCZVEORNGztlpANMvw0DsMpvgYgNeY6fx1jvRAz0PbpX90erUni\\\/\\\/48\\\/uf3Rua7Xzrf+LnH\\\/lTRY9VgFBgFXMk+AMgzzUhESfd45Tm6itXFyIUdrMpBKUL7OG8UpiFfZZkwlVGO8H7dsT3zgHgI5sTFrw0oFwWTgkA0QBixEP5MW5OVuyY8zESgUREzm+p1uABuw87yTA1kSqZLI6RF3O7j4mX7uFMrHUFOqDuLailD5eTMAKzhRlw2K9K2IeQ6QGwa0XLx546qHrz70XhT1yXJJOopIRX1QVgwaJNRSYUng\\\/yqD\\\/SCWcFURIrBEznPTQIRwWHrk+PH\\\/m9JxwsHVnJcY6JWTCFL9mlWDIua2yOfZkU3M1Y1fm8mcg04HPdSZz68FCP5FpA8R2kc\\\/2AA2GnBEMWIJ5YoqkeNTSr0jyAq\\\/mTe3aeerQ+IEpdpzxnY3dx2bnX3sbcIgEpyVnmg\\\/AaskkEtewIJgAeY4MoxzMMDPNZJJMHHdEFYTwfSccBErF40QSjnAd4fly0CcVEYdEgAuv4ktJUkmigGTgEIs4S7LdlY1IDSHSYgz2CJdNMDgXOqTZG+Y8gpfLQRiIWRSFQa8VvNhSwLH3vu29DBrK9TD9s5jz0qjWkAuZ+WyC2yQZcBjMv3xl7pPndp87dPeFNjs+OWHcFofQA5\\\/sjBIu+XWN8Ca2XTVT22idAQqXnAoJj5miKJVdA0Gw45LrkVsR1dr+J09eff5y2O3G42PmjEsXU0htRhJgS65ZAjycaV1nOWe6QNniN4usCQwUFICQx2RkmEOda5mWKMl3mG3gf+whnmDPGakLXeqCTC5BCM916g1vdrf3wMmo67R7fOPKxpmp+r3rm1devsGkKFHOZhYEPQc3MnAuymJliTIrJQchBGfYRoA4GUfFcTFx8oSYO3P46d\\\/4\\\/Pm\\\/fOny955XKiIIp1o7+rc\\\/u\\\/P0wbf\\\/1z\\\/v3LnLUpIQO44d\\\/vBvffX6y5cu\\\/PmPEywbUEY9SnT6hBKCFXMmso4URpXXrigBxsDMOlBKmjHMIVM4pZvfyfaIhe0AxfeD7peNIwtztSQ4wezWpMkcGzFE70MZUtQLW+3bP313\\\/8cfWHrzehiFpCSBSEl9g1udsDcITzy4\\\/403rgSOD72AEtgapyWNNfsSRMKt+A8+sF9Gamtli1kSU0yodzzyavBrBz500hvxb\\\/70HZYBRWGCr8+KKs6Ia7aLaGZ9nCqSIGcCFzfrs30lYl5P7IKa5NWU2FGR4cqQgBxgl0OprDglXJAESKQMR1pO8neGOU1lUx1AABCe6x7Y6+6YJHZVL5SdcPDiFal8Z2zs+SutGyMb61cWWqN1YtKiafH7Z4NTkpOpRm7kzUTMUrXX2l6jbpw7Ih5BA\\\/lUjnnm7JHpJ04cZ1z78ctB0CMIb2x0zxc\\\/XN+9c+R7L3Xu3CEATmXvU4\\\/u+NADTeGJv3hORpKsNc5sjYcEhBC+J5hkENnu9ZzXfyoOn4bJuJro0eE8TbckUbQiIyyDimFZJlDssBVMP3KTcZSxeWwEHCtSEohI9jns3P3p+T0PHtz\\\/8Qev\\\/+AN5ogCRaRR9vLO3aUf\\\/Oitr3ztyTNnDkbdgQASgGlmMqsXtpkDMQMV78iRmZ8+9969u7HiPUNoKCP8RmXnjgMfP\\\/3+j94O2u2Ux2guiDhwZ5QWqzfLWevXCmKwOkPxLISzyXU8v2btgZN6SMHR85JYFZdEOuuyRu6sOIVWJsrilCoMJCERxKmmeFxMphIdSvkTI5WpSarXpV+R8AcL63J5jZlj1l9lxDu4f\\\/2tO826krfvqrEa1aoUNAlgEoAy\\\/c1ysAzOIUqZNG63s7hemZ0m4Wnbc1JC9zXTZDabS8K58dL71ekXbv\\\/0najXJxUBCDY2r\\\/yHvxqdm968eI1kCFbE8uazr7sj7uL5a2oQkiOy+8BstVwSYbFKzaV+JPtBwZzwA1lWZYOLUuwOD\\\/tFdgn3IZwZtxcfCCi8XYTkwniMS0aLVrKilbMCivphq\\\/3+91976JufWbl4p3lLswpZq2j32s3\\\/z7\\\/8s9u3V86ePex7jtLpLFsjERBI5QZ6POj1\\\/v2\\\/e+f7f\\\/lSr9Miinn67NXgj4jG2Om\\\/9WR7oTn\\\/8hWOApIRyDAMzepCpLDUcpwgbMnN2Oc0yTYhMqVNJKWXcFi40CaK2mwIDoTruK7jOo7nOJ4HzxOu6zhxI4aZZMQcRSoKZRjJKJKhlDECUxJrp1RO42TsBB5\\\/QcQKDsRowx2tVevV2o7x7upm9+Zi1I9Y6bugI6oglqjVIxVF169HBzwSgq\\\/exr7d3FojOJkUaokON5gKuFVmUkxKtVe2Djz+gPB9GbiAw5l6iK3HAjCr9Ss3X\\\/ifr3M0YBmCFCvmQffeD18g4VDUJ46ImWTYmr\\\/91m\\\/fTfWADHeUrPJk4xZUx6qte+tRP0iyBrJnr7ah2tDteF\\\/RLqv3TJSQegGzpQoTD1jOG7bSL9s0O+fUWwpjsiIgW3CRXBWsFJEkGQF9Ft7Ku9dvPXv+3Dc\\\/9vK\\\/+t5gIyJWHPWgIlaD9lbwx\\\/\\\/Hf\\\/72H\\\/sQbpwLwUg\\\/OC4n7FOZWckoCJVeqSQgHHYr5DdQH9v7xMmdx3a\\\/\\\/G++L8NBInbIaeiwxe6RCH3YLZNMzjjF3+ig56S7DkKwcLWiFDkOCQ+OR44Lx3MrVb9Rq4816iPVkYnG6MzE9J6x6ZmR2ni1UnXJddlxGFCKJZECC8VCSkQy7EWdje7yYnPlzlZrcbPX7nbag26rHw5CFUlWilNou5LkkluvCp+cuV1yIOX7N1tLS1sXbrCWF4itGgw8NBTt3RFdukmqgvUWzU7Q6oY4ekQtTvJyD3FvxpoyG+tPwBTLZwYpbcPaXuuOTtWrY\\\/VOt81wUgBG2h9QiS+GBpoRh5QobsX5tgwTaRIQMakIUY+Vw+SQcKEPOEoZ+BwbaKY5P9yxg7s3L9\\\/mMCAlkekgmiWfKmt5GLgNHpalboOqZdcwoGcD24\\\/i2LeURAhbRMXaRsk4ikvZO2wP+XIUj7hboH9Psfb6DPtKuLeePT9xcNeDf\\\/ejb\\\/\\\/+c+EWETGHPaiQWClWgyhMmX5W8zi\\\/N9L0wcAiCEfLXaJS33ly38Nff\\\/SV332+tbSVRA9JpEAqzTsNgFsekk6ZtZBIIIgaT+CQcJCEOxIuOx45Hrs+hAfH9evV+mhjcm76yLm5uaO7KhN133MrDrGirXa0uti89v5me70bdMIwkGFEiqEYpCRxJAR5nlNtVEYmquPTjfHZnYfO7B+pO8w0YIp64cZK+9rFlfmLy51mPySWAmLvBHmeurUiV1fC87dUrx9LxOvLTsru5YEgMDlGwqX1DapPkO5mVSrq\\\/A3sneLVxTihTet9pu0TLWatJBIN1lthKEf2THdXNrSRK3MGqEi6yo7+JccV9fHJfrMZ9hQcl5jheF5j1KvVepttpi5USCA4TmNyYtALgiCedurZh1EOaQaOy47nNypz5w69+e9\\\/oEXZOFXF\\\/wAhzTAAzn2r1OQAtsAL3OwZhprplLtaso1CtrCr+fQsNzxOUEyWTEIqxyByHxP6SJYR0YBCETbFe3\\\/47Id+68uPfOPDb\\\/zxz8LN5JKajmiZISuXYThh9UjgaJ0vcivs11Fp7Hzo0IO\\\/+KHzf\\\/nu1r69PrmD184jbdUyw0I8mF1lGPADwZpEAwexLxdify\\\/hsdb2Fz65nnArwq9Xx0f3nJw9cm5u6uDOsYm6VFi\\\/u3XjvZXVxXZzrdNvdvvdftCPwkGkkSIEwfH03GHhQClK4JSZhqArfN+r1v3aaK0+Vh+brIzPju4\\\/M\\\/vgZ4+zpMgRSwu9yy8sLr93L2oyBy47DaqIpOOUyubGznAp3Jr2zfGV2wRBSkIOOAgxs5Nv3KCOS3t38a15wCFw0sFKwMYYQuYibYkVRb3e1tWFXadml995P66BY\\\/ZDPHX3QUI4RAyO9nz03Ln\\\/6hvLP337jX\\\/9R2G\\\/D4I3Nvbkf\\\/PN6aN7f\\\/bP\\\/mT5jXc4YoD2ffTJR\\\/\\\/BV2+9dPHN3\\\/5zpQNv3CURWU0eZ\\\/7+2L4Zr+53Flc5VpTmhMbBpQBMexRclO5BqeG2HX\\\/sxgxQwvSGZS7PaQvQPPw5exhiOj6bGTTSzJStVu9wKBmM+TvSfi+DJauIogFD9FbWXv2d\\\/\\\/zEb3z2oW9+\\\/MIf\\\/nSwSiwcigbIVC2UYXBdyp\\\/Vt8HR4ShR2m+I6siBD5868rkz1\\\/\\\/63YWlbu0fflTdXA3efZ86y6T96\\\/MCVmzODMi0VRTaztIjPS8GoA3ehK+\\\/L1x\\\/bHri4Jn9hx4+uPvgFLvO2u3N919fWrm5urGw1VrvRP1BLAEW05QVGwNu7YkpiAFmxfri6LpQvz8JEZHorid4ZSkB8kfq47snduybmjsxM3d08sgvHG5t7Lnz\\\/vrNt24tXFoM2j326wg6FA44GlBm9pgg0fbOEBwKiLwakaAwRC\\\/A3ARf7fONLZyeo9UGt1uAMmUV7WE9svIkXuWKOGIZ3f7ZhbN\\\/+2l\\\/pD4IuiS9JPvQlSj5qTS7cP3x8ZG9O9p7Z+DXKWIiiEq9tm\\\/G3zPl1CoaVEBAdefU6L5d1etLul9FMiJmoVvNSM9K7brn7n7wwNqVe0GznTAVlT0SYOSQopzukQRMU6aVlYtQyfOwOb9yjT2Lkkk9F1gAeTqEMWvPc4MN3DCXWFcOYQZwNpDJhhmKFIEiAnEEJrTvLb7wb7578pc+9fhvfubSX7y2euUuD7os3FiVNF06SYVtA6gSoSfhJbaSFfJq\\\/sTY0WfO7X740KX\\\/9Pq9129gcix45WK41GbHIa8G4lg\\\/KuwRh9lmtlBmIlVMgVNht8JuBW6VhEPMDAG3AscfmRydOzl77Ozc7pOzQmDp2sYr333v5qWlzcVNKVWsqqokkTJgXGz4RerEDI2ZyWNfedgbr9386ysr52+QDCnKgHXIoNqJBCDQ3xwMWu2Va0uXf3KpUnGm90\\\/OnZnbe2bvwV9\\\/vLvam39n+ebb91auLcpum4I2RX1SAamI4vAL2r2bLtwl4VC1TmHEoeLlNXKIOCKleGUTh\\\/fSO+8TyWQRl6tHpVsU+nBhSSpsza8Jl+YePXT9R1ssPOKIVMrf1EY8ioRLXuPuS9de+b9\\\/a+XifBgSOVUmGrQHr\\\/6zPxmZGV95+yoJQaiwcG4893bYGaxdu6MUkXCYpJSKM\\\/snfZZ55HiNXZMzDx9+\\\/be\\\/p6KQVARlSZsaSgt5kkRZDThM\\\/KUINctMQnPjDBtjYe+srOEILjO7hAHaKAMAWHhvKmGslsHnODbIY2JJMon9zL1V+c7vfO\\\/UF5988tc\\\/deW5S3deuthb3+QopCggOYhFmhWn6Jss2ArEAdDxyavArTr12tSh2VOff5hd5\\\/Xf+eHW7UWWirrN3r+9xWCanqFN5iiCcMivkFMhOSAZZvO32MdXo+Eccnz2qvBHUBmtjI7Xp3d0uzzo9hyoyd2Thx6YO\\\/2Rw2M762u3N1\\\/5T5evv3Gru9mR4YBN44REHQcx5IDt1A4kFDnezNm5fZ84SQBqtY2Lt6JekEhTJ4cuGydz0o\\\/laKCDdq+L+c31Oxduu98Zndg3dfojh089vvfMpw9ffWvx6vNXV67cGTRbenuQksTA4VnaOUP+OmSfKlUebPIg5FYLrkO+Q4OQlrZorEFTO3l5KW5sWN6NuSIjqUH0IEqGUbdz7cVLcx85efulq6EMSAUEqdOMrWZPVLzxiZGl5QozggHd\\\/OklZoZXQ5yeYOvW6tbNZVKAVwOIIKKQb75wgeRAeD45bq1RrY1W76w0e91AjzpICHJ8uJU9T5zobbWbt+7EKyfVaysQcM3vFznamZJzGeVweGMmP9InSrRWUKKcgIyRZ0gwG3R0ZHwSLozoc5NIDFPkywkSpXx5IqFIRcl7VlFHvfcXz9977\\\/bDv\\\/zJE584ffl7b919+0Zvo8nhgE2d\\\/FjiPqEjxnZrHrlVb2RkfN\\\/08Y+d2nVi9sL3zt944b2g3aKoR1LGCYyKKGjh4DG6c4+7TfS3SIXxIIEccnxyHFJhrMynZaRdH16dahPVyZnP\\\/OZHTj6679p7a6\\\/\\\/5PaRh3Yce2xP2AwvvXjz8ks3mivNqN8jGZEMOYVfKZmrnlOBd6NJJiDAzCqKIsUKkDIiFcTmRMm5UxDlFUQSpr4zgeGwikKlVq50fvL+3Vf+tDFzbOaBL5z++D\\\/6aGuhdfH7F+9eXu02Oxz0SBDN7OR35jGzj+\\\/dpUGPZMBRSAoUhjTSoCAgYr63RkfmaH2DIxUnxcZIIMOWGzxILXbOMqBwcPeFS3OPHjvw9KlrP3iNZZgYlPJ7F24NwvAf\\\/tYz3\\\/6zV7rdkGNNkkSjmSiBZ5juLrqQV8wSAn7Fe\\\/TxI\\\/uO7P5X\\\/+w77c0NVkzC0TtwdPfUgSeOv\\\/m7P1D9buoyRMxD9xFZOMAyKUNLg8YEByLfmdT7YPwR2Oj+UsBNJkxgz\\\/FB4EKSatEh8lP4nEpCQbISBX9w5HSBkmJauOz45Prwat7I+OwDR8995XFnvHHjrdu3nn+3u9oM2l2WUUrDZ6WIFCDIcZxKtTZe333m8NGPnayM+LdeuHzt+Qut5XUO+xT2SQaxvrBSTIrgUK2OwyfoxlXqteFVKRzoJZIMmgDhEByGQ24FlVHUxqi2Y8+Dh\\\/\\\/2\\\/\\\/VT9bonmDtrvdX5rVf\\\/6srdC3e66xuxmUkGAFAWqMW6+ZyxK5NNSI5LXq0yNXng8496MxPz33m5dXU+qQlVTC1mzoAB6dlpjr90USQE4MaAdeFAeG6ttmP\\\/zKnPnDz91IF+K\\\/zZ96\\\/dfO1GdGKXakZ8ZYHGRmn5LnW3KOzj9H6Gh06Xui2+c4fkgFjS9DhB4O4CqZA5QlLX5TOjdFgqXBIuHJ+9Oipjex4\\\/\\\/cA3nvrZ\\\/\\\/PbneV1kn1SIQGe6z75xPF\\\/\\\/I++tGvXRKin+IYxCzLpErYQMRxfAgFygUE\\\/+P0\\\/fuHb3\\\/rrTqtNAAmP\\\/IZTbTz5m58Nu\\\/3X\\\/7e\\\/UIMmhZ3YUtu6HWz0F9ho+5ENHMyhc43OvFEVmk6jyZUYfyQXgIbq1iJn6wyrRkSZH302sMhttrIK0eQWsNGYzhkYJp3GtPoixyenIry6PzY2sW\\\/3zpNzM2cOjE00Olud9uLm5nK7t9WT3QCC\\\/NFaY+dIdXq0MT3mONi8trB64c7qtYXO2iYHPY4GsRlTgjKJBx1aa7Tq0cEjPH+H+iEclxyXoh6H3Rit6nqAS47HXh3+CNV3OAeO7nv0+Fe+ecSrOL324PnfffP9V+d7W23ut5J9HiWkgUzKMdfSR4IssycugIhJHsJxAKggYFZIxvEG0zFBwBHp0ksrABqXOzGmjhP12JsaTsWt1nYe2H3yY0cPf\\\/LQ+mZw+Wbn\\\/WdXIwhqr\\\/L1qxR2qNehBw8ReVhtwg3VtWsUtElF5Ao6fgg37nJ7i2QAknZ7zERoCc16iUc1bpX8MacxcexrT47N7nzzt58NO00K2xQNSCnHcaanJ3ftnnJdx1jNyPDu2ewhlbnkNAmXMtpcX1+4txoO+syS4JJXQ3X0yKce3v+hwy\\\/9i293lxYobFPUh+7AKZUBJ80xPbMtGzHE1jfde7lbag79YUTCsr4qhpEkjP6oOSFETkLC2oFFN9k8tQUozEgyYGQmZhFnHZxaWMXtTSfdinA8cjx\\\/bHTHvunG7NTY7kl\\\/tAbfESAmKKnCdn9rYa1zd621tNFd3WTdTtRBKd5+CTYtnhQlYEiWqDdo7iCtN7m5SSy1LTM7euLnw62RVyHHJ7828tDps584ffLo6PJKp9vu33ln\\\/tpPr0aDAUcBhYPEzUvfaUUJ+tyG2ZpgNGVIV9liflkMYFs+BMlAUhAJYhl3lWJzxRxtKdFTMS+pcOHXndrIrhMzpz976vC5uXvXuq+f31p646raWCW\\\/SpurdHyG4OLmstg\\\/Kl9+hfpNkhGBaHwEu3fxpasUDcCx51EC02eDOyKy++i47FTIb1BlvD499cRvPrN2ffXiX74pW+sctCgKEklscw7HtnhPTmEw+VoI0hQnGVJ61rg+3MqOowc\\\/9I+++Ma\\\/\\\/\\\/7Cq+8YOzA5HMlosJvnSImfNuUDYwlQgSzAjTHfcguspfIQWCDsm2pFMObeZSLdQxWdLNZvYdOzrThsIHHMo17FhQFUxHLAwiPhDYLu4voqv+sBDohIKWtqk6Ir40aINpeUpDRDQqWykrpy0ZwLhqB+n+7dEQcOMJRqtUlFLCNAUHWcq6NUn0B9vD4xcuDJ\\\/cc\\\/fsRd7Tz\\\/p+9cf3cl6ra516Sgw9rKJs0\\\/lUTsT6oMPRhr0hhX3rGeKhvycHl0tCVCoXeg49dmZ8ZPHWzdWurcvMuswDLpdFmksdQ\\\/jZkBxUrGOb9SkYwW3u4uX1m89ejhRz5\\\/4pkvz7xd7199w+tuME+P4eAUrW2xWhezO5TvceDFiN9mlw4I7JzglXVWAMWUF5TNrPUVgFIkJFTEKuxu9d\\\/60\\\/NP\\\/oOPdlr9W3\\\/9hoxCckBqEBfPmrzPdkhhNpsZbLAQACdOffVg3HHJqZBXGT+w+9yvfOzyd15ceuNS3GmLIX4WLNGccVqNyqGEwRwmjAtEihxGmhxUZws7DqUIyNxDUsWlHEAyXxDaNPB8NQiUwOFSDBjKZNQNhivSa60Sq7rYwiUkGSEKWAas\\\/y0HLAccDVgGFA30H2gHSRlBx8PY7y4VCGcLCSMEEbFkarcxM03skGRdkZJXJ6\\\/ieM6eI9Of+XtPHjw9c\\\/H7l1\\\/4\\\/ZeXri3IXou1uWzYRxTEhrJKIhZH4iTepqDLeAQPt1LbMemNjUUhJe6zMp8CUdKz0Y58SaUHIUh43vj4yd\\\/6yu4vPDZyct\\\/GW7dku5OBuVMOdqaTypmMMWUuYhqTqoJg497W+6\\\/d67b6Zz9\\\/9NiTc63lXmcjEE\\\/uF1VXvb8sdvq8ukmDkFJniM0m7d+DzQ4phQzPb7rBm5E4MSoUArWGOHZ6QNW1d2+f+NoZEk7rziYrECloMqEJTE\\\/+DdaHqeIErY5EEDHryGvmmleHX588su+xv\\\/\\\/MvdeuXPv+Sypok4wbAUiVFNnQmObkImNIkZaLivfHUVu7pGwT2icyk+25buiymDJheXyT3YnhPEsTBbJ1CV4HVOJVk6Kms9Eo238SOGKyG0PL0zw2NI9IhVBRHANzVXhiV2t3lZIpvGLu9py9s\\\/AbzBUa34Pqjvrkjkf+1qNP\\\/uLjC1fWn\\\/v3r956\\\/WbY2aKgQ4MOhf3YV1jbets9GDDbfHpAuOTVZh458eg\\\/\\\/vLBT59pLXS6SxssA2IJUihggLJWW2o4D0HCq+zYufeLT6BeU4rWX74abm6RChG7i5u6G0ylMiBxOqKSzDmSQbR2c2P+rcWxqcZjXzlcmahszo5Gh3bytQ2+vUgVlzpB1oiWTJ5HO3fQZjOZc6qSszg+dWNQEYhodj++8DXya\\\/3X3ly\\\/MH\\\/sc2cmDsxsXF9WobSI8LlEjwtKNvGlcDiVKdE2stWR2SdOnvu1T80\\\/+9bVv\\\/qZHLS16z3inIgzwBonrqPD4Nd24bCt7noua7V+w0F1D+XtVQGjRIHlDJMtFc5pHKKw1QoOtChX84NtjWLRb3OWpfaPshojR0FESt6JNbbTE05HywSGQtkAwEblwSaQJSWo8GIDExIUCeeBB2himgaYPnv007\\\/xod2Hp174gzff\\\/v6Fzsq6jn6kOz2cwqCSd5VEMKMXkx5pgtyKqI6c\\\/vmnph455E423Kq\\\/+PJVDnuxzCab79byvMsiDQSEKyNE7dA\\\/OLP0w7e2zl\\\/jQBc8yjjjYVb3qXMgTIh+0joCK+aIZTho9e++t7i12D3z8UNzs6OrP7nbnW\\\/jxC6xc5zvbMQ2BHoRd3s0O02dPoWDNOBT5gbtUEzGF6neD1yfKmO0uEA3rvHWetBsrV++O3ty7tAzZ5pLzUGzn0gtam0nkRm2xjTLVNxEdwpcjSsi1ye\\\/Br\\\/ujU2c\\\/tqH93\\\/4xOU\\\/+cntn7wu+\\\/EOJBnpHRiDAljZJx2X6yaVILFwv92Yl6xAugktzQ+yNLGM0xIZ3bjMXtlsmrJpUgLThBsWSyMLacXAyHlvQyqxduIcXzT9ePr01buOEp6rUhkdyQC1wVI8SzQYUs18ZAor8ZTfr1N1grla++ITJ546+PDnjm4ud5\\\/\\\/o8v33r4VdZo0aFPYpShINGlUYvETV3hW282cSWgojOejOrLr1L7pk7tDxQvPX157+waHKRSGswMxxsfp5WhIJ2gpQUJvo1M9smvtr98I1jdIBuCQlAags3XcALAEXbPmR0b51VdPSVKRCoKNO827F9amxvyTj80MJG89NCcOT\\\/OVVWp34\\\/6WhhNFIXbtpPVNJDx9rYIRt7g5k3shUvAbNLaLmuu0fIeba6QGJIOg3Vm9chcQx7\\\/06Pj+Xe3VbtiNCC7BJeHGAt56bBvD4j1y9L99cqvkVsmrwq16I6NzTz344C9+jMPwvT98duXdqyroUNQjGUCXgrpJluYmVj0HyotmcSFvyMVLDM9EOaN2MZXUhACKpWBSahhe85nwV0bTAhXUY0rso5FLaFGyA8t4GkactuaZqWoSTIvhrK5LJ8LItlyOspkdMOm74iwGkqY4EVyCQ65PboVqY6hNNqZ2ffgzx08+Mnv5zdVX\\\/\\\/RCZ32Lu1sUTyAMZ1kignAqvj8+KoMUEp0lPEZCAIJDbsUfa+x5+FB\\\/vXfruQs3v\\\/eabG9RlIwuU+UWISBcOD6cKgsnq\\\/Qy1zYhPH\\\/H40fb790ON7f0aos1ArMcOIkhwsl2YCqFlDquZb0KPQjRAoGd+bfvuUKc+8xRty3XyIuaRI5HnS7JKBYE6AdUr5Jfo36od1qS7cd0qjSXQW2CxqZ5a5mCLjgiDqBCcAQVykGwcXN5\\\/erSzOm5\\\/R9\\\/qDG7U0YIe0qRq5vhyZ8k6LlV8qrkVeHX4NcbM1N7Hj916qtPTR2dvfmjt65892e9lSUKu7oOhIzi4sWQHciEQmxPRnwQlm958YehD9LdUUs\\\/gMnSfk2HdUPsY7PCAvc1xkTp17z9Hky7vYDd8LE68mndbDYbwGXN2qHS5LHILjMZp0qaiArN9yWvzn5DVEemD8184ptPjEz6f\\\/3b5+fnW6rZpPYm9VoU9iiKs764HS8EhDvzmUf2fPzchX\\\/+ne69hbhtoFR+iqTVJQSd+vTJRtV54X\\\/5YdDZ4oEelIVIGnexPo1wRa2x48kH6\\\/v2Lv\\\/4jf7de6x0tNSdKiYpSUWJ9FKmeYFY2SFRc0uw5klPRSJG7aSUmIRlw0xQsfm7kizDQTR4609ead5tffzXn5jyKy8FvKWqfGg\\\/3ZK0FWtp0717dGA\\\/bayRJIJIMNkwlftR30mNKbV+i1RIBGaQ0pc9IuGQiFhFWzeD1\\\/6\\\/i2P7Z488c+6R3\\\/hUe7G1dmlh6+5yd7UZdnoqGKgwIlZwHOF7TrVSHauPzU1NHJ6ZODwju\\\/35n1y498p7UbfDsh9jAGSIBGOMWEGPCxxCMpm2Bcu7gsBMDh\\\/KlkQ+5zPVeNLpkq1ia0mEGZBR5HuvbDqLcFG5EKWelAU7iu10A3LitIZYZi4n5UT9PFUxilVUgILoaPID4zOyua2THc+Jc5AWGoNLwiOvSpURMTa179TeZ37jY+1m\\\/9v\\\/\\\/Kcb97Y46MT5ZzigKDRpBwQBInJcb2aHNzvpVNy0l2S0WDjRjCEC4Lj7D03fvXgvaG1w2KOorwkcsUhm\\\/D4FCa+2b3bf3\\\/uiP9YIW917dxfIlFfQwnOaEZjI6RrLKdW8S6REHZ+EIClJhky6T0iGnwcSmnSiDhTv6kiyuvbCpeZK+9P\\\/5Yc+\\\/bcPPvc7S2s3ujR9gKprvHiTBkwh08oW7dzNK3dJ6fxWskbb6u7C2DS7dVq9ThzFp2iqtsiKlSQhSUhSoVLe1vXBm\\\/\\\/7oj86Oj63a\\\/9HT+39yFFV8QiIAtnf6pJUXr3ij\\\/quCwqjcKN779Ur1\\\/\\\/q5d7aphz0WPb1cRYTYqTkrBeqkoWQkII5Fo9Eua6EvSbLGkSmCF4phj3dzC7lmTkfSLmCU67RfeItiolurpYsmGYPAe2YPQiLAVwwO+CM68+xXU0GF+ZMNjBh\\\/iL+JRPklRBKRUa9dStUGUFt7PRHTn3ilx6\\\/9vbCT37\\\/xe5mm6MAUR9RSEpyLOWirfOysSQptXn+xvix3d2ltTSvSyRobbECAIBP5CoJFbAcUBSQipB5mKZqdYgCFXUGolLpLawli4nS7i6xVlEj1m2V7OSK1R5iQXuv4o6M7f7MY+5offGv3+ovrMSWElnanApDxcK6CaVBT2iJWS1fiv7yf2o+\\\/fc\\\/9Mz\\\/+cM\\\/\\\/Z3X7r5zj9mnuYO0cJt6A+oT7ZikRpe6TYYDzZAiRQAm93DQ57WbSIfjEJlWpWLo4Kkki4hUyHJAUX8waC9vrCy\\\/d9Wt+l6j5o2OePUKhH6fHAVR2OpGrU7Q7XM0IBVxjMQIKZnFa9h3Uh6nKvGco0qgdPJesLAuMbROTUVNSlSpYyqTa\\\/hfDeUN58HYzJZp8zDEKYqcYBRJH+UiQNsN982\\\/sp0YZEwOWBh3HRVNq9UMLps6oaRGJUwxLTDW4XY8cmvkN0R17NyXHvnQVx99+9lrr373rf7GBoc9kiGzJKl594lcKqXqfSo+0YMQEWsHt3Q4wWZSnaowKWVo4EpSEjGKgC3\\\/CaUGS+t3\\\/uynYw+fbL77fuaOqksvDVJRUkllYT6YM\\\/UvEIRDbmXP55\\\/Y89WnyXPcqbHr\\\/\\\/q7Sg30XB2miFumV6GIwCzAksDEgX6h1p3gJ\\\/\\\/muUe\\\/8fjnfutDL\\\/7h+Ut\\\/c0Gt9Wh8F006tNGkZod2ztIgIgSsGdgCNLmPO1vc3aC0WxYHQKnjbpwAEwhaaiiCcAhhrMYPJxyIsCloUWjly2y3pCTMjJ0cJWeZzBSukv6cecDHdSCTiRS1wWCcV3Rluk8ByGV7N3lKt+yXUHSDNP0q8xyJYn5YLPJyfHarUcT3k44qQhBgiyOa+5cNUlUqUl14fP6NmrYwqdygA93j9mrwR9zG+Lmf+9C5L5976S8vvvPDd8PWFgddigZQUYossws8w+RNa72DYjUnsvR2E0Z0Ou1LlcU4UWhPnEzjzy70LJSjKFxvR82OCgYp3DFpo8RjGCVjVoXlmpoBqACIyq5J4XsKVBlvQDgZCZDZXGW6RZNIV+iVqrQzC5RkGXWX5Sv\\\/8WXZDz\\\/xzXNKhVd+\\\/K7q9Kju0\\\/Ruam2QX6XJXdTcJAgSoNEd3NqgfjPrJ7FWOkxp3OYJriBBkKSEJbJeAvpPQ7ayJeeS8b1mXaTzTE75EGyLrHH5INK6yVwmf1bwqEhtJ7g8uLgFMIwNIssmeDAaqwUqbq53wlyAxaSCAiLWjmKCBbQzS0sMxc7BLm3TRQJr1DhUkZ\\\/zXVz7h7EAIWJ713gHUmXUG508+4VHH\\\/vy2ef\\\/6PyF5y7KXhtBV8Pt0y6fPfbUUnqpbq8QQrgOjB4WJ1pymbhrahEoHAAo1voJK0CBBCcTUaGUGUiNtaKI2YFhdM2x2xxnVkPMrJaee2\\\/s3KHBZm\\\/px++qKEigJwwTi1hETWSxQjELXXkO1vnVP3o16gVP\\\/\\\/KjzOr956\\\/JwYCCNtUb1GuJub1esDNa25BRxBv3KOqTEJRm2lkYVOX3kaGTWGM55d4VDAC3MnaalQ7YaqullpG87Wxv+yIM+aDH+XWck0l0C+ovtlQfGUOlXDLIZNP6KS9VasG1oYMA66lO2qzTPQxD9hem4JupQ2xHTkPHO+MYZ2R+lCbhGd43dcFlczRPif9ePOf12KuiMuqN7jj7uYef\\\/Oojf\\\/P7b1z66SXZb1PY40jPl5LaKVMW1f5OImESxysGghxwku1k4GBDzYNN4SikoECYDZL0E+uhlooxNDlWtXGoOMI4GWNZbhVPHxJ4Wn+thebmnf\\\/w4tbVOywDUiGnOZuZpwhBcPS4XOfDGfmVOVbdZhVuytf\\\/9BUBevqbj8P1r\\\/7kquwp2mpR3a195vGxUwe6L1zY+oPvaMtPIplA5BOtUiktNDGz4TjASW4oC1ZCKCigMWdgDFNNI9t+hhWAIQdczj82Wyecm46bJxWzOQM0NF5sU57UAJkQ22VnyEWrV8KmJVR50svWuxo2DEnldCpwfBYuMUOGLAOiAAzWQCpwoUNU4v1mHVqWXSxsiiKbyuG2LWeKxrPtjzOGm0NCM2tGRGPyzBcfe\\\/Ir537wO69de\\\/Wq6rco6CEapC3QpD\\\/FMQvBcUm4iDt7EWnMdHaLZCLozgZwNDngk+ZKxjfS6z1DM5orM2EMZqq+hq1NiizNCGiUSjYleB29gRVAVZcpHLAaQCYcf21+nIzyWTjkVMitkHCJFaKQKSSpMmcOJoYCK1YqUuqVP3q5348++UvnPNC7P3qXlYIkZ2REVqrRWM3GP+qVJiy7RDaUpDPyARUcbVN8qGUSCZvZZJGPkiZzMhLkzL0j0XBFjl+Q7BmUpKm5\\\/JTKWBS8bcMTbl56wiRMwCrgeOgkPbMczDcsYYzanAr5DXdyurFvb\\\/fOYrCxRmGHIk6Y8ipnHFaYYHC+lOMiYM9Q9ipLGkqZ\\\/JyypUDQ+mWOp7NQUZs487nHHvny2We\\\/dV7vQA57JLUhpmKyAwUQA693T0+dPbJ1Y6l59RaH\\\/QTLn2juZagXXaGpON6xYIM\\\/ktX7ccc8EQtLm8oZXNSE5JsohRzKlGHgjJkUSMSiwMSe3swq4nj7KUslEoDjkd9ozO3Zde7A2qV7zWt3adAmFSUlVWLFCqUzXtmhd777Rq3mfujnz3Rb\\\/esvXOEdOzo\\\/erd\\\/\\\/kp05x45IKUSAI1K3rwwFjobDUNkrjVZ5WOFnxRGnK16LhN6YcOlkYzrzZkytzX2ztPthmJCh4Db2JgZsrWjDIK8W2qnXKa8VA5HNUZsXACXpdFVa1p53o6p0\\\/+nX546d7J56cb5f\\\/p7g+WIWDIxFBuElBIRjvt1bsoaqTwEAWDaASdIoLgpGg\\\/lXThV8kcxuuvYZx997OvnXv\\\/+5Ys\\\/uSj7TT0MhIy0fm7m7aN7rwAJx6tXTv3qM1OPHG0vrL31P3+7M3+HVBQLH2YTgpTIm4wBWBguLoniZhzyshqSc4esfk1XpK6biUId0u4fG4e9OdPNtCFYxvyMGFWbNQ85ww855FZqM9MP\\\/8PPTT00tzW\\\/\\\/ur\\\/+KetG92kgaA4bYCxluJiJpJtev1PX3Mblad+9bHNTrC+Hsrzl6QvqKJo1xSFfeozsWLFoIiUJLdCYZdNQFa6Yzh3qLKBKimqTLCJac8BNZCPXGxuWhT303aGZ8UAVZCSsVZ0bmIYfwKR34GZs08+xb5PAxPlI8sknwcgqtM7xh87JcYbk2eOVvfvh1slRwtmp6YLogj7LtKdSngXsKHexr2xHBfzKO2EFwuQQOwD41bIr9PE9NRXPvrErz556eU7b3\\\/\\\/gsrIEAnjiVLWjEpsLxQp5Y3UqvunSYjGron67p0GXsCM2CkFyRS3zOxrFEFlujhp1mo2Ejhjo4jUp8T+KUyIX2YiaoLmUmF8pUcjGdEpXZ1ggByXXL+xZ2rs+CwJUds9UdsxapwpacNDxU4YKiIZcNgLms3X\\\/\\\/i1pasrj\\\/0XH66HbZIhDUJyx2lxHQePUG2EhZvo\\\/CoSDkjZAH429lJ6sexdxOb3bdp7ZkRlJ\\\/NGjZ1p7m43HKMSAdvth+Sm63OhE5\\\/7nxhS58Vng0XmZrKcGLaPyznSMTMr1VtcW37hne7qVrcb4IEH6cBJTO6h6ihrOWptipJ6A5h7q+jGS8WXI1vqo\\\/gD08QT1uBEpA6YPvl12jXbePqRT3z51Or5hde+82bU3qKgRzKI+3isEo10zUtisIKSUBE4Gqw3V9++0dpodTba3eWtGNKq+xhKWRx562IysRknU4S3ShNLJPBXGNCqxLs9045h2wMI+aKCs0WbXRNWirPhpN3XAwQ5HtyKGG90u\\\/1Os7d5ZaF9b504YpU4gnC6A1UG+OaQo353ZePlf\\\/ditd175GvnKhNjxIJCJuXz0pKYnSInkVyByzK6H4w4vYOcNVpiV4KMn2ki47UzkNGJYSMdJUMUn2D2b\\\/Ib0LZ9pG2WH7Z96yUCaJT3JyzJA5HhJADKSwrkuUkWQyONR\\\/rSqDDcWr\\\/yr\\\/7A3znlnzjsHt5X3TM9aG7Q3hO0sUzddR60EAacRolk4GUk6kUdZ9wPQ1uYEGaTjsSWLOYiuOT45Dew94B3\\\/ORTZ2Yrzd73\\\/+OrvdVVGnS0zAnSEzfLEg1WkGKSUdTvX\\\/vd781\\\/9\\\/mdnzg79tDe7vydxKOCldErT4HUhn53to2U6S5odca5AFrgeIJoofitQ6ggyG7Gw\\\/gXY4tVW+pPZwksXLiV8WN7d3\\\/y+MV\\\/++POnZVgozNYXdcsWE7FqjMZ6OwqkQo56LbmF1\\\/8N89+8b\\\/\\\/Un\\\/l4Tf+\\\/LxUTCOjtHqdUcWuab4zH1MiODJOXrbWH2y\\\/QzaXLGeQYDDnuuicFdG2n12KkhoumrYNhfA+q46HfpPzVH3SBh15EUIMM7KwFjcXAgyXokH1GcMSKkTUk8213vytrZ+9tvnSe07YHz9xiLY2OYrIrWHHfuw6iOoIHJ91Kzz2iNU8MUCIAiej1L6qmK+CrRlhloVyMhJkx+dKA6dPY3L3Q4cmjj+854f\\\/7uXmvSUKOhT2kWWhqbl7wioghlZnUFJbKUatrd783fbr7+46NUOObn0pUpHK4GyANUjl3FkWMalsVpbPezijXIAsChJMOzbr4AUVzbb1b3E+dU9Z7qk\\\/qXBrlWO\\\/9OTy31xeeulS6\\\/r8YPkeBU2SgS4mmVN6FMPS5tKInwGH7dUrd179P15\\\/+Iunjz51CEGPpneQYF5rEjyx\\\/zC5DXLrMZYV4Bi0ZBCsmAs323DmKWjZIsUdkulvGPerOOvbcAntCMXhMbYfHg4PfSVPDsOEXH84N68FBbtPirLuzLboMhigSaTYm9j4uh8rDkWhWrzT9fyGzzsePLTx1gUZBNRvEZiqdYzuJNej9QUOeqBcOWQPUHh4+IdZqaYrE0azQZAQsTeL49PoBI4d483gwCH3Q58+8eJ3Ly2\\\/f4+DXgyetuo3A9duQM\\\/ATCqiiMlRWtrcFRyXjopZzyrSRa7\\\/CGRqqMmih+b5sCHXa\\\/A8s8lFrJJGBqs1BglwRi1PJpdCQ0xSB09KrIigIZpR9nKJ+FIc3UAAXKEEmjeXORpQjCmPjPQ16e8TQKnJkUhkmiUp4rB\\\/+W\\\/e23lwx6N\\\/5+zipdvN9XUe2UntJi+3ad805vby4mp8UzhzOMy6vuaozTiz2CSqszWlMJWyQGbKYoW+wmwQ9lwhpw2Tw4cNCXtZ7C0d3yNT1WUiZDUh212DIh7u\\\/8+ozAb\\\/NjO+DiEDivoUdvjuTa6I9uL64Pb8wQcO1BpVcjxm4k5LbSxQe41qI2LnHkzPoT5GRlSMie0kLB6qGVpgTxORquLF+isMsKYmQYOzK7Rnrzh6lBY7dXI\\\/\\\/POP37i0\\\/Pb331bdFqIASqVOriTAQmjjrgRfr2B2TVLIIoHhKlaxnLMOKHq3C4eFyEw\\\/tbRZbACabEVTM1tow1CRiqCRcOOrQQJCK8roeB4\\\/BvprTYVkirnI8UdIOsDCSTF0uiTkWJtcsL4s+oV0rc4cRpLDLskBcYRkjIG4g8lxHhg7C\\\/hwPOh5qe4aEZMMZKf1+h+\\\/vLHafuzXPuy6Po3PklslErywhqlxzO5IWgOIEba5pVaGJkMW91I2YDGYcS44IcsR7qsMw1TCXLfj59BmZbETA0u7LNnq7v1JtNtF3lJ0WIqWhn2uKFJEHJFIfCqX7mJqd\\\/vmbSfozh07uHj9Vns9iBP5bjt+vcYY6qOojXAYIuhyv5vkwpzTJLdBqhRDNK3ujqGDoP0AhSCvgn37aWRc3dpwvfqH\\\/84Tbr32wp+9HLWbGSyGANerTO0YO7yne2+lc+MORz0tv2L4mybGznEkcZggmVlFcWPDqTiuS14VostwSDDFqJokPxGCnFiUQTguHIcgyHFI+UREcDLqZbaNyXEc39M6yA6xm5hewPA\\\/1C40sfFoDHTW2EuROrQJIUCuT45HMiATWa77VUCkFMtAgwpYCLAgVpZGZsJI9sYnxk8ekEHUvHhD9frx\\\/ENFHPW6K+tvfuu1T\\\/43nzn2yVOXLvVUc4M6axQE6uZd58GDamONmyFBMNLZKVtjNR4CZiQeXpOkLq4F+Jn17HbyaNEJuaQ0w7AysCxL3H66SOzS0L4rhlCEkbeNycndY4gPXYLYgEqcylcWqVrjkerm8mYwUPuO7V++rjaXVtm8au1NxeuAoPo4du5F0OdBj\\\/ttCgcEZc4pkQPK2dLgnCWBAlryWbhUb4hDB3kg1fVFVEb2PDR37OkjP\\\/69NzfvrWnyC7RQpxDOaGP\\\/3\\\/tb40f2Dda3rv7LP+jdvJ4wXVK5wMRqN9bPdZkoYCLHZccht8p+TRI4nYKwy4rMFQTtkOH55FXh6i984ohApLwEoENMqZ+2S15F+L5X8cjzKfKTcydZCsIjv6YcQcQkBLl+fsQNxPJHlYbnOcKrkFchjijm6af7yiPHIyHgeuRWkhmsYC3eoUDat0Vn146z61OP7\\\/vaJyIpb\\\/z2t9dfeJNJo88VlOLIWb5w5\\\/JfvvvE1x9c\\\/Oc\\\/Wx8dp+46AdQN1cXbzpH98mKPuxFlWJgMHlwCIGMuupxYiH6+7+ChlGNORcguhvDu7tOV4fs+CkzsAjn0P+ebH3niHpfoapcQKPJ+vUaebRBMVxbo4HFqNrubGzfPNw+ePug4WFtYSc3xErAxUbcpuy24HlUa2H2U2uvUb3PQg4ziNgnn619kXZksBsbpnHDFxAQdPapur3CnD69W2zH2xDc\\\/fOHVO++\\\/eo3DXqyPFg+vyWnUnJmdSggaH\\\/N27ujfuqVpbwSHiQHBjqPDHQmXHAeOR46QEPBrJCrwKuR6gWSA4Prxr2aoxSR9Fw78OjwvAKTnwa8KUux6iIGaMp5aCwE47DjwqvAryhHwfKHqMfhGTwuIyK2iNsJCMEsSgF8lruZF3V2fKg1URpQQ7Aj4FYBZhmkBysIj14dXFcKBX0N1jMIBOwMOA6DPMiQkCmW64HSEf2C3ch3HE9U906QkkfbTBQmH5EAF3cs\\\/vnTsQwfOfOnYz\\\/5IhusLMXFpq6s4EPv3yms3SSvdCzZQ69b0rIBhifkdZOpuF2l2bIUEbL+PkG31JJaW7PkyLhMKgtzI47ntb7jM21EOSwaAQB6kZvZjMIyDiHzcZEUK1O3Swl2qN2hrLVDOjfMX9x0\\\/MDoxdvvydRUxS8vSDaQ4lAgH3N0kv0Z+DY1x+FW1uUyDDilJRRG3NCFJzEC17YHYN4vGmLx0naVAdcRpjJ\\\/58hP1Rv2tv3o+6jZJFz8qpNhZGuHq5soPXxz\\\/8NlwoPp9JrdGHFFcLeoBoye8Sn3nxO6HDk0dnKrUfXe8Wj24a\\\/bvf1K4PoRwJmojh3ZO\\\/PrHhZLCkD1I0WcE0l55LDB1bHpk19j03lFSETSQRim2ZfDhuHAcsWPE3TU+\\\/Rsfd5RKpoCafSjI8ZTr1k9Mz37jSer2nbhToruZiuKk1RF+1a1XJ\\\/eO1796Nmr1nJgVqZRiJibhwPXgueNHpqd\\\/4an+Vq+10lp4+\\\/bW\\\/KrstSnsIhpoAiQDEB4cp7PRqq2t80Zr87WLDILUPWE9h4847HVXV5\\\/9tz\\\/95P\\\/wpT2PydtLa7x8g6M+Kak2OqLmeyePhBfeN7oSyrLj5AJ1zYRspacuWy1fNtThLWB0uWdbYWjHBSQ3bxM4iwSo+7RVgfFHh+SjKPB9MATCQjZrKWf2klPvNDGlgrV00r7jtHgbMiKG6zt7Du8Tnnvn4vthECRqvJzAQbIWS4zxq42QXyO3SqSo2+Rex+TzJT1RxELrwoXricMHSDlyfpGIyKujNj730LGv\\\/7ef\\\/+v\\\/+PbFZ99RvU09moeK4tFzTCx03PFRVWnQiZPq+m26fY3UgCHg+qjUJvfteuiLD+8\\\/d0D4Xnd5M2h1JDMT0v0WMQkBj5UgcpJLo0i7N1uSrEwcMTkg17L3iAs1lSDPHQEQDRSHiiogJ3kVxawHOkSImEPFDpEv4hfVDXpllEtCAEQREzE70FbxMGSY4AAKkExgcqr+yO6JWsW7e3np7e+dv\\\/vm+6rXibWrSYjqqPf4Y6LfkteuqEEomz3WfPZUVk\\\/XpW7NqY8\\\/\\\/M2P7P3YyR\\\/\\\/9hutF39GQZuiHnGfiGuHZwHRu3JD\\\/y4SjTmOTRdzPVLOUjdmKxHNmfBxzkCCyd68yFGVTDuX8r3E+U4pU+Elts2Ek0e6QwBiKMNGD9uBKB+JlIOmmTIDXiZSFAW0eJNGJnltiYAwUPNXbswdmdt\\\/8sidqzeD3oApNsGGKR6eKsX02tTrkC4aGxOiMcFhyEGP+u1MQwVg4UA4YmTM2b9HbvXU4iIJh1yPXN9v1B7\\\/4pn1e63rr99QYT8WiUn16oliPkRIYdAnZxODAT34AAcdWlogxxWV6sGnTj31d5+SzO\\\/+4J1br99o3luTg15m3M3K6OaxRnamkKREXAAMYdxOZYz7YKpTGdKMiaI9GziKrKeKWLqXjckhZ2eZVRlm7HkRt9S0K7CeNBjjE+F6jZ3j+x6aO\\\/HJU5\\\/+rz\\\/7xnemL3339bDVoqhPfk08+kTUbMo3XiPZpdjUjBM8DTEAxSBiGaigf+kv3z3x9NHDnz7x9qXLvNon5ZAUxHJwa6l+4oC\\\/Zya4u8CkkaWcUSMy9gQSBgWXM2zK1mrq6MdD3OFzCg3bFXbW0C5nQz+kGYN8wqqvu1vgrdPwgSCXwTh5yPsiWw8GJpA9llNJjjfqtWliN9XGqLdFUiqF+Ss3p\\\/bN7Tt17N6VG91OhxQRSQsDy6mhdtIr6ra414YQVG3Q5B70tPSgJBbkuBDkjtTcffuDO4tqc4sgSGjKfOPQ2cOHHtrzR\\\/\\\/sp\\\/3mFmmOkkpVg5WVVKiIVMSrS\\\/RWiIdOMZFo9w8+dezpv\\\/\\\/xxXfnX\\\/y9n7aXNyjqUxTGbCCydCViCThmynFzTH5qvpYYcieRy5fMA1GUD5c5RwiigkhRnDhwhhPIuLMa4K6E2+w131tYvPqziw997fGHvv6YqPjvfOtnHLnOuTNqbVW++zbJHskQZuVhOJfEev4y6q633\\\/ve5eO\\\/9NjNR45v\\\/WiFVEAsSCklVffa3dEzR6nTCTa2WHDc99FJAOdNYGDqk+QmCkMbMwYdpeA6eL9isXSXlAKwi48vjiYBYrdkEjIcIl7QlbEFUVHAiad6LigI4VMCgyDFBFq5TTv3Ub8Z+ycDq\\\/N31KB77Nyp99+52m01WSHj76UAKSsUK2KwVNTZpM4WvApVx7DrIAWhOzbiH52l9fXuuxfUIEqoVQ559crY5JOfO3P3wuri1SWOBiQjZGTWzBwmC0aKiRVtrPJ7F8WnPrZjq\\\/nYNx+\\\/8cq1l\\\/+3HwadDoV9wyRYkelWyznDIIMwV2x5FwW+SlS42LrZ8cOFHQGM7IrLUG+U58Wy7pzF38jGPOnYg4VLwhsE\\\/Tf\\\/4KeDXnj6G08113p3+2509aq6eFF\\\/\\\/NgTIpHtSZs8iXEikYo47F\\\/6wXtHPnLwzOdP\\\/ezld1VzQCrQoA4eBN13r049dGTl\\\/FXZbmbJZSaflQquGBTa1Ewcdl2HIb1\\\/tpufQEk\\\/n4tLnAsoMs4zLVLzRKsVwsNmng6qe1METVZx5VHStp4vFdqnKDywBHiNEkXFjF6lqN5AbZR77UQiFv1e0G11D5w+Ouj0giBkw1KPrUzJLoJTDJdi7g\\\/I8ca++rH6F5\\\/c+quX1dYWyZAgyPXJr6My+tDHHjz30ePf\\\/d03t5bXYslQFWbaJAbcHuagVwhi4Qb0iX\\\/4SdHu\\\/vRff6+\\\/uU6DDkVdkgPE2l4BVAQZQUVaApRUhNgGI\\\/2OFtKNSAuQxa4P6dcRYkeNxDkj+T6pCPFPZfzN2H5DUvywECqEtnNKvkMyIk7eg1ZA0t9REZRE\\\/KNQW9ak+kjxqyRi+IlWkmTG+u2NHbOTZ77yyPVn3++\\\/d4nCDmScAoASEXRKCsJMZVjjLiAjKRSd+8Kp29c2u\\\/dWwRGUBClSUoZh0O40jh+INppKqsKBATJZ6Om6hK0ljWJ6x0VVM1jPDhrK2QFgLHgUhvIZExL2vjDgP2XoAAe1PakZRNHOs6xVQ9upbJRsQgNumvj6mkCyjBc96GJkknrdeLwLIlAwCDpbzQPHD8lI9XuDmGln7ODcjTFGdg45rvD8yvG56O5K59n3opUmuS7qI6iNElzyRypjOz75Kx+av77x5t9cVmEPUZApZ2dIfBNnkaRnwiOvsnN28qNfevD1P3n97jvXKOhQ2IldDdKdE0s7y9T2EIkNhmUtFPu0Jew+ZRr3yuSPJq3LTFJRW52xbfRLklThm5bpTap9pK25k2cmw+Qo82NIuVoqJSuw4dmkyAl79MgnTtx97cbG\\\/CprVU82GCGpsRZShFDiqwMi4uZKZ8+pPdMHd9585TYnSQSzJJaqH7ig+sE9\\\/ZWtNPPUKH59+CZE\\\/HQBIS9QVOY4lCfI87AE8L7E2mFoHsunExlsNffQ1Ac3M4QpsV0qAFKR31ug4dw\\\/FLxckqI4RfhabrJJSjG5l9obQEYxD8OotdHac2S\\\/63mddp9gyK+kJkQGBwqOC8eFcN1atXHiULi6Mbg+r7baFPQp7FPYh1\\\/B5JzYfeDBTzxw5NG5v\\\/mTd5pLa4nOPJuwcNOZIsF8CopHZ\\\/7eh\\\/bPPbjv5T94qbe+RkE7sX9Joke2plNBndSSiWGrD6Wqm+A8mwkG6892vCl9TCrLm1B7iEmpmAZVZFGZbyMhJWVu2+k7JzLcEZODSYAcb9Dn3Ud2jcxO3njlGkcxpBsZ\\\/iBxehMuhEeOC+GSk8DTIKRyyfHOfvbEjdfu9TZb8T6MT2GEnQGNNKozO8K1LWQwxEwaL41NuSW1vag7CqVdWfFoaMsPA67kyLbFncN5JZyCuD1zYghjegzCxj3nQhxyeCBknhQ0xJXe+k6qqoQ8KxdERGGfag0o5igw5HdIKtpab+0+OFep19qbbc7ugZP0IVJUpAfhkuN5UztrRw\\\/2b98LlpZjERdWJAQ5HokK3LHq2M5nfvWROzfabz97nQddkhGIoIGXEECGn06eWQAOOY62+BHVxqFPPNDvBZe+\\\/wb3WxR2DXutJNTkjV9SOV0Fy4uCDZw6JT7BafDJEXCLfyzIb8JyJKstREl\\\/P7OjsTekSW5MZFHjP2YbKclQ4qmPcBU7tanxg08cvvzsxWgQIZXSjYG+DqA3nk9OhdwqHB+OD8dLGWS9Dh16dN\\\/IRP32+TvZJkwEwqOtTn1qwhmphZvt2BiDYELe7cLGWEtly5iJSrVPsM0gISdUZB3Qw0JiCXFiG4SprgkLpwfsrDoX+HNxbxjzPV9AosR60OQ66MsqQ5rZR63NWDY32eySaWt1Y3J2ujY20m12OM1tROrO45Lw4Hjk+pXdu\\\/xjB7sXbkVb7dS2EsLR2k3U2OFM7zr41PGzT+55\\\/gd3NxY2qd8B0+jhmUOffXRkz1R3taOkHg9q2TWX9PnteuT45NepOupUG0efPtFZ2rzzykWKuqlYve12GHeSoP2hzJ0WyzQVKfM5m8TcAwobJuatkv3ItDhhFJ8ha\\\/kW2fqWqzPSHoMhTZfccUEx2dcf271j\\\/6OHrzz3fjhg42GChJfguSvkVMitw6uPnjq093NP1aZ3dJeaLBUBMiJB4pHPHb\\\/80o1Bu00qivPheF2JwWbb2buLCdwfpCb1mZOUOY6HHXhQQiQqLFQwCLYBZ0Gjdlu8dq7xgQIZKmfHhDw93c3vfVhvOEPLlaIMLC3+7Qj\\\/vL0YgKlFGPS4uUaNSbRWDRsORSqKQp6\\\/dG32yP49p44sXLsnJVuyGnq1OE5t\\\/253Zrr12hUVBiQc3c8EMRyXJicxOSUO7Pendz\\\/68QP33l+\\\/d\\\/EO9zukpNuoHP6VT0wd3eMo6U2Nrbz5vpAhsgxQ51ia\\\/lUhvyY8tzpe6y2uxua7abGUma6otBlouZGZHG3eFuq7LdfUbk3zNlNhpE6TzDZ0OfFRM5immXyeHhhyUidocwA96mfoGTqriJUiqXzfHT2yFzsmadBD0KcoZBmBde8sTkfZ8VGrzv7Cx8YP78Zg0FnY3Lp0g1Sowt6t87ef\\\/MZDex+cay4sslOJndVi72TJkepfvV1\\\/9GQvjORmM+bva40s\\\/QCliBRDUCzbNwwEA0MbOvH\\\/iW1xjDEDm5YNKWyebShYTmWKh80TbAZTCQjWEHrK39n0P8NJtPnthbLKMF8Up0YQnLJJYOfWIGqtY99J6rc4HKQ\\\/0mMiFWHhxsLkoQPT586sXrkdKZccjwBSkqIAiOon9qlu2Hz9KksVFwuuh6qHHRM4cUKudrnL8srCSJf3TZ78q7+6GiwvUL8DGRG57LoBEYQYO3uwsndMgAVIxN558dAeCQ3KccTYwanNK\\\/Oc6SnFwpscb0ht9EOJLGKiPMHp7cgGTEiP5Lw6xdCqw0KOoIzrY65B2HNC05g0gedm3X4F08qeGbGPDnRNKBIlKF33RlDKaVR2ffxkrRNQpCCVUIoj1mWjiGt4Qa5Qru\\\/uHI8UK4AcSTIgYhJoLW299f1LZ77w4I2XL\\\/fWB6Qi1uZQMd+fuD\\\/ovnXVOXdavXOVO70kw9fycBFRRIqIFSAy2T5rwbExxIfJUYTFUUXWLxk2RTQuOVuTi8R\\\/ASkqICENZzEGXACja\\\/XVYVpmXBAs4+2SZ3ABZ1PWSuKcA0Vh6siKpKTVuzQySRtLhv5KnEQpprV7G6OiMf3IQ2sL3YjqEI4KAxE2Kwd2BKtbwd01ggOhMLNT7Jggx+HegJst9foljlzyR0StfuSxvb1A3bm4yL02hX1WMtqK7vzpc4MPnx5stBd\\\/8GawvpVVd6Sycw+CXZfcqtuo7\\\/oHn3LZ7CIm+Sel7G1O3nKscm9OpzLxBUO2ly1QVSkWEShOrDgvyJc3V06XQ5FqkKOnGq4JehYbw5djbXZO8adZs5RYbfVu\\\/t7zrcUlHvTTKUWS9yZcYccj15947Njkkyf7t5c6798iGRCIIqhI3nxz8dzPnZn58Nlb529we4NW7lAQpRNLAKof4v3bIw8e716al\\\/2QQKRCjgYUDUgO4oNYSdL7MH8hgFxAydmCI\\\/YRKui0oECsjb9pm0SkWvf57WnEpCKQIN7yLlvcJNhCpR9A89uwSfuADA8uNQZNJUT0Te+0aNck1cao3yJSzEwwmeZorXXlBO360LlDcxMzUyOX3t+4s9HuXLvLbuQePUSqDxUqYt7qqaUNlhFIsXDIqxNU7cDMA585\\\/taz11pL6xT2KRqQjDiktVcubI35FWAAAIAASURBVLx+hWXEMsyGB0omNzWl2LrkRwCUjBLDA1NzzYh+BjiJTZoXWyctLNOVtJ9dYskT36xSzhrD8N+4rx6zAQmwax82ypCUKJbu1RQrFiMHExFxh1mFgRx0qd\\\/R2jNkChbHMwmHhLP+7MbG829yFLLU4uuCAJaDzYWt1t2tYydnbr9+j+o7eIaov8lBn\\\/ptdLtEIOHKZhCs97yTJ9StdYJDQY97TQpaFIKigCggIlIqHjunegdxwg0LugCwJVmEvOi1tbRtlj1Zm5OphCNRSFzTM898aPy1O6Qm4aImVHlrx5CUH7r9Snn5oKERWMeQ9UWanKGgmzgQiFhFX\\\/NQ\\\/Wo3qDx6cOYLXz\\\/kOTj05Ozv\\\/cWtQc0Xg97g2m159Q631qEUwdNgzeTJJUarU0dmRqGuvXRNDXokA0QDVpG+AyoSsRKHsidsCQ+D2CGiZJ6uhElKyUSyC2MAW08hy4IoXekwbz+Mg4lzuAc2NrUx+EFOR2iIADLDhE9R5lVij65yMh6xjkbaJ0gEk1O9QKGlPeIrloIQVKKPLWKrRggWHkmHNDmLEjp01A9bW2\\\/\\\/+Orjf+fc2GRt69YqdTY47NBonfbso26HggjsMruD1YE3VZn40LmdirvrraXr87LlEkDUoYg0hZOYQUk8zLwobYEJNuTmze0Du9KGYY\\\/CdtZmYm5pWAwkMnN92KVp8rtukYBEnPMIzcVhq+rjQtGXIQbi+wQLWYVtB6MpTJcURSE5jB27eWuDVESgxM7SI9clr4Lq2MzMqCcQEchzaLweXF7le+u01YUgch2SREwQLkvJxBAuV6pidu+hqZFos7+xsMEypChgGZDehOmSjnV4Zap1H3crBWcfX7iO4wig4LaTqoNo1Fsa2DLdL1s61MgADdwfJ4JwJdAJzhaLqUdtI3SR7sscxjn1c4BNnzNSU87MwThmpiPu5BbUO9N2lAyR6eFl5D5iYq0mGlcVUXzkJbw6EBH6FPp33rr10V955PATB968c49cQZFAs0VbTXJAfpVmZsTsLG90qaU+9fOHn356v2r2f+dfvHD5VU514jiKPzEnZsOcWSwiM9QxE\\\/5UYzdnKlTkOSFXxVuGcSjqElpIVFMkJ231xN48pfIWQ4Mg833Kw9wUI+ciivwIsTSV5bTwoLVl3nec2n0iLSbvxPJBUQgeTBysrrFqNiPp0qXF3sZbt9X8EqIAxBgbpZ3j8CvKr6m1dWy1SBL5NXH6uDuoHD0+9c5rdwbtHskwAbgoxMIwqSO8k9EYk\\\/KA47FhIvTiOpo0xDB4nLHrUaY5n9qOIJdIgoy2JPLTpizxQb6YQNbEtAARzCUVvBEZjfWCHNIYRqLEWW\\\/U9CRILNHShWwsBqWL9nSmykLrrhEL4\\\/05EC5z2vZU2oWONcCIZacZbt7Y2PfI\\\/vPPXpGDLfJCjoiUJCaEkhaWeaNN9ZHRIwdPnpoebXhOwz388IGrlxZU0CEZMEkiRZJISQKgPVszw5x4XVkRzuyEFtO5NOYYXTRs16rOUSjMgpLNjlAqIKJvrjucGbgtPK0ox1Z4Bsb9jXwNrr4JaGNiRYJIStpap6lZWpknInJcEhUSrrtrhze3a9Dvvnl+5d1XNyoj0erFG\\\/zwQWclku\\\/Nq34PYYfUQPfmyBFUGaFqjfbN0c7pPWOV6tz4hX\\\/3kooGpGOgUokDkW6oOsKtOdVaFPRjCEgqQ6HFkdwKaXY8SJkDEmQpQFpdGEo4uS4mDFIRCnQxUy4VJW3R7EUK9Gqj8cX2qJZze8+oSzij+SczYgO1ZJDy0sYMGx25ZBMLAcdnxUSChDIiEAAB13MqjWgQctAm7hsqw4pIQUUqDBffW37g81OVPXu6zbU42EcBEZNTget447XKwV1wsHht\\\/ejekU6oljvByMnZEXens7W2fuFKsLYcDkCIiIWeWMRnov4Cqe9AFgwL1oGwDD1jl\\\/AMqGAZghRSoOL30yqAeWhYc4eOHcuB9pRVMUOn80R5m8GihVVSByNn7EUJYN+J3+LWOlXHqDJCTOS4zuS4c3iOt1rRyoZw6735C+w0KrtrgwvzbtAVDUEHxuTNAYcACY3GZlboDzA6SbUKv\\\/7uzM+dW19vN5c3MsC04R1JEKJSn\\\/3yJyfOHlt98Z3W9dsgmeQGDG0v5VXIq7q1qluvstn31tNEo2BnonIZolJrVBQvZqIWZ1EpkaVPtmCD5RbHqXCodVstuhyz5Vucfcn2gkhDIxeFIvSjhOc29u\\\/msQbJEFFEUqZnvRZTh3AnP3a2cWRu5cdvrvzwBY2DSncCWOlW57X3Fk5\\\/4cT49Ei\\\/c0TduU28Qip0J0bcfXuEUtRs9y5fawXet0PM3+vV9k68\\\/+p88\\\/a9geiNVMP6eH1y5yEICKjW+mbr7lI0GLC2x0qwfpw10ijOtiwpXsudjlIJiNRaNJtiDKHWF3ofzNvIIsbfdu2xiXmjSueHGAI7yC+jvE1ZGRDO1iiMcYAxZUbr\\\/+nI0+1g9gj6XX+qoUbrcn6F+j3vxP7Be1fZqZPboPE9rGR4YV6cnqV2lw7P0GqN7y1T6h+oIt63jzcCV4mZo7vuXd0IOgOKNKsgA7iAiCHcicmJD5\\\/19+ycGmvUb+\\\/TumQJvYQJpISjHCE8tzI7pt6zvGxhyZIzyvNykyJTkiAkFm9gG6JlNMATOmXWH0EGFAZZwStBluQ5p4l0CkzJvPzcn7P8hLmM9Bif8mKkOv2psyOdAVSshKBb2qnKq\\\/ArlQcOo+I3NjurP3qBSRIZets6z1dy6fbG6mL70FN7Bqd3d3\\\/syK0GqEUso6VVeXeRlSTXo8rY+mb\\\/+R9eGTs+SV5E3Wa\\\/t9Hvb1HQETJwK9XxuV31yfHR8RFIKYMw6A9aa1u9ZovhGOB4zsykTCFgWLhoHUVZxSbkaW0Pu6KwD10LKV4y4zANoQBicm16KPIM0eFUQ06TnWIIzdv0FptKKIfQQKvHOlpXgR0PboVcv\\\/H1D3tVv\\\/dnz4XnrzoNv3Jif+\\\/tKxwyuX1Cm7sjFHWo3+ULHefIHnX9Fp0+wdUK3bwBCZKSJid4Zi9dW6\\\/PzO7ZM3Hj+ZvMMhVTS31dGACrcHNr7bnXRh84uPSXL3au3tKWOVnHRQhyPHZ9t944+V99VljOgUw5xR62c27KMyC5kIcm\\\/4cBbY+PAaOVw0mCo4zUN39UcgI85xiya+E1mJTZGkoJClmAZTObsfJmRqFVsdW9\\\/R9\\\/0lpepbBPkYyh8OmyhiPqjdm\\\/86nqwd3Nl85z2COODL0vQUykQlZhFKqFa5uH\\\/u6Dm4QNGax9Zy18\\\/x73mnHLmhRFRBXmTmewtbo1rbyKcioy2upQ1CcVKaJg0F+9dksfLp4nRnZM7Do8t\\\/vQXGdto9vpdjrdQbMTdPtKSjJ8Q7MbpzmZECxEbDIpI0JEiqAoqWMp3xfNjexzFP9c8MznmOwWJAwN+8ztZBnzlUapVKIZXtnqzZTZvBAS6XtOofei3nAPzlV2NsJbK\\\/35BbcqGsf3tS\\\/Nq15AYJIhKeLOJIIWB10OpLPAtRNz7dcu4tRxsX+\\\/ujnPbg1HTgv4ND6668RuFli4vsxyQBym5puZm58KaNBc\\\/t6zKz9wVBBwRiBIVCQcl1yfFCvHkWHIylRjya4LjElvUU7Psr\\\/MKzbCorRDMCXcn6T7klqvgMCs4kmzOXA3bINji08IMsCWnEHM9eJCvLwK3jqxfgFQIAckhSExQA6RiiIZBDEn0+JGgyBU2L37e38BB7LTJtk3bSeQygXJgIPWytU7p+XpflNt3GkGCyukmIBYbE6\\\/ifoobS2rsB25U+rt92vTI+17fVaSSCVgOo0ipIESweLKxtIqgSrVaqXqjeye2v\\\/IA73V9dbiSr8fDTqdQbefxDbEHXBth+r4BIdkSGEPUY8i41ayyrddSun2Vj5hyoEjc3nP0lGr1QWUUXmpDHqdpf1l9g92aGfkPaKQR4FDgIR2qYJw4Lj1udnK3Fzz2t31\\\/+XPsGtW7Jn15ya6V+Zlp5MRXpRSgxbJHkU9IhosrKpG3dk3Hb13hUbrzo6dMgwpgnrnfWdmx5Gzkxv31jfuLVFkjCUInHALWDJYKRkinoyZEz\\\/NNJcEItfXe1NJlXThOJNBKQrBMg\\\/XT2AjK4u9HxImhxbedgFHZwcxu1yHBY2ZhKTU5zgbtSOW99XD1VjeW3AsIcOap8vQbclYM8JotRk25ZwK41BmqyKYyeR8pYwqSSpkFZDWyFIqtTwhFaion3CjYpFyPb5n4RAAZlYhhf31O2veamfwn+4Ga33s2sHtdRJuqhZFJEhGtLHAUPARdpW\\\/p+qMjURr\\\/cRwQYIlaztepRgxtb\\\/XDnttsbW2uXDxul+r1EZqtVpt5vjB2mh96eqt1lorCGQ06DNceDWujovaqF9vRJ1W1Frj3lYM8JMMM28vlZNJnAhgnbYGRgOMrBhnTkYU5tCYyqaERTxrJi9gmxUXqVxF5TXYHVSdL8UEM83ZcxuN0QdOBFv9zbcvy0BRjWlrzfulz\\\/Wfe09t9SgMYikEImKSSjJnmi7RrXv+yYM8WZWrG6h4ePws396gIESzMzNZmb+ypMJIa10mTUoLhslKZXYOWZJp4Jx1riU8x\\\/Xy4EK2sQ5W\\\/VAED9mMm0SBDvHmcdnRvJAKCZ+Em+i\\\/aFePgGQAhKwAipgUsQDYwufHIldOKk1Pwo23jgxJ9iEDJj3LlMh8i4xGWV662mbzpPFQa8apUJuBx\\\/4cyqi0STHr90kWkA1ucsSI5HyRW6vt1dube0echa0+ju6j5jovajSMICJU69zfoqhLjksra1Rx+zfv+ft3ybWVrIHL2XwIbEEbmIQUot+K+q02EVZuL1VGR9ya35io7xwZHZ2eavbl2lI3oJHHnjnzyCdOLN1e+8+\\\/8zfte9dJBrH0m1QZPd2c6VuDwUSp1AaYArnUPh74usURnhXNuLTjatR2GDbPMLug6fFMhjZ2ug9FTErSfg2eO374gKrV2tfvhFtddnxyKqDQ3TcpX7uq7q3SoB2LuLAiARIeMYMkqwggVor7HFy6jgdP0ECy71GgaGSUon697k\\\/tbJy\\\/vRUbelLioKKPZK0PTzkVpvQyxDEqU9rWqGTH0THTdA40knfAloVFqjubO7CQ6LjEr+KS48Gtktcgv8FOhVyfhQsQRSGFfQp6FHYp6oI4MbhXVp85CYPk+uTW4TfYq5FbgXCIiYMuBk0OOvEvKua4\\\/86WLxeX5NRGdZFwf7XRsoridC5Wr+Bc5cTWQeNoxwto\\\/FOCyyFC2FcL1zf2Htr52nfX2R2hU4dpbYuiHsEhkjwySmt3iCNih1bWhCvDe8ve5Jw7PhJutZCKxWhx9hRynG0IRUokwGmKIhVthrTJTTDBaUztrswerB46tPf4oU\\\/\\\/0tmxnbXdJ3e9+\\\/Kty6vLPNhC5BA5ujQE2xOALFMoNkY48zjN5ZVJ7uJSHiRnyBrnFgqXSQbYdR3nJDh0MiBsghdMcke8ppkAIWqTY6N7dstIbr53VSmlN5jjUOPAVO\\\/addkMaGon9TeJQI4Tv6gQUMyQ8TEMYiW5p\\\/jqLRw\\\/SV6d7zZJCszM1icdVJzNhY2YKZOi3YUnKlUlFctUx0EmbUND4kJ3ax2P3CoJTwshkjAMjOzWIUqQhGzYitsupYl2TeLH4pDjk1dHY6oyMeM1GlypkFch4SDoc2ezv74Rtdeox4YpJ2eDo9RZSbjkVFCbqO2YcUbHuVKHVyEmbq71l+5FmjqsJEEBzCyLIEMgjzjO+b\\\/qj+5oU3vhwvGZNdswsxxNCd0xAljoHeg5lerIoT3kuK2bS2rQiw9oxavz6\\\/sfnvVlr39P4ZE5OnWE3u6RknAc1geQDuerm6hViCRvtCfPnFh54TzLMCU0QqUsahMSrchALhEUBJHw9InQ6cnORggR1fdEoedKgJhUrUFebAfCOk9JscSchy3Z0NAsXTBEJ5N7zlmp6LIlXjPM0BcFJlM5VQIoMPENRyQ24GzGPBAE4deqY\\\/t2u\\\/X6+pXrYS\\\/gGLOiBIWN\\\/XvDxeVwtUUgahKNjFFrjagSWyZo7jmEJhMxM6CYBbV71O\\\/T3n10t0cEXlkZf\\\/zsVjfaXG6yUpmRJdHI8SN7v\\\/FM5\\\/27qz97i6WM4b9K5fVb9VtyK+RW2HEdz2EHkVTEhb6WCWQxQ6BpNgKyz8mUqyogHBY+3CpVRsXI9Jd\\\/+eMPP70\\\/cBwF4YA8VhyG3\\\/2DN1\\\/5z69wgtKEUoRse8QgHjgkPLgVpz7+i3\\\/\\\/mRNPHowcxwGIadAb\\\/Md\\\/\\\/teXX3kDKmQZEEtG0pjhHGuNC6055KyYmRV5bmX3ropwKOiTlKQkSZmm8dbIHwJCMFwId+rph3Z\\\/6SkQ3frTny3+8GWwZGaSwebCunRFdcQfrPT4vWVx8hDPr\\\/AG0fgIdbYIiKviXgfjDYLbX+s6uwJnclwudxNhRRO4S5lGE4lEdVr32CoMN6FfgKUUvXbFD6SrXnnu9qG5+nJzcPvCbeyYpME6qxAyIkgiQaSYRKzEo+8d5yQGs0EhDGZ0CkcxCCrsmmTDrJkJE6qTnyizBYgrjYqZSDay9oDIaP5x+Sd0460xPbnjyNz6+\\\/Pda7eVVLGUCxPA9UOzg6Xlwcqm1vCl5hZN76Nuk1jFNmD6LHc9wEmALxRTbKTD61s4NceXFsDR7kl3bb7ZaQUaXKgt2sEYfeT0yJljIycOjD14kFgS2Ca5ctyFcPQ2ESSEckXkCO\\\/QjvDqbXPolCsPc+rMKB3hEDiWvU5KQXjk+Ow1UB0b3bXr4Y8c2n9oIhGogAt2iT\\\/8ydNvvXwnCPsc9mNAgtET4jjB1sZvVVEdnZybOnh4Z2plFoZyZHqGKmMctkm4UIEeabBVgWR1jtlB5xSMmnxexRyO1w\\\/\\\/0ke7vTAKQ1JMUhl2jHFTQp9CTizFLch1\\\/L0zTr0Wsaof3YsfuRxFpCIK+73VTccR1dHq5mKLllZpR939+Nnor9+kqUnaWE5yGMWhJL9KJJhVb2HVO3dC\\\/ngtFoaLg5WWk3LIrZJbJWYKO9qUm1hROKBooAXBSPhwPLde3\\\/3h48227K+svnF78fmlbuXAjmBjUa0ukpLYMUtBjzYWKOhy0k0wHLZNYf48DpTYZE3kZDLgptIAjKJSVdIRi9s5bJ+Fw+S6zUMztoNn4Wn2AyDiBhMEMblVb+zoAdnuLbx1Jep2OTUL0Dvw+OFgfT1YWo2julIEQZ1NGt1JrVVipvoYEzO55FeZWrHbnu6h+R6vrdL8XX7yURyYdu+t798\\\/sfD+hookKZWpawux8dJ7RBjcW2tduh0LAXJKX4r7v5xaBepPVGm49caRX3\\\/aQ4kMpcnz42yCX0TGGA2qbGYt4ozXq1N1fN\\\/xucnZEUXkkD54iQkKeOjszOGHjlx6YQ2DLZYBdPs+ZV2lBaFwyatRdYRcL6GZapAYtJkHCZ90cojEVpGKQJxS3GT2\\\/gFEG+2r\\\/+7H7bUWD7oUasErm7jDRlyFQ44Pv77zyQdnv\\\/JkNIg2Xr5EGiGoiAj9Zi9SauTQXmwS9Tp8bR5TR0Y\\\/\\\/1j7J29wFCXaqg5HgsdHAOZwIFf6TnjQOXxM3pqnaEDRgGNhBEVKUdSjsBsPk9IBQ9w0JmIWQjTmdlf37Vm\\\/eIP9GsmoeeUuM2RviZwBBT2K+txZhevQyCRVZrG+wIMukUmbEta8Mb1ayPCpyJ3PSZbskgmnQEGT2ZjYMsyhnykSY7OZYLjkasiL45FbI69Ojs\\\/CISKQQhSM7p9yRuq9u6v9pRVSUaLuGtMHxo4fDpqtYHEl\\\/kRRQKRIONRZp137qeOQEDh0mPbvx7XLFEVEnNweQXBpZoYWF4hdunyNn\\\/mYMzo6Otm4un6XErhwKsXfv3174fZtYsl6RKm0zZAyRPuypiULQY5Lfp8GAxGEbmYNXTKNZbNjxjkmTO78Sl\\\/FYeGRW0Wl4Y+OP\\\/mxw9Wqow1BdRWhw3JtzHvosT2X3xpT3ZF4+ZLK2rz6XWlnQscjr+oIR6dQmnYEokSVxyE4SUqClDNhrKe0hCEUPRmYiEhAOJKD9a1gdZXDPmnlyBTnlR6rKQNKu9M5lcXvr2+9c4Gl6i2ssiZnkmAg7EeDldbOSe\\\/65hYHTQq7tDiy47\\\/+\\\/GBxdbC2RF1FxPA8JvBoheoeNUNiFTUj\\\/8h+eeu2thOGCo3boEyQEggsHMAlxyFmr17dcexwwM76W5eIeOLsqebl97nTJxVxl\\\/zHTgT37nEQkgw4GFBHoT5KI+NiYid129xcixtB4By\\\/YaiNGkxmG4hYe77CHB6z4QplkAAKOBCgjCBhWucKbTHJbg3VMartQHWMhGAV+VXRmKlzt7l54RoPAo7nsA4JQawAqh\\\/eF7U7\\\/TsLWf6mr6liCpnWF6gxTmHkHT\\\/kfOhMsLFBHJAQsVsKCTQa3Nykfpeq49Tt4+qdyt\\\/9RHW63mn2mKMEzhbTcJiDWPAvEVnilL6UdZxFUqYKIkXS1Yc9MvSrrYPAFlCGOaMOsXUwGoP1NHbpM6syPrVv9qGz007qW5tcb8UcER15YKq6Y7rb2aCoT2pAKgQUGx0vxGrZbjreSAwRkxaCyLpiyfeQsHHiEIjcYIILzK3UW0pFHA0o6mfikQYehTNVAOi7yXLAodO53iQSRAylGKSHFhxx505zdm7UoTDsNilsR+8Nlr8zrRyHZo9Tp01bdynoUNDhKKB6jTbaREq9fZ4e3C9GPNmN4rOYDTmDrF5OZGmFA+GMzu6qT+\\\/sLG+0VprkOI0HjrSv3wzXVjRCgImwsemO1cNuMzm4mTtN6jTJr2B8CpUaBX1uabadLSGJAqM29TlMIIf6cHONRZDodqbCRHFhrdLfyMOxUUa8SHOhxDETXo1qE1Mnjh37\\\/CO9gbr96g14aF28HCwucWToncTkVnj7dslBOJi\\\/yymsSW+bNDEKApraQRsb0bvvy1bAmx0xOUF+nQZdYgWStHMHLd5L5A99Wu\\\/X2332R9utAcf60Nq9nY1qh2NpXau6S5E+EhBMikifFExwdHgpWDoYhAkmG+ZFScfYYLWkMZDASeOevCrq40dO7p0Yr4hUbTpJJnUtMndg7OiZA++srdCgxVpwkSVSY3btIB9P6kUqg5P5oIgkH6MUE5d1BMCw51lpuQP7eKF0UoFEcoY4gg4+KYaBDBv5RHw2TghjQztdDwkSYJZKqtU7zQdP7haQpEKSgWoG3b982Xn6NOoeyzHqNbm7QTLERpsadRaCVETBYHDhinP4EFbXOAZ8MnITosSfGHDcamV8357\\\/H2P\\\/HSRZkp13oue4XxEqtc6sLK2rq7Xu6elR6JnBDDAASJAAl1wsCWLJJddoNFuzR67xj\\\/fM+N4aV3C5giRIglyAAAkSA4BDAKMwWrWWpasyq1LrzMgMfZW7n\\\/eH+1URUQ2O1bR1V1WqiOvux8\\\/5vt\\\/HS+X9u6sijADJGStLvxNsbYKU8YFpiZVtd3JEbEWkLyk6\\\/BwRQk\\\/trSG3cGyGV05Qq6E6TYh804PtmSgkySlag2+US6RPwpTawIHZgNzcy0jGvOcEEtSTY4DYJyIX42R5tEyr3Smx4ujVLz518dUrIQDa7rX\\\/8KZsRVpyksKnkQGz+PwcOba\\\/cD8WVTFDDUXMIeVqOzAwopaX4KDOyw6fHhNSAnKAEEpFEgIiBXYBeAHLZXZ2lt\\\/dhKvloOWZnZ4x1LpZ5IhIpEAGeqqMOSd+wihJfk6m6zdAjpyxNPa9q9ygPnimnC4wA+czQ0KOqJPDHHBK7uDwM0\\\/POjaT5uYBrbZyLHBc1EOfSom\\\/+OLcnbfvi\\\/YB+A4wKzbLxi9aIlqiDNUw5qbFTKJUp4r9GX1d4sQ8HTm+AbPkjsIYKE5MI0J1N4ZMOx67obuU9jCRkqktECnR2WuUyhbHuGyxXGi31Nv3+BPn5bVVijxETm4J9g6wPJDEB5DHuevgzES0sQWoA72Td42MDBA5Y1ZpbHjg5PHm6mZ7aUtf2O2CPXRmvvr2NRBhSschks0mmxlGRiRiyLKuyPTZJgXtbRC3sDSAUyepsQ+dhgGUIWbjdykVc6h4QAgx3sKUJRZyF+wicBsISEmSIcowlUFkMEGUGWebw51zYExLjdEqYKHCKiPkVpRQFPgkApKR54cCwCaQAxV4\\\/jy7EcJylfT+wmygCEjxuSkaGhN37hmBWKx4yshj4x\\\/Db8OxWVAMgAHjaPP4tOQ0Mgn7u8AdsBwcH8OLJ9TqJlejTJwJ215SrZFloe0WJ8YJ0N8\\\/pLAFyPUPm3QReqZmDLgDvEBWARhX8S26K3EuTfH6M2g7pneYqEMJOXAbeAGd0vGTY489MqL17ApAAvz4\\\/fpQmX3sySF9oDGAC+eHhibHq7VtsFyIbMAIUKX1cx5kQUmGSlwpmhobkqUKMbiTMnLkDI0ytf5myy1CBIsxsFzkjpFhJRZNosTAmjV7xPdjhqZoVKQxdqbwVe1WR3HkTiyscSvgHdKhhI0NdmxANqvk20BStQlHbNRCIg3tvrtcODUjtvdI6nhICboZa8oNsBxr8vI5ANy7uRD5gdGXcxw5MdO6dVcFXqbJDKAIBImgY89PB\\\/dXDeU6xlvFZSWCDFXzENo1LJTZ1DyFIdX2QURamp6mbWckfqBkkn5lxeEKFtlFa2h87rMv8oK7+e13woN9iloQgQHg6U0OGVgOK1SgWAFug5AUeSbDRH\\\/nUpAiajVUq55Oh7hDEm985fUmkdjubFV9qNfo6JCVh6BUwkIRIh8O96xzJ1UQyXsLsX6f5fWlia1Gb8cKtrdh6iTUQnKLUCiZH3NwBLlDioNls9lpnJ9VC1sgyZ4fQqlUGBm+DzK03NnPPD\\\/3088JRWv\\\/+bXae7dBBZgjFJnVSFnoLbPBKYJbZq4jCSJjwoDeUEgEoj6O23Q6H2t5WbZMAu6AXUS3fOHSpF22YpQ8+L66cfOgVGLPPTZgc\\\/PSTIy5jz018\\\/3VZbILENogLdDB1Dm0GGnZWD5qOr7l5uHo0O9Mz\\\/NNKdsBSJSjETI+MMg7IYQeSGHoMil3h3paOubr2sNDAxdPtVY2vOUNgmRWqUQYKACr4CB3idnAGIgQyBe3F6znHmXzc7QUUacBjbZlTYa8AMAhkkBKeUGkAOfmaH0dWOwdMSUoVsYGR4\\\/P1DZ2mntVfeMDAmSqMj1DSnqHtTSkwBz\\\/CkgGq+vs5HFkFskMyzw7KNU\\\/kVTUaUi\\\/jYUyDExAoQz1PfTbhGRuGRBPOJUAwJhgpMtRM1ayhp+8MvfXvuTalqqMrX7rbexUzWuq2WFKkJAoJUhJjSMQkU53IB1YpdXGmMUZADJO3AbmEEL7oHHvrQVxc51kyEZdNjqo1neo2QLWZCWHP3oFnrgiv\\\/06DA9Dsw1SACpABkog40aThdlBJSMvBIugiMA5lEvgVkAEMDJGOwdgFfHkLNmOurMMvIiOa1uopJSRTCTFaLsDj56FkWFgOPMLL08\\\/d45r1iVkQihVbJNIdH+IknFlWwqZc2pSLG0YdT88xHbSB\\\/+BGTV9ehtH08RywCkVR0auPD4h0cTrcoD19fbyg8NyhVdrczPjLtM1nM2ef2H69e8Mec0ScBdYEMujKbOFxcruVLqIeZ4b9gZt5ltwlFV+QA6bCgCoAMKh0om\\\/+EroRyAilDrdMUPbyQaNxZYFBQDI7MkR+8xs9cP7G\\\/\\\/k31PQNk0ckiQFB3LLZbBLiECtvRiuBbSwaD\\\/3QtgOYKMDxOxCKVKSkINTgaAJMhIrG3j2JGy7GTEd5647fOGkDbi7sOI36iZrABGArFKRD5UOby3EiZQpMNZM6HxFocBSiVrNDOuD8mQ8ikWaEvw2+D6UBrE0AANDEATk+WCXkHEkoUIfhG\\\/KUlSQ4Y4SEhDjgjGGrHxisjIz7N3dEYc1kBGowNCOdedQ6\\\/cTgaWpIpKYiYSzwuLihVCGrITkt6i5BzJS9YhNTbFT82r7gPb2yLGU56l\\\/8x9IKRwcxNFxUGMQhSgFNWsQeqQVRmn4Xjz6392BmVkKQhgoQWEQhytkM2CIp+aAO7S6DbwABQvAdYouECgzoCcAIiFqt1ftkzORUAdfe7t9cwkpSoJZKEEIphG2hptCAGA7vFi6MPAxK4ORpx5CaFY7jD0TVMoIOOLBugN2EYuDlx6ZO3duWF\\\/wGQAC3VloeS0\\\/9OTmRuvYmKsVuQpgdn5g6vjU6v428RpwB0hpj2Ea1QCApmqmnHQkIY1h18ghxjWlB18mXhlTp32y2zLGWMvb+Np7ncMWiQCiEESYCbHJwqRSeJTuGznjQ86JCW9tl0Iv\\\/TskSUkH0SkNQLGtl5+BbRPI\\\/RpfW7auXIj2d8nvMMbZQEUeHQBIsF2QgtptaLfx2HHarZKKQAl3bKAwMxm2\\\/KPlTdKXf610AUQE9+Rce31LRpFmN+czm3QHnFMnZKeOq5u3iTDJX0HoxwpO3Gd+h8IAnQKMTOFIwXKLx195vDQ7vvon32\\\/cvKGDg\\\/SObJkXS0lSUf39W1v\\\/4Vv2YFluVMslt\\\/zkFW91w68ehY0WiZBkgDIkJeJiR2UQYVomK5NJfgwCUKCkNmVZg9xQIpUCBLWzA80mv3CWJoZgwJFvvw1+B5hF+7tAEpBhaRjHpvnwhGodqnYdIo+0GgOMvAsYB1+ARKgMkuViqYSTk7S6jmfmQSEtbQAAoIlTtwtFi9DsILokiLy9b73ZvL+poshfWiEZgJLxVEZlhsuQ9o0Rte8GuG2VysrzeJe2Idd76MvryohF00gTrWewwHLQKfPS0NUnZgoFSz+xEjHw1e17RyrwFMk33q0+fnnEso0KeWDAfuSJmfU7S7JTAuGZizEofd2ih2MoifpRTzDPZeziCGOeP5z2WZkrZLiz7+1XSQQgQpAhajQ9USYfPa+2AkaI\\\/jbANUVKICZzSxM7yRjykguVQWrsZ0g\\\/CEqJxWX37Glx7hzdfaAsh08Oy8YhSAEyBLsMUIRayK6cVz6i9IsTA3bFad68p7xAh64Z2iIQIBRPzquWFx4cZeJD8hJ8\\\/feOGjA5gZZFkSTdRIwT2zPWkHg2jpYZNTllKAwRFNEdGHz58alf+gxnTA5U7v1\\\/V6TwQZrnwYpx4hEITx7ubv72fyJm2eXK8Ol5b7cqg3ZpfHjq0TNHdx94ewdCGr2CKUgwE9mT1Ubmw+VBCYo8ijy130QRkDaro4RGoNbX2EvPwf0lVETcBeQISJGHaJHXkev3FRIwBKcAg+NsfJIaNWgcUSiAOHAXnCL4wK4eLxQH6NS8IsFOz8rdBu3upbxQUsAsi9vM9Ai0FSgCJZWS7Tt3gRQIHRMrKeeRpywhgvSkXgczAepQeyKl8WNISN1gEMqP5DF7nULAxPxuIqW0baIwMDwzcfHKmALggIQkAT5caCwt7lCngYzfW6jv7PszsyXUXxXh5ZdnX\\\/\\\/O2FFzn4KWAe8CmOkfsEwLKHdTxHzKLFKaU5Gnm2J69GnoI3b1loAMfxVAhhB2dOQ4xRQJ6hOwEU849L2UYrMdKQQLuAXcAVaIbEs9ew7ad+FoBVRISr8kAACqEwavvcu\\\/8Dm5u6faPhuugF0AxkDnnzoVYoOF8eGRv\\\/6r7e\\\/d7vzwg87KCgUBKD9efhohS7xSoIFB\\\/\\\/Z9REz82VkwZ0o1lEoe1KFShnoEaBtXJ1KOAKq36Vinhwi85LDRAX72ohoalpw1251y0e2s75NSGUw4WfESkqhCiBTJABiPonbt1tHwibmA7PriprdzWB4pjDxyOvT86uKS6Hjx9TTj+knptZjRjjIDFFIRhL7a2clkjDMcKuNwRX7ta7w84Fy+FK3vqWYLwAIlySqA8AEEAQOF4HXA86HVgWIZBkaYxWF4nCIETyIvnpsuP\\\/+ZcztPHHvnT2\\\/X3l+gZgjM0iQ1BA4Wh4KjCrbSLs+kVaAPDUM5MDIaTMKxYwQQJV4QRAROuv1IBMiR8RRR0aUTzeyiGfR\\\/Jikck5hFjcS1gDvgFLFQeeaZubnpUvJpmKJr72z51QPwmoBWY7\\\/2YKk5O1tKfLhTU8WT56aPNrfQq5Hwgcl41s7MMsVuSkVGSJ79tgl7FPqEXT6QbNgkGvuTkubBJYUaK6qH9eb17O4J5akZsVogawliNjCbR5LW9nHEgVNT4Pq0sQGCkgus2q\\\/jgyX29IXo7iIbHYTCEERtEKFmdaNtlS6eGLow1\\\/rTu2GHqDgGjENrFykEAGAO8AI4tnPpdHD7AUVhDlCSUO4x3\\\/tut\\\/HMBbx+nYhieaNpyWLmmWcWYqngnDrBLYdankAVLq2yiU5Q4kv\\\/8F\\\/ZZbt1b0UFHVQyiVewjJhVAUBCUGYALIq8o\\\/ve+JmTxWNj+2vbQXW\\\/bkFlamz8zHFLydbefn2\\\/FqOs0gCGPJkkpyYlbpFQhFy\\\/0nxkgM9NRgv3odORfkTo8DOnWaMpNnbBLoIQaLkgA9LZtxrHJwS0W9hBBYQBwMQczo3Pnpn54l94dHJq8PyxgY0Pdw\\\/Hp3BoCNo19OuIQHaZCmMwMCwdS4JCEwOaaboy28hxSKLSN2NFGaNApt7XC4mRid1jjDNmJGV5nhPm2tcZInb2NmiWB2rjErPAcsEp2wNDjz06adss6SAFHbGydEhBB4I2AVPN4vvX9p95etwtaBIPFlz+5LOzN959EDWLwDugBCmKufjpL8qqN\\\/tDKLGbBoeYS+9JrsTdKCJUQKaO0NcEAiRJWt6QYoiTmoDFBSlH5hC3gcAEEpu7InJuOYC4ukf3Vqi5i2UHz55FBrR9QPWaXjPy2rL1K18E31cKYGACfAfCNojQnR2DmZn6999vr+8H796lThXCFkgPCIgXkCFwl9yK+\\\/Fn5V5V+ZmpIOS2gvyupcD30A9pZAY8D6VPwgcZxc4I5OWSPTVOjClE6nSig1ZQa6kgRLfonD8Lqu2\\\/t0ydpnFjC5\\\/MPkVA+iTU4mwldUM2HvUy6av9xeX5cyenj43srmyIUNXWN+sky4PFsbmZoenpTsur7+6FHQ8AiGQsqMBUXIoxzNKyCBywinqzxKJjzU+K+6vk+QAMSKlGnZZW3ScuDf3si\\\/7ybudHN6jThE5gGj9EBvoAAEBsbAzHJ2GwzIcrlcnhgUpRVxnuxBhOdWh3HRo1tb8NioM7BCWB5SiYLQoYA6bbSByYhQBgO5X5eeB2a2OHAkuberKuiJwaU8N\\\/uA2WHqhyxpAxZuC81EONzV0qMVOtm8tDDKHQ69ACywW3Mj49duzEgEqInIj3Vtt7ey2SAoQAAIq8uwtHGzv+6ZNlFle+Tz458c35yc3DHQpbJiYxJwmI3xXEFG2UX269VP2YcNh1EczMHMEAfxkz2dfmp0AGKEhlX8lsEcziyoIDs+yh4dLMZKfaCKuHIGPEMyAiRAyEkuB7EETUagMRjA+w6REaKigvgGYIkYL3F9wXL8uthtwmaBYwPHKmBhgo\\\/9YdFVK4ugWWA8KHqKNJUCbiLvL4UAGLVrSxA3YZuGvG4CIyrHdSJHxQgrIDVGZB0yufuRAdHIZH++jXmQV8sMwstIoFkiQjFW5uURABkR75om3b8+MIneCD2xCGoAQqSSqKecc6Qg+s+DWS5oqBSFqegoyIZKDWbi8cv3hm7uz89tJqFAoi1aq12o0Htm0Pz03NXz7v1WrNo2a7VpNCUup1jDEnWglQGQBC4DaoCEsl59yJ8O4itT2DUSEFIqAoAsTRVx9vr9X8W+vSa6LtEBICMcdihQIrFsG1sVyU41OqrdTOodptr9TEG2fHT54cbJWLW0sHdHcdo0O0XTUyDsQBi8RsUFHQ8SRnzHFNoihYwPj4s49c\\\/NXPWZa1+OXX99+7QyKIu3AGwYbZFClE4By5RdwFu2gVXct1HpYgmAQQYEbGFhcuSMAy7Rn9KtlguVgcePzp+cqwK+MVK6X64Rt7HS8wVkYAAui02otLjXMnyya2jaAyZJ+9NLV5bxC8GggfSI9DWa72w7xSpQtmnxluYgYA0MNoTtnymM214dweHnRCCSIEITEjkc\\\/HAyZdLk7cYrZ99pc\\\/PfnMuf2ba3f+76+IhkwXIYOQYejYpiUDBErSXk1uB2ApPD4Hx4+hh7Rbnx9wLn3uSn165PrNLY8Fwd0HYm0NZABE0PBxfJo0PlivIo2WddCaGgv+6OsURTHoTQAioIXcAWcA3ALqhmJMUSG7iG5l4ur5p\\\/7Wzze2Dq\\\/99rf8Rp0XbWrVxepy0GmTUnE8uH5hFGPcOTMHNguu3SQVYZJqrqSBoMb9Pysj9U87skaiiaRHZWt3FmfPnjh5+czKjbuRBABGBGEQ7i+tVVc3ysODxy6eCdr+\\\/uZOp9GWUaSn4bGA2wLLZTMzgBahhSXOH7kQ3rir9CkHhJyDW6TSAIzOhku7h7\\\/9nXCvWbh0MhofEOsrrgrcyQkYHfIXVuVRXR01KJQEW8As4BxLFTg9+4Pfexc6wvqpi+7ZUX6\\\/JO4sQ+sAkKFbhHIJBgeAKGQcbJsXisg4ISIydArjH3sMxkeI4alf\\\/tjsS+eVEqQMe8a0CwzXxXwEY4wYSkTijFmscnK8urhCmRSImBhI0Gs4iOs5ivVkZnSHZkaPTqk0PPL8s1OcM2Wsd+Q1xNq2D66D5Qo4BT0dUZZ9b9X\\\/aUFoo7ngM\\\/boE1Ovf3c4bO1D2AaMAGQm6SH+whniPebpi5SMqYi6dNf5GLuU\\\/BwnTZEiwuHShb\\\/y6bYXkpCcFIOYeZG\\\/ZMbHPwJDiUxaTunkbORYpYvHi9OTzVYLSCAiEDKLK2ZFM9M0tg0cIHRNmx0cYAhNBULAxGjlifOvXp66enoILw2O\\\/WjwP\\\/3Gm7IF4I5A2AIZQNgAEOA60O4A8nhyw50rF8TeLoUdoz5TKibuCZBEXgQeASUeIA4I6BSs42fnvvgJZ25seHyoMjXWvrckWlWIPJBBGgWHDIAD48zm7rkTikR4fUEfsETS7H9GRaQSkLmVVhppxgAZuaZ+KVEpUpuLy+Mzk+eeuHr\\\/xt0wMoFhRCCFbBwc3nnt0C2XisMjx5883dyvNnf3g0BSUmU5JWv+uNhpssEh+8xkuLBOAQAvAip0CjQ0DmGASrLaDlp2\\\/a3beP6UOjwCGeLJeXH7XnRnTYWSRKilbYAckECFoLAwO0OH+\\\/56HewCfC8ILhxzHpuVG6tkcWjWKQgg2IdmGwZGhB8BAnedGFtGIKW3vkf+mRBg+5vv7v3wGigBUmYi5ql7\\\/KCho8wCxqyCM\\\/vfvMJ6oFjY\\\/ehl\\\/F8p6Trm+Wo3PbPAKkBhYPbExNRMGZPWFeBRA4aGh93ToIIAlAJEtC1WLIVQ2DkUM5M2xZroK5eHTl2cXKhuQuCCDI1tCVN9QMYVkmjX0n0h4Sn29ytlUV5IuaaObpTUO\\\/e\\\/\\\/EbzoEZhB2VkrEyU5eEmhGdm7sPM5qWBs3\\\/t1dLZGW\\\/7MDysJ6AtVKHroBMIcXMHOgSBwNAjikBJ4Ax4mawyWgXyEJfroyVL6jZfESH0QAQQtsFvQtQBGdDOGhQroAiQA2cA6B6bAD8Sm1VjiNE3GYZJ4Ju51ur2WcnBQpGfPUPMoVp74\\\/u3KrOD7dX92of3VKcBwkfpA6kMEIaQMVYoDjxyztvaCje2SYbGZ6xl7hDnx2ayyq3Y+gQpWR2TxMoEREmk1MH2Lklx9rGLD27eDz2fdHpujM0NWp2gE7YO6+WRwdETx4ojozsrO52GT26Zl4cLE5NBnZynHmvdewC+wMoQjk5Q2AbvyB4Ca2Sa+1J0hOx05MEubW9REEEU4kCZj01DyYKNVVARgIwbfQqUtKbGZOiHy2vAXXDKsE1ytAx7R9bLl6KvvQdD09DYh8gDkqAo6kgAdF3bqCKUoAg2vvZG\\\/d46SdFcWJGdts6lMD9UL9sCGTCGlgvcIW5bBSdq+2D0yXlVWu4OlA\\\/FQswotpNiwQa7yMtDjzwxWyhberCg47bn5+y\\\/96tzUs0KMtNlC9FCBIaWg8konxBKZfvqE9OL7w8qvwGRj9rZHk\\\/au+AKsTsUCT8i4KTLqJxGxUAXRQeASeXtVTs7u2ZEEfsJ87NIzAF1kKNduvfrf1ScGfW298PDAwOhRAUqKlTsUCjZ6ECkwOtQUAcZAulrp4BAkBdYI5Fz7OTijj8+Ujg46Lz9wY4zU\\\/KrIWmVDONAFvgeDI7EZ6DNSwU+NOTfXdJCfAO51RG\\\/yWXYYlgpF06fUIyJo5pqedGdRQoV8OK+Ktb\\\/3m1ZPxCNGggfTBMh2WwZMOQFt\\\/ToeX9lNdje1Qo1TGS0qWYo63JO74Rdb1R2WKQQDZuyulcVUp26eHr9\\\/lqn2TJkpKSHoUD4Xm0nqO8dVqY7zvi0e3LIGhh64qcenXr0xOKN\\\/Wvfvk9z56yL58BrYuipo7ZStqx15PYhtTpECKSAImPPRaSGEJ0ARydh9hjsbUCnAdwBboGSbKACIyPR4hpEEiwBoKChIJwQu002UGCPn1dv30O3SCC0WzdQFil0S7Y2baCSBFLUD4\\\/ePwSN65ORviundt7sUsLYoUcSSe8FriSSZjKOfSf0iH1S6DFn5OXJcGJoYuS5ZyZyvmggsNC2GAAmjl2Ghtkg8\\\/59hXDlkYlvjo21OjUIWqRC1EoZzM67MrAAhr1xWKZxRH0so2nEmsnGyfyBUkoRkACpWyCB8fjnh6WZIDHjYyIlvFW\\\/s7qSEOkpZhyXx8v7R75IHvEsOwcIQRZPjbHhofrq7n\\\/+T8H7x0erH64erG6yASyfGuMNq7m8oSIGzAKSUCjDwCj4Hjq2c+VisLCkhAIE4Lae9ZkrXLHozs0oi5NSKgjD7V1RrVEQmSsVAjCkdi042ADlgwhQPzPZ\\\/YVxPjBQuXiyvfgg2j8AJVBvK2Z8kFt4lHFWWBmzDuZwKNkMbq1jUkgg69UjIDV\\\/Zn7jwWq7Xov90\\\/onkaRMoGRrfx\\\/qHh+eOvvZM1d\\\/6hGrYBdKxZXVtljfpO0HcmWZDquk9MxUAYmMFy52OzL9R5L21tB2cGIWRyeo44PlsqjpnDsV3FuiSAERyEgLKWhtDafm1Hv3rVefpLUSrazgwCBwm1QUBQIjMTDo6IY76fsxhJg0Qo1vSyYhu4bdBgiEwDDhNZBkYClAzhiPLS1djY5sPkwuSCmj4Qbjo+c2WC46pdNnxqcmCiy2ozFAhqCSyVkuXCmRPSZ5X8QRT85XLj5+7L39Heq4IAMAhZjWo3HjmhAyQW5d33wak9JLv39IphYSIUVKkQnojfkgaV+UEvhCEtgBxIARSQIZ6tQ0Yw9Ajb10RudHDlZqyrEAwQAZFBIwYA4fGbanx0iF7ev34fgx2Wkthe1wcZn8htprdFQ4eGJq8NLp4Kjpb+0RWuAO4fwIba45xybEQVu2BXBbo6iQMxybYY7NChYjIIBofVe1WrFHMubWadJ0eRD2lkF4QAJ0+8DEeGl5JrNHhgqnj7fv3Bf1GiqRaDlS\\\/W6a5UqZeHSyzG9l0pBTkmkuKFiB3pCB6od1BHby3Mn1+w8aR01KS39NWAIkAYIBC6TXObi32d5rlqeHGrvNaGMPl7eirQPyJDAXmDabKJCmNM83xNFwU5AgIthZg5mT9qdesZ89Q2\\\/cCN\\\/4UHnSsJn1nVgGtLHJJsZVx5M\\\/vMafPCmqO9Sq49QsFCsiCHwvLA+5SdaFJkYTqYyuWudOKMrc4vL4iXjAAISk9IgiAxfpDhxAxK5k7LyW2yAJwSny0uDVx6YLDlPGuYuIYCEggUxN7phqechMy1WcJIFExQJ\\\/7pnZD18fFM0CCJ9I5JBSqRRNb8AqzZROrLnJdkGpkBSSGMU+kcrG7yKBQIXGysh47D\\\/NLvJkZceQddN\\\/SMRi2ugAhNwqlkbmx5a\\\/vaLCAFwbnCKENjCJHO1jk3xiLFhYVe0OnjhFWzv8zATtrFN9C2QIIlSk6vfXmMVKp+cHL53yGyIKWfHkCTYyShW7\\\/fZ1sB0sMbCKaHOsVJBbamNLbjUhCglUAm4yMdugSEWADJ0iFStQ30MwYiBzh2PmnlIcH3FnJxvXb6tOh0iPnU3WbLL2kKivxNjKrMgepmieQ53gZYmgVq1GoX\\\/i0tmNheVGrUHaQWM+lSJCJAkyoqh9uLL2lf\\\/pD0cvnTjaPGrc3S7ODbtTp737S\\\/JAqSAEpUCKlGmffh8MGAAxje5Dqwh2kY6aVLLgsTmxsatuVDAQ1I6fL0NqQPLaOF1Wq3v0dtu+fEpeW1KtEAeLcmBkpxaWpoeBW8llwFSeCX3YVA4yBWZ2LUKmKUyO6ZjpEZn+wO5Hs7syTfUzkGN\\\/oO1CYWDi+NTlR8Zj7icqgHZb1PY9UipSWoFJLAMOUiYMkE9PF12bMSQAlAAnzgwOToweHu5C5KEEo3TNnkd5ll6\\\/aC\\\/q0tRgjiOG1C9FymaI3DI8Ie2XVz2HodldGSS9MaVfbcJUBM+QsUK5UB4qdA4adLgPbhGYC7xgVVznzIw4OPI\\\/vE1SQWWIjo6g3bGiQX95CbwakNEwE4CU0Lz3wBoaL129Mnpi\\\/uoXrvKC\\\/f6\\\/+XZnZAiGBwBDWHtAhzW1uaV9M\\\/FQSqXOEX08GHARUXkAazukAsoh7RgiQ8YrsxOFqfHDD+9ILYXRfPe8FjxpR6eE33gdWl2g83xuMqaN6cTFp7RjmLUbrQc3Fk5eOGltWUf7NdOhiYmDoG3BfkvRzs611u6dpcL5Y9H+Rri7zmxljVVKj57GMOrcWZJtD9KZiYqrHAkSTHIdEkQt4i4wR77\\\/oX9UU+\\\/dBr8JwxN44iTsbVO9joUSACcRqd0mu3ycHqzSTscaLDiPXmjfO6RqQ1F5c827cHHcKbu+rw89A3IlbhempwZPzx7dXpVRJiwt600y+CkdyeSCXWAFlxBENpIJenSSWW8sdXVKWYLAwkLliafmp6dLCpIMKPrR6zt\\\/9MeLFHgQBiT0JhXDgxgnboFTcIaH\\\/vIvX3zxiTEjvSMYGneuPjP7o9V1CppAEmOPbgYEj+kuQaq7CZwJw+whN2YlNfnFq5RtWVZliJd8iBwgBM3qT52WWdURAjBeLNgTg97KmvI6qET6FZEDs8rDBRcgaAVIRCChVCqcPM258O8+kLUjIAVuGewiVLeQM\\\/Q6qnoIFKVjWSPKsWS707y2dPK5y+MnRiNJxz92Zf+tO7RwBzo1Mys3qRhE2VAgw\\\/sSKSWPMbQdONxEpcxpqVUWjCOzRi+cQMet3liQgYemTE0iTJLCgjJVJSU\\\/r\\\/6\\\/lVlkGc4o5RFbmfwKQGVmYQqCTmflzvKJi2csy93f2VMqBkLqr6EECR9IgQwpKkt\\\/mI0V5eae8lXYbEbr2874gHNsHPlUtLMnqkdEytx90iDYTMyRinB0GKSU33sNiyUSANtb0Gji8CCeOe389DNwbS34xg+h1VZ7VShw8KW3UnWem+KPnJR3dqDdPFiqPv3iVHmk5B8x0ysnJORoOce+9PHpzz9bu7YUeL7SgXvZFBdM5CegU3u4YzOLuWenopWtxE+Yg7NSt3kindJhirsnbqFTsMtDjzwywZnp\\\/Sugji+vf7DV3tmkVh0iH6SAbAYbMuAWuGWvOfnOW0MvXh1Bm2l7ScFmLz838\\\/a3hrzOIckwXv\\\/6MM1cNTQ\\\/UqsUIfP8Ze+GCZ+JEuYM9iEeAihSNFQ89Zc+VW8FIopQSEaEipKZWOZcRVKIhNbYAJ+f3Pxnv9d878P4mGBGy8CtgYmhSEDHk8Q4mxjAkzPi3q3g\\\/gMKOsZVaI\\\/CwSaQAi5l4MUkZ+3HVaBhaoSgBDjWwYF\\\/sFIVnO0uH1EgQFLcUY77t6TSmQ1iouNP5Yaj0xAFyTkZk4E4s+yh86eI1NHNeyrUK1Bh0pHCLG+PsqRWzO6IYOC\\\/1K2dSyCVmLNVZ6HAusANfG\\\/p9uK5K2dtG7fWdhRxyEZeJzGdBGJtg81Nw7rUjV0KRbBWA1LWyFBpboqPD0bNjndQV5EytzUlEYCY8RBiuYQT42ppGcKQ2ocwOIauRY19ajU4oTM5EJ6YsidGxWGN6m04MQsLG8B4uLhvPX+Vd5TaaTT3G4pBZWr4cHWHGKcYLkFS7vz4Wqdab95aFX6Q2uH1Rs4yGCuM47Kdgu1Yp37pOSup3rAnuUqTVZCynVNKc8Bi6KBTmjk+Nn9qSG90epEs3a8v3Vyj+gG0DkGzC7KnllbYuBUAXFscqdfPDo0XAFEf7qfmK9PHxlaq2xS2EzeD0opYNHxMJCCl4h6moswnR+jJH8kTn7I\\\/LcUoDdH0N799o1FtUeBR4KEIgCRBPpKFFBAQcATkg0V7asx\\\/sBonDqB+cTRnfmRutOHa4WPHrbESk75Y2pRrOxB6oCeQAyMQtEF4wC1WdIXXiPdBSkJ5AZA4A86tydLejYUf\\\/fh9dIAcZ+DMZOvmvgq0u4YylXB8czM9gkSBgQAMLJt2V2LKvWGRWI49cvZYJML6whJpvVuSMgTdQwgTyYp9IlaTzHrM1BoIvaFMaU2fmeXqolmJKISFGwunL5+emZ\\\/Z3thTxNDcXA0QB5RAEajqEU6Po21R5IEKYlsXieph8\\\/CIu87g+dPu9FTnoC4O66LdSjQlpBTanJ87LVe2wGubcrG6RuPHoFAEz5O7u53\\\/7fcpVNDu4PgkyA7MT8HmEUkOoZIfLvPHT0Iz8JpeqyVGj42tvW8bnrfJNwubdxZbd+7Hp4HKSiQzViYExtBywHKBu1GxIL2A5TwBRuGftMJStnkPmdSsOGYxp\\\/jcC8eHxgoxjo8YwcL1be9gH9pH4NVABEASlaSUg8qAOwgEXqG6XV14UHtyfDqWacPQgH350vjq7SIgkgYoKInpQZgIkkWSq5NPremJg0XsDXQzzyhp4x9nkfQ297zdKgWdWKgp88ionDwAAOA2pH1UM5lAYtxyrJmz49Wiq37uKv3um+F3r4NtGY88SSwPEXLoHAFjQJzPTqmjA1ACuAWK4oQvIqcCtutUOLeVd\\\/uWkKCv+mxmqHx61rsfCE+fDSK\\\/2yjoMYhioUhBG\\\/U0AhEZB2Zx1xk5MyfbnfrSOimRUFEoxSBlMUUpV6B3TSV+M+qm3acknz4dsbjRpilpEpUQUbh0a7FQsudOz3PLAWbpcAhKmDa6img2rNkRJIlJWLxSIAUpIfzg6Obi0Y17IMLRJy+WTszaQ8PolMkqo1NwT82rzT1qtICEGSQQwf46qBArZegcyaUFOtynVkttrFKtAa2Afe4lNjQIQFQ9kNfu8MtTAri\\\/354\\\/Nc5sFywb4h4pKAkiJOFD5EHUgciDyAPRAeGB8ED4EHmk\\\/0X4FHkUdkj4JCMlpVIU2wpSqW\\\/WcUfdfl7KBcQClsqlq1cnESHuUaDwxeKNTfIa4DchbGPUgbBNUSf+3nwUAQifog75jeho9zvfvtv2BJnWGRDD55+bqVRcUARSao8fk4Ij6CgTw1SVIYjAcJBBkkGA5dcKYpZI2x0Vm6pBkQOCEhS1IWqAaIP0QWoGqWd+SR+l\\\/s8OiE486RbmPDJlAgPGK2ODM+cm1t86sA582mmAkNBpAAMQAXJGhUFoVGOfqsSxYepIMBm6BMjRKVNlGgDtAiscPx7cvAOtA\\\/Br4NfBq3WWV6P9\\\/YnLZ5xSRT\\\/8qY3SjJvS0E3U8PiZE9hpUNKtYdwqlUYfPd+p1o8erJMZL0tIQ1EhN5PKwPL7CiKSk\\\/AhUJQssy8L1jQ+TzTpmigBSUS0urg2e\\\/r4mStnl+48EBHFL4022UtSgrZ33cunBYl4X1SYouAUKKF85W1s+du79vCwOz\\\/nuKXIE7zoUKuu6prHmi2aCI62YXAcxybpaJ86DeQOSAntCO4u47njMDPCLU73V9T+gVpZxdMX92rw5PkJd2i447cNElfb7c1dLOnam1B4zGHq9d8SiEzn4zKGQIoyEUvGsUDZD8Os7lLvdxhTQkBFc+PW\\\/FgBIxkCKACb6N7N3ZV76+Q19OCb4oc1rUWJo\\\/ZbIYM6rH5g7axcOnVmnCEqhIBofr48P1u4vRKayr99KDttjARDFIQhkQgFBS2IOijDFIWspyx9\\\/PbZ\\\/m5sI8w\\\/KAx0anJkKEbZTiP1\\\/FN3PuJWVZI5p11d43Ojluts\\\/mDBizpQLGLBpaMq2A5wGybnYW\\\/T7CREiKDabVXvAOfgOFgcBMGI2RAKq1JxTp1s3b6nggCUAAjiqQPz96q1IBy+eKp+dzFo1AEpqWAN\\\/NKwK5CQgVuCKIDA1713RHQqxcHLZxsLy0H1ECg5A1V3MFr6w2I3\\\/rRnOVrdf4R9S5LkXk6GDJvSpLW6DQhQRmJraX325LELV84s3FyMROZuS4QkVKeDBwdO2Q2bUXcr0WDklEa9R0eNqCP4yGjlb\\\/xiQYjOH\\\/0gdIrKk7kgKv3It+uIFpueU7sbJAKwHACbmh5tVZUXQr3Bh8o4UFFNiUW2LtxXxivHjg8v7u0Qs4hZGaWocdkk5xmkTIccJJtYPCpEZJyhJrWm5r3MwAcpY3OKe42kQCGiAhlB5Fe3tv7ZP\\\/kOlQYFoIwCLvyDjcPO7gYEDYg6OpvS0IqSRYgKAEAYEFVrC3\\\/n\\\/\\\/jW8OwMc0sEpIIOdBo7D5Yp7IDwgHHRwT\\\/+j2++9voGFEqKUIYeefXl6\\\/chbIPwyVxmFPREfFNP8AhlEn2yMEVJClSApOLQDgSQGQlu1qAYEz10NHxCoNSkcG6NnRqrVzve1paqVXGQ4\\\/wEVbchjHD2HNT2QATx8SLR5lCvURQAt9hTz9LHPw5f\\\/gqsLznj45XPvFT\\\/0zeV34ll3xDn+jAg6R2GMuyMnj5W32DewSEYcLmJB0iDHgigOAD1KukJFmOlocrIufn9O4tBrQEquwIpAbr2DH3oITe7tAFm9d3yqOdjKLMM86epAUPrb0BGsLm0PntCnL1yevneahDoekPf+yUABI22e3IuvLGQExWbJzTVHxBjoCRHqX70\\\/uHSll0qFC+fitoNsbyqOn4a6a47RJ0GIOHoGB3sgkRwCmBZ6vYSDJRoZ0sUy9iOYHoWAmLnB2pD7uSZ0cV3UfPhdTCTIUAidFXzlEvzRgA08AVuAzJEYIxleUpJaAD2vPqY6fGTxlaoiMLOwerawUED3EEANNWvCCkKIGyDCOKzJUl6MfE8cTNQ6qH70vs34e4GOGUgBUEL\\\/DppKbMS+kF\\\/cHPhwf1tsIsABJEHYRuCDkRtkgEqkeTAIebGepiLPEDK5iwkkjQiJOJJ7gizwNI37biySDUAmKoUwGRy5fq9nDOLz56f3FmthfUaeA1qduDMLB6fp1oLuE1BmIlwJeYWMCTgHAtF8CLYrEIQ8sGBgScud4482WyYw9nwaUzqgd5jwnpYvRcNnDvNGWvvHWgzd\\\/e9zHFgdBJW7mqKwsDk6PCxid0bi2GzlXPWQ+bV6HPW4UMr0fjPrMxUOtE09cIMkihu7IfFQ3MkKkUIEmhzeWMe1dnLp5YXNzttLy62AUCJRrt4rsQKBen7SfMDuwLEkAGzLLcweGy8fv1a2AxDQGTEZ8adM8eV58ujtqq3THa0fhA6TYgCGBwCXwBn4Ldps8GfuiCLBeAOBQoOGsD2lQi2sTJ+cdpy7EhYIDkoDsickYo7MujtHlEuljDF4Zr2HWDsCylw1yHGVCaEnuJhokl\\\/RIQ+CgkwsS5KAgqUHgQAKqROzZxBmn8jQ6NlNVR5lbkJaKiNzognAoCQSAqIOsBtAAIRogxBhEl0LpAiGUJQNyFEui8qAhCeZu0YIlMK9U0jmLC3LMKuHZ2IJDLGiwNY9JAjKhUPTRPMDCBmpdvMKrgDZ4611vb8g0O9UyCzyXKH58ZGj4\\\/d\\\/L0bIAKIfJABLa3jxXNYHKT798EuQ9RMpYFTEzJkODhBIqJb1+DBAybDwcfPte8s+NtViAIEIi3fAdQMobSjgTzqePW7i7NXzjil4tH6rmliZf9XGYH6gd5th+amKlMjO9fvRp6v+R1IyevWter6eKbzlFZ4SDmazfQF6stEp353yjx+RBnAGsLa8vakYKcvnXpw877naSGYAgAVCbG+VRga6gSCEEhjtokom2YBjFv22JUzra2t8KgWQ4xRrKxLRDYyyM+fhXqLqjU4OiKlgFkIDPSOPD5O1S0II+AF7HjWsQmxH+qgeQVh9U9urrbPPHlipDg2LAKf0AIUwNnMn\\\/\\\/k5KefbL33QIRh7vwDnSCMyBAIJBERKsaY7ViOVTk\\\/U1vbybbUHlr5Z0+ChM2uhBkHyQhinL5pFKlEMyBNoZ5CwWNjLdNB2cYUgtIj8xmIDF7WbAagIpRJ7Re\\\/WYZ2JZJYYiLqm\\\/zaFcfcc+cBBRAOFCd+4cVSOwARolAcgWvNsdK6XIWAyJm5ZyssDJVGnruw8ZXX1v79Nw1IkttoF449ckIh27y9Q5pFTwAigiCA4TJwhCCKfaoAnLvnT3rX1ynwQUbAGQ\\\/rw+fmOyub\\\/u6B3sVICQCGzCJnEPwjEO0MyUIBCBni1u2VyScujRTKteU1pbO9kqStkXHY3UXbHZkddUcHdz64LUIf9fKLbzFZYWdXtUndCfJp17xrTVrdTN10xA\\\/ddCDsTsxGyn+gbmboF17B3vpWFIanr55fvH4v8INkWiLb\\\/ujJea9aIyBU6TqM9bucMRg+PR1UDzpbe\\\/qJjC+jDBDVYU29cw1KBX58Dk\\\/MycOWaobgBxA0odWgwMOJCTqoAnC1dug8dk7sHQICkMBR17+7tqzk1f\\\/mqamz0839GkQGeXB4bTnsyMYbdygKcltXon\\\/HmA2jJ+xuxSpXzo5WEIH6WXfjBIZ+dDPzWqm4AiJQEhiLoVhJFZeE6XUFbpn4W1KEuqmgFDCZFsx6DJ2Zkptc5OybqD+\\\/0j09hRSvwN6uTPf8s7dbjoQsaHoH3\\\/6gXfNAhBAFIMNkkm96roowEesBWhWntldtvHMbVGTYZ8xmdnH+ysz+yqHfbseGeoYTw7Sxjq7NZ4bkSgvsEiIHzrFUYkC0vwkCwSpwmw2fngsPqv52FbVVTUWglAZFgH8EMkJmAylKdjcEACUV7d24P37+xPil8wd3l5RSwC1gNo6OwMAg7u0Pnpzjttq9dltFIUihPxwzHe6eNHnqFxWaowvkT0eyEPrl0fftr+ccGKmQP1OyJAEgqHexo92DKIzOPH5x5eZip+0BASEL2hFUKs7AgF9vEKM0RwoR0ALGirPjilR9eV3LtTDWWJNpCUpQEhq+uN3GkXF85nkGIT5YUnsBRARK0d4ujk9DxJRyIreIw0WqtZFbcHDgjBb8VrR+e\\\/fiJ88uv78qQg9kQCJovnWt+daHwFjcmEg7CpgmN5q8ALRccFpWqRy1PUaQz2XCh3Wa09DMtIRXZlmhRGIZuJDCJM07N\\\/DN1rSZ6G3tNcmMADNzyqzwJ0MPI9MSxLxgEvq30jGbRNmdxoXIkblKRdXDYK9GUajLSFSyZziGJg4REEi1dN4BcmA2cAu5XRooTpybePubD5RSQAIQcGgYwgj2d4hz6+IJGCzKkBMiRJFlAW0cqlACs5DjyLm5qNlobVdJhtpBi8iIMVISVZCUGGTYdjYg0y5+UlJG0f7C2sCJuYlnHzu4viBZAawSTs3A5vLg2WMkZHVhUUVRolvCTOwk9UlAw36K3J5LSQZ4Z3X\\\/7d4e6UcCZBHzSqf0RVdavtM6rK3fXpg\\\/f3p3fa922NBVz9H9dWd0JGi2SLG0X4EckBcnRkrT49VrdykygslE\\\/Y+pttshtACRGk36\\\/vfQAhwdss8eZ3Yh2j6Q+1Wqd9jcSVAuVQU7PSuvrUKxYHGLFYvBTmv95vbLf\\\/Hq4MTgUadJJgBdJjGx6cjeaJcoB0dhUvu7KGJxLDv0psRRl84SUxkTYnaRqFhWozKdD8qz3qjnTTYeKTKdeiTCTAQzZlXAOZBh9pYRJ+lRbN3K32Cz8NiH7CuxBIQhOjpEVYZ6rIIyIiX7fUJm4hIyiWEm5oTzuUszkvH1vZDGRmCvDRRByaW1Va03iJY37JefpaqiB8ukQmtgiDoE9gAyGDk1RaHXXNkAKWKkAKNEvwpK9xo1dIeIkIRW\\\/JsAabSUhMbqrhBs4Pnngs2jytRkOFTBYTfa2u0sLVMUQRKb16fo6bl3ZHM8CD76f0l3lLp03h\\\/hIEvSDR6iq8mQukDpSVvrqL5+9\\\/70hbOS2c1qDQCDVlg4cQw3t0goMIcAAWPuQGno9NzBtbsqjBIZPiaZUowDc4DZBADSN2k7ACSY3I1ktWNNjrOpITZSVj5Thw04NkcB8VJJjYzzs9NciWBxT0Vqf78oXWfqwtTR2lYK54wbaAiZmF4zXNLnsE4QkhBHbZtWZbobImYxa8mEO7sK8m9XmsFJGQMwEfXCMrCr5U2JSz\\\/RGCZHLULOEkg5HnP85mnBfSwrw4c+LPkbIXbNbIwdyahqY11LP4Zy4sRSiMYUnLaymGUXC8++evFw8bC1tAcooVzAizNWvaEcLr0I3IIqDlNblqeH2geDFPlW0ZHSxsrEwHwZlHd0c1lpPwTjRpGnHaoIQCzRMkHmtQNAJEmEgDZym+xSu4FDbfbpv\\\/OluSszB9uNH\\\/3rH9S37xhot9aHxK1QTDxD2KVyR8wfhj2i20SplUhVycr3QjMlTB\\\/wQdda7Q9FyM6ZSOmkLuk1Wxt37o1duii57VVrSihu8eL0ZHvnIPlsls2HT83X7m8IX3TbargNaBO3NVE\\\/nhOydLClJMhA7OzAzjYWC+zCRWt+VB36MD02cWp6+Ox8q1jc\\\/t4dKNo4abeHKqu3D658+uzyG7eCkJPmICgTUkL6TCbSrztlPAWZ\\\/BbEmNaeycDJzhX1U571UeRU0WlKRy7oIU8Lzl4l0ni7eEWlhzBl57E9TnnKWOoxpaSlBsgupRX0Pdszmy7mJ35IRBERSZG+LywDZDN5jyxhjZNOJtXfhRkP2kPTI1Onx979rfeodQheA2QLOlWw0b1wSh4Oi04kOyJa3Bn41FR4+XT4Tscemwz3guFzg4y3Dt+9F2PdIQ0CMKwunUzIjfLTbK9opBqMmM3BsaBYgYFxHJksnZife\\\/yYO+BOFyxXz58MGS2zfrt12P3ACtizBKl3EEgxbS2lh2TmE4h9ClrMZfRgP98TplG0RlJD2mSjIGz7+7cWxq5esmze3D9q3l+vHJvu1CNSCpRCkONXTvpHR8FRI2k4oU4atV0CBiKIlx+k6HhkqbVZVwvMJsHlwpYqt\\\/nU2MTFuU99\\\/vzEaGF\\\/1\\\/va+lHj\\\/apaOZLr7fud6OrffnryzPR6s4VSmDkhKWSIrkuKSMpY35wxxaHh1QOzdVHIMpAIhFyuX9Yci1lRfbIUMRu7kivmMZe6TZnJuVZBYQaqmHnvMJ+mFH95zDEHM\\\/GUGb9ptjXalYiW87JgwixO\\\/CUIyISu\\\/ZDpfMsYmAD5kxCBceQWMltJAhJAANwC7qJlz1+Z6YTRxt018hogPRibpNXFSEZie9caGy6fnI12a0EAtQ9WrM8+U+4EoydnS4Ujjo2Nt1cIOTCVBC0hA+OEYczIfm2bOzZzCsgRSDCLsUKBDwzhUFkWi5EXRp0AIouCTmd772i3Oeaww5Xd+uoaRR6YxyNvC8xRKDB9m\\\/u1YjDzvufe7WREkdxeEPK2id6GD\\\/XmZBNkI4DTKjk26lOSLKRACRH41VuLI5fOYbHQOvCssWmrhpHnoQiGzk+HgV9fPyAdD8ot4CVCjjICKQEi3ZWOPfdoYkNIB2YS2ha4BbAYMAcHBuxjs2x6whkemRkqjBctBChVLD5UYPMzJEBJ6+DAOzzwLrx0YWthX0gZS1LY6FOXjn3xpaM7G1vffhuiMO5eJOlCQPo5swvMdmJpJXbdpikjuomPnu7hBaY5SZTuXJCTHGZL2h40dHIqUZyyRlk5WbLiTbWJveqN7LaQafHlskGxa\\\/dFyMtiTTwPWoxx17UKRbIYShH3tro2f2SOM\\\/Xp50qnZtf+4Cf+5iaA0nmMpZHhRz535e3X11oRQqEArAC7e6AIgBGwqBGKO+tW0bKmZ3Fo7Ayoz\\\/\\\/9z5U4f+OHGz\\\/+8o8kFgAD5ICOjYyIBCOBjmWNjvDJUas4iDKUnof1lmo0pJCkUASS2g21c6SEMgMgHTtZHm6PTXz7H399cMBqbGy31lch0DBlhTlMMnXfL9KgtG5\\\/JmZdNV0jjKQGzMj7Hzqmz3d++q1PyGjZkgCRVHlJBihMUgR+9d7K8JXzxdH50B0qPTLRXFgvjDhUcmpL98kaAAzBAYPWkoKQoWZUAyBjHJFx4BbjAwOFsUFrZAQcLkMhOn4QRFEkpQAACFe34MGmh+6dgbEhFZx++sS9e\\\/vt9xflQQM4xyKPhq33H9Q+8cLJmz94sHPX13FZVsGe\\\/YVPDl49W3nkzPgTJ5kMLSNQyRDkESSiQsYsNnputrm5m+2GYLbSSPdAQsyJcLKxf5gRO2F359NUkNnOCvUWnPFf62rQYYIcyWsw8pNgzDb6ssFpGVIbYo7dCNl0NcMdHStf+BuvhmHISTEiJFLKfNn47qmR\\\/UV+8oRw7PFIbfzL\\\/wRgoV3EQuXY1ZMDw+UH722pSECxYqCptgUkwS7AzHGqDEVFB0vl8szUx185e3J+kANefGLqvfWLcDhKzSZ4LXW4D74PUQBCkZRRtRnuVCEMSSoiBmFAIBKyY0z4ZIAcGUMFBBbOjYh712u+rBFR2DKGKSUghhtgxuOqdz1zWUHoriby9Sc+VDqTGdYnGo98lBzCwy+GXYdm1x\\\/n9d7xm0wKSCohjh7sFh+fLh6bvnhprnN1fr0a7L73QA0dA1aE1iEGDQbEygVnoGgPVgpFR1\\\/RQJJLpJT0QiGEjDqhX9+KvEC02jIQQGRkU4wZEoxd8Dz\\\/x7\\\/9vXf+eMD3QjgxSn6NDj1gFtjO6n61cXHozNPzu\\\/e3yXJBSaXA2zkaOh827m1sfuU1EpHGxqNSZokwrR1lxC2rUDz2i0VSRFmAZ2YFxjTr3IUwOXUI+iCUKONX6I3sjNcWdqWRpkFPfUFMOQ9EZuCSVUdQV1e1qyWTYhoNKzXb+kVQpPyGt\\\/anH3oND6UxTyWp7qlDiHFnaHj6iyWYGvaXtxGBmA12sTA0\\\/PynL+7drTY2DqHTgYIDu6sQtkB4UCjgzBRVBiCUIHz0oTBBFcdyAIjIa0Xh6n60tU2He9Q4Aq9hgEOadaRiyzKzwClpmFjmXh2bwvQeVXRgbobWVqDRNLwSFYGIQIaoMg6JfAR9XgSaL0MeLlXL9E3NJ7HS1xv7Gcq6UBfY78Le1c5OTmfzvGB2jqF9k6RUsHrw4l946YVPnvIU\\\/OEfLx\\\/4yGoHrOm40YBFIY8CIiWJUIqo0\\\/ZrjU6tLTqeVggTQjZPNx3CkQAVURInSIKUEFGnVa8CEBxu2RePK4Gy5gOD4NC798ba4y+dvv39e0drDUKgSKz++28d\\\/PhDb2svOKglDdJEcJgimS3XKlfa1cuUlZXqzniS7Z7epeNJeG6tIPYpa7KoNuy6miHmpEyYs5NkTf2YP5WhRwSFPY9FX9Ma5kWvGGvPUi27thdb3OahaC5sNg8bICIQIUiZweDHjSvGkRfqS1vWUKmzvAXANJ391OXZY2dGf\\\/N\\\/\\\/4lo1cFh0D4E0QEZQrECA6N0UIetI14olOdG+ZAtDne\\\/8xUpPnfOP2y\\\/986m0252Dg7Ia4EIYneFSrZ7AwUtDsLwMdq6iUqm9PAUlqDALcKxY7C\\\/B4cHiMmbTobSQhK7s9Cp\\\/8QuN1DvevcIMqT2nF6G+gm4H+rufOjMCPt8M9ibcRNbrEkBSUQYqTgSwbFwbMzhXiPc3ZHbG1GrDkGLooCiSO9ACLGqA7KIgH6HNLLUgIscSKFSJHxASx+S4vYyv3QaVYeaAVnuvR8vP\\\/7CyYsvnXpzbZ2QEUVRrVY7OtSa6QRtHMsJtJuWg3IAOUVB1AncwTLaDkUWMAZSe2Ew\\\/+ND0jQxG0UfqFYXFyNz2+96xTMhEXo+SDnfbWYfzqZAdck3khgyYpj6RRCzSoCEaZHOSOPlB0igg\\\/i4brQUhyoWMFJkBJ8iNLH1pmFkNgVCRlwE22GwgwQMuAOM26595aUTD5YPd5c2QQbALWjXgHEYGgdmQ73GSgVndqw0MQKeV792R\\\/LizY2ZtWqndWtNerWxk0MDU5XWUlWZW71+hbRnwDiMqH0IUqAMUognQmLIQteB+eN6BRqzQTJcTbSvqQ+Leh0MidUEHy4ZpYTvjQa1nVUWWz3D\\\/ofIB3vmgtnIy7wkADNMDMr3dSgx0apO\\\/fqPbg9PDahI3v2jd7zbS9SuglfHyKPIBxVhLMOnWNnYtcqzXQvzn2QsTuY\\\/9HYo0XD4mA1E4s4Sv3BCiZD8llfl139y\\\/9xLZ67\\\/6QetPd\\\/E+iYUYCUxq9s0j5MFyEBJRayx17z88vnC6JAXtE3ODGmfkf4GelKNspqTnNIIs3RO7MdBo65rPuTZ34iZfixmQgXpI3Q8afgBpQHQWYFqSjpK+qExiTzxTCCjkdnhxn4r9EKQkcZvo5SkFKY\\\/K6KWy+gnm9vAHGAMkZ1+7Nj8lenf\\\/413ZRCxyQk63IdimYoD2G5a5Nlzo87xGX\\\/joHbjnooEIALzrMJQZ3stPNyAqH1wbXPwxNTIhfna7QUpM7hxopwBL6YGpy84MgBE28EL52h1gw4P9V6f2LkMDY2IEospdOEgc3znLAYGsJsxh1147VQ9RQTA0Z3L9zp7y87euQV2YzAw+yUQuotbTPbDuJJBUrSzvH\\\/z9YUPvnPtYHGZmnvgHUHYRuGh0oV4nPYKCkkhEMaDp3gIq2JuHGVYShnzGkFG+xLz56SiWgOPT0AgKVT1vfapF06Xh8qbt7ZAaVmz8dchZamYGRCQZhxw1ykVrn726saNlcZWFZREJZI0sUxqpG4sMZNKi8lYJX6akSX93uSfmHyUhgBnwLgmIBEYMP3XWCz+Tj4biz3xacp3+p9M\\\/475a2T+AqPkN7H7W8L0G2OUpik6aBfBLlQmR5\\\/7y5+89u2bW7eXIdSWeQFKolJJ\\\/h6amJP4xzfkyIJTKv3Ur7x4uO+\\\/8901QokWACgol61ObfjYwPDZGW+32llYjqqHJExqHZJypobC+8vk1SHySIRB9QhlOHbmWHBUk0LGhXpme0JEu4DCjx9QrWVn6Lhw9hysrlLtUNeu8WMGKf8g08vMNsEzTcf4uO\\\/xCvZspIm4N1ONIACClZ2uY16XC32UqXlWysOaN\\\/mrPWEmE8SkZ\\\/tAJEVQa1URgJSM3TdRYvTW\\\/aikbqa8CiVRHWTmZbq9xAxhSTML47oNlIngBVLgCbq\\\/wq6cp13RqXmLP1h8\\\/meu3vvB4uHaFsgQMAIQmZ0049EFIiVRcZICIn9\\\/aXO\\\/3jn9qatb1x5IGcdrSQlKUGqlyyWD0UfW9tnuP\\\/YMPPKj4O5bet7pmc8+w774xbwy52FlPqYPUGzYNaRGckrolk6\\\/cMkeKa\\\/d2TQ6FZl0ZTIaLmO\\\/Stg0DLiFlnXuhfODZyb\\\/6J+\\\/K5HB1ARJHy1ZGEB3bDzY2Kvfvi8D33R19E7EbGY5tgi82oHOI9FforPTUp3W9KXTh8ubrXrTZI0CoRbxEJCUGGtWzc5YKOK5M7S2TvU6xC2cRE\\\/RrfAkyAKzsZc5kZ1M9GRRPez6lNzTORZm+xvqH4IT6XOf+ajCNdPcTk9DvSAlKF29aBhJiDLKohaywHB4uJI\\\/31PIlHyZFAaEHl6fAmp08MQ0kNXe65x4ZHby+OjytU0VhSZkM44fzpzjZtysfb1oO3T1HBTsS8+dDRt+dXmXEmp6st+bmi3\\\/yxwmDE0vN8nfMn8Bufl9NPWepfmWce\\\/X\\\/NKzmvQzIEfO0XxU9gvpT24Bt+JPwpKPQmZlP7P+WnGOKgf9nXAr\\\/k5s4DZwB6wCOCUsVuYeOf3yX\\\/3U\\\/Vs79xfr6ugQQtPQz55C8XGqrRIcmYW2C265PDb+6q99bPHO4d2lNoyWaXIUR1weNNXWVufuUnhUoyiAhEWkdYKMl6dHmIqCgwNjtoxRGsIPw1Zn6sy8kirseBkJJyIgWC4ogRrfDAjFIp44STu7+h6oKx3MXsfz3u54VGCeB8j3xvr4aLoa0zltf\\\/ovcWSzvhP2zhq6gymwfxsGe26nXcjm7sWhNwwJCogUMImxuibXh4QcrLKPKJ2S2GaEZBBHSbpsRqOQbm2xdUj\\\/hmLQ6dD9ZX7hbLum3v76nc\\\/+2nOzF2fX3m8Tj3SWlRk\\\/JFIGjMH1lstKA85zV2TBufeb3x31XnrhL72sovDBD24KzzMIIyVif3DPrZlyBHnqgZRm0rXzQsJsgdE1ssUU1Is5tFl+18KHzapyv530wExv06S4GaMZcActlxUKM1dOfepvvFrfqb\\\/7G9+QPmGxDJ0GQQCMp99tJuc43hFssIu8NPTE5x9zKsXbd3fKv3DVHinWvnNXfLAiFhfJO4IoQQoYnIwp5JQYPjFVW1jW4mxMnJlAAMxvtTfuLM+cPV5wsLq5K3VnzjgqELhNRIgKbJsdn6eDfaoeIGj+b6+YIm1dZlV+0LUC6b+gp4nd2OReV6YFfRn48dWm58sCfgSxJquf6VqFMco0LhwloEJiqSc9noenVmXK3aMzUI6uyXNSX8U1dCIJ65IJGZwUACDKiIBBq6XuLcOli+trRws3tp\\\/\\\/5WcP1g7auxGoiEBhtjrRxw5yYAyL5cqnnwHOm3\\\/6GqH15r\\\/7sfLDF3\\\/t8zMXTtz8+jv1rarw2iQioDiPBXLM8zztP5dXkRFkdlU0WTkbdnVbcnpUo1PL8mfR9I0pl9ubnz\\\/mPqmJcU7McowB4+bGyCzLLVTGBs+\\\/eP6JP\\\/fCzoO97\\\/+zb7R3qyAC4BYWB1AJkmGco0I6dDXOWLWAOWQV0ClPnpz+2OcvfvOb60dSVUZc6fvq7eu0tgZBG7QGNeuciaEynIPyw85ePD3SJpI4uoVIRp7cvL04c+HE1KWh3cV1KRSRQBkBQ+A2AIBl4ekTan2Vaoc6iQTj5mfXaZPSsjMdeTIZIIB95uaZN5HoI8cLlFe1IeLwM9Btisso5XvOWOqyp2bvL9ini0O5bg0m7fWkeQ7pPh5Pjql76A\\\/pgsAk0Rl6BQmQfHuYtiOTKTMY4TUwRowDd4C7YJdheJxfvTyI9s\\\/9rRdvfOPW+195W3XqJupVaSU+A9tBp8BcBwCKn3+JvKjznbcobAMpYNwuFo8\\\/deGlv\\\/zx0miltX20sbhb29hnJBljoOPblWIm7Y0kKb2Da04UAJIOw9GBoVqiGkdXKC03yb1hcXiZ6QODIiKlA0Q1\\\/06BUrprQ7GPH5ElSza+KWnFHyJDZvr6yYFDyfhZaaEStxAZAhZHB4+dmxo9NoKMvf2Vd299+4POwRFEHT2WQLsIg5MAyrIQAKNmC6IQVKTVTsBsslxwy4WxiS\\\/93VcrM8O\\\/9xsftqVi\\\/hHUq3L7EGrboCKQgYFuUDKFIUAE7hRHB0vTM4d3HpAyR2UaOq0ZTciBW8x2huZnhuZm1z+4L0MfRIiOQ8JHp4AXL9DCXaodauYqZuJys1CPRHSZ4OtjeWDXJIC61lbP8RirCnN9Gur6p9UPHJLrx+QWdjp\\\/oMx3RAj9Insw2wuA3qg+zHeRksEJ9lPKZVQn2Ns6oO49gLKyLOoSn2s3OkQADNCHVl3dX2k8\\\/fSbP157\\\/otXdxa2N68FZCiDCEDALVasTH3q2ZEXrgZBdPDOzeaP3ie\\\/ZTIiESMZLr9+Y29hY\\\/bK6WOXj42fmznx5KlCwSkMlTr7zUBKAWQX7OLIQLTXFFIqJXXAC0uvrcbNpIAE4uDkoApV1PSVksoIwLTPHLXXQ1DM3Sg4UC5Ghy0TFaRfBGVWFzBmjQ34hy0II33N5pkZSEyzRYtzPjXU2W9CJFhMbdCqX6kAGNoWtyYHg4OG3wqP1vbv\\\/ujOxq21o8195Xcg8kFf3vRuIsT0S49f+NknZShv\\\/D9\\\/Wr+3AoJMZKfloF1Ep3DxhdMzp0b+4B\\\/\\\/pH0gyKvK\\\/U0IGsA5kADRgawRKX1qGaiwND7oV\\\/dJRQbazWxtR4qdEyaPSElV29wPQyo\\\/frm9sCq9iCxEZeP8KXqwSq1WWo9QkprU5YWnLFsCU\\\/wZPbyKT2ZSub4OPtRuRHnuKPbqQrG\\\/Kzi52mHm6KW+oETKlpI98T7pBBPhYQapzM6U2hep7wUVu41Xugjq8h\\\/rF16ZIlshYASSQeTBYVXdeXB\\\/5Mm5hnzsF5463DzwDhSRAuETKUBuDw\\\/O\\\/vSLhfFxX4rqN14jr40iIJ1HiwBKkhKt3XDxsL74+i27XHEK9uCZqdnPPnn3X3+foggQhs\\\/Pnvm55z785z8U7ToEHZBRrB8infdEaGkgJ7OtF3\\\/tMwcrjYUf3FFhGyLf5PvEu6IWDREi2tbQpfmx564u\\\/+6PVNAGKdDESykAAsu2BioX\\\/+rHl7\\\/8Zmt9z8C2uyQBjKPt2iMjl\\\/\\\/WK4u\\\/\\\/UZ780CfQiYzQx+knDsD5WO\\\/9onNf\\\/eTztZh1GyB3yIZkIx0GjsoCUrHtSuGYv7Fs0OXTyhF40+ea9xbJcYRlA7SwUJ5+uKJ5770+Btfu71dC6hRhcMtiNoQ+eBHUBmDoKmBIwiZnDZkgIxZfOT4zNqP3wUVYIruTtpglqGqI0fOiaCzd8AlFc+dc47NOuODzYWVzvW71G7HeRWUhW72MekhZBGsaThF38tftvykj1S\\\/UK\\\/9N\\\/UTYs+nxT4tgawngzBTafYuYMzpPhLjE3Udj73feuoxwJxqv8u78dABZrYvlauvDQLHMBoBEJQEiFAEFHVgZyt6x3p3wP30J+ce\\\/Zmn3vny20oRkQIZAoAKQ++oVZwYszxPtTsgIxBRPBg0\\\/DLSiEvuhFEQcs5G3I7Xae\\\/vkwKw3EJHyihqH+yLRtxFJMIkx4oxk9NkuaxYQaFku9Pe31WBBh8ap5V5JfQ8kHGwHHduLPL8zv6e8pqgpBlCaoCK5VjBqIgiv17r7O\\\/p+WcqrzFf1wLbtZWUYRjUa+39PRAhKAkmDpgAECxHiEgK6TU74dERhS2IfJBam5ajBpOSFPmdgxoBUST8g4Zm52h9DDql8vjYi7\\\/49P5u+8P3tmV9H\\\/ZWQHogQlN\\\/ejUoDEL7ADJxsYk4zh2otDd3RKdj+G6ZdFddRqAKARlyV\\\/eBidsissK2PPEzL7ujg4cz46vvXEfUehroZQNlNdbUw9rRSbm5ZJEufsifoS7D3jB1zJajXTBRwt7xVR+9cELhfogJOIHBm4ZJ11USM2bTrEcm87ew58qXlgapb7ELOpX9KOzC5mBu7gcKTI5iCFEHggasr9XfHbo+7n7sk5cOHtQevH7HjCsAokZ75be+1nnpkdbieuvBOpn8vRg6qIExSoGUxCXwCC2HkXIISCmSEpmFJFEI8BsQtCDyzemReEz1cJxzAAIq24AYBeS3INT83ywdHEyX0nKAMSSiMKSgHS\\\/sDKhbSdB0MBmB0EWjzGuNkZgFJCAs21Jh6IFZ8xnyHzJQRaCyi8CkgLCDYRtESDKlbppKDQlIURQufeXHou0FTX\\\/37buEzGgGrSIrFJ\\\/46Ucqc8N\\\/\\\/NsfhJ0m7K5A1ALhmy4oEXgNGJoEuwxRK8GC6a0CmGUPVNrVGpnNKAeX17reGI+giCSijYhYKtoTIyoQTCrmBQikTPBG\\\/MhhP4Ag9bUtYLfZrNuf23VLJOjmp0HfFWvwFt1sPsLeW1ffWQh2qa96v3NKIlJyiJQu\\\/37OupMhBHSXoqlQLp389WiQkfIFKuXl6Zid72j2lkIQAYgAmE\\\/37i0rNle8+tIvP7G3tN3c8IgkyAgUeSvrq0vLQJJEBFK3BLLptrHZXQ9aEEEpTojASEbEQiUCEpGOFtImSTJjjPh7YgzIAi5ARUgKRQAyBClAivgxVYmBj7RKhgikVCICRaCUKQ61a0yXZ3q1KBWLgaJUjG6CZRRwC0iSDq4QEURhTFvU11ALmAVKcSIQAYkAhDBWibiiM2Rr\\\/fNL4e3sLfzON4FxYhYAQ8sBuwRO4eQL5898\\\/PxPvrd6tLRJ60sgPJAhmJDteHzUqsLgNBz5QCKm5SMgQ87Y9Hj7ziJlIuAJTFspxYvoUsIp8pFRPjWhRkaD5bW1f\\\/77hfmJ5od3KN6niJKsqC5MC2HXksmMCh+O8HrICuy1wVD\\\/VWL1zN\\\/6fpWHjea7bBXU07ylrKUns2wy\\\/iZEyBOJKXvaYu\\\/ph10TesoxF3IflROgGFpM3hita0IlQATAXAg6Ynnp3a9alV++\\\/NyvvPijX\\\/9+cIQGFy8iczAqAUqmga3Z+D09AtE8OClVEtAnBWj2kZKgyIy5tGVb31YRgZg5vmSklFQJYocUSAkkkumdueyapB2BiT9eLzNQoPkRSoIUKma8m1BkSsKSEDkH4rqSlHpDUQSkUBoYKSED4DpVkCmJ8ZEVQ8ApA2aPX2wlIQpIa2I4kOWSXWDFobHTUx\\\/\\\/lRduLR4tf+tt2lyFoAlREG8KyixpRJAByg6NzkB1C0DGfArk5QKfGJHvBcnENr4rck0fMnI823JGRipXzgf1tr+9Gy0sg1JiS3Vu69RaH2VEht\\\/Xl5LUXT32mVH3DN8A+yDL+yxXeug5ZRmHTF7e1I2ceWilS93phpmeTX4+0fUj54w+2bUdVyBdXVeMBzSImYsf9TZpMHMjNXUCpglnmJMLmfpfKQBEJUkDbJqivcjf+Kr1mV99+slfePrd339XNIhUBBpHq5SpnbrepKxfSNdg3MY82izl9sYemfiyB8BYnOFO5nqZvAtaVKVUBlzLzNpWAklypttjMgn91FWZPgB1SChmGIfx9s9AMeDm7BakQb3x5dYk\\\/mVmPECYxqEmOLl83Bsl2XJozFjcRrswODny03\\\/9xeaRf\\\/t3fyw318BvQqRbU7EgJo2OIWoewugc2CUQHQAEzgHRrrj+wooyb6pRuiLjpmRFjrZdmZuqHJ\\\/xdqqND25FjWYK7dHzQKWQJJnhh8qoQQgpJ3noiXtIiE7ULXboZ7CGLhZwcvfp\\\/SgTa01Wd6HZfx7fg9x6GJQNHy6Xy6\\\/qLo1GPJ\\\/OzfcwjXqPsVyZYWPSgKFuPV3mJMQ4aTb30qQlcqw5VZT4JyybartHN+x3fzD96VcvhHX\\\/wz95V0Y+cGGe5jjtFru3QY0GdsAugFMizpWe2sWMDJ60JnUXXmXKKnO4mPGJQbulTugM9N64us0tFEHpcCggiZBRkMSiGYbxga+PMA0dznbJCUCRkjpKlDKC9VhpiCYnFZkRi+t3Ju439+Q0GXGfA1YR7GJhaOBjf\\\/Fxe8j54f\\\/67fbyBghfOy1AGdthBhYQQ1\\\/bdZiYh90Hpv9EipXccOfQEPf0bwLXyxwtXjhxzB4oYatdfe9m1GyRUaKp9Naj17leh6RSCzw9xJOeYSBkXq6HlKPYNQDsrVO7MrCzvlETEtqDtuz9\\\/Ji948FD8KYI\\\/ZuXfdnqaWkYgzep64jDHtlqYheMXyhEfR3PLM6ssy65sHVlQXdPV\\\/U6NFIPAlDALdU4XHlj5cOK9dQXLzcPG4s\\\/upXMZ5BUzH9VueoBEdBCu8SHxgYvzFfOTLX36iR9IAXEzEOsL3KZpiJk\\\/PLJpIszYMgyVW4qo828bAZtpPShqp+teA6TfBRLP223Fw4NwU9X0ZnvitK5PqGpH5AxcEpoF0CEpAQCIah8OmqCouP6AAR3wB4ceubnn5y6MPHNX\\\/\\\/hwf0NitompsaIQjXkPwMm0vtO6EGnAeVRCH1gnDvMGhvvLG0DIqCNBt2rrKLtTo\\\/zSll4fuvGPQp8IH2MK+h9x5PLJOXAu13zCezW21N2++5PqegdrvftpjwEJJpNZaK+q5B6NPZ9vizif4kXOMfgwJyZI+6cYGbqh5TxkuqnABNDTRLeZHw33MCzzbYd80IpqQNjlChBwrrNE7AUKQUgARUAgbBQeGp15f1vkWPD83\\\/pmaAdrX+wYlKLdFmoRPzKZhhQjKHlHHv12WO\\\/+HEvlA\\\/+j\\\/9AUpq1wOzYyaL61S4EacK7dsLqIlMbmlVX5ZOOeoz8RUHO8ZyehAryAKIMey12JRIQMaScgC472SFVGCkVRwYnrp719lsi9FFGhAqBgWGiIxqbL0PkxCzgLjhlq1x56guPXXr5zPf+9Y83371DQQPCDqg4FY+6aAJEKWROQvsQZi9CswZKOsenoDAEvAQQGUhpueCMDhbGB\\\/3d\\\/dbNeyoMTPpSQhw21+nsAkuUMZDP\\\/KE+sukeYsVHSG372eupe8PvPYkycjer63DIfa6ka0Lw0Wu1z6mI+LAPwT6\\\/n3HlGO82ZsZ9iXqY5fwBmBgCLF2lpJuxUnFStIrjFvRxQaBUbFPUs3JMEK5maSGADCBsAzKxLt7+TsGx3S\\\/+rVe+9k\\\/56rVFUBEoZRpmSmjaZa5BizhweobZjsNV+dRc\\\/cO7BAjIMcl7oR6ZRU7+brYbTCAM+VZ3vhBJDISpxpx6L6tEvc9P5lpM8ddkuS60kYiQXXSu\\\/NWfGpqfefRXx6Mg2PjqPhmQh0LgMUhMW42spBpnbuHJn7769Ocvff933nzwxl0KmxA0tNsQlSClEICIIbNIz\\\/1ylBsCAGjWYOokto7c2WPe5iENzqLftBwxeukEMFZfXD9cWafIo0TqnYa0ZCKHu11IBPleJuZ1Hd1NToKHX71yMtE\\\/Y0zf52hL3V5Wz8ruHayZoQL1dlER6KG6nC6ffmb0gNmyNjueT3LXMWNDYaTb92hsNWAMNXZq5+E2tx1mcWSxK1opGYYqiuJ7jjTdSBVpv1+Sb9zd6dIwfBHXLMiieu3t+5F92nr1v3vhq\\\/+nt30zNEe0wK77NgADQIr8nR+9Vzw2FjY6R2\\\/dJr1iiYCIhAIZGX5pLAPtDSrAuALMtrCo9+03vUFmjllmAUaAKm6LZK3buZFSXhxCMU81NpvHSYXpoNAtFMZHCFDatlUumMEdIgCjrE2WMeAW2AVwB6zS4KOfe\\\/SJLzzyk\\\/\\\/49p0fXFNeDcIWCD\\\/Oe4sR5gBxSZtAa7i5+FlFQMuenD714qXBycr1\\\/bvW\\\/JA7W8C9ncbKZrBfpdAHGVFsQEUigpiBkiJAKF9wUOYOkghGCPHhSwuzML3eg4qw6+aH6RGa32kzG33cC02+iPXRCBmCbAsDu0b92HspTSxF+YWdWclJnkaX87fLpx\\\/nFSeiJJ6Y2RzkDlqOVS6Nn50dOzM9fHyiPFRhjiWFFJFEzizLYkHYrrWP1vb3HuwerOxKP9DJuHFXwOzHOVuD6YuYCRgyRlYBRMu7OPbaB5vBCLz6N1\\\/+\\\/m\\\/wtetLhAygHeNvMbZIIRKRjA7euta4v0oSwloLRASAwG2pZKQ0wkSfXSw2amDPC4sqMSFnFfNJrUNxA5ZZuoYGywFmAwbUcxXPVFUYd6gQ05aDVqQyru9yestLJzgKSEXN9tJ\\\/fmPqY1fae4e7r11DreTUZTASmfGAFa\\\/Ail0Zfuyzjz7\\\/84+99uV3bnzrXdnSwATfjHaUIspfUDGJqSJgNjCbuAO2y4oDLz498+m\\\/\\\/FRENDQ28Mb3FoP7S3J9hcKmTlbErNswvv\\\/3o1bH5r2cRYmyKbX40Udcn5Mu5yTErPXuITrp\\\/GmHmVv+R4CeMDca6cZkdLU5u0vLPuqZfj9tTysWk3Z4vAKNCc0BywW7iHaRu4Xx09PHnjg7eHyyUHTb1dbB4s767j2v0QlanowEt1mhUqiMDg7Ojs6cmz39zAXPC3fub6+9\\\/6C+uq0CT4\\\/mSXLtcDCILozXkp4KoASlUAo62FV\\\/8p12I3yrPFz60qUv\\\/I2X\\\/\\\/S3nKV37sTyeIYSiUQqclcCAhlu+5QqyDiQsAoWc13uuNILTGhFHugSk3IQACQRJQkZmN2LKYPG0HU4gsXRconbwDgoFvdvcoSG5DPnYxIwCWnhWvAd73oYO81JCfI6q19\\\/ff07b1EUKKFAKjPhwFiawyzkDtgFckpOZeCxV69+7M8\\\/8drvv3\\\/z2x\\\/I1hEETYh8UiKOBFbxKIO61VFmOq8QlJannzg3WijbFYDjo8UfPtgRh3sgApAi9u9LNBCG7IWYsoOHPo3KvDQMoW8k2cMFLvgRg4mH\\\/sHDxvt6rVi9yhvIWwIx\\\/X4x07aN5dXpYJC66RM5OXU+5Af7NT\\\/zTBpATnG1CZaLTomXBibOzZ976cr4qZmte1vXvvx6c2NfhBHJCKQgzdsiw9Pa1a4Wp+BUKmPnjp392Pn5\\\/\\\/bVjesrq6\\\/frq\\\/uqqBjjkRj5weTbJF0dglMPH19n96vg1P2RsLvf7X8yheOf+KvPc9stfTGXcksCD1CBImghLFbpbBbQGDEGDAsDJfnf+5j7tnjkx9\\\/YvNrP0n7L+mLEvd1TQdB+yrjDrC5epIG1WDcmuJFd\\\/D07ODUiDtc9tq17LQAs6swZ\\\/BNrt66+ckRuenJIwLnyK2kVgcgVFKjXKSPueIq3Qs4cgfsIhQGC0NDT37+kSc\\\/\\\/8hrX373va+\\\/Kzv6DAxIRkjm2pbcyjAH7MeUahPnN0ohrr+2NHZyzEW8+fqqCtooA1IRxqqXzNNEsUKf8h68Prhl7Eqk7s+DgS5KWfegLZ\\\/3mR1V4Z91N8y3UTFdhP0VNRkOXrrTpEq0rMGKsqg9QuoS13QLR\\\/MXkzgjJ7b766ugOQAdsAvoFEoT44987pnjT5xd+NGdd37vjeCoRpFP2kwUm18yibg6+J4r4fl+a\\\/OouvXezcrU+OUvPfux\\\/\\\/6Ld797c+WH16JmEyIfzBLiwKz4XVPaggxuERp7wDjYRQCAetVjxe\\\/+fvDsT5\\\/45K+9XBos3f7ebdGsmxmJZJQYapLATdRtGOUMlgvHptBxh6+c2frGa7pVixl7pFY5YxwbJlWcOaGxTvEYBs3fRH1uj189fvEvfcp2Hf9Lz9\\\/5F3+gDBwtjVhLQhApn3VHhkDFkXFinAAiAuIcuAMsAIz0CNy0gpUAkPGrylKZBOPALWQ22EVwy8Wx8U\\\/90jPnXzjx7d9+49a33lN+XcekGddfugIhE19FmSxR1FFN5rlRkoL29e9fe3BtBRlrHbVU5wgiH1SUefX6NBzxYe196IdV\\\/ujeCXatXugKi8zQRTF7V+hrGvyISfzDylHTNaCHfoeUP5i72zndX64nELjHu5F7PoBZwGywXHBKrFiZOH\\\/82b\\\/y6er97T\\\/9n\\\/+guVvVhFnSEyeSqFTahTc3YIM2I6Gbflwxq7nWfvtf7g4en7n8516ae+xn3\\\/u3329t7RGzjIuUmPawgYrAdqlQhtoWaDyJDCFEUAhRGAUTb38fOoAv\\\/5Xnx6dHfvzlt8I6Qsi1sQCVICW1ntv8qIoAVWtt9\\\/5vfXPo8unNP\\\/y2CjxMki0S9o5Zb4ZlJgAlmcDGxG4fG3NjAQNRaXLELbiEOHTxOC8VVKeRy2GLzec95q\\\/Y3KzHCcxCxiVZUKyAXSQtowXjGI4zqTCjuY2BMeaOUEKnWJoYefXXPj53cvyrv\\\/7a\\\/TdvqaCptX7JtQ0z01pKS45sEYSpyJcUyQjCpiLR9BtACmRg9L3aZxhT7BNNfspszBTg0I1jwgQZbYYk1HfI0NVMpi5hZ08oPX3EJ+g7VEz3RCRIQU99z0zMVyDYLUnB7MgPMx30nnkEpWjojNEeYt1zPGUyIkB9BtpFvQLPvvToc7\\\/48evfuHbnm+94B1UIOiA8MPrmKKb9CEy1XclsTcbpn0L\\\/k2QU1Fr7d7fsSunKn3uxXe20awEiNz+Akqh8sF1wK9A+ApIpHZAAVAQqABHQi5cOzp9q3K8\\\/9\\\/zs6LHRndVa5BtvXmbwS9nBJwnZXto4fPtGuH8AIoyFbxmkBWPIOFo22AUslE8+f6l52N5f2kUpYidHmm1kylTLUYRjl04SyQdf\\\/nHt1oM4\\\/Vsll0ZWKI6\\\/dLV2bSWqNXQvKn5PmElQ4gWrXDnzX3167LHzA9PjtcWtqN4wvg2jGoxDb5J5LLPAcsBy0S6CU8HSyPSF45\\\/9O5+kkvOtf\\\/nj9Rsr5DcwbBt7hOZHapt8HtgJGSUhdqMWU3EsqMQCEsTUmZzOIaOgSspN7HLJUdYCkNmKHtaNhI\\\/Kr4beJYi9RWzfSR51Oc7Nf3MszPakTmtelwAAV\\\/5JREFU82I6osuWxXHR2PPzYI6PEm+XeeEMYnbp6mFgip\\\/IQso4cAecArhlVqpc+uwzl155\\\/O0vv7723oLstCDyQAQo4uWnxbhmycUTgyTpmghNvLiKuegKgEQoj5arIsRHfv6ZwFONnRopQCSUAbglcCrk1YEglmhxQAZWwQxIbBeLZQh49cbe+odrV14+ee6ZU42DoFH1475C79YIWpZNoWZyGrhlTLXPCE0sB5yiPTZ65pOPBQL3bm2o0AMZJr6BjD0EASCstXbfvr35vferH96jwIs5cXHKAndYoTT+wuXajZWo1kDzp+nsB5gFdqE0N3Pmr\\\/yUWy4VJoeaKzvNxRWzZ6V7teGdGjycVYDCALgVdMq8VL78yuWf\\\/tXnd4X1gy+\\\/f\\\/DebRU0IWhC5KVbJCkEBd0rMJnvYzbfDmNQKiRlqoo302QcRLn6MMt8wVywd\\\/oYd3NhehZVjmqBea\\\/8Q\\\/srfWVm2LUssidoz0De\\\/AtHd7a\\\/rbfbzpTPKce+izD3reTNQ5hZjJgKsgEzrFu90dpgu+CUsTh44aeeOfPS1bd\\\/98fbt+6T34rfWoFKYjY8Nf78lAR3UhePk3K1OhEpqm\\\/Vgrp\\\/9rOP+fVWe79BVhFtG6wCeHUEhlYBzK8iAAMZQtiGsA0ygr0aLWxSu90KcfPG5szpsaufuaCAH+60pMxkhkK++0DxXpCJ0shEO6A26bJi+fIvfWr2lavlU1PBYbO+sALCLC3s9ZgpGTVb4VGNQl9DU+JsYwTkYLu8ODD14uXajeXwqGGMsynVgiHjyB1eKk89fdEZGujUWzvfedfb2gEl4m54wg7mwCxiNnIX3ApWxnFoamBi5JkvPfrUF67cv7b9gy9fb1cbtLdmbPIy1OWJAQp2hR8CpiMoyBKHORoson4SspRkhMzdOEYw625WJn0oQ9fM2ta6DDf4EEtQP+98XpP8UbDPPi7gfLxq\\\/7ZLqh3NOuUf4uzoVuY8XKSGvX+p5+ePg2\\\/THwwpoXpaLrql2SfOnv\\\/EY+\\\/+hzd2765Q0MLQ048RkSSD09bPbnyQ5iqKDMMjG8pIBCRQEoUKSG68fk0xOvczz3U81hg9A0rQ69+EwrDZa8MWRG2QEpT2BzHgDkQ+Uo0iD\\\/xDiqYO\\\/PFv\\\/PpPHvvsped\\\/4bGp85PvfuXa0dquYjaEHRR6miwA4l2cVPp9UJaclgoVOLdGzswS46zIhi\\\/N4Z\\\/kLig5NYxK1OSpTCQWoiEgQ2axQskpFJhjQwx1yvC0AEiBDP396q1\\\/+dWJx08fLawfXbsLSsUPMcPE18s4MQe4TVYBnQovDx1\\\/4vQrP3OODznf\\\/70P7r++KMMQZADIUYQkwsyZnILf48YFppCODI9cU8CJcWCctBwq15GCuEukzGxQKSIBJAFj2wdpR2\\\/cJU2JcakmJvMKInQjYbJGiq6XvFtl2EeClBG3dLdvHnYCxxkX+TthahTqWz1Tl30B+9nec3l4SYpmho2f3jSSg0uPiw3a2QW3XJ6bfuGvf+HWN26uv3eXgiZEHqrIuHVMTcyQW3pqz2wXbQetAloF5A5YLuMO6tkGMzxcs22ax4ESmmVrt10YGjz\\\/sy9sNgpKKFhfBL8FYRuCJsggZyBKzliSQAJAQejDQEki276+vr1UvfyxM1c+daHVFM1DXyo9wk664tinqDCLITkJGTKukLtjw5Vj40G9vfLVt5tLGzqdK+nlxPkQ2as1ZnJi4vsbt5A7488\\\/NvFTz1GpVH\\\/\\\/LoUBKJFJ8kheDxlU64c37nsbO6BJjYmuliEgJ70t2iV0SuiWS+NjT3z+0S\\\/+148eNsQ3\\\/p\\\/31j94oNp18JsQeGC72KmDDIEEKBXfBSCNtDCTEdOIwvQCovtwjr5tgu2CXdRdcbSLaLlguWi5aDmo\\\/47RTlkpbTlTasXVflJmaFksYrYB2NOr6ne09RkS9lefddnFU0UK5ArwfqdVt2IG8\\\/fKnuES9g+o7PJPUG87FvNyGMzdydPeNwdmg12wK5Wn\\\/\\\/JnVt9ZXn3jJmkYRBz+agCYjAOzGGOOU6wMDEzOjM7Ojo6ODFRKBQASgjp+cHBQX1\\\/bre7XOp4nokAJQVKkAAgTcx9S5C9\\\/+8OhycHzo4XbX\\\/8eBV5qXMgE9IJWhwEHgHgUgQAMNpZhZlbZ7ub1ta\\\/8o\\\/r5j51++ZeeeOTjZ976yo2dO+uqYxPGvgEUiIyUQCUBMVbLUDakk6SAwLv\\\/B9\\\/f\\\/MkNktTZPSBljpRYWZO4t\\\/Qi15JUNELZhPyvZ45SWgPFiPPi\\\/CRzXdVI4FqYggCUNO77rsaEDl1CBsxG7pBdAKdslSonnjn99M89Wjw29rWvLCx8eBjsVMlrg9+CqA1KgjUIrgthU3usUq18aj4EgjRUwzThkBstFHeA22hZwG3mOJbjugPFganh8mjJLlhEFLTD9n6zvVvzWy3p+0oIc\\\/NMMhT0xNjoCTXYVgExUx9kiQ55\\\/UpP\\\/kDfgTv16GLSINcul+x\\\/6SgkYcxkB9QPqVrxIzXk1KPKpowQpF8qV4YOmqSXEOPAbbScmUfPFoaHH\\\/z2j6Wnr\\\/gmI80knluu7ZYuXjrx5DPnr1w+NndsfHCoxAAiLwyCMJQSEQtFt1h0hZD1o\\\/bW5sG1m2vvvn1vaWFVhEGsNiQgBTKCsB3V4M5X33zk73xpcLJcazvA9QSfAYg0706\\\/1MTNMJNxkBwgBADY2oSJKXLczu7u9T852ru\\\/9\\\/SXnvjS331l4a3VD75+\\\/XBli0xaWEAyRImk7fPM3A\\\/TqS8hKAUilO1Ga6mNCKAUyoiUIsq38szjaxl0KjIQmhMRAUkTzASEJA5eey8Skbe2K2p1iuvDbmOlZguketTkmNWFSQEslzul6YvzT\\\/301akrs\\\/eubd763upRxNXeNngN8JsQeaYX2vB13GoiV8ipKjMtAGKcjBrRiDHAKqLtMscdOjYxffX45IUZt+RSO1CRFEopUojIbW4BoG1Jm7Wrjf27m9vXlr39KkUh8RCiADEgDA0QBBBAArA0ZML497Af2D3\\\/m0QPb+J0o+8zFSw9DATz0cNIxKGn8pQWTIvmh4VZ5OCD2PWd5FCHicAfMxK6bMiW3hQZJz0VtMvFyYlP\\\/L\\\/+qxtfv7759k3yGvEilACIlmMVKpcfOffzX3r2uRfO79X9B4s7yw92Nreqewf1Zq0V+KEUgiEWSsXh0YGp8aHj82PnzkyfOjvtuvaPf3Trq199d\\\/HeigraJEMghciIW2AVsVA+9vnnx8\\\/M3fidH4rGEWjTjVECyNgIk8YAojm3LWI2cAecIszMQcuDkLA04IxNXvn8o4+9MG+R\\\/OAbN++9ttjaO6TQM8EbMlb9G3YtpfdlRGQs7RtrH5Z2hGRHsloqbRV4ZWj40Yt2pXL4we3w4ACEBzKI3QEsDqvg5oxNGzOYMmaSkCaIhQGMITJiFjAbrQI6xZFjExc\\\/efHyx8\\\/XdtvvfWdx9d0l5TVpbgiEhI1tCAIIdax0BDICpwJhB0Q7HsGnxXes\\\/I7nHDweBdsu2gW7MjDz6MljT512hsrtg0b13nZtabe1dSC8QMUTHURAxpyBYuXY+NiZmdlLc9y169vVtbfu7t9dl74HkR+ja8zsStOBMQWNmpc1USf1eCa6F2GWKJUV41Ifnm\\\/vbZD6XgWzX4WAEIafwuysM\\\/EudTOukfr9Zxwlma5MyvZLc9AX6GqKxnIQFm+HRXQrJ15+8uLPvvy9f\\\/SHYa0KfhOEbx4dbluFyqc+9czf+ztfrLX8P\\\/z6h9\\\/97vXDw7qSoZIRaY92XDHo9iAyhpxxyx2fGH31s09+4dVHLc7\\\/t3\\\/yx2\\\/+5H0ZdrShARknqwBupTA19cLf\\\/8Ubv\\\/Pawe0H4B9B0DLcsZiul0vqTNxJjBNawGxwXDh+Eg6agBydCkzNVmZnn3x8+MIrp5r7retfv7n6\\\/nL74IiiwIRVSJFPO8mEqORGUJr9rHnvZnKntUTolMdefPLsf\\\/8LzLK2vvn22r\\\/7Jnk1iDwyvJbEfmmE6XE2BsZvWbze4sqQ0OTP6Ekgc4qDU2Onnj712BceiUJx\\\/TsL915bCtttCloQtEB4cGIaGIOVXYhCiNogI1ARoAWFEWhtmSIi3tu1\\\/i7+KnH9aRfQKVrlytSF42c\\\/8UhhpLz84zurr98NG02lP1saNpoIPTX3yQJuoe2WxobOfOLKzOOnDpZ2l757rba6pfy2mWPJgJJ1aKIBYkqiEVJSP+8v5H+z5+7X6w4n6AL+drmiMEe4BspFOCkC4FiYy00He7Fk+LB2bB4umHPkQvcizF0tE3NAqj8EboNdsCqDj\\\/2FTz74ycLh4hqEHY0GRCBEhpZz\\\/tLZf\\\/gP\\\/uLS2uHf\\\/4d\\\/+Obr19u1Qxl2KPJMOaRFFTIEGaIKSQYgQ5KRlKLV7ty4uf7G28tPP336lVcuv\\\/XmQqPeyEwLEJDLCJ2RgcG5sYNbK+YWF7fX030Lu9R\\\/8bulx8rtFszOQKsFUQQdL1Swfm1raaMzfHr8qY+dPPvC2TBifluJiAjjMyq5FJk+Icu2i3tkLvGQXcuJuDv23CNDj58nRABefesOeW0z38NML9CATCDORUqu3yYjSUvPyHLAKaFTBqfMiuXhuZlHPvv4y3\\\/1xdGzEze+t\\\/iT3\\\/rJ5vUl0ToCvw5BE8IORAEcHoFr4\\\/gQVA9BqXgqKAA5gAKKMt97krKou98OWC44RXRLlemJx\\\/7cC+c\\\/fmXhh\\\/eu\\\/cfX9m8tiVaNAj0Qzr2tKENUIcgIVUQyBBlSFITN1t6t1c33V8aOjT\\\/5518UAht7LSWy0BroilIi\\\/AhHLD2kjdkXf\\\/uQIX7iWqKHDhUzDhdEAI6FmXzHrhveCV2AsoeGh3aBHrKsl4wkLe5tQjzoiUUYLjrFifMnz3\\\/6qWu\\\/\\\/1rUNIUoggQiYhwt5\\\/NfePHqYyf\\\/P\\\/\\\/L11bXdlXYgqgDSld3ESqBJJEkKqWjxjEJGDUXEtby1cFR8AtfeHxlef\\\/uwkYm1geRMULLr3vnvvjU\\\/rWVqNUGyhGBMI7OwswFJ\\\/lN884qCX4HZqag0QLhQxTC6JB\\\/0FrdbN\\\/\\\/7j0VRc998ZErn7pYnh5u16MwYmRyyOLYs3SFMN2XTFuy8cygq6OoBA6em1Oh2Prj19sLy6CCTCcpSbdOa\\\/74q1jIbbAc4DZYDloOWS7aRSwMOoOj46dmnvnFZz\\\/2l54dOzn23tfvvPm7b62\\\/\\\/yBq6hK9DWEboo4ZAyoJjSaSwNlJqB6akbp+GIpDEDTjbyIOOdVVtL7HOkXmlsfOH3\\\/pVz\\\/TOei89Zs\\\/2Lu9JDs1iNoQdUD4KAPQeDsdGqHHwsY5IYEEKoHmei+FH+4tbu\\\/d2zn7+ceHr5yqLe8JP8qrSbNOwuQR71VMY49ZCPu3SfsNxLuWQy55AfNitQyyk9LuaFfaBfWueaI\\\/y4jU7\\\/6IfTulkHH4xo8aJ+6MXjq5v3XkH9VBhCgFkUld1s7RYrkYIQoVkvQNZJp6reP5gpkAlAROwDnabqlcKFjMcd00uhkASIIUIEJ\\\/vy6CYOj0VGdnl4xos\\\/tNoFxFoWtyCaDMw99pwd4WjI3Dzj40I1ayFbnyCKqre7Wl1YWfLJx49PiFT5699OKZ6srR7deXV96779frFAmUunmbmMRlwubIBifkbE1KtJc3bv+j32U2D\\\/erJALN0UCGQIxyvRDIDcRZKlJF5gC3LYuXxoYvfOzC2edOVqYHdtZrP\\\/r965u3t9q7e8pvgQhA6HMpw0eL9cN0cABhACfnYGUFyNIMOJACuIsqMILEbPebu+CUmFs6\\\/vylCz\\\/91J1vXl97+55oNyA0qXLJ+w6gNHojw1oyuqs49BcTXI1SUXUxeOP\\\/PLrws88\\\/9zc\\\/\\\/8G\\\/\\\/V59ZTNtapoIXpn4x7JDwjQxHFLyVk7DnQv2i\\\/uk2Ot8yPVsqLtj+lBbVTInxIfkhGZ4gdB3wgJ9a85cAyDdMmKAWgyPAYZJ8itzyxc\\\/\\\/\\\/z29fXDxRUjjkna7sxCt\\\/zMs4+89PELY5ODS\\\/e3m\\\/U2MQtYfPNhLAu\\\/MHcGbiO3kFtou3Zx8Mknzv3tX31lZmbohz++e\\\/vOSnzbpES9CcArJyYL44MH11d0s1vL4ghUToaYF5xjLk6EIAiBMxgbhUYdRIQjo2ADtNvU6QQtb3dpf+nt5epmfXBy5PIrZ0997NzI8QnHLQaRJSUDywVmmwkYj3+lAaNxMnbyi0D5gWy19XwvPv942pLRn8fS3X8XrQLY+lcJ3RJ3KoMzU+deOPfYl5545peeOfbI3N796rt\\\/9OEHX72292AnrFepUwNdcQg\\\/o4NJNIDS1OGdNsgQJqchVCBjCJVTAenFb0qS71sAp8QKleMvXj7\\\/2adv\\\/P7bG+\\\/eU55Re+uuFeoRvJF9q6RBHSc3GxoVxSQhAJUckiKIDhb33KHy2VefbGwc+o1OIldMezNZkBNlwjofOlzAHp3ZQzqsGTZCn1iWnHEhd1JZPb\\\/VNW\\\/ojmf+CKDTR8w5sqCUnsaq0THalQobKO3cWKaMZZPiaCREbjEetsNjsxP\\\/8P\\\/3X3\\\/7mx9+8N6DldXdZr0OMiTQ8JiEXQY6lAgYHx4pnzpz7PkXH\\\/mZVx\\\/dqwe1TiRjspgZ3GsapxKgor0PV0585lHGUTKeihHyfu1cmZEYuBAI42FmdR8cDpPjVG2CjMAZxLFBOjwgRGDMC6z7bzSWbuwNHZs4\\\/pmLc6dnLjx1Unpyc3FvfWH3cG2\\\/tnUYNNpAAqQifUqTyvjHVcYoEMdQm9j6ZECUqWMZR8YpzfG1i0Ol4emRydOTx85PTp+dRIdtbDWuPWhv3N88euuBahxC4IHfhKCJUYd0NIXucGg8D0DucAYCRXB0BJLY9DTtt6jTAulBoQJWCVVESUg915aL8twT5x750rNv\\\/9ZP9m8tU9iKr\\\/SGgJj+sJlbN2W84XFGfCxUVslQVwIp2cGFr7\\\/DAJ75lU+\\\/9k\\\/\\\/uLMjKKGZpMok\\\/ZkUwsNdgPSQZziLG+mbQoFEvSrRrux5yulprL6Z6R9BlSLoGUbkANvUpYbtHhV2R8tg0isvz45z1wmP6sY3nYueA1ISSR3tNP\\\/x\\\/\\\/LNV1459ZnPXP3Fn392aePo1rXlzY3dWr3TbodhKAiAM+Y41kDZHR0pnTgx\\\/ehjJycnBrYOmr\\\/3x++\\\/f2P\\\/H\\\/6Dz0nTljRBiGhUnZKUbG3sW65jDZRl6BugWzbCgrrK0pgBj4AkjUNHR3Tt7MDxkzg1Snt7QAwmChC1NCmMlAUAEnntkDWuL9\\\/8nY2hE1MXPn5xZmrwmUdm7AI\\\/2m\\\/v3NmqrVYbe63WYTNotCM\\\/kFE8qMjgEhMnVOoqMGpMMElqnFuOZRfdwmBpYLw8PDU0enJs5sL04HAx6IS19cN3vnZj+dp6q+GrUoU6dWgcAkkolMFyUNqgbFRC97dAScqkpmlossn3099Dq0lSwtRxtDjVA\\\/DqUBiEqKXVeMA1DL80dmb+sS89d\\\/0P3tm\\\/vUxhGyIPIh9kZFZ4nFWW6xJnpEKUsz4l5QmZ1x8RREcF7N63r1uDlYu\\\/9Ikbv\\\/n1sCa0zE2nL8e1C+X5K3+WKRf\\\/y6Z\\\/mMVIPOzA6la0WdkvQbmJH\\\/YVquJHTx+zWPQsXzdTXFO3Sk+3DVh5tEKRlJHMbYSJ+0xDuSRtbOz+0\\\/\\\/7xvBg8cojp1555fJLT58sf+qyU3ItzhkQRyDEiDAUMmh6fqNz6+72P\\\/9X3753d7XpiWPH5+McP8o8UikiUfqhXSoUxoaDajXfHqOsrp6yL2Xsy9VtHiRhRlpbW3DuFLQlbK\\\/j3CVyLAglaKY9+oAOTLriJx\\\/g0Mght9\\\/8vTeZF7guGxovzz1+\\\/NhTxy++fK7IkSnlNYKD7frO0lF9+8hrelEQhoGMQqkipaSM8+GJMWScc9tyHMt2mO3yQqU4PD8+e250fHrArrgSIGoHtb3m3Z\\\/c37y+1jhoBh1PRcLgkg6lMeypCOsKlM4gUlAow+AEdhomtExEIKIMNSXZIwmQKIhgZ5NNTQEfp9oRuIOEDFRgbChOsTg89PjPPbv23vLGe\\\/cp9DKuX90oZIRgBC4aspO5ZVFv\\\/y8R9yQxs0rH+3iqY9\\\/7xvvP\\\/90vzL\\\/yxPI331TaEqWtGBq1k0M5YVYR+FADU57z3FMtUr+hBnUJXrAXR2MWYR5PneFApr76zL8S9neF5GxdmROwt5tD2Idgj1bJEV6ghIQEBU2U2Ch1JRKClNITUXiw1\\\/7hd\\\/df\\\/8E7xaJbGhislIulou3anDOMJAWR7HSCZrPd6XT8gKTenDgH4YEiRA2MAMzOGEgBKRIRV7JQcuq5QzvbZDPi63S2SpmygBQhoB5shgEtrsCls7BxCF4EVy7AtUUAAhIgBc7M09o2Tk+ACOm9N0mCAiZsuxNUtkP88EcLDlGpwAcGnaGpwYmT4yefmB785ClusZBhBIyMNItUHLjL9C9CjsSAOBEJVT\\\/0DtaqD968X9+tt+pep9nxm20ZRKAi0rN1lZgtFZBOehFEEhUBSSKJfh1qW+ZuiRaUxqA0CJ0j7ByBIhJSx6QaMr8SEHhqcw2n5nD6BNWa4A5C2ADGwCowy778+SelgNvfvKYCL7326ydNUwUyDGQz7s9QlDDTP8mAC\\\/WtIlEjChQBQSussmu\\\/+YPn\\\/7vP1Jd3qjcXSWrQnkRQ3RAMpB5KIP2ZB95HVKxA\\\/VxL1N+mAXn4L+aFZ30ibjO3oj6XTchp0jJJND13Tuqm9wEAMJtTKGI7aZpQl+WQS\\\/3QG2p9GEUy8puN2iEgR8wjP\\\/R4mpQWQILtIrfMBYolrM401cXIYqREIRhnSf57EhgQB5tSShgxvOuErZP5URUQRhAiPFjDc6ep3sSL83RnUz92bH4GCiVwB2n\\\/kHa2QUUwMASujcjIa+DCgZBSILYBDgAQGeojzrXsgmuXC9x1LMfiNuOOhZzpzVIpICFlIEUQRUEo\\\/DDygtAPRRiRlKAnPYlNVndiE9MzmWCcpGzLtkMACFUEERAQeEfQsJBbwBk4FeRO7DhpQxjodQvAaH8XZ07h1Cw1OmCXgDEoDIyenpm9Mv\\\/Gb\\\/1E+G2DPyQFCKjja7iFlgtopdU1ZWez+eopvVkRAoESerhvKPcyAkAKrcbq9tpbi+c\\\/+8xbD7ak1DPGGLEHEg3KOa\\\/26n6eP2o1IuVaqN3nJvaVv1HP1RCsHBW+e4CC6SFIee1nFh7X3QzKxCCl6zGNScuNQzDzahIxzG1N+vSjxP1DVKq4o+Mj1cMmMAkqNK2LbIeLCLJua\\\/N1OCBHqzhzbMIuOcrELWR+grTQYIyxbrF8Xi2ISYOaqGdgarrhZhMHBh2ftg7g7Bk6bMBAERoSR0bpiUdg44iWNiH0sFwEXiEiONgh3wPGMoxCA3RSiBJZmAgbUutW4gaixBcDyWzDLDCZJkzoUlwpo0GnLC8QUnmX6T0mHSDKNkdARCT0l28CEVgFKI6AMwBWCZT2lzBQRDsbOHMSxichikBE3B248nPPr9\\\/eqa7uxXprAUSIDLnN3NL02fnTj58Znx3hnGHKyEmvh9TDINei7NALNu5v3X\\\/vfnNvn4QPKorLDZ8i+\\\/63Pnz5f\\\/jS3BPn19+4RiLQgnhEBcB0RM\\\/DHEf9opb6jdv6kiywyzCcP3QybZk+LorMKZUO76l3QIiGcYy9y6\\\/\\\/9DC7GvP1REatF\\\/kBc23kLPZ6YgamahBm07PDf\\\/tvvvrP\\\/sV3lpfWhS8BAKR+NZPGiTKVBtOmeNTYT8ctXrxy6m\\\/+9U8OjpSU7rt2v0IIyNCywLGjSOWTGyh7B+oVImV3qLhdI5EAlCAZwMEBFCvwsSd4oYgPtuhzz6nDFuxWcaAAZNPmOvgemvYdoVDU7XzFlFqQM7Yy6t5usvdblVl+SSiAZn9QJiRY5fqcqekhVVqm+QxE+cE3AiCIAFp7KY\\\/PLmJ5DJhDkujwEE+Nw6ufh44\\\/uLo6MjN07Q\\\/eARGiiEAJ02hlllMZfPbzL7z6Kx8PpOzUO5i+1Bl1e1qJxhkG8fbvlJznf+6ZlXvbX\\\/2\\\/\\\/nj73jJFhCQMrFEEUbO5+e7imY9f2Xz\\\/now8EH4WNA796U8P02B3mw8fut6oTy5vZgbfTTW1ehLRIC6\\\/MBPb2zUziQ\\\/x7vzPLqFAHuebr1PzOTUEpLx6Bwsus20V8Nh9n5vTcADRDs8eH\\\/sX\\\/\\\/Mv\\\/c5X3n3tJx\\\/s7hy024GSESiVAhGMu5wjd5njVkr2zMzoy594\\\/Be++Ey9I4JOlOn2QALY1WIUbjuBVJ1aE0GSQWfHL0RS\\\/GTzIzLjgvTEN7wwBUyAQlA27NWcnaPJv\\\/ozGEQHC7vB\\\/V2KOrC7TZ2m0UbqQCUNINPbG2RNmInCIQkIwG5xL6bvGWTSKbJTteygjJJVlyoBKI1AjH\\\/2ZNH1oXclYuhE1EkIUQfqATEb7DI4A2DZOD0NIpydxZX31hrrO6T5y5pPiQy5\\\/dgnHv35v\\\/Gp9390\\\/09\\\/76127QhklBRjlMB4MGtSj60QyACZ7RROPnbqs\\\/\\\/tKz\\\/3P\\\/7iv\\\/97v1nf2aGIUNfVMiIRrb52Z+6xk5Xp8fpyC5gFjIFKLYeZHgdl8EAPvRkiZtKxMi7l7kEi5SVqlMWgdTO6rT9LAfPwMxm7TlikDJLyoYNH7G0kKZ3H0t49lEpyx5GMU3KIZaaojKi+0\\\/h\\\/\\\/6NvvPjC8S\\\/93BM\\\/+\\\/NP1g7bK8v7t26vLy\\\/vNmrNMFKgiIGyHV4ZGThzevaxK8fPnZqojJbrgfi3f\\\/DuvXsH\\\/9M\\\/+BxPCRQx2jOe+DtDFemFYbVmOtqUArmSYCPM9IGxqzOcq26UqUhJgpIlbg8XS34R7Ttv+G9+AF4Vwjaq0KQCxjFo2PUmZpPh0mBLTNOMM7PctHmmW0fZ+KFMJl42IDUGj8XoMVN4Eub28+TJ79peifpgFGLhCQkiARur8K3vOKPDs3\\\/+wvXf+IDC2F2pP5RZlbHRl\\\/7ci3eurf\\\/hr3\\\/L63QobKMMYrsmxrB4hT3dQ\\\/NNMO5x9+aPm4EI\\\/uL\\\/+HOXX3n8rT\\\/4nhIhEQFJUhHK0K+1DjcPT3386rXVDWKcgHUJTnLnUGI1TGse6uI6YQaTgr0Nz3RKQV2WJepPXSQLs1\\\/8IXEvmA3RQOzfKO5iiuZdvvlhdxoDGhdOCkgF+0fg+aWZibDRABbXXZSaepRSUqmNzb1\\\/9W9u\\\/fEf\\\/eDMmWNXHz392CPHn3n6FNgWAEghkQgYA86kosAL97eqP3rz3q3bGwv3t\\\/aPvPn5WUbEkUH6TmAahMDY+MU52QmlH8bfVRIglEkSIurrMOtizZv\\\/IElKoPD8B6udhRVFFNy6BUGdRBBTYWJxlvkqWYwBdlUhmCZ950AGyaLNrMOu8oag2wWQg3RjOhSnbI8gzw3M1uPZGiWjWMi1DhQFbbh7s3zltFJn6xt7hnxhhFCIyGZPz8ycnPxP3\\\/i+1zjSED3TOMGUWgKZhInEiWCOemTAI0ly\\\/dZqY7fx6MuX3v\\\/q60HYNuAvRA0L3r27ef6zjzPHkQFPsW7pyZcloFJPS\\\/NhN788pAIePlDPLAXqct5CJp8wvXqlOnPql+P0UVbefkAZSgAjiBlfOMSRGGhiMUFJGcjmQWPmydO1hRU0h6GM73gERJJUoKQQ7dDvrK3W1la2f\\\/T99wcGiyOjQwNDlUrJKRY4AkgFHV81Wn7j6Kh+WOt4UjEHGAKzlOiIODE39gemlDdkfOLKfH1tnzTxNkn5yaqdiHpegMwAgzCjKwRSBIxAhRQ1g5WFtf\\\/1XyKSqNfT2HqSoFQ+sgtjtHn8CmGX\\\/j+9JlDP25mk6vb4brIxCFm9BgGlBOK0GM3w4buSQrD72chszV19RdLNs2BkuhLsNsKmn0xEEBQBB2RuweWI7YZHSmDkg4wAOXIbGQKz8hMLSre\\\/uPlESoIUxKLIjzqNoFR2GedxLaCITGZ4c6PKi44zUPDaHJBTL27ko+QylGvSdl8d+5rpqe+yoIe4Da2H6rAzM3Xq7rHinxGO1qUqSaYQ+spPGROi6QQY+d\\\/BvfWzn3n6nltQURsZJ4WZQSpKglCRSTxWEpQQkTrab9YOqjoaIc4iZ4QWAZA212hAk11CtJSIQkXSbKJJSWMCZ9xKcXRudPW712K\\\/X14zkNmMsfs1yhGek+a0SUqQ2s4XiYOOnumnyPAkyDpeWClpV7e+YkVO\\\/tKfqV1zTQRzL8wsqD63CcpM19K2Uz9wQ16XQnkKRO+MKvfBSClpsjI1uP3+GgmRxoPqL4mAANKU3VzvfWjhiafOn3j2\\\/9\\\/Zl\\\/Zacl3X7VX33nff0COH7iZFcWzRHERziCSSJiXZim0hUmw6spUJSAzbMAIEQRAHyE9IkA9BYiROgnxwEngI7NixTSuQZQ2WJTu0RHGmJJJqstndHHruft39pjtUrXyoaZ999qm6zwQ\\\/sJvv3aGqzjl7r7X2WvcKssbSqzkPq3a2YCayc23rtS\\\/+1eTSevXXSlRXbS5VIvJ86\\\/z6tfPXlg+sbZ\\\/NpIkZbuAusmv0nf1+FW30RQyFJtxKQ56Q0TJzY3ctl4hgO\\\/R\\\/owzhtUULarqiflbK+fG55LP1Y++uPPX4nsP7r2xdqf2n22VwbWN7Zc\\\/yDYcPXF5fFw5rUz2SMwo1sQIZNMPpkNJlJMuy0QdvvRnj0dX1K5LPpE1EGWAwlOHo4F0376xvr594n\\\/lMONdjoOEwGK0IlxoTCw1Lirp7Z+naBgpRVLAkahsIu88xLuebza9QJ5H53Xp\\\/awea\\\/HiQClukotu0U1SAlcPXNreMDQPCu6W0qkmFbDxeOXLde8+8wFoTX5lfMKuOS7KtiElIcctDd973kw8XxAyVILya0meLjGUik2tbJ\\\/\\\/qu5OLF6sgyqKCk5oPUDKfLObFzs6105dXPnjk8hsnQudCduvTyAbmcM\\\/KGjSOtdWa7Uws4uYSDhNnmuP+5oE30algXKV07ga1mKYFcSrynbkUk80z58+8\\\/NZdn\\\/zwi++eZj6SYgbWmsli\\\/vILr\\\/\\\/s333iF3\\\/50\\\/\\\/pV79w9szFIstkPqh8dfV8jYAoSm5QBmW8QTbIiruO3vTLv\\\/hj779z\\\/pUXX5N8CtaxXtmQg6XBeHz0Mx9959k3phsbUszQpi5LEJ9m07aD3Eal3FNkbRnLXhpjN\\\/uOGDGqc6NUK15o1AAwkesM4kWaYtYsbJ2wRr2GGQrT1Ux2c8eCesyrzGi2qBZGWVpdXrl+72Rro+qB2zTPOlCpkCKv7YYhzOXZ3\\\/raK3\\\/8nAzGIhlrfwqGdttSzIvp9vali2Rjss46H4C1+TSlKMqiZrK+efD2I6chAc4rqHBph3EnqOYPVRHhdI\\\/0hNUpMbbOPEQTEkrPWNR1oFJQAWJNju0Vkpoe7aYoQikKFLkUM86n7zz7+mP\\\/7Gd+8OXnN96fymBWdk0iheSzN77\\\/9n\\\/71T\\\/6lX\\\/5uV\\\/7d7\\\/wu08\\\/+\\\/\\\/+4tULF65Od3YknxT5VFrqrxSzDGWwJNnSyji78bo9P\\\/rpR3\\\/6qUc5nf3af\\\/j9C+cvsjRmLxXVwyUZjg7efnjPDfvPvvJW7VCSs5la0NPZqkoHxRA87aNYF2x1fViAMCvOJrOya94bQeCOmUxRAx2Nlt7REzIkhlqfFRi9Fc3cTKojattYSPgGCrPNxgPJkE9moTZAdaTlOVcKaEhKMd28Nt3exmCpMsiRQgWJ149ePpV8R4q5YFAKfQpSp4WzdQYppMhnm9s3HD0UnPNtiBOhcSYGY3wW+Q1IPtrGkpGrN0wQY50QyTaodKhYkZDO18atusCUCN1BYpO0idnlY99WqI03I0mUHXY+vXz8vVMvv\\\/WBTz547A+uFpURSyGSs5gX0+0\\\/\\\/\\\/oLZ89c+dnPf\\\/yf\\\/Pwnfv7nHj1x6tKbb519\\\/djp9947t355YzKd5bmMhoOVleG+A2sf+OCNd995891HD33gluu2JfviF5792p8+e+rk+7WcrfJ3k9HyaO+ee37qseNfeXHr\\\/AXOJ5LPWeRo1mFVr2nDH5oAV7sg9QwAbVIrXZanRXQa0FzZVDRokphQdOplAsSyDep6EQn9lKNrNA+RAYO9bQNKGlUfGhThbJYX87zprMEakNP4XTlQ1vTeRU7MGoCrERLXoyS55DMppiAlq4OQ85YXRVNjV0wjWRRltnctimxVp00ULsOuWcL9K+l8IcmxJhMXk8odHSI0UKFLFRIUN0upNSALuTI94hQfslamXhpSsJjLfJJvbx7\\\/0rd\\\/5Ff+3oWXj196bcJ8KlkhLPGM2Xyy8d1XX3vzrXee\\\/sPbH3zorvvvv\\\/VHHj\\\/6qc88XAyyyWSeT2eSc2k4GC8POcim0\\\/mV81dOnjz\\\/tW++9sJzb5x88\\\/h8Nm1WIJAxG8loGaOVmx+5e++R61\\\/4718uZo0LU16nyrCRtgUPLmPAgnHSJFqMu+H94QnbHTFfUGcyOZjdRHuHkomY4khMqmr5qw866O40OICBUNMPg+sXpVoV1cRjawrSWCJI7XTSQBPIhoPltdHeNWDAbCSCKsqiRKry2WxrY765wdZ5pCb2Gax8s21kwwELWhLGdgOEbe09ZAWhJsZlMsgwNxjuOEZ5VYedXH0zQ0ICqZ80bx6sQ01vwLT8jQypnK0sUMxZTGW+vfnu2Xe\\\/8fI9T33suXOXJ+dLbVqp+it9OOdbVycvPX\\\/lpRdfG42G+6\\\/bf8Oh6264Ye\\\/a3pXl8WiQZXmeT7Yn61e2z124cuHMhc2NSS7CMkqN85KaIDIOlmRpGUsrB247cu+n\\\/8Z3f\\\/8vty9frpJDqUPtibjDZlvXaaoWYR4xqDsmapNmGpLV8P6dkLMSW9HUhQmInEGVoxR4CAb16Iy+tDsHoxEi1UIawoLt2HsxnUNkOB4Cg6ppM1HwlRdxVr39YHD\\\/5z5x799+lMS8EtwLUc\\\/uFjz9+qnnf\\\/V3puvTanKy5kyKKu+mULqGMlshAzBeXSo2t0PZUMzjhZujfYSdQhQ+tsNYIeMLXiAiGEa3MLkWJSKKwnnnDggHxkgqmHdAbYhQ5MjngimnOz\\\/40rcfvuvI0c9+7I3f++Z8W2QGmRHFtGLVOC8wFexMZoNz29fOv\\\/+eoNxSA3FLRbir0c\\\/6LMtKs1CM18YH9j\\\/4+Scv\\\/uC99154jfOdxsKoKY0qQE5Xm9QYqRaJqPXAJvUAWgONdvTf4J\\\/enWe\\\/c0G8AzL6bHHlFFaPXr9O1beQDl3cqMnaM7QZem+mU0lyujXZXt8YroxLgYR678oHp6gTSyUbsCiEcu39y5ffPldQ5vNcgCzLKMjL+GIp1k+cyacz5QaTNU1pUWsq2vVdJ14s7Vu7dOq8VSOQ6ETEAqiTthNhE1dt1dvoCNw2l5tKMYM+\\\/VoAvlCH8hKMiMGI1KBq4DWM0LxyUcWV55DZ9nxz8Oqvf+nRf\\\/pTg6ce+97T38oFwpyzQjBvm3sUIvOmFmALz6lqpOmYTPTaaFnGa8O9ex\\\/5hz\\\/G6eyVP\\\/iLYrJVzdfkVRozGptK1gxeZxA56pQXzaw32hQ952kOTAefISXdYbQ6VX0YIsAYbBsSD5QFlTURo\\\/YB9BpmpEhIHurDo5kOKstDFsX2zvb7F9Y+cN36sVPNxGB1Whb5fDqdiGCUiWQyGJWoxYlnXjnxrVer64nKig4k80k5hMXZDMgqRU02wGAJo+XR0rCYl0SF2vyzAbMM49HqTdedfe77Si7byvEkFEkjNWKvk+H17qnma0ADTMcvRcv8VwHF\\\/UR\\\/WhbQOhnrHw5djRmlZwuNiUijm5FiLvmEs63tixdf+o2vHr7n5gf+zuOD1TUZrcloRQbjSoNbNqPl+VnkkueSz5HPUTsgSvmXCosDKm9FWVrFyt6l\\\/fsf\\\/fkfHw0Hz\\\/\\\/mV6dX12W2LXWcEFoYXX28tLtrs6lHwtiAY4RzAQm1ZUA0wqYjMcKrWjY3OihTMdTSDEy0g9HtS2vtT\\\/Mv3INXK1RSj4NSeAdgbLV\\\/VZdx++z6Bx++QwaVw2oZCEMRKebn3z138eK1Wx64ORsNZGlVllZlOCpYFPN5ns+LeV7MZ5xNOdvJZzvFbFrMp0WRS5bV0TGrMt4jSysHDl935NaDb796cj7ZqcZHSntbQLJs5bq9+w\\\/vn1y80qgRm7IoZDndeM+QGLZjSaquplbA0RtKZPgWtUxBxjfZthzxidlm3gQ7HxJxbo3Sv62i9ECAHr6ACfzVe8xkY+fSOxePPvnh\\\/XfedPHti\\\/lcqvwdGwUVWpS3gz+VLLvKexqMZLQsSytY2bvnphsf+6WfyOb58\\\/\\\/rzzbOnZfZVpN3XcbKNjQ9SBMLbgtIX8zXYNC21lSIMzudaOmWqKm8PIh0EXnmAYJdXXDdTGylFbg7EApiitopCKpQ0cF4sLp6+yfuO\\\/XMsXxnR4rSN7FCZabb832HDtzzqQeunt+6dGab2bIMRtUQ12BJBktVSCuGyEaVf0DpmzgcY7SM8V4s7d1\\\/5IZP\\\/qNPXv+Bg1\\\/5z3989ewZyadllB2zgQyXZLR8\\\/T23Xn\\\/PB49\\\/6dliZxP5BLUmEYFJghGIR671dgulX0SKSErfEA0ale8+RAyVB\\\/K\\\/eJBXBaLVlnEtgNbmwEiizmWo5GA4C1VI0Vjyg3NcPv7Ot379T+7\\\/Bz\\\/60C\\\/95JtffP7yW+9yOqrs98qMCn1qKXhB0JagzAZ17MFytrxy+IePPvDUY1feOffq735969Kl2u2rtD+oqKqawqL3iNPubqqUAT3lvGnyyEDeYLZMJjk5zwda3ZI6lA+R+MXWt7RvSg0K0H0oVKqRo8BRQ+\\\/NgV5KcPPZtXfPz\\\/Niz5GDl66sSzaQPBOUdjvzfLr9nf\\\/zzI23HnnqX3zmtcdPXDx1bjadTWfTKVlwIIXMZ\\\/PxUFZXhsPKx6BgXZIjG2TZcHnf2p0P37bv0J4\\\/+x9fPXPsRGkPVyWQZkMZjDAc3XjPrVfePjvf2W7wNm8KUE+vu\\\/0b01hZePvJxDaGUIDVjL\\\/sezi9f7qbbJTLi+D4rYWh8I4sRGy9qLzo1nmNVSTQkgzHGK4MVvfc99NP3Pqxe9\\\/+1psnnvne1pnznE2kqLiEmgVmq5wsg90rl85BafycLS3vvfmGW5+8\\\/\\\/BDd5786kvHv\\\/Fivn1N5jtVFdoUoqJsHcSd8OQC+KWhdBg9sD4dBytjQ8dbUHGtzbVlkq1N4az0hB2Nd4ckZFPKZhZNqnatIMoyYMAybmlpD1YO3vv5T3LC159+hpOrMt2Q+aQyp8mGGK2s3XjkI5978o7HP7R2YHXGLL9u79asuPLelT0H9l5348qgmM4vXFkqOBRBq2OqOI18ll88deGFp7\\\/95jMv55PqlZENWHf+SwcOPv7Pn\\\/re733j4qvf52QDZdRPRUHV6XfB2JfbDMcaNBcjiOVKCYRG\\\/ZxahPExGPJJNoNJorpUe2zHLsA25kmxiNUKzKgDm5oacrAkw2UsrR2845YP\\\/9zHlw9dd\\\/zPXz734rHN8+vFdMKikDxHmcxcUEfAVvby2WAwHq8cOnDzI3ff9Yn7L7x1+rU\\\/\\\/MuN02c4LZGYeb38KrdvqhlzWBrA1CdwBO+UDoVXwK1jsWXmtBZWZxqmMocLGG7hLvEwt3kA4MNDdHqT+qZX9YsIsqw+iJZktILx\\\/gM\\\/dOeDv\\\/AT3\\\/r3T++cPSeTJuenAMDBEMMVLO1Z2r9vae\\\/KnkPXP\\\/GvnjrxnVPX3j730b\\\/\\\/2Ejy5\\\/7oOye\\\/8YrMths1L1uOsijy2c7Vzfn2NotpbYIMDIYcjmVpVZbX7vzkg7c\\\/ce83\\\/\\\/VvzDevlmneyGvnNdXzV9suXESK4nuJOoPz0HF3SRgleGaGXlCb9ERi+2OcVvsrfeQhW\\\/ax6pFaab4UUkBkzsqIISfzy28df+Y\\\/njt4xwc+9KmHHvzJh69duPaDb37v0rH3J9c25zs7nM9Lf1dggGyQjYajlZXxgdXDP3zHLY\\\/eVYyXzr14\\\/Nv\\\/5Y+vnDqd72xytlOVoI2akU0hqsjXkJJtfat8yaeeDYUFEuEpIQLXK6SLECZP2Y6rHtFOjERzKt+ATlpJMKcc7xntL1JbH1az56Uuv1Qj7lx99+zOZHrko3ef\\\/JPLHI6FeU3mF8IZSSnynXwy2Rjf8pGja9ftuemOGx944q5jX3vl1S986+rp85xscb5TpwhTKfiaedRciqL6NM0WMBwPl1fueOK+k3\\\/5ar5TQd9opvUl0gDZoSXquZUItYYLXCkVEGMmEu1UdWB5SO+ZQM+QEtpOpBSiRUA3rXKNekbcyC7CmaBKJZ9LwdoCuFQAzuazyYXvbVw+\\\/u7ew4duvOumGz90yx2ffoSjbL61IzuT+WTOghgNBuPR0p6V5fHSdGPn0lun3\\\/zicxePvbt1\\\/iKnO2Wgj8ynKOYsjJoxnHBVzVvoKMPWQdaI130JCk1VAqVfTzBCqREYJR+F0U7HCSdgSs7LAKC3KV+BGk9SKF\\\/dgMLExrXVQ2WpPJdiUmxvvvn0M3d+7uNnnn9r50zRTDNXNzefli398v6VO3\\\/sgfF4MNvY+sq\\\/+cqZ774x37jMMhymVS\\\/RXlYqdWYVtjeS4TJG49sfvzefzN955nssA31rKWI140qlUKu9PXTZhwYbF0TgSGdPgpjSh\\\/gIjwwbuYaZICPTWmIlKPZ6JGqb36j+TPa1Yc1UsPkgRQ3lF7lgznyazyfrW9fW3z6Br4\\\/GB\\\/ctH9yzfGB1Zd\\\/K0toKMhR5MdnamV7b2bm8tXVhfXJlUzhnGWTbhq6Ubn9UMZ2N0UN7RCBmddQIL10Re9vFV\\\/QgbEVJQ6HXpTp7ekw7c2GsDGI\\\/rrCEhl8ceTeXCe9b5+dR1zNQJChBNNb05ZjLbOfy90\\\/sPHn\\\/HZ\\\/9yOu\\\/+XXmpfdp3vZGzFHkRz76Q\\\/lg+Of\\\/9g\\\/ffub7s\\\/WLrDIqpmAuhZ5\\\/DyrwejhQRDJkTS+6vHLD\\\/qOffvi7v\\\/P16bWrpRYKRc5mcitSz0KX9xCvA+QCWIB5EqIRw5hGrHtCtWaBCDUKc1CgCys3\\\/RvQ7DlSbaFYSY2xNqqTDMuoejZsOwYqS2wo2QBVDLp+WstSJ0eRlxb3pRYc5X9TxVHULsAa\\\/HOoWO9USkx7STKvignNXwo+SVon9EJophSNPWkSNEZajWWJa4sRoJofqpvDUh5YxaENV2R5z97bbvnhX\\\/pbb33h+bPPvV6lUJQLTEjJMBjsuf2DUgw2zpxnPpWKmp+jmEtRGH18jZDWIWM6QnxpRcZ7Rvv2PfqPP7V9deOl3\\\/pyvnmlRIPKyKeqt1SQDBswPDAXpFG6q2kF9mXxuuMyzg800Wj0FGoIkRmExRR9BJaxNI1BpcRI7R8aLwBWG40ywgxFCUuzDMGrzP8GyDKWI7yN9Shqbr1y+CtqE8667CyKdqhPpfBCHYQI0LD0bkezxdnRZob9JGNpJhrBW\\\/TirbKGEUbNnhUo3cYo9sBkK0CMPVUCo6n2zCOUsL86RWpsvCnzCilykZkgk+lg49SZU19+7r7PPbp19tLVk\\\/PqBpdDTEIW843jJ6sJ3jIjuSha6Nt++\\\/pyNzaQ9UyMjNey1bXbHr9v783Xv\\\/Q7f5bvbMl8okT5KjS7floQpjWJNyzkFAWRo6ELoNFZjcFtG2B8pHtfrNBnt9BhpERrjMAMVQU4wD0kmtVS52H9EIaIT5ksXYAEi9JxuTZNKEvNGfKZFHOUrEOZlVcVn1otIQYChRmEICXlN+BCpokuOqwTxB8WQtRv63hkBvYu7opazG6kU5SIiIOkUf8Gj2Bjy1vdJ1aBd+0tbInN1nSewMaZK4Lsw59\\\/8tzr78+2Zw2WDhFUC2+OKgm0qJNegyZHubCijkwtE+BKOHQPVtZuf+y++z\\\/9yDP\\\/9f9ee\\\/e0TDcxrxDRata+pumdGw1fQdYMqwN9V9uXGVHvVeZuDDA+Eu\\\/PZhHC2QEknL9Wt4WmxIpzDZHQCMUBFghXuTT+R9WAH1leWbRnXQ7WbkIlYlZ6uig\\\/aakPWNR0PEjnBtjjh76OpXeQOQBv0AnAOJnkVeXlJuIlw8xdzZQvyUopli0z3HGMtjcJaj0jjFGvrQYoG6fXx2vje37miYvHL0w3JsISh6Ow0KNfsa69pOBRZYZnaGMPR6gJiWxl7faPP\\\/BDf\\\/PBl377qxfeeLtM3kY+lWJe170SnKtKhht2H7SyGLa0aB2vGQHjpJWnSezJZNdCcxJGz0fQGSJZ+USEYUjjh+ahSOir4CdAtXhSwEmzIakhbcZgCQOgjfIrmqwlkULxB0Sro2W8F3aZyCWfwgXOGwRDSABkV2s43Zb1w6qdhSt288OJisnmoovdHPTBThbFpXcuDlaXj372I5sXNrYvbQQyw8bpsFnfyFgFy2YotRyDOmZ8MKpI+aVVLO8d7tl772c\\\/dutDd373f3\\\/9zCuvc3JNZluoLPdzpUPUQEtrLWtNTBi2cDBtBP1W0Ldmc7VK1e8MMD6igxPRnvhJOqr7QIN4Yhp0LDl461M6WEpY9aO2DGSzOI3vLZTMmupOGNp60RVBV2pr\\\/j7a19onFrt\\\/SyNBdMVM7HpJxgvQjERAnP6z81PanOYIZEKsamCRF5ffPgvg6Gc+OtyzZ\\\/PclXwuko2q2d8yOLnhG1BHFGd15ZkNMViS4ZKMVmS0IuMVLK\\\/uv\\\/Xmj37+4\\\/uPHHzxt79y\\\/rU3Od2U6Rbq2bTIgLyupzpGyYypDLoRUcPmpKNinJ5w6YjToQHSE0iPSMAExFUtwv3SOUDgHNiIlN8S6LKbrQiBOq7+IxpER7R8jiraWoL\\\/WMQZx1FKLrCEVDQPvPMVMVPogqsUGwmWvk2maNV8A9IHL8VhBI2LqbuaY4zU9rf6FKn3RxYsiisnzl97\\\/\\\/KHfvzBmx85OtmcTzbmZFYvtkELg2fDWns4qqK\\\/h2OMlksUFMtrK4euv\\\/2J+x\\\/+2R+5durMd\\\/7nn15973SlyJ9PUcxaMYaaC4ETKa+HS2rzf1dtFFwseDdVH5vx1haP9u59MLlzq5FUlYWQrEhDftIcC\\\/CXMeA\\\/HWod1uhPcGBS\\\/Y+WlUTQBtPqp1tQNnJcjldatzyUIBwyoJs\\\/gGfu4apnqMy2tPNnmlQQj0IMoRbobZOLLMLkW3g4oSDWyrElq2p5cHOaDcYYLstodbR3\\\/x1PPnD3Zx55\\\/8TlU197+eqJ96YbG5LPWfkjKk+6rDoSkQ0kG2Tj8coNBw\\\/df9uHPvXAbGPz1d\\\/+2qVjJ\\\/PpThW+XczKLDQJrSvrWBGHgVBzeeZ\\\/wcpk4hBCJhVqAANGI5qxcBahSqyo9opKOYB4CcWFqA7NNntwsFMqvTeikdPovSJjR7abQjwO1EoP4D+GgYpHNVfwyUAX8+CuVqCEoLEmkZQuLNb4iuut0LcIU59HDf22YRax5L\\\/JZrSdAhPoDyzYAG0H2TY4bPu6AcuTbTCWwTJGqyvXH7jx\\\/tvv\\\/omHRytLZ157\\\/73vHNu6cHWysZlPp8zr1PQsywbD4eryyv7V\\\/XfddMdjH1o9uPfiD9478c1XLh5\\\/d75xldVQ6BStHiNXPl1txquVhkoQENY+QaT3WMWbUUwbKhaF9KwxlO8F9j3o+d4nsDV\\\/HcJ53hi1HGL9cksXepixDONMlphgZDrFm8FTU383iwAzObMitV9AssJbDLLpIe6hFiGNkKKnNGakQ\\\/ITnukDP0Y1QS6KPFlFMINyxngI6Wqs4a7Kbr5y2SqrzWGl0R8sYTAa799\\\/4LYjh47ecvi+2264+eDOLL+2ubOzMynmOTPJRkuj5fHa6hKmswtvnr7wg3cuHHtn48z5fGe7UqXldfww5zUhwcYBMTCzMEuC0X\\\/4tqKJioD0qflerUVlCLLvQV+d69xzPYiExGhvWX0gdLJyhy2kNnhGl3TZbrG6LlCniXM+m0K9zkX3VQ5IhlIxeUYujGHKwiQGFhPHpIGk5FKu40CcJQaSu1n5UX8J225YBjWUQ5U2PwBYRiY3jV82ksEI2VAwGK7u2XfowPjA3tG+1cHaEgYoCuY78+nWZL6+sX1xfeviVeG8XXvFvBEDl4p\\\/0PJSNqDKXWNqodJu1glxDHSqmrewnQvH8DDa91DcViZ83uIhHQRFDpIrQHSOPQPxUYL\\\/1PcYafZbL0LYwi+BVsAoIcyvk85Is2XpDIsYV8UMS3J0LjP0IbCdYHH0w9aXNAkiAfUQMK0cAbvgT6DuvuudWE+o6amrZv4QNQTKGIwRhLgEKo\\\/uJui7SZgp8tLMEnXyaWWDH\\\/d+seGq7p1JuuPwTsREYqowkOkad16GSdjV3wx74fdAjdO\\\/WauYvmCZ+DqTSJqB9ONlZs9hQothzzS6e76E6w361RqzdapdIvbjcoggIl7sSDQPkgoBQtT3xdR8ag0HLXBae99sDdBYD+NNExLHATrL0rQnjB7rwClT96NsvfVZlEygMEeRERnKP5YGSNWrBmr0eqqmxDwLFT7DykHTLDa7AlO3ot2QLLiRaDMYNx0wHTgN6U4T+VtrR6E9NugpNqIxOuo0xFDhwBi0IMwWkuKLnVXuOf2JtY6Go02hYVTjukKbYjMx7yeR6Q78yr21oPerRaZm7ROIrFuLdO+CiTG5qHaJJKKMQXggzvLqVM+YfUY37\\\/RtcNWTmIMgqnlQtjItOMVNE7pUBcuw8SKh8kqHRN1d\\\/HxGzrENa0V0l+eBuXna\\\/IIL9PS1gJv2DbSVZCskjqJ\\\/hQuJRTyuTTwHviZ8D8aTyDDUrgF7+MoM5u669ClcgBw3CuZ4o7GJDj4MEz36hs1FNDfaW1lHhXYwHOhcaUQyWY2KqhzejqvDIN4CXu0aCoQUl60dlUqBSBkxXoXQ0zmBwRiFVodb8yQ21nVRalWUcCj6AbcVpmnt9F2BY3yf9Kf0KcR2QLV6RodpPEFdgop2a6PzLBfZljpIEG9gzz4BD4YyJ7SZNghblxas84yYkqcbEk6PcI45ekcT00w+2o1VoPdLL0TNXPZgmAqdRx9d2E2fhWSX4CPC+MK5CR\\\/i7QSsaPp188FQZ78qbyRR4y\\\/xHgajSCnliNBzgGpxRnbmpjRFdMAHwal2D9QrkIE7zG41h7RFLEUgA4wPJ\\\/CQNFoNq31poBU0PwBzN6ULrGeHrLTj78U4vyRpM8RdCjrwq\\\/B3UhfDPyKg3wzpAT86Vj6ee14KuHbyJ7xaNPayIYIhcavUhiPqjr4LPYhu0acRqi01WlO9t1O5ubZWBo3WrFls0IedbkAsCcFAMOwCnuFAM+IBlyS\\\/xQSQEavnQdtfyEDGRzw3NaebkGBAJWIlTOEJCN1K1F3mQHLYtw+ad7gMdMdlSJOikOymujFJjzti2iPG3WT8l0\\\/Ir8NkPrE+dnAuE1oVcBD2BWP209JNKUi0vTfBsAR7ZKUITw7Yde9Ia2P1vBZOg+pcCurTWpFiXIztmjH+MV0tnIlWhXjimF0qJbyqtPynXISM+Adnc1XzKdrS0JuMAUB0Quvw71lipXlLFOlTSBLwXfq06SLuGAE\\\/TF5xILW2et7FjcPTXoZ6ZrgNr48vmZqqJp00dmiJr6OFQXdRgbjoQPdXpENdIYBgJVAlajAA3hVsNMMhics6n4Ex1aSuGtOMX7RLx8467GYSErVRh65ELUK4j38UpNRssvCsKVq6iCnGgfAeSziDhS44YT4mE0OyzkdbgGFjjCPBEwwx1UJDXAoBQD\\\/LVj+GSPw00iUK4NSjaBJpKSkBN\\\/TmhRY0YXoXM\\\/mLqeXnVP9GyV2fx4FCvJEIQwTd+yN0LA8Q80juZK37RzbD9VGd7++8uk\\\/vF214Yw32n3KekJ0sbAzTBzeBkjL1QzuUi9BsVoOcvQWn84kCZTNb8Zu2ycAujqKuy9\\\/\\\/i9GRDdspYcE5DSDeDkRciUJYS6oHJdCZMWgKEf+KREG7qYsRzkl5TSx7WsOIY1Have6Lbl1Snd48YALpsJxU3AtCpLPTK8TljUBLF1rmwFEYQcRFIoYBKSndB8uCJ3HoqwJGjFQUBUdX35ymExCGT9jWTMmyXUl0YgXCQTXa5GL3s3SexBDZ1dy9uIMSTZhmV7nnK7GcTDSg+4Awl4z1DEDfrt\\\/cCPQIgMIVaFBUpk5U2Lz42ISx9i3U2eaGVEfIX\\\/Q3hw26UTTlKBAF1NMV8cNdvhUlE77tMNxT43VAbWZnUdtWii+BMbO554s8f3ShbxcyRtrmrMm3gES8eW1K67r0uAB++BBHnRIQbrjwwEkm7kXS4jpxhrATAAgdRGmzYHV+L1LQoPrONOOISbyIf21fgESgir2T8SUIfcOCxz\\\/hSmgVTilSytdCxeVvmhg0miXHe9RtK7M+5qfNcdUHvSlWNfNiH8Xk06P9NKk8ydnoV0wQQMJ+XL9NG+jZbt8tpk3phscS15aphp6pOrPXH7b2cu\\\/5BJ1VjWj5SzclANvB0Ar8geT3p0vetZGotDRg4tYk1XT6NGMdMEZjOxJdeV340SxKBB9SdCQcrEu628DpqxRbfgUVHEObPKZQH4r7MAuFw2ApdcHkXtHmCR3V5UC65GYIDKR8kPxfh4mcroJUNTkSWbiYOtYf1KrHvyw8wnQjmJzn6p2Wjz5A36mSkjM4OEQPZGeUocoSrb\\\/w9DZTv1KnQTtgu6gg5cmvi1L\\\/nTDdMvADPJipbQ6le0dO79lMrZOQA2YS6wiboNptzWZ0BXCwSOwgAwsYoJtbE4ddjG8kNIgWsc+xnUmaeqiG7gkE\\\/g6w8IFnO4BuszH0EYNRTR+kHGkUBG7fmLJgY2Sd0KnZprllbfctEYCTWAD1LunD5+yGL3sHMWB75yZNwXDmuvVdrIDpWsmqvEVg9G9oRqRLEAuMMYCenD2Z8Y7Z2tAMnV0hfJjVr2nSLNJ9JG1\\\/vT8C6YsFRYVJlxmE22aoMW7xJCsWZoEL+zC24UwIlKN+AA5eQ92pMUbSe6cVGQ+RVPsJmewnYJlDjau3WjZLe2qQWw\\\/Ii+fX7KJWjFRmnYdpi+ka0WYoeSMXW3upM1MHqDA4R9ofYXpkKfxjXMHYLm0XE9rDmAaM+vlQYBx9RATWKIsh\\\/FR7H0D\\\/dGMoisYCL9iHbsQmdsazpxybcaaxYvDRSE\\\/KHYDO8coQ3aeLnCF9uPiUF+O9C105lnCffUbRI6EnT2Kah0HOArpJnz6yL2A4UjA7o6uvsnFSRQpjRsH6i3bbJaTHUmjLQURAku9Ra5oqKmAmiUY2BalD6JX8nB3AgdOc0D1iQQkUWFQFcJAFz46SwNvA\\\/AoxAbUGllmQNDRCDx5oVBuED0uEwqJg2oOqTeVCm2d89DEYCoy9YJTIwJpEKmMjlwrrXkYMqJzeO5J4wuvZI7q7LJWCtEFaoAqdYEbOqFJIC+S0xnspyCdA89LAWPWQo5qZYkps2t7kVEcGlALuI2FlFcUnge7EX9sdho1cm9iu3JngqmFcf5rYnCjuQmnrZdsyxWHAyeNBc2fs6jOT+1T0R8T1I6XzsAsbNYrtArTAGWbWQhIO3Ck9roIAetSAiM5XxMbSsfmBa6oQdGCIAUqXrfefXadni6XCNHohtodJcm+A9JQ\\\/irhkY4ZXlgt0jSxiYWfcsAHDaqaLZlY1bXAAH0ZC2BgS7VAoCKY5XHjMJwNJUdsvaIeqCNdBWJ+gk31h2O7HVmdmPKojnilZResHgtYTIAKQ4aoFxBm4MDtkBArG8B7dQwzODzjgtuXRApMQOBxF3CPQ7dPswtC9DNWEYzxdyLiIpXdIexoQhGUNwmVNBw2kukO0FrCW+apsdKJm2YeegcqBG7Edg7WR7h4DgKMXbdGLYEeOhKzwI6V1moEG0lBbtJnjFB7vA3huxdJpKpfeKNC59PpbcCRwNnuNdvu6qrZhH0ZNvzjw7GERdbYRTAsP\\\/Uff5aRRsFhvTKT5Vfg0aNpvvPNkQ7BgJMV3+CAMPF9g9tyiKMmzrGyGbrcZTonHlzz2vkMLVtD2eezpcpL8mUJI6G2zsfYFqR9JAdbUUQRmlRrOhtzFCmTKYybxvOzClM2eutEWiz50vuPhZtCOKSbPK3ijBypAUIgurjPhPwWmBEbJt7bSKPSFkTGJb3XntFqbskYq18+uMsjhtWfnUDzSO6K2vZ49haGrPTRyHbZMWTRExl4mAm30NsVldCxCEBodInH9k5wkA1i4ewXaqh6RZ1t82WgfTexqy2qlBXR7VDJ5jNOhzR3MshpNbB6jRKvC3kNLImFqoutLQQQdBw5Tb8EuOICS9vn3yY4IEKY44zYGhG1wIjp9C1FP1qfE0\\\/DH9HprI0+Oax7GOBYm9ujvSlSzz3r6I1VgeyTeSs42aBP+wIeeiXkl80xHjzskSnHpHPJAYrSkY6wRSaLAJ2XRF\\\/cLq3D1sIFEEsNCBLo78N1bg0bjEZFuK9EF0z5sQdQS03iBWnyAnlprEtJ6Nstw72hGfJqfGGDpcHoHCrvK\\\/r4lNL23NRI8rKRvyAepBzTsIzobtrC37G1awhEu6LkYwkMDo8cynoxViKQ7oUcJNotUUpDz5DFK9UA8DeoJJ3rvI+0UYLLUly5l3i4K4+QHriKc7WXtou8DNSwkHu2P9+\\\/Aqyb5AaEeqfSgWoTFUkd4tlMIoCBTfk1h6JE5ibGLgZyQfwrHowN4Ah1HaYjbxbcfTQqa1UK7OxPFoVkX6\\\/7RqrbSK9B+biCEhWifhFoTXxJ9yk8sumyURIazO3oobu0fFALsu4WR5IKSGApjULU4eE2sq+4mjRhovpvzCi5S0tmFkwu1UoGxHGPUjPbGsk7LZOveBgKxfjXgz5CuAeqTEH7H7JWB2M2xJV68bzhVicQrmSESJM0voj\\\/Sl5aiT8iI5HcM3bTRXwikiKj2IGcaQ+2xJ40XgHvtA7fXRfrMvobU+61FXheL3gN2Xz2v72SHmXLvGRwa3tGFeXSv3NG7gI5eAP3mFyLSKGbQ1SQxhJc7cFgmNExcCPf3NiDTwSB2s9MVANiDnHh+li2ynzwkiLjodS6WVwioHRLQJ6FzUieG2dxHkTHOZ\\\/wdnAtFJveufsg3PKPgyCwTTw7hXSDv6oVZEZRu8cpCc\\\/HJTZXiTENTXOtDKzVnVKXTlgGtlDtqIyLQZxg52YKpeVl2DjWqrckZA4WPBtTCRfrNtmNjhA7kPwwYX6BXNoa9iFmVpg6looU7CtokzgbYFSfRe6dO8t1AkEzcO7ZA2+KTStJD8CgL9ggEsMEdEnt+J69b10ekLPYI7frbIZb3W\\\/9CW5K3eriKp0bX4VdqWJyjK+u8yVGTltIbhjuz8TFJB03We48PBjL9Wz4WEndR4WbPaEwzMkYnnT6LbjQPF392GSc9mCIU\\\/vAZhLt7ltjR6OlPwt7Do\\\/dFFchIlHRr7LDiClGZ2ji44I4Wrlftq02fsPK4Rzh9IiTwEmzrILQtPYK3VtcTpFPJ9sFVlJKiiAMtKgcwSJepVuwNZnJGTcy1R3\\\/oPiwlI3Ud05g8KZCQbMezuvqLJMyXET9EcC5u\\\/KnUfCaJoB\\\/0k0C9brPpR3plPbsYn+lbdr5UeAFuo+vRjzph9wN3NtPRh0SvDMTBhxhiEm5fhOCJsSNxTDymbqOCLk69llkPvYvf5mr2TfI1LFpzMoeqpMi5PqhRQjaRrYIPauwIETcKicKVImc926Ex5W7Zc6pFjlLJx5WOh2LUGNAWcf5MU+BIgvg1F0b\\\/ta5XFsRRJIkGmRCgDlwlFl1wkQ\\\/M3Xw2plyvo09O46Pl0TX0LFoDZ5kaegEdXCdVArFr92tSwONKYPFczNYP2YOD0QaOeb003GaDUfHGCJdmOA3EFkM3biXBrgnbfDcMh\\\/a0gXhRkolnJRzUQFy8MT6pGDQTHarFYINWWxwZZc0ml58E3BfSfEBnSnBTdkEnWNHRZjNB7C9URrOfrkjb1CgOBaFJLGvcjc6vhCNdYifb0IzVtS78cCEys+1TmS+axW4WGtlEwCV6+pCOBP3DpoferJE0Eqofg9WVMw06VJFXoLpoLs4ZJz\\\/STcbR9B3cHZvON3QR0WCot+N\\\/WqoPKTiRDuRMr2wLa9tgC0gYtaB7XjIemIwpO3oBmi0y0wyqcgGvVUlAh9pZKoUP0+FrIikZ2hfVP886ypTwyiaa9a92V0q\\\/xX3QKjanqGc0UCvukXVBbozPJHqIjbh9mrI8CyY74Lr90SG5gJTrvfV8g0QqZKTB65BChQXfTclA9mDr6eYgeGEusKc3PEh8QLGrSjRzsaByGgshlOD1QlYgABrYhaSkTNCclI5F0xR9p28GAZNwpj2EZAAWtipp208h\\\/M7+R6S65U3zgERpQzVXnZTa1KAo49Oj3A5kgPGhJHCHdvg3+cgYdEJH7bhgMqosuirDM4myoAN2QNcygJfsDR9EwQKIBQUgesNPunqehQ8ExBgP\\\/Y6xuw0CPLsL7ArBYThxSyc9CbsvO5EWTKOrbRJJDEz3OM2YSIOIB0NSA7sQq2EY9u6h8DZBA6HjWtb3UDCMoQnvQTgGFAw1MF1xaKhwocqFgYcGooJBnx9BVkg4CM4FmSiLZDMuZrEbJeaCyw8BfNcHHuo6nG5dF8KtZgWy90Ojs4T4a35Htd78Cirp+wbbH9C5ifAbNtZ2QOjcR5O3Bb0bS7JbSV4IzZRlfmLuQiA4XUczuhU8DdJYG7zGlYuzm4BED0JkHJy6rjOTZZZqPMUJhPO3wuhLu+IrYgFkv2mS2e2a0xJi7DSBoXM12PGCfUAl6Zi7udcluLWscAFqF23XFrdjAtUpYhmp\\\/8nUU0sxy5YJAKgLMkr8aEfLwC5Ko\\\/muQzt8ic5GzdYV0Tdv\\\/fUQhaQ2nr2wIKnrKRhNvUXofqKsJKMkLlBinSG8naxDr8m+fYpdzpzssDpF4F6+oAoA7rOANAq1wPIPenr65q6syziEJg7WFZbOkRQwJ2ahcIFggMAjrydWw\\\/kzgRTbwy4H196IqI6DBIjuVuO7WP1VBn3k+vF6xmS6d\\\/go5LVUuUiJhArggjVOVxPkDAcEsIRRNiRukAanGfe+7k1PElOO71p4WgZMAxv3oFAwuXhfSQVTREi4aeyQrjf7QCAyxHl7YxuZ6NNiFa7lw9nxHdOsRjfuGvpEGCSPIr4ZlIQTcIn74tlV18WIX9o33znrW\\\/NmcWLR1cIoCaO9U7ApNoxXd0uKIaB0AtomWjMMX5SJbiG6+pG6goZpZA+pl8zJ6BB+kCqonRbbjj9Z0hmH7sbZOd4Vi7NM\\\/RgPf8KmZgZ3NUJ+0wcLabwAF9XQAd3YrPNO0J\\\/bnKf0ryaSOy0WsCBBZJjTU+tKKVuzo0qIijSyg5hw6hp4WjP4mU2g0rLEbhTpe4Pk5FSHHWzP3Wbci0NcT1obv0O4lmnQfxlZNdcIsZmBr1EEc8W6h2jDAk\\\/vUnBQFdb3iCEpJM4IEpy\\\/0BUxomklx7wOpjsLfyFUFCK5\\\/NyFGe5BOqA3iLFMOosppB+LJOD1FCPO7gMX\\\/q3pOmSddXRYpgbVKMIK0UAdsHMo0CYtRMj8NEhNoLReAENPmY2APVksCczUgzyJiEBjsG0GFz2MTacSktBK3O0VQ+TGaQaRnTKM7rBqwpaVjsaolXdIqxlq2gQgVmgqg1Qm7wo7ZO7ufEvg+8zEI+k2gQxCmKJiOwwrhPi1cLh44PE9Hm4uydZoV\\\/9ksdOWLwkAnEYWLsykpqZUkLan3xBGdaN03GO65Z\\\/TIVDnQdEF1rpelw4oHtrvpj1kFXesjW2iN0K9u8EEfkgCtmN6I2LAQtcQOAI0MkkZwRFz0PniiQ2QnfCdxUuJhFS69EdI+Supcp3+GyA+DZC6XmQHMIzIXTqJxJghNYSqf9hNNl2HZV1DNskTyffwjMZXYIWf7JZK68Q\\\/1F5+TEfZp8ts3XIgjX+j3lzgFF+SagxMyetK7+q4lgTQFYxLovYMSqPbdDadQBDCtvAE67kNqobTJxzELR1tu+xXikwTHWyvEpgkEGBvWXdf2CnWCh7e3pMorGZEJTInrIIXKUO9aqEXeASkTWUK8nqM3ocWfkU4JdB12ZAgOKjNq6yllEkLoqYn+qFiOj8XCzK9exkGH6WegjZ+I6oaYbwb\\\/SzheHK0I3dE6f7Brp3QIPxONhMMKIRYjuPEVaXqSTb9q25yo29KpOrKfnNU+shzFPlmHrLIGiVlz9v6btGmG\\\/tYg008DDFH9252dLPNhRpg+VCaLEr9LpR9W+\\\/beOpBGAUdEm12tDchzCiFg7sEoyZI5xgaY\\\/EmX0pBCG2WVpi7HQ86qutQXhNfUENjtRPsSzrkiJLKNqC+hhojEv+7UhD5HJBEmHAUKRZDM30b3cQorsAkdzmtUag6MzsRFzpu4qg8hLseUrF3jLR3lKRbYcS09S8QptpKd4EYcv7\\\/A5V66wHRWfq9AAAAAElFTkSuQmCC\";\n        var img = document.createElement('img');\n        img.src = src;\n        img.alt = 'Shop & Service';\n        img.className = 'ti-shop-service-logo-icon';\n        img.width = size || 20;\n        img.height = size || 20;\n        img.style.width = (size || 20) + 'px';\n        img.style.height = (size || 20) + 'px';\n        img.style.borderRadius = '6px';\n        img.style.objectFit = 'cover';\n        img.style.flex = '0 0 auto';\n        var txt = String(el.textContent || '').replace(\/^[^A-Za-z0-9\u00c0-\u00ff]{1,4}\\s*\/, '').trim();\n        if (txt && !el.querySelector('span')) el.textContent = txt;\n        el.classList.add('ti-with-shop-service-icon');\n        el.insertBefore(img, el.firstChild);\n    }\n\n    function applyShopServiceIcons(){\n        var titleEls = Array.prototype.slice.call(document.querySelectorAll('h1,h2,h3,h4,.ti-card-title,.ti-section-title,.ti-popup-title,button,label'));\n        titleEls.forEach(function(el){\n            var tx = String(el.textContent || '').trim();\n            if (!tx) return;\n            if (\/Istruzioni AI configurazione\/i.test(tx)) return ensureShopServiceIcon(el, 24);\n            if (\/Shop\\s*&\\s*Service\/i.test(tx) && !\/^https?:\/i.test(tx)) return ensureShopServiceIcon(el, 20);\n            if (\/^(\ud83e\udd16|\ud83d\udee0\ufe0f|\u2699\ufe0f|\ud83d\udcf7|\ud83d\uddbc\ufe0f|\ud83d\udcac|\ud83d\udcc4|\ud83d\udcc1|\ud83d\udce6|\ud83e\uddfe|\ud83d\udce7|\ud83d\udcf1)\/.test(tx)) return ensureShopServiceIcon(el, 18);\n        });\n    }\n\n    var prevRunConfigBot484 = window.runConfigBot;\n    if (typeof prevRunConfigBot484 === 'function' && !prevRunConfigBot484.__tiUnifiedChat484) {\n        window.runConfigBot = function(){\n            forceConfigAiUi();\n            var p = byId('ti-conf-ai-prompt');\n            if (p) {\n                var raw = String(p.value || '');\n                var extracted = extractLatestUnifiedUserPrompt(raw);\n                if (!String(extracted || '').trim()) {\n                    try { if (window.tiAlert) window.tiAlert('Scrivi una richiesta per la AI di configurazione.'); else alert('Scrivi una richiesta per la AI di configurazione.'); } catch(e) {}\n                    return false;\n                }\n                p.dataset.tiUnifiedChatRaw484 = raw;\n                p.value = extracted;\n                var restore = function(){\n                    try {\n                        if (p && p.dataset && typeof p.dataset.tiUnifiedChatRaw484 !== 'undefined') {\n                            p.value = p.dataset.tiUnifiedChatRaw484;\n                            delete p.dataset.tiUnifiedChatRaw484;\n                        }\n                    } catch(e){}\n                };\n                setTimeout(restore, 60);\n                setTimeout(restore, 800);\n            }\n            return prevRunConfigBot484.apply(this, arguments);\n        };\n        window.runConfigBot.__tiUnifiedChat484 = true;\n    }\n\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ forceConfigAiUi(); applyShopServiceIcons(); });\n    setTimeout(function(){ forceConfigAiUi(); applyShopServiceIcons(); }, 0); setTimeout(function(){ forceConfigAiUi(); applyShopServiceIcons(); }, 500); setTimeout(function(){ forceConfigAiUi(); applyShopServiceIcons(); }, 1500);\n\n})();\n<\/script>\n\n\n<script id=\"ti-config-ai-sms-unified-final-485\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigAiSmsUnifiedFinal485Installed) return;\n    window.__tiConfigAiSmsUnifiedFinal485Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function clean(v){ return String(v == null ? '' : v).replace(\/\\r\/g,'').trim(); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function dbName(){ return (byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : 'NEW_DB'; }\n    function getBox(){ return byId('ti-conf-ai-prompt'); }\n    function getBtn(){ return byId('ti-conf-ai-send'); }\n    function ensureUi(){\n        var rb = byId('ti-conf-ai-reply');\n        if (rb) { rb.style.display = 'none'; rb.innerHTML = ''; rb.setAttribute('aria-hidden','true'); }\n        var btn = getBtn();\n        if (btn) {\n            btn.textContent = 'Invia';\n            btn.style.setProperty('background','#10b981','important');\n            btn.style.setProperty('color','#fff','important');\n            btn.style.setProperty('font-weight','800','important');\n        }\n    }\n    function latestUserText(raw){\n        raw = clean(raw);\n        if (!raw) return '';\n        if (!\/(^|\\n)(Utente|AI):\/i.test(raw)) return raw;\n        var last = '';\n        var re = \/Utente:\\s*\\n?([\\s\\S]*?)(?=(?:\\nAI:\\s*\\n?)|$)\/gi;\n        var m;\n        while ((m = re.exec(raw)) !== null) {\n            var chunk = clean(m[1]);\n            if (chunk) last = chunk;\n        }\n        return last || raw;\n    }\n    function appendAI(msg){\n        ensureUi();\n        var box = getBox();\n        if (!box) return;\n        var cur = clean(box.value);\n        if (cur && !\/(^|\\n)(Utente|AI):\/i.test(cur)) cur = 'Utente:\\n' + cur;\n        box.value = (cur ? cur + '\\n\\n' : '') + 'AI:\\n' + clean(msg) + '\\n\\nUtente:\\n';\n        try { box.dispatchEvent(new Event('input', {bubbles:true})); } catch(e) {}\n        setTimeout(function(){ try { box.focus({preventScroll:true}); box.selectionStart = box.selectionEnd = box.value.length; } catch(e){} }, 30);\n    }\n    function setLastUserOnly(text){\n        var box = getBox();\n        if (!box) return;\n        var cur = clean(box.value);\n        if (!\/(^|\\n)(Utente|AI):\/i.test(cur)) {\n            box.value = 'Utente:\\n' + clean(text);\n            return;\n        }\n        \/\/ If the current last Utente block is empty, fill it; otherwise keep the conversation as is.\n        if (\/Utente:\\s*$\/i.test(cur)) box.value = cur + clean(text);\n    }\n    function wantsSend(text){\n        var t = clean(text).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'');\n        var action = \/\\b(invia|manda|mandare|spedisc|inoltra|trasmetti|scrivi)\\b\/.test(t);\n        var channel = \/\\b(sms|messaggio|telefono|telefonico|email|e-mail|mail)\\b\/.test(t);\n        return action && channel;\n    }\n    function channelsFrom(text){\n        var t = clean(text).toLowerCase();\n        var ch = [];\n        if (\/email|e-mail|mail\/.test(t)) ch.push('email');\n        if (\/sms|telefono|telefonico\/.test(t)) ch.push('sms');\n        if (!ch.length && \/messaggio\/.test(t)) ch.push('sms');\n        return ch.length ? ch : ['sms'];\n    }\n    function validEmail(v){ return \/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(clean(v)); }\n    function extractEmail(v){ var m = clean(v).match(\/[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\/i); return m ? m[0] : ''; }\n    function normPhone(v){\n        var s = clean(v).replace(\/[^0-9+]\/g,'');\n        if (s.indexOf('00') === 0) s = '+' + s.slice(2);\n        return s;\n    }\n    function validPhone(v){ return \/^\\+?[0-9]{8,15}$\/.test(normPhone(v)); }\n    function makeFd(action, data){\n        var fd = new FormData();\n        fd.append('action', action);\n        fd.append('ti_action', action);\n        Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k] == null ? '' : data[k]); });\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        return fd;\n    }\n    function post(action, data){\n        var urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.ajaxurl && urls.indexOf(window.ajaxurl) === -1) urls.push(window.ajaxurl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            var controller = null, timer = null, done = false;\n            var opts = {method:'POST', body:makeFd(action, data || {}), credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller = new AbortController(); opts.signal = controller.signal; } } catch(e) {}\n            return new Promise(function(resolve, reject){\n                timer = setTimeout(function(){\n                    if (done) return;\n                    done = true;\n                    try { if (controller) controller.abort(); } catch(e) {}\n                    reject(new Error('Timeout invio: il server non ha risposto. Verifica admin-ajax.php, API Key Infobip, endpoint e firewall hosting.'));\n                }, 70000);\n                fetch(urls[i], opts).then(function(r){\n                    return r.text().then(function(raw){\n                        if (!r.ok) throw new Error('HTTP ' + r.status + ': ' + raw.slice(0, 260));\n                        try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non JSON: ' + raw.slice(0, 260)); }\n                    });\n                }).then(function(res){ done = true; resolve(res); }).catch(function(err){\n                    if (done) return;\n                    done = true;\n                    if (i + 1 < urls.length) attempt(i + 1).then(resolve).catch(reject);\n                    else reject(err);\n                }).finally(function(){ try { clearTimeout(timer); } catch(e) {} });\n            });\n        }\n        return attempt(0);\n    }\n    function askNext(flow){\n        window.__tiConfigCommFlow485 = flow;\n        ensureUi();\n        if (flow.channels.indexOf('email') !== -1 && !flow.email) {\n            flow.stage = 'ask_email';\n            appendAI('Indica l indirizzo email del destinatario. Scrivi NO per annullare.');\n            return true;\n        }\n        if (flow.channels.indexOf('sms') !== -1 && !flow.phone) {\n            if (window.tiIsDemoCompany1702 && window.tiIsDemoCompany1702() && !(window.tiDemoAdminFullAccess1709&&window.tiDemoAdminFullAccess1709())) {\n                flow.channels = flow.channels.filter(function(c){return c!=='sms';});\n                flow.phone = '';\n                if (flow.channels.indexOf('email') === -1) {\n                    window.__tiConfigCommFlow485 = null;\n                    appendAI('\u26a0\ufe0f Ditta Demo: SMS e invio al telefono non sono gestiti. Usa il canale Email.');\n                    return true;\n                }\n                appendAI('\u26a0\ufe0f Ditta Demo: SMS e invio al telefono non sono disponibili. Procedo con Email.');\n                return askNext(flow);\n            }\n            flow.stage = 'ask_phone';\n            appendAI('Indica il numero telefonico per SMS, preferibilmente con prefisso internazionale. Esempio: 39333xxxxxxx. Scrivi NO per annullare.');\n            return true;\n        }\n        if (!flow.text) {\n            flow.stage = 'ask_text';\n            var dest = [];\n            if (flow.email) dest.push('email ' + flow.email);\n            if (flow.phone) dest.push('SMS ' + flow.phone);\n            appendAI('Destinatario: ' + dest.join(' + ') + '. Scrivi ora il testo da inviare. Scrivi NO per annullare.');\n            return true;\n        }\n        return sendFlow(flow);\n    }\n    function startFlow(text){\n        var flow = {stage:'start', channels:channelsFrom(text), email:'', phone:'', text:''};\n        window.__tiConfigCommFlow485 = flow;\n        appendAI('Ho capito che vuoi inviare una comunicazione. Procedo con i dati separati.');\n        return askNext(flow);\n    }\n    function cancelFlow(){\n        window.__tiConfigCommFlow485 = null;\n        appendAI('Invio annullato.');\n        return true;\n    }\n    function handleFlowInput(text){\n        var flow = window.__tiConfigCommFlow485;\n        if (!flow) return false;\n        var raw = clean(text);\n        if (\/^(no|annulla|annullare|x|stop|esci)$\/i.test(raw)) return cancelFlow();\n        if (flow.stage === 'ask_email') {\n            var email = extractEmail(raw);\n            if (!email || !validEmail(email)) { appendAI('Email non valida. Indica solo un indirizzo email valido oppure scrivi NO per annullare.'); return true; }\n            flow.email = email;\n            return askNext(flow);\n        }\n        if (flow.stage === 'ask_phone') {\n            var phone = normPhone(raw);\n            if (!validPhone(phone)) { appendAI('Numero telefonico non valido. Indica solo il numero per SMS, con prefisso internazionale se possibile, oppure scrivi NO per annullare.'); return true; }\n            flow.phone = phone;\n            return askNext(flow);\n        }\n        if (flow.stage === 'ask_text') {\n            if (raw.length < 2) { appendAI('Testo troppo breve. Scrivi il testo da inviare oppure NO per annullare.'); return true; }\n            flow.text = raw;\n            return askNext(flow);\n        }\n        return false;\n    }\n    function sendOne(flow, channel){\n        var data = {db:dbName(), subject:'Comunicazione Configurazione', history:flow.text, admin_copy:'0'};\n        if (channel === 'email') {\n            data.email = flow.email;\n            data.send_email_opt = '1';\n            data.send_sms_opt = '0';\n        } else {\n            data.email = flow.phone;\n            data.send_email_opt = '0';\n            data.send_sms_opt = '1';\n        }\n        return post('ti_ai_send_email', data).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) || (res && res.message) || 'Invio non riuscito.');\n            return res.data && res.data.reply ? String(res.data.reply) : 'Invio completato.';\n        });\n    }\n    function sendFlow(flow){\n        var btn = getBtn();\n        var old = btn ? btn.textContent : 'Invia';\n        if (btn) { btn.disabled = true; btn.textContent = 'Invio in corso...'; }\n        appendAI(flow.channels.indexOf('sms') !== -1 && flow.channels.length === 1 ? 'Invio SMS in corso...' : 'Invio comunicazione in corso...');\n        var tasks = [];\n        if (flow.channels.indexOf('email') !== -1 && flow.email) tasks.push(sendOne(flow, 'email').then(function(r){ return 'Email: ' + r; }));\n        if (flow.channels.indexOf('sms') !== -1 && flow.phone) tasks.push(sendOne(flow, 'sms').then(function(r){ return 'SMS: ' + r; }));\n        return Promise.all(tasks).then(function(results){\n            if (btn) { btn.disabled = false; btn.textContent = 'Invia'; }\n            window.__tiConfigCommFlow485 = null;\n            appendAI('Invio effettuato.\\n' + results.join('\\n'));\n        }).catch(function(err){\n            if (btn) { btn.disabled = false; btn.textContent = 'Invia'; }\n            appendAI('Invio non riuscito.\\n' + (err && err.message ? err.message : 'Errore sconosciuto') + '\\nControlla API Key Infobip, sender ServiceSMS, numero internazionale e connessione server verso Infobip.');\n        });\n    }\n    function install(){\n        ensureUi();\n        var btn = getBtn();\n        if (btn) btn.onclick = function(ev){ if (ev) ev.preventDefault(); return window.runConfigBot ? window.runConfigBot() : false; };\n        if (typeof window.runConfigBot !== 'function' || window.runConfigBot.__tiConfigSmsUnified485) return;\n        var prev = window.runConfigBot;\n        window.runConfigBot = function(){\n            ensureUi();\n            var box = getBox();\n            var text = latestUserText(box ? box.value : '');\n            if (window.__tiConfigCommFlow485) return handleFlowInput(text);\n            if (wantsSend(text)) return startFlow(text);\n            return prev.apply(this, arguments);\n        };\n        window.runConfigBot.__tiConfigSmsUnified485 = true;\n        if (btn) btn.onclick = function(ev){ if (ev) ev.preventDefault(); return window.runConfigBot(); };\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', install);\n    install(); setTimeout(install, 300); setTimeout(install, 1000); setTimeout(install, 2500);\n})();\n<\/script>\n\n\n<script id=\"ti-config-open-rescue-488\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigOpenRescue488Installed) return;\n    window.__tiConfigOpenRescue488Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function selectedDb(){\n        var sel = byId('ti-ditta');\n        var v = sel && sel.value ? String(sel.value).trim() : '';\n        if (!v && window.tiCurrentDb) v = String(window.tiCurrentDb).trim();\n        return v;\n    }\n    function openOverlay(){\n        var ov = byId('ti-conf-ov');\n        try {\n            if (typeof window.closeProgressPopup === 'function') window.closeProgressPopup();\n            if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(true, 'Configurazione', {notifyUser:false});\n        } catch(e) {}\n        try {\n            if (window.showPluginModal) window.showPluginModal(ov || 'ti-conf-ov');\n            else if (window.openModal) window.openModal('ti-conf-ov');\n            else if (ov) {\n                ov.style.setProperty('display','flex','important');\n                ov.style.setProperty('position','fixed','important');\n                ov.style.setProperty('inset','0','important');\n                ov.style.setProperty('z-index','2147483000','important');\n            }\n        } catch(e) {\n            if (ov) {\n                ov.style.setProperty('display','flex','important');\n                ov.style.setProperty('position','fixed','important');\n                ov.style.setProperty('inset','0','important');\n                ov.style.setProperty('z-index','2147483000','important');\n            }\n        }\n    }\n    function setMsg(html, type){\n        var cnt = byId('ti-conf-cnt');\n        if (!cnt) return;\n        var border = type === 'error' ? '#ef4444' : (type === 'warn' ? '#f59e0b' : '#22c55e');\n        var bg = type === 'error' ? '#450a0a' : (type === 'warn' ? '#422006' : '#052e16');\n        var color = type === 'error' ? '#fecaca' : (type === 'warn' ? '#fde68a' : '#bbf7d0');\n        cnt.innerHTML = '<div id=\"ti-config-rescue-488-msg\" style=\"margin:14px;padding:14px;border-radius:12px;border:1px solid '+border+';background:'+bg+';color:'+color+';font-size:14px;line-height:1.45;\">'+html+'<\/div>';\n        var retry = byId('ti-config-rescue-488-retry');\n        if (retry) retry.onclick = function(ev){ if (ev) ev.preventDefault(); window.__tiConfigOpeningPromise459 = null; window.openConfigSafe488(ev); return false; };\n        var close = byId('ti-config-rescue-488-close');\n        if (close) close.onclick = function(ev){ if (ev) ev.preventDefault(); try { if (window.closeModal) window.closeModal('ti-conf-ov'); } catch(e) {} return false; };\n    }\n    function actionButtons(){\n        return '<br><br><button type=\"button\" id=\"ti-config-rescue-488-retry\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;margin-right:8px;\">Riprova<\/button><button type=\"button\" id=\"ti-config-rescue-488-close\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\">Chiudi<\/button>';\n    }\n    function markDb(data, db){\n        try { if (data && typeof data === 'object') data.__db_name = db; } catch(e) {}\n        try { window.__tiCurrentDbDataDb = db; window.__tiConfigLoadedDb = db; } catch(e) {}\n    }\n    function cachedData(db){\n        try {\n            var d = window.currentDbData;\n            if (!d || !d.Tabelle) return null;\n            var known = String(d.__db_name || window.__tiCurrentDbDataDb || window.__tiConfigLoadedDb || '').trim();\n            if (known && known !== db) return null;\n            if (!known) markDb(d, db);\n            return d;\n        } catch(e) { return null; }\n    }\n    function renderData(data, db, label){\n        if (!data || !data.Tabelle) throw new Error('Database senza sezione Tabelle.');\n        window.currentDbData = data;\n        markDb(data, db);\n        try { window.configOriginalDbData = JSON.parse(JSON.stringify(data)); } catch(e) { window.configOriginalDbData = data; }\n        try { if (window.modifiedFields && window.modifiedFields.clear) window.modifiedFields.clear(); } catch(e) {}\n        try { window.tiConfigDeletedRowsManifest = []; } catch(e) {}\n        if (typeof window.renderConfig !== 'function') throw new Error('Funzione renderConfig non disponibile.');\n        openOverlay();\n        try { window.renderConfig(); }\n        catch(e) { throw new Error('Errore render Configurazione: ' + (e && e.message ? e.message : e)); }\n        var cnt = byId('ti-conf-cnt');\n        var html = cnt ? String(cnt.innerHTML || '') : '';\n        if (!cnt || !html.trim() || \/Caricamento configurazione in corso\/i.test(html)) {\n            throw new Error('Render Configurazione non completato: contenuto non aggiornato.');\n        }\n        try { if (typeof window.updateConfigSaveButtonState === 'function') window.updateConfigSaveButtonState(); } catch(e) {}\n        try { console.info('Shop & Service configurazione aperta rescue 488: ' + (label || '') + ' - ' + db); } catch(e) {}\n        return true;\n    }\n    function buildFd(action, db){\n        var fd;\n        if (typeof window.buildAjaxFormData === 'function') fd = window.buildAjaxFormData(action, {db:db, ti_config_open:'1', rescue:'488'});\n        else {\n            fd = new FormData();\n            fd.append('action', action);\n            fd.append('ti_action', action);\n            fd.append('db', db);\n            fd.append('ti_config_open','1');\n            fd.append('rescue','488');\n        }\n        try {\n            if (!fd.has('action')) fd.append('action', action);\n            if (!fd.has('ti_action')) fd.append('ti_action', action);\n        } catch(e) {}\n        return fd;\n    }\n    function fetchDb(db, timeoutMs){\n        var urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.ajaxurl && urls.indexOf(window.ajaxurl) === -1) urls.push(window.ajaxurl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            var controller = null, timer = null, done = false;\n            var opts = {method:'POST', body:buildFd('ti_ai_get_db_data', db), credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller = new AbortController(); opts.signal = controller.signal; } } catch(e) {}\n            return new Promise(function(resolve, reject){\n                timer = setTimeout(function(){\n                    if (done) return;\n                    done = true;\n                    try { if (controller) controller.abort(); } catch(e) {}\n                    reject(new Error('Timeout lettura database dopo ' + Math.round((timeoutMs || 18000)\/1000) + ' secondi.'));\n                }, timeoutMs || 18000);\n                fetch(urls[i], opts).then(function(r){\n                    return r.text().then(function(raw){\n                        if (!r.ok) throw new Error('HTTP ' + r.status + ': ' + String(raw || '').slice(0,220));\n                        try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta non JSON: ' + String(raw || '').slice(0,220)); }\n                    });\n                }).then(function(j){ if (done) return; done = true; resolve(j); }).catch(function(err){\n                    if (done) return;\n                    done = true;\n                    if (i + 1 < urls.length) attempt(i + 1).then(resolve).catch(reject);\n                    else reject(err);\n                }).finally(function(){ try { clearTimeout(timer); } catch(e) {} });\n            });\n        }\n        return attempt(0);\n    }\n\n    window.openConfigSafe488 = function(ev){\n        if (ev && ev.preventDefault) ev.preventDefault();\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') {\n            if (window.tiAlert) window.tiAlert('Seleziona prima una ditta valida per aprire la configurazione.');\n            else alert('Seleziona prima una ditta valida per aprire la configurazione.');\n            return false;\n        }\n        window.__tiConfigOpeningPromise459 = null;\n        openOverlay();\n        setMsg('<b>Caricamento configurazione in corso...<\/b><br><span style=\"font-size:12px;\">Apro subito eventuali dati gia disponibili e verifico il database.<\/span>', 'ok');\n\n        var cached = cachedData(db);\n        var cacheOk = false;\n        if (cached) {\n            try {\n                renderData(cached, db, 'cache immediata');\n                cacheOk = true;\n                setTimeout(function(){\n                    var cnt = byId('ti-conf-cnt');\n                    if (cnt) {\n                        var note = document.createElement('div');\n                        note.id = 'ti-config-rescue-488-note';\n                        note.style.cssText = 'position:sticky;top:0;z-index:6;margin:8px 8px 12px 8px;padding:9px 11px;border-radius:10px;border:1px solid #f59e0b;background:#422006;color:#fde68a;font-size:12px;line-height:1.35;';\n                        note.innerHTML = '<b>Configurazione aperta.<\/b> Verifica database in background.';\n                        cnt.insertBefore(note, cnt.firstChild || null);\n                        setTimeout(function(){ if (note && note.parentNode) note.parentNode.removeChild(note); }, 3500);\n                    }\n                }, 60);\n            } catch(cacheErr) {\n                cacheOk = false;\n                setMsg('<b>Caricamento configurazione in corso...<\/b><br>Dati in memoria non utilizzabili: rileggo il database.', 'warn');\n                try { console.warn('Shop & Service config cache render failed', cacheErr); } catch(e) {}\n            }\n        }\n\n        var stillTimer = setTimeout(function(){\n            try {\n                if (!cacheOk) setMsg('<b>Caricamento configurazione ancora in corso...<\/b><br>Il server non ha ancora risposto.' + actionButtons(), 'warn');\n            } catch(e) {}\n        }, 5500);\n\n        fetchDb(db, cacheOk ? 10000 : 18000).then(function(res){\n            clearTimeout(stillTimer);\n            if (!res || !res.success || !res.data) {\n                var msg = res && res.data && res.data.message ? res.data.message : (res && res.message ? res.message : 'Risposta database non valida.');\n                throw new Error(msg);\n            }\n            renderData(res.data, db, cacheOk ? 'refresh server' : 'server');\n            return true;\n        }).catch(function(err){\n            clearTimeout(stillTimer);\n            var m = err && err.message ? err.message : String(err || 'errore sconosciuto');\n            if (cacheOk) {\n                try {\n                    var cnt = byId('ti-conf-cnt');\n                    if (cnt) {\n                        var warn = document.createElement('div');\n                        warn.style.cssText = 'position:sticky;top:0;z-index:6;margin:8px 8px 12px 8px;padding:9px 11px;border-radius:10px;border:1px solid #ef4444;background:#450a0a;color:#fecaca;font-size:12px;line-height:1.35;';\n                        warn.innerHTML = '<b>Verifica database non completata.<\/b> Stai usando i dati gia disponibili.<br>' + esc(m);\n                        cnt.insertBefore(warn, cnt.firstChild || null);\n                    }\n                } catch(e) {}\n                return true;\n            }\n            openOverlay();\n            setMsg('<b>Configurazione non caricata.<\/b><br>' + esc(m) + actionButtons() + '<br><br><span style=\"font-size:12px;\">Il messaggio resta visibile per evitare che la finestra rimanga bloccata senza indicazioni.<\/span>', 'error');\n            try { console.error('Shop & Service CONFIGURA rescue 488 error', err); } catch(e) {}\n            return false;\n        });\n        return false;\n    };\n\n    function bind(){\n        var btn = byId('ti-conf-toggle');\n        if (!btn) return;\n        btn.onclick = window.openConfigSafe488;\n        btn.setAttribute('data-ti-config-open-rescue','488');\n    }\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var btn = t.closest('#ti-conf-toggle');\n        if (!btn) return;\n        try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        return window.openConfigSafe488(ev);\n    }, true);\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bind); else bind();\n    setTimeout(bind, 300); setTimeout(bind, 1200); setInterval(bind, 2500);\n})();\n<\/script>\n\n\n\n<script id=\"ti-config-open-rescue-489\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigOpenRescue489Installed) return;\n    window.__tiConfigOpenRescue489Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function selectedDb(){\n        var sel = byId('ti-ditta');\n        return sel && sel.value ? String(sel.value) : String(window.currentDb || window.tiCurrentDb || '');\n    }\n    function openOverlay(){\n        var ov = byId('ti-conf-ov');\n        if (!ov) return null;\n        try { if (window.preparePluginModal) window.preparePluginModal(ov); } catch(e) {}\n        try { if (window.showPluginModal) window.showPluginModal(ov); else if (window.openModal) window.openModal('ti-conf-ov'); } catch(e) {}\n        try {\n            ov.style.setProperty('display','flex','important');\n            ov.style.setProperty('visibility','visible','important');\n            ov.style.setProperty('opacity','1','important');\n            ov.style.setProperty('pointer-events','auto','important');\n            ov.style.setProperty('z-index','2147483000','important');\n            ov.removeAttribute('aria-hidden');\n        } catch(e) {}\n        return ov;\n    }\n    function buttonHtml(){\n        return '<br><br><button type=\"button\" id=\"ti-config-retry-489\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;margin-right:8px;\">Riprova<\/button><button type=\"button\" id=\"ti-config-close-489\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\">Chiudi<\/button>';\n    }\n    function setMessage(html, type){\n        openOverlay();\n        var cnt = byId('ti-conf-cnt');\n        if (!cnt) return;\n        var border = type === 'error' ? '#ef4444' : (type === 'warn' ? '#f59e0b' : '#22c55e');\n        var bg = type === 'error' ? '#450a0a' : (type === 'warn' ? '#422006' : '#052e16');\n        var color = type === 'error' ? '#fecaca' : (type === 'warn' ? '#fde68a' : '#bbf7d0');\n        cnt.innerHTML = '<div style=\"margin:14px;padding:14px;border-radius:12px;border:1px solid '+border+';background:'+bg+';color:'+color+';font-size:14px;line-height:1.45;\">'+html+'<\/div>';\n        bindLocalButtons();\n    }\n    function bindLocalButtons(){\n        var r = byId('ti-config-retry-489');\n        if (r) r.onclick = function(ev){ if (ev) ev.preventDefault(); window.openConfigSafe489(ev, true); return false; };\n        var c = byId('ti-config-close-489');\n        if (c) c.onclick = function(ev){ if (ev) ev.preventDefault(); try { if (window.closeModal) window.closeModal('ti-conf-ov'); else { var ov=byId('ti-conf-ov'); if(ov) ov.style.display='none'; } } catch(e) {} return false; };\n    }\n    function buildFd(db){\n        var fd;\n        try { if (window.buildAjaxFormData) fd = window.buildAjaxFormData('ti_ai_get_db_data', {db:db, ti_config_open:'1', rescue:'489'}); } catch(e) {}\n        if (!fd) {\n            fd = new FormData();\n            fd.append('action','ti_ai_get_db_data');\n            fd.append('ti_action','ti_ai_get_db_data');\n            fd.append('db', db);\n            fd.append('ti_config_open','1');\n            fd.append('rescue','489');\n        }\n        try { if (!fd.has('action')) fd.append('action','ti_ai_get_db_data'); if (!fd.has('ti_action')) fd.append('ti_action','ti_ai_get_db_data'); } catch(e) {}\n        return fd;\n    }\n    function fetchDb(db, timeoutMs){\n        var urls=[];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.ajaxurl && urls.indexOf(window.ajaxurl)<0) urls.push(window.ajaxurl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl)<0) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            var controller=null, timer=null, done=false;\n            var opts={method:'POST', body:buildFd(db), credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller=new AbortController(); opts.signal=controller.signal; } } catch(e) {}\n            return new Promise(function(resolve,reject){\n                timer=setTimeout(function(){ if(done) return; done=true; try{ if(controller) controller.abort(); }catch(e){} reject(new Error('Timeout lettura database da '+urls[i])); }, timeoutMs||18000);\n                fetch(urls[i], opts).then(function(r){ return r.text().then(function(raw){ if(!r.ok) throw new Error('HTTP '+r.status+' da '+urls[i]+': '+String(raw||'').slice(0,240)); try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta non JSON da '+urls[i]+': '+String(raw||'').slice(0,240)); } }); }).then(function(j){ if(done) return; done=true; resolve(j); }).catch(function(err){ if(done) return; done=true; if(i+1<urls.length) attempt(i+1).then(resolve).catch(reject); else reject(err); }).finally(function(){ try{clearTimeout(timer);}catch(e){} });\n            });\n        }\n        return attempt(0);\n    }\n    function prepareData(data, db){\n        if (!data || !data.Tabelle) throw new Error('Il database letto non contiene la sezione Tabelle.');\n        window.currentDbData = data;\n        try { data.__db_name = db; window.__tiCurrentDbDataDb = db; window.__tiConfigLoadedDb = db; } catch(e) {}\n        try { window.configOriginalDbData = JSON.parse(JSON.stringify(data)); } catch(e) { window.configOriginalDbData = data; }\n        try { window.configWasSaved = false; } catch(e) {}\n        try { window.tiConfigDeletedRowsManifest = []; } catch(e) {}\n        try { if (window.modifiedFields && window.modifiedFields.clear) window.modifiedFields.clear(); } catch(e) {}\n    }\n    function renderPreparedData(source){\n        if (typeof window.renderConfig !== 'function') throw new Error('Funzione renderConfig non disponibile. Probabile errore JavaScript precedente.');\n        openOverlay();\n        try { window.renderConfig(); } catch(e) { throw new Error('Errore durante renderConfig: '+(e && e.message ? e.message : e)); }\n        try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        var cnt = byId('ti-conf-cnt');\n        if (!cnt) throw new Error('Contenitore configurazione ti-conf-cnt non trovato dopo il render.');\n        if (!String(cnt.innerHTML || '').trim()) throw new Error('Render Configurazione vuoto.');\n        try { console.info('Shop & Service Configurazione aperta rescue 489: '+source); } catch(e) {}\n    }\n    function cacheIsUsable(db){\n        try {\n            var d = window.currentDbData;\n            if (!d || !d.Tabelle) return null;\n            var known = String(d.__db_name || window.__tiCurrentDbDataDb || window.__tiConfigLoadedDb || '').trim();\n            if (known && known !== db) return null;\n            return d;\n        } catch(e) { return null; }\n    }\n    window.openConfigSafe489 = function(ev, forceReload){\n        if (ev && ev.preventDefault) ev.preventDefault();\n        try { window.__tiConfigOpeningPromise459 = null; window.__tiConfigOpeningDb459 = ''; } catch(e) {}\n        var db = selectedDb();\n        if (!db || db === 'NEW_DB') { if (window.tiAlert) window.tiAlert('Seleziona prima una ditta valida.'); else alert('Seleziona prima una ditta valida.'); return false; }\n        openOverlay();\n        setMessage('<b>Caricamento configurazione in corso...<\/b><br><span style=\"font-size:12px;\">Lettura database e apertura form.<\/span>', 'ok');\n        var cached = !forceReload ? cacheIsUsable(db) : null;\n        if (cached) {\n            try { prepareData(cached, db); renderPreparedData('cache'); } catch(e) { try { console.warn('Shop & Service Config cache non utilizzabile', e); } catch(_) {} }\n        }\n        var slow=setTimeout(function(){ setMessage('<b>Caricamento configurazione ancora in corso...<\/b><br>Il server non ha ancora risposto. Puoi riprovare o chiudere.'+buttonHtml(), 'warn'); }, 6000);\n        fetchDb(db, 22000).then(function(res){\n            clearTimeout(slow);\n            if (!res || !res.success || !res.data) {\n                var msg = res && res.data && res.data.message ? res.data.message : (res && res.message ? res.message : 'Risposta server non valida.');\n                throw new Error(msg);\n            }\n            prepareData(res.data, db);\n            renderPreparedData('server');\n            return true;\n        }).catch(function(err){\n            clearTimeout(slow);\n            var msg = err && err.message ? err.message : String(err || 'errore sconosciuto');\n            if (cacheIsUsable(db)) {\n                try { renderPreparedData('cache dopo errore server'); } catch(e) {}\n                var cnt=byId('ti-conf-cnt');\n                if (cnt) {\n                    var note=document.createElement('div');\n                    note.style.cssText='position:sticky;top:0;z-index:10;margin:8px;padding:9px 11px;border:1px solid #ef4444;border-radius:10px;background:#450a0a;color:#fecaca;font-size:12px;line-height:1.35;';\n                    note.innerHTML='<b>Verifica server non completata.<\/b> Uso dati gia disponibili.<br>'+esc(msg);\n                    cnt.insertBefore(note,cnt.firstChild||null);\n                }\n                return false;\n            }\n            setMessage('<b>Configurazione non caricata.<\/b><br>'+esc(msg)+buttonHtml()+'<br><br><span style=\"font-size:12px;\">Dettaglio in console: Shop & Service CONFIGURA rescue 489 error.<\/span>', 'error');\n            try { console.error('Shop & Service CONFIGURA rescue 489 error', err); } catch(e) {}\n            return false;\n        });\n        return false;\n    };\n    window.openConfigSafe488 = window.openConfigSafe489;\n    window.openConfigSafe218 = window.openConfigSafe489;\n    function bind(){\n        var btn = byId('ti-conf-toggle');\n        if (btn) { btn.onclick = window.openConfigSafe489; btn.setAttribute('data-ti-config-open-rescue','489'); }\n    }\n    document.addEventListener('click', function(ev){\n        var t=ev && ev.target;\n        if (!t || !t.closest) return;\n        var btn=t.closest('#ti-conf-toggle, #ti-config-retry-489, #ti-config-rescue-488-retry');\n        if (!btn) return;\n        try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        return window.openConfigSafe489(ev, btn.id !== 'ti-conf-toggle');\n    }, true);\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bind); else bind();\n    setTimeout(bind,200); setTimeout(bind,1000); setInterval(bind,2500);\n})();\n<\/script>\n\n\n<script id=\"ti-config-open-rescue-490\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigOpenRescue490Installed) return;\n    window.__tiConfigOpenRescue490Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function selectedDb(){\n        var sel = byId('ti-ditta');\n        return sel && sel.value ? String(sel.value) : String(window.currentDb || window.tiCurrentDb || '');\n    }\n    function showOverlay(){\n        var ov = byId('ti-conf-ov');\n        if (!ov) return null;\n        try { if (window.preparePluginModal) window.preparePluginModal(ov); } catch(e) {}\n        try { if (window.showPluginModal) window.showPluginModal(ov); else if (window.openModal) window.openModal('ti-conf-ov'); } catch(e) {}\n        try {\n            ov.style.setProperty('display','flex','important');\n            ov.style.setProperty('visibility','visible','important');\n            ov.style.setProperty('opacity','1','important');\n            ov.style.setProperty('pointer-events','auto','important');\n            ov.style.setProperty('z-index','2147483000','important');\n            ov.removeAttribute('aria-hidden');\n        } catch(e) {}\n        return ov;\n    }\n    function retryButtons(){\n        return '<br><br><button type=\"button\" id=\"ti-config-retry-490\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;margin-right:8px;\">Riprova<\/button><button type=\"button\" id=\"ti-config-close-490\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\">Chiudi<\/button>';\n    }\n    function setMsg(html, type){\n        showOverlay();\n        var cnt = byId('ti-conf-cnt');\n        if (!cnt) return;\n        var border = type === 'error' ? '#ef4444' : (type === 'warn' ? '#f59e0b' : '#22c55e');\n        var bg = type === 'error' ? '#450a0a' : (type === 'warn' ? '#422006' : '#052e16');\n        var color = type === 'error' ? '#fecaca' : (type === 'warn' ? '#fde68a' : '#bbf7d0');\n        cnt.innerHTML = '<div style=\"margin:14px;padding:14px;border-radius:12px;border:1px solid '+border+';background:'+bg+';color:'+color+';font-size:14px;line-height:1.45;\">'+html+'<\/div>';\n        bindLocal();\n    }\n    function bindLocal(){\n        var r = byId('ti-config-retry-490');\n        if (r) r.onclick = function(ev){ if (ev) ev.preventDefault(); return window.openConfigSafe490(ev, true); };\n        var c = byId('ti-config-close-490');\n        if (c) c.onclick = function(ev){ if (ev) ev.preventDefault(); try { if (window.closeModal) window.closeModal('ti-conf-ov'); else { var ov=byId('ti-conf-ov'); if(ov) ov.style.display='none'; } } catch(e) {} return false; };\n    }\n    function makeFd(db){\n        var fd;\n        try { if (window.buildAjaxFormData) fd = window.buildAjaxFormData('ti_ai_get_db_data', {db:db, ti_config_open:'1', rescue:'490'}); } catch(e) {}\n        if (!fd) { fd = new FormData(); fd.append('action','ti_ai_get_db_data'); fd.append('ti_action','ti_ai_get_db_data'); fd.append('db',db); fd.append('ti_config_open','1'); fd.append('rescue','490'); }\n        try { if (!fd.has('action')) fd.append('action','ti_ai_get_db_data'); if (!fd.has('ti_action')) fd.append('ti_action','ti_ai_get_db_data'); } catch(e) {}\n        return fd;\n    }\n    function fetchDb(db, timeoutMs){\n        var urls=[];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.ajaxurl && urls.indexOf(window.ajaxurl)<0) urls.push(window.ajaxurl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl)<0) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            var controller=null, timer=null, done=false;\n            var opts={method:'POST',body:makeFd(db),credentials:'same-origin',cache:'no-store'};\n            try { if (window.AbortController) { controller=new AbortController(); opts.signal=controller.signal; } } catch(e) {}\n            return new Promise(function(resolve,reject){\n                timer=setTimeout(function(){ if(done) return; done=true; try{if(controller)controller.abort();}catch(e){} reject(new Error('Timeout lettura database da '+urls[i])); }, timeoutMs||22000);\n                fetch(urls[i],opts).then(function(r){ return r.text().then(function(raw){ if(!r.ok) throw new Error('HTTP '+r.status+' da '+urls[i]+': '+String(raw||'').slice(0,300)); try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta non JSON da '+urls[i]+': '+String(raw||'').slice(0,300)); } }); }).then(function(j){ if(done) return; done=true; resolve(j); }).catch(function(err){ if(done) return; done=true; if(i+1<urls.length) attempt(i+1).then(resolve).catch(reject); else reject(err); }).finally(function(){ try{clearTimeout(timer);}catch(e){} });\n            });\n        }\n        return attempt(0);\n    }\n    function cache(db){\n        try {\n            var d=window.currentDbData;\n            if(!d || !d.Tabelle) return null;\n            var known=String(d.__db_name || window.__tiCurrentDbDataDb || window.__tiConfigLoadedDb || '').trim();\n            if(known && known !== db) return null;\n            return d;\n        } catch(e) { return null; }\n    }\n    function prepare(data, db){\n        if(!data || !data.Tabelle) throw new Error('Il database letto non contiene la sezione Tabelle.');\n        window.currentDbData=data;\n        try { data.__db_name=db; window.__tiCurrentDbDataDb=db; window.__tiConfigLoadedDb=db; window.currentDb=db; window.tiCurrentDb=db; } catch(e) {}\n        try { window.configOriginalDbData=JSON.parse(JSON.stringify(data)); } catch(e) { window.configOriginalDbData=data; }\n        try { window.configWasSaved=false; } catch(e) {}\n        try { window.tiConfigDeletedRowsManifest=[]; } catch(e) {}\n        try { if(window.modifiedFields && window.modifiedFields.clear) window.modifiedFields.clear(); } catch(e) {}\n    }\n    function hasConfigContent(){\n        var cnt=byId('ti-conf-cnt');\n        if(!cnt) return false;\n        var html=String(cnt.innerHTML||'').trim();\n        if(!html) return false;\n        if(html.indexOf('Caricamento configurazione')>=0 || html.indexOf('Configurazione non caricata')>=0) return false;\n        return true;\n    }\n    function render(source){\n        if(typeof window.renderConfig !== 'function') throw new Error('Funzione renderConfig non disponibile. Probabile errore JavaScript precedente.');\n        showOverlay();\n        try { window.renderConfig(); } catch(e) { throw new Error('Errore durante renderConfig: '+(e && e.message ? e.message : e)); }\n        try { if(window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) { try { console.warn('Shop & Service updateConfigSaveButtonState warning', e); } catch(_) {} }\n        var cnt=byId('ti-conf-cnt');\n        if(!cnt) throw new Error('Contenitore configurazione ti-conf-cnt non trovato dopo il render.');\n        if(!String(cnt.innerHTML||'').trim()) throw new Error('Render Configurazione vuoto.');\n        try { console.info('Shop & Service Configurazione aperta rescue 490: '+source); } catch(e) {}\n        return true;\n    }\n    window.openConfigSafe490 = function(ev, forceReload){\n        if(ev && ev.preventDefault) ev.preventDefault();\n        var db=selectedDb();\n        if(!db || db==='NEW_DB') { if(window.tiAlert) window.tiAlert('Seleziona prima una ditta valida.'); else alert('Seleziona prima una ditta valida.'); return false; }\n        try { window.__tiConfigOpeningPromise459=null; window.__tiConfigOpeningDb459=''; } catch(e) {}\n        window.__tiConfigRenderedOk490=false;\n        showOverlay();\n        setMsg('<b>Caricamento configurazione in corso...<\/b><br><span style=\"font-size:12px;\">Lettura database e apertura form.<\/span>', 'ok');\n        var cached=!forceReload ? cache(db) : null;\n        if(cached) {\n            try { prepare(cached,db); window.__tiConfigRenderedOk490=render('cache'); } catch(e) { try { console.warn('Shop & Service Config cache non utilizzabile 490', e); } catch(_) {} }\n        }\n        var slow=setTimeout(function(){ if(window.__tiConfigRenderedOk490 || hasConfigContent()) return; setMsg('<b>Caricamento configurazione ancora in corso...<\/b><br>Il server non ha ancora risposto. Puoi riprovare o chiudere.'+retryButtons(), 'warn'); }, 7000);\n        fetchDb(db,26000).then(function(res){\n            clearTimeout(slow);\n            if(!res || !res.success || !res.data) {\n                var msg=res && res.data && res.data.message ? res.data.message : (res && res.message ? res.message : 'Risposta server non valida.');\n                throw new Error(msg);\n            }\n            prepare(res.data,db);\n            window.__tiConfigRenderedOk490=render('server');\n            return true;\n        }).catch(function(err){\n            clearTimeout(slow);\n            var msg=err && err.message ? err.message : String(err||'errore sconosciuto');\n            if(window.__tiConfigRenderedOk490 || hasConfigContent()) {\n                try { console.warn('Shop & Service CONFIGURA rescue 490 warning dopo render riuscito', err); } catch(e) {}\n                return false;\n            }\n            var c=cache(db);\n            if(c) {\n                try { prepare(c,db); window.__tiConfigRenderedOk490=render('cache dopo errore server'); return false; } catch(e) { msg += ' | Fallback cache non riuscito: '+(e && e.message ? e.message : e); }\n            }\n            setMsg('<b>Configurazione non caricata.<\/b><br>'+esc(msg)+retryButtons()+'<br><br><span style=\"font-size:12px;\">Apri la console per il dettaglio: Shop & Service CONFIGURA rescue 490 error.<\/span>', 'error');\n            try { console.error('Shop & Service CONFIGURA rescue 490 error', err); } catch(e) {}\n            return false;\n        });\n        return false;\n    };\n    window.openConfigSafe489=window.openConfigSafe490;\n    window.openConfigSafe488=window.openConfigSafe490;\n    window.openConfigSafe218=window.openConfigSafe490;\n    function bind(){\n        var btn=byId('ti-conf-toggle');\n        if(btn) { btn.onclick=window.openConfigSafe490; btn.setAttribute('data-ti-config-open-rescue','490'); }\n    }\n    document.addEventListener('click',function(ev){\n        var t=ev && ev.target;\n        if(!t || !t.closest) return;\n        var btn=t.closest('#ti-conf-toggle,#ti-config-retry-490,#ti-config-retry-489,#ti-config-rescue-488-retry');\n        if(!btn) return;\n        try { ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        return window.openConfigSafe490(ev, btn.id !== 'ti-conf-toggle');\n    },true);\n    if(document.readyState==='loading') document.addEventListener('DOMContentLoaded', bind); else bind();\n    setTimeout(bind,200); setTimeout(bind,1000); setInterval(bind,2500);\n})();\n<\/script>\n\n\n\n<script id=\"ti-config-open-cancel-safe-492\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigOpenCancelSafe492Installed) return;\n    window.__tiConfigOpenCancelSafe492Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(s){ return String(s == null ? '' : s).replace(\/[&<>\"']\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];}); }\n    function selectedDb(){ var s=byId('ti-ditta'); return s && s.value ? String(s.value) : String(window.currentDb || window.tiCurrentDb || ''); }\n    function modal(){ return byId('ti-conf-ov'); }\n    function content(){ return byId('ti-conf-cnt'); }\n    function newToken(){ var t='cfg492_'+Date.now()+'_'+Math.random().toString(36).slice(2,8); window.__tiConfigActiveToken492=t; window.__tiConfigCancelled492=false; return t; }\n    function isActive(t){ return !!t && window.__tiConfigActiveToken492===t && !window.__tiConfigCancelled492; }\n    function cancelOpening(){ window.__tiConfigCancelled492=true; window.__tiConfigActiveToken492=''; try{ window.__tiConfigOpeningPromise459=null; window.__tiConfigOpeningDb459=''; }catch(e){} }\n    function show(){\n        var ov=modal(); if(!ov) return null;\n        try { if (window.preparePluginModal) window.preparePluginModal(ov); } catch(e) {}\n        try { if (window.showPluginModal) window.showPluginModal(ov); else if (window.openModal) window.openModal('ti-conf-ov'); } catch(e) {}\n        try {\n            ov.style.setProperty('display','flex','important');\n            ov.style.setProperty('visibility','visible','important');\n            ov.style.setProperty('opacity','1','important');\n            ov.style.setProperty('pointer-events','auto','important');\n            ov.style.setProperty('z-index','2147483000','important');\n            ov.removeAttribute('aria-hidden');\n        } catch(e) {}\n        return ov;\n    }\n    function hide(){ try{ if(window.closeModal) window.closeModal('ti-conf-ov'); else { var o=modal(); if(o) o.style.display='none'; } }catch(e){ var o=modal(); if(o) o.style.display='none'; } }\n    function retryHtml(){ return '<br><br><button type=\"button\" id=\"ti-config-retry-492\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;margin-right:8px;\">Riprova<\/button><button type=\"button\" id=\"ti-config-close-492\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\">Chiudi<\/button>'; }\n    function bindRetry(){\n        var r=byId('ti-config-retry-492'); if(r) r.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation&&ev.stopPropagation();} return window.openConfigSafe492(ev,true); };\n        var c=byId('ti-config-close-492'); if(c) c.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation&&ev.stopPropagation();} cancelOpening(); hide(); return false; };\n    }\n    function msg(html,type,tok){\n        if(tok && !isActive(tok)) return;\n        show(); var c=content(); if(!c) return;\n        var border=type==='error'?'#ef4444':(type==='warn'?'#f59e0b':'#22c55e');\n        var bg=type==='error'?'#450a0a':(type==='warn'?'#422006':'#052e16');\n        var color=type==='error'?'#fecaca':(type==='warn'?'#fde68a':'#bbf7d0');\n        c.innerHTML='<div style=\"margin:14px;padding:14px;border-radius:12px;border:1px solid '+border+';background:'+bg+';color:'+color+';font-size:14px;line-height:1.45;\">'+html+'<\/div>';\n        bindRetry();\n    }\n    function makeFd(db){\n        var fd=null;\n        try { if(window.buildAjaxFormData) fd=window.buildAjaxFormData('ti_ai_get_db_data',{db:db,ti_config_open:'1',rescue:'492'}); } catch(e) {}\n        if(!fd){ fd=new FormData(); fd.append('action','ti_ai_get_db_data'); fd.append('ti_action','ti_ai_get_db_data'); fd.append('db',db); fd.append('ti_config_open','1'); fd.append('rescue','492'); }\n        try { if(!fd.has('action')) fd.append('action','ti_ai_get_db_data'); if(!fd.has('ti_action')) fd.append('ti_action','ti_ai_get_db_data'); } catch(e) {}\n        return fd;\n    }\n    function fetchDb(db,timeoutMs,tok){\n        var urls=[];\n        if(window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if(window.ajaxurl && urls.indexOf(window.ajaxurl)<0) urls.push(window.ajaxurl);\n        if(window.tiUrl && urls.indexOf(window.tiUrl)<0) urls.push(window.tiUrl);\n        if(!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            if(!isActive(tok)) return Promise.reject(new Error('Apertura configurazione annullata.'));\n            var ctrl=null,timer=null,done=false;\n            var opts={method:'POST',body:makeFd(db),credentials:'same-origin',cache:'no-store'};\n            try{ if(window.AbortController){ ctrl=new AbortController(); opts.signal=ctrl.signal; } }catch(e){}\n            try{ window.__tiConfigAbort492=ctrl; }catch(e){}\n            return new Promise(function(resolve,reject){\n                timer=setTimeout(function(){ if(done) return; done=true; try{if(ctrl)ctrl.abort();}catch(e){} reject(new Error('Timeout lettura database da '+urls[i])); }, timeoutMs||26000);\n                fetch(urls[i],opts).then(function(r){return r.text().then(function(raw){ if(!r.ok) throw new Error('HTTP '+r.status+' da '+urls[i]+': '+String(raw||'').slice(0,300)); try{return JSON.parse(raw);}catch(e){throw new Error('Risposta non JSON da '+urls[i]+': '+String(raw||'').slice(0,300));} });}).then(function(j){ if(done)return; done=true; if(!isActive(tok)) reject(new Error('Apertura configurazione annullata.')); else resolve(j); }).catch(function(err){ if(done)return; done=true; if(!isActive(tok)){ reject(new Error('Apertura configurazione annullata.')); return; } if(i+1<urls.length) attempt(i+1).then(resolve).catch(reject); else reject(err); }).finally(function(){try{clearTimeout(timer);}catch(e){}});\n            });\n        }\n        return attempt(0);\n    }\n    function cache(db){\n        try{ var d=window.currentDbData; if(!d||!d.Tabelle)return null; var known=String(d.__db_name||window.__tiCurrentDbDataDb||window.__tiConfigLoadedDb||'').trim(); if(known&&known!==db)return null; return d; }catch(e){return null;}\n    }\n    function prepare(data,db){\n        if(!data||!data.Tabelle) throw new Error('Il database letto non contiene la sezione Tabelle.');\n        window.currentDbData=data;\n        try{ data.__db_name=db; window.__tiCurrentDbDataDb=db; window.__tiConfigLoadedDb=db; window.currentDb=db; window.tiCurrentDb=db; }catch(e){}\n        try{ window.configOriginalDbData=JSON.parse(JSON.stringify(data)); }catch(e){ window.configOriginalDbData=data; }\n        try{ window.configWasSaved=false; window.tiConfigDeletedRowsManifest=[]; }catch(e){}\n        try{ if(window.modifiedFields&&window.modifiedFields.clear) window.modifiedFields.clear(); }catch(e){}\n    }\n    function goodContent(){ var c=content(); if(!c)return false; var h=String(c.innerHTML||'').trim(); return !!(h && h.indexOf('Caricamento configurazione')<0 && h.indexOf('Configurazione non caricata')<0); }\n    function render(source,tok){\n        if(tok && !isActive(tok)) return false;\n        if(typeof window.renderConfig!=='function') throw new Error('Funzione renderConfig non disponibile. Probabile errore JavaScript precedente.');\n        show();\n        try{ window.renderConfig(); }catch(e){ throw new Error('Errore durante renderConfig: '+(e&&e.message?e.message:e)); }\n        if(tok && !isActive(tok)) return false;\n        var c=content(); if(!c) throw new Error('Contenitore configurazione ti-conf-cnt non trovato dopo il render.');\n        if(!String(c.innerHTML||'').trim()) throw new Error('Render Configurazione vuoto.');\n        window.__tiConfigRenderedOk492=true;\n        window.__tiConfigLastGoodHtml492=String(c.innerHTML||'');\n        window.__tiConfigLastGoodTime492=Date.now();\n        try{ if(window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); }catch(e){ try{console.warn('Shop & Service updateConfigSaveButtonState warning 492',e);}catch(_){} }\n        try{ console.info('Shop & Service Configurazione aperta rescue 492: '+source); }catch(e){}\n        return true;\n    }\n    function protectAfterRender(){\n        var c=content(); if(!c || !window.__tiConfigLastGoodHtml492) return;\n        var h=String(c.innerHTML||'');\n        if(h.indexOf('Caricamento configurazione')>=0 || h.indexOf('Configurazione non caricata')>=0){ c.innerHTML=window.__tiConfigLastGoodHtml492; try{ console.warn('Shop & Service Config 492: ripristinato contenuto dopo sovrascrittura legacy.'); }catch(e){} }\n    }\n    window.openConfigSafe492=function(ev,forceReload){\n        if(ev&&ev.preventDefault) ev.preventDefault();\n        try{ if(ev&&ev.stopPropagation) ev.stopPropagation(); if(ev&&ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }catch(e){}\n        var db=selectedDb();\n        if(!db||db==='NEW_DB'){ if(window.tiAlert) window.tiAlert('Seleziona prima una ditta valida.'); else alert('Seleziona prima una ditta valida.'); return false; }\n        try{ if(window.__tiConfigAbort492) window.__tiConfigAbort492.abort(); }catch(e){}\n        try{ window.__tiConfigOpeningPromise459=null; window.__tiConfigOpeningDb459=''; }catch(e){}\n        var tok=newToken();\n        window.__tiConfigRenderedOk492=false;\n        show();\n        var cached=!forceReload?cache(db):null;\n        if(cached){ try{ prepare(cached,db); render('cache primo click',tok); setTimeout(protectAfterRender,150); setTimeout(protectAfterRender,900); }catch(e){ try{console.warn('Shop & Service cache config non utilizzabile 492',e);}catch(_){} } }\n        if(!goodContent()) msg('<b>Caricamento configurazione in corso...<\/b><br><span style=\"font-size:12px;\">Lettura database e apertura form.<\/span>','ok',tok);\n        var slow=setTimeout(function(){ if(!isActive(tok)||window.__tiConfigRenderedOk492||goodContent()) return; msg('<b>Caricamento configurazione ancora in corso...<\/b><br>Il server non ha ancora risposto. Puoi riprovare o chiudere.'+retryHtml(),'warn',tok); },7000);\n        fetchDb(db,28000,tok).then(function(res){\n            clearTimeout(slow); if(!isActive(tok)) return false;\n            if(!res||!res.success||!res.data){ var m=res&&res.data&&res.data.message?res.data.message:(res&&res.message?res.message:'Risposta server non valida.'); throw new Error(m); }\n            prepare(res.data,db); render('server primo click',tok); setTimeout(protectAfterRender,150); setTimeout(protectAfterRender,900); setTimeout(protectAfterRender,2200); return true;\n        }).catch(function(err){\n            clearTimeout(slow); if(!isActive(tok)) { try{ console.info('Shop & Service CONFIGURA 492 richiesta ignorata dopo chiusura\/nuovo tentativo.'); }catch(e){} return false; }\n            var m=err&&err.message?err.message:String(err||'errore sconosciuto');\n            if(window.__tiConfigRenderedOk492||goodContent()){ try{console.warn('Shop & Service CONFIGURA rescue 492 warning dopo render riuscito',err);}catch(e){} protectAfterRender(); return false; }\n            var c=cache(db); if(c){ try{ prepare(c,db); render('cache dopo errore server',tok); return false; }catch(e){ m+=' | Fallback cache non riuscito: '+(e&&e.message?e.message:e); } }\n            msg('<b>Configurazione non caricata.<\/b><br>'+esc(m)+retryHtml()+'<br><br><span style=\"font-size:12px;\">Apri la console per il dettaglio: Shop & Service CONFIGURA rescue 492 error.<\/span>','error',tok);\n            try{ console.error('Shop & Service CONFIGURA rescue 492 error',err); }catch(e){}\n            return false;\n        });\n        return false;\n    };\n    window.openConfigSafe491=window.openConfigSafe492;\n    window.openConfigSafe490=window.openConfigSafe492;\n    window.openConfigSafe489=window.openConfigSafe492;\n    window.openConfigSafe488=window.openConfigSafe492;\n    window.openConfigSafe218=window.openConfigSafe492;\n    var prevClose=window.closeModal;\n    if(typeof prevClose==='function' && !prevClose.__tiConfigCancel492){ window.closeModal=function(id){ if(id==='ti-conf-ov'){ cancelOpening(); try{ if(window.__tiConfigAbort492) window.__tiConfigAbort492.abort(); }catch(e){} } return prevClose.apply(this,arguments); }; window.closeModal.__tiConfigCancel492=true; }\n    function bind(){ var b=byId('ti-conf-toggle'); if(b){ b.onclick=window.openConfigSafe492; b.setAttribute('data-ti-config-open-rescue','492'); } }\n    document.addEventListener('click',function(ev){\n        var t=ev&&ev.target; if(!t||!t.closest)return;\n        var close=t.closest('#ti-config-close-492,#ti-config-close-491,#ti-config-close-490,#ti-config-close-489'); if(close){ try{ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation)ev.stopImmediatePropagation(); }catch(e){} cancelOpening(); hide(); return false; }\n        var b=t.closest('#ti-conf-toggle,#ti-config-retry-492,#ti-config-retry-491,#ti-config-retry-490,#ti-config-retry-489,#ti-config-rescue-488-retry'); if(!b)return;\n        try{ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation)ev.stopImmediatePropagation(); }catch(e){}\n        return window.openConfigSafe492(ev,b.id!=='ti-conf-toggle');\n    },true);\n    if(document.readyState==='loading') document.addEventListener('DOMContentLoaded',bind); else bind();\n    setTimeout(bind,0); setTimeout(bind,200); setTimeout(bind,1000); setInterval(bind,2000);\n})();\n<\/script>\n\n\n\n<script id=\"ti-config-ai-focus-end-493\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigAiFocusEnd493Installed) return;\n    window.__tiConfigAiFocusEnd493Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function box(){ return byId('ti-conf-ai-prompt'); }\n    function visible(el){\n        if (!el) return false;\n        try {\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return false;\n            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n        } catch(e) { return true; }\n    }\n    function isConfigTableEditorActive(){\n        try {\n            var a = document.activeElement;\n            return !!(a && a !== document.body && a !== document.documentElement && a.matches && a.matches('#ti-conf-ov .ti-cfg-table input, #ti-conf-ov .ti-cfg-table textarea, #ti-conf-ov .ti-cfg-table select, #ti-conf-ov .ti-cfg-filter, .ti-conf-window .ti-cfg-table input, .ti-conf-window .ti-cfg-table textarea, .ti-conf-window .ti-cfg-table select, .ti-conf-window .ti-cfg-filter'));\n        } catch(e) { return false; }\n    }\n    function isUserEditing1598(){\n        var p = box();\n        if (!p || document.activeElement !== p) return false;\n        return p.getAttribute('data-ti-user-editing-1598') === '1';\n    }\n    function markUserEditing1598(on){\n        var p = box();\n        if (!p) return;\n        try {\n            if (on) p.setAttribute('data-ti-user-editing-1598','1');\n            else p.removeAttribute('data-ti-user-editing-1598');\n        } catch(e) {}\n    }\n    function placeEnd(focusMode, forceAuto){\n        if (isConfigTableEditorActive()) return false;\n        var p = box();\n        if (!p || !visible(p)) return false;\n        \/\/ 30.9.1598: MAI spostare il cursore mentre l utente sta modificando manualmente il testo.\n        if (!forceAuto && isUserEditing1598()) return false;\n        try {\n            if (focusMode !== false && document.activeElement !== p && !isConfigTableEditorActive()) p.focus({preventScroll:true});\n            var len = String(p.value || '').length;\n            p.selectionStart = len;\n            p.selectionEnd = len;\n            p.scrollTop = p.scrollHeight;\n            if (forceAuto) markUserEditing1598(false);\n        } catch(e) {}\n        return true;\n    }\n    window.tiConfigAiFocusEnd493 = function(focusMode){ return placeEnd(focusMode, false); };\n    window.tiConfigAiFocusEndAfterAuto1598 = function(focusMode){ return placeEnd(focusMode, true); };\n\n    function scheduleAfterAuto1598(focusMode){\n        [0,60,220].forEach(function(ms){\n            setTimeout(function(){ if (!isConfigTableEditorActive()) placeEnd(focusMode, true); }, ms);\n        });\n    }\n    function installTextareaHandlers(){\n        var p = box();\n        if (!p || p.__tiFreeEdit1598) return;\n        p.__tiFreeEdit1598 = true;\n        \/\/ Questi eventi indicano esplicitamente modifica manuale: non alterare selectionStart\/selectionEnd.\n        ['pointerdown','mousedown','touchstart','focus','click','mouseup','keydown','keyup','beforeinput','input','select'].forEach(function(evName){\n            p.addEventListener(evName, function(){ markUserEditing1598(true); }, true);\n        });\n        p.addEventListener('blur', function(){ markUserEditing1598(false); }, true);\n    }\n    function wrapAuto(name){\n        var fn = window[name];\n        if (typeof fn !== 'function' || fn.__tiFocusEnd1598) return;\n        window[name] = function(){\n            var ret = fn.apply(this, arguments);\n            scheduleAfterAuto1598(true);\n            return ret;\n        };\n        window[name].__tiFocusEnd1598 = true;\n    }\n    function boot(){\n        installTextareaHandlers();\n        \/\/ Solo gli aggiornamenti automatici della risposta\/chat possono portare il cursore alla fine.\n        wrapAuto('setConfigAiReplyHtml');\n        wrapAuto('tiAppendConfigAiToUnifiedChat483');\n        wrapAuto('tiAppendConfigAiToUnifiedChat482');\n    }\n    \/\/ Quando si preme Invia termina la fase di modifica manuale; nessuna modifica del testo viene eseguita qui.\n    document.addEventListener('pointerdown', function(ev){\n        var t = ev && ev.target;\n        if (t && t.closest && t.closest('#ti-conf-ai-send')) markUserEditing1598(false);\n    }, true);\n    document.addEventListener('keydown', function(ev){\n        if (!ev || ev.key !== 'Enter' || ev.shiftKey) return;\n        if (ev.target && ev.target.id === 'ti-conf-ai-prompt') markUserEditing1598(false);\n    }, true);\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); else boot();\n    setTimeout(boot, 300);\n    setTimeout(boot, 1000);\n    \/\/ 30.9.1598: eliminato intenzionalmente il setInterval 900ms che forzava il cursore in fondo.\n})();\n<\/script>\n\n\n\n<script id=\"ti-global-action-unblock-494\">\n(function(){\n    \"use strict\";\n    if (window.__tiGlobalActionUnblock494Installed) return;\n    window.__tiGlobalActionUnblock494Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function setImp(el, prop, val){ try { if (el && el.style) el.style.setProperty(prop, String(val), 'important'); } catch(e) {} }\n    function isVisible(el){\n        if (!el) return false;\n        try {\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')) return false;\n            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n        } catch(e) { return false; }\n    }\n    function closeLoaderHard(){\n        try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'Operazione completata', {notifyUser:false}); } catch(e) {}\n        try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n        try {\n            var ov = byId('ti-ai-loader-ov');\n            if (ov) {\n                setImp(ov, 'display', 'none');\n                setImp(ov, 'visibility', 'hidden');\n                setImp(ov, 'opacity', '0');\n                setImp(ov, 'pointer-events', 'none');\n                ov.setAttribute('aria-hidden', 'true');\n            }\n        } catch(e) {}\n        try {\n            var root = byId('ti-ai-outer');\n            if (root) {\n                ['ti-mainform-blocked-494','ti-mainform-blocked-469','ti-mainform-blocked-464','ti-mainform-blocked-463'].forEach(function(c){ try { root.classList.remove(c); } catch(e) {} });\n                root.setAttribute('aria-busy', 'false');\n            }\n        } catch(e) {}\n    }\n    function resetGlobalUi(success, text){\n        var btn = byId('global-action-btn');\n        if (btn) {\n            btn.disabled = false;\n            btn.innerText = 'Esegui Modifica su Tutti i DB';\n            setImp(btn, 'pointer-events', 'auto');\n            setImp(btn, 'opacity', '1');\n        }\n        try { if (window.finishGlobalActionProgress) window.finishGlobalActionProgress(success !== false, text || (success === false ? 'Operazione interrotta' : 'Operazione completata')); } catch(e) {}\n        closeLoaderHard();\n        try { if (window.updatePluginScrollLock) window.updatePluginScrollLock(); } catch(e) {}\n    }\n    function showResult(html, color){\n        var res = byId('global-action-res');\n        if (!res) return;\n        res.style.display = 'block';\n        if (color) res.style.color = color;\n        res.innerHTML = html;\n        try { res.scrollTop = res.scrollHeight; } catch(e) {}\n    }\n    function buildFd(prompt, previewToken, definitiveConfirm, tableScope){\n        var fd = new FormData();\n        fd.append('action', 'ti_ai_global_action');\n        fd.append('ti_action', 'ti_ai_global_action');\n        fd.append('prompt', prompt || '');\n        fd.append('global_confirm', '1');\n        if (previewToken) fd.append('global_template_preview_token', previewToken);\n        if (definitiveConfirm) fd.append('global_template_confirm', '1');\n        if (tableScope) fd.append('global_table_scope', tableScope);\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        return fd;\n    }\n    function postJson(url, fd, timeoutMs){\n        return new Promise(function(resolve, reject){\n            var done = false;\n            var controller = null;\n            var timer = null;\n            var opts = {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'};\n            try { if (window.AbortController) { controller = new AbortController(); opts.signal = controller.signal; } } catch(e) {}\n            timer = setTimeout(function(){\n                if (done) return;\n                done = true;\n                try { if (controller) controller.abort(); } catch(e) {}\n                reject(new Error('Timeout: il server non ha restituito la risposta finale. Verifica log\/risultato e riprova solo se necessario.'));\n            }, timeoutMs || 900000);\n            var fetchUrl1321 = url || window.tiUrl || window.location.href;\n            var t0_1321 = performance.now();\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1321: Modifica Globale - fetch AVVIATA verso: ' + fetchUrl1321); } catch(eL321a){}\n            fetch(fetchUrl1321, opts).then(function(r){\n                try { if (window.log1088) window.log1088('DIAGNOSTICA 1321: risposta ricevuta dopo ' + Math.round(performance.now()-t0_1321) + 'ms, status=' + r.status); } catch(eL321b){}\n                return r.text().then(function(raw){\n                    if (!r.ok) throw new Error('HTTP ' + r.status + ': ' + String(raw || '').slice(0, 300));\n                    try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non JSON: ' + String(raw || '').slice(0, 300)); }\n                });\n            }).then(function(d){ if (done) return; done = true; resolve(d); }).catch(function(err){ if (done) return; done = true; try { if (window.log1088) window.log1088('DIAGNOSTICA 1321: FALLITA dopo ' + Math.round(performance.now()-t0_1321) + 'ms - nome=' + (err && err.name) + ' messaggio=' + (err && err.message) + ' url=' + fetchUrl1321); } catch(eL321c){} reject(err); }).finally(function(){ try { clearTimeout(timer); } catch(e) {} });\n        });\n    }\n    function openConfirm(html, onYes, onNo){\n        if (typeof window.tiConfirmYesNoAction === 'function') {\n            window.tiConfirmYesNoAction(html, onYes, function(){ resetGlobalUi(false, 'Operazione annullata'); if (onNo) onNo(); }, 'APPROVA MODIFICA DEFINITIVA', 'ANNULLA');\n        } else if (window.confirm(String(html || '').replace(\/<[^>]+>\/g, ' '))) {\n            onYes();\n        } else {\n            resetGlobalUi(false, 'Operazione annullata');\n            if (onNo) onNo();\n        }\n    }\n    function startProgress(definitiveConfirm){\n        \/\/ 30.9.1325: segnala al controllo di sessione che e' in corso un processo lungo (Modifica Globale),\n        \/\/ cosi' non viene interrotto da un ricaricamento automatico durante l'attesa di risposta del server -\n        \/\/ stessa protezione gia' applicata in precedenza per l'attivazione della fotocamera.\n        window.__tiLongProcessActive1279 = true;\n        var btn = byId('global-action-btn');\n        if (btn) {\n            btn.disabled = true;\n            btn.innerText = definitiveConfirm ? 'Esecuzione definitiva in corso...' : 'Generazione preview...';\n        }\n        showResult(definitiveConfirm ? 'Esecuzione definitiva in corso. Attendi la risposta finale: la UI verr\u00e0 sbloccata automaticamente.' : 'Genero una preview. Nessun database reale viene modificato in questa fase.', '#cbd5e1');\n        try { if (window.startGlobalActionProgress) window.startGlobalActionProgress(definitiveConfirm ? 'Avvio modifica globale definitiva...' : 'Generazione preview obbligatoria...'); } catch(e) {}\n        \/\/ La modifica globale usa la propria barra interna; non deve ereditare loader o AbortController di altri processi.\n        try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n    }\n    function processResponse(prompt, d, previewToken, definitiveConfirm, tableScope){\n        if (!d || !d.success) {\n            var msg = (d && d.data && (d.data.message || d.data.error)) ? (d.data.message || d.data.error) : 'Errore modifica globale.';\n            resetGlobalUi(false, 'Errore modifica globale');\n            showResult(\"<span style='color:#ef4444;'>Errore: \" + esc(msg) + '<\/span>', '#ef4444');\n            return;\n        }\n        var data = d.data || {};\n        if (data.requires_table_scope) {\n            resetGlobalUi(false, 'Ambito tabelle richiesto');\n            showResult(esc(data.reply || 'Indica le tabelle prima di eseguire la modifica globale.').replace(\/\\n\/g,'<br>'), '#fbbf24');\n            var answer = window.prompt(data.scope_prompt || 'Scrivi TUTTE oppure elenca le tabelle separate da virgola:', '');\n            if (answer && String(answer).trim()) {\n                setTimeout(function(){ window.doGlobalActionConfirmed(prompt, previewToken, definitiveConfirm, String(answer).trim()); }, 50);\n            } else {\n                showResult(\"<span style='color:#f59e0b;'>Operazione sospesa. Nessun database \u00e8 stato modificato.<\/span>\", '#f59e0b');\n            }\n            return;\n        }\n        if (data.requires_template_preview) {\n            resetGlobalUi(false, 'Preview generata. In attesa di approvazione');\n            var token = data.preview_token || '';\n            showResult(esc(data.reply || 'Preview generata. Nessun database modificato.').replace(\/\\n\/g,'<br>'), '#fbbf24');\n            openConfirm(data.preview_html || 'Preview generata. Confermi la modifica definitiva?', function(){\n                \/\/ 30.9.1332: chiamata diretta e immediata (rimosso il setTimeout di 80ms che non arrivava mai a\n                \/\/ scattare dopo la chiusura del popup di conferma - causa isolata tramite diagnostica alert()).\n                window.doGlobalActionConfirmed494(prompt, token, true, tableScope);\n            }, function(){\n                window.__tiLongProcessActive1279 = false;\n                showResult(\"<span style='color:#f59e0b;'>Operazione annullata. Nessun database \u00e8 stato modificato.<\/span>\", '#f59e0b');\n            });\n            return;\n        }\n        var s = data.stats || {};\n        var finalMsg = 'Operazione globale completata';\n        if (s && (typeof s.db_modified !== 'undefined' || typeof s.tables_touched !== 'undefined' || typeof s.fields_touched !== 'undefined')) {\n            finalMsg = 'Completato: DB ' + (s.db_modified || 0) + ', tabelle ' + (s.tables_touched || 0) + ', campi ' + (s.fields_touched || 0);\n        }\n        \/\/ 30.9.1327: dopo una sincronizzazione template completata con successo, svuota la cache locale\n        \/\/ (localStorage) di TUTTE le ditte - senza questo, aprendo Configurazione su una ditta gia' aggiornata\n        \/\/ si rischia di vedere ancora la struttura precedente al sync, mancante dei campi appena aggiunti.\n        try {\n            var keysToRemove1327 = [];\n            for (var i1327 = 0; i1327 < localStorage.length; i1327++) {\n                var k1327 = localStorage.key(i1327);\n                if (k1327 && (k1327.indexOf('ti_config_cache_507_') === 0 || k1327.indexOf('ti_config_cache_509_') === 0)) keysToRemove1327.push(k1327);\n            }\n            keysToRemove1327.forEach(function(k){ try { localStorage.removeItem(k); } catch(e){} });\n            window.currentDbData = null;\n            try { if (window.log1088) window.log1088('DIAGNOSTICA 1327: cache locale Configurazione svuotata dopo sync template (' + keysToRemove1327.length + ' voci rimosse)'); } catch(eL327){}\n        } catch(e1327) {}\n        window.__tiLongProcessActive1279 = false;\n        resetGlobalUi(true, finalMsg);\n        try { if (window.tiAlert) window.tiAlert('\u2705 Operazione Globale Completata\\n\\n' + finalMsg); else alert('\u2705 Operazione Globale Completata\\n\\n' + finalMsg); } catch(e1330) {}\n        var reply = data.reply || finalMsg;\n        showResult('<pre style=\"white-space:pre-wrap;margin:0;color:#10b981;\">' + esc(reply) + '<\/pre>', '#10b981');\n        try { console.info('Shop & Service Modifica Globale completata 494', data); } catch(e) {}\n    }\n    window.doGlobalActionConfirmed494 = function(prompt, previewToken, definitiveConfirm, tableScope){\n        prompt = String(prompt || '').trim();\n        if (!prompt) { if (window.tiAlert) window.tiAlert('Inserisci l operazione che vuoi eseguire.'); return false; }\n        startProgress(!!definitiveConfirm);\n        var fd = buildFd(prompt, previewToken, definitiveConfirm, tableScope);\n        postJson(window.tiUrl || window.location.href, fd, definitiveConfirm ? 900000 : 240000).then(function(d){\n            processResponse(prompt, d, previewToken, definitiveConfirm, tableScope);\n        }).catch(function(err){\n            window.__tiLongProcessActive1279 = false;\n            resetGlobalUi(false, 'Errore o timeout modifica globale');\n            showResult(\"<span style='color:#ef4444;'>Operazione non conclusa correttamente lato interfaccia: \" + esc(err && err.message ? err.message : 'errore sconosciuto') + \"<\/span><br><br><span style='color:#fbbf24;'>Se il server ha gi\u00e0 applicato modifiche, riapri la Configurazione o controlla i database prima di ripetere il comando.<\/span>\", '#ef4444');\n            try { console.error('Shop & Service Modifica Globale 494 error', err); } catch(e) {}\n        });\n        return false;\n    };\n    if (typeof window.doGlobalActionConfirmed === 'function' && !window.doGlobalActionConfirmed.__tiUnblock494) {\n        window.doGlobalActionConfirmed = window.doGlobalActionConfirmed494;\n        window.doGlobalActionConfirmed.__tiUnblock494 = true;\n    }\n    var prevDoGlobal494 = window.doGlobalAction;\n    window.doGlobalAction = function(){\n        var promptEl = byId('global-action-prompt');\n        var prompt = promptEl ? String(promptEl.value || '').trim() : '';\n        if (!prompt) { if (window.tiAlert) window.tiAlert('Inserisci l operazione che vuoi eseguire.'); return false; }\n        var warning = '<b>Attenzione: modifica globale database<\/b><br><br>'\n            + 'Questa operazione pu\u00f2 modificare pi\u00f9 database delle ditte in una sola volta.<br>'\n            + 'Il template standard <b>shopservicemain.json<\/b> resta sempre escluso dalle modifiche.<br><br>'\n            + 'Verr\u00e0 comunque proposta una preview e richiesta una successiva conferma definitiva.<br><br>'\n            + '<b>Operazione richiesta:<\/b><br><span style=\"color:#fbbf24;white-space:pre-wrap;display:block;margin-top:6px;\">' + esc(prompt) + '<\/span><br>'\n            + 'Confermi di voler procedere?';\n        if (typeof window.tiConfirmYesNoAction === 'function') {\n            window.tiConfirmYesNoAction(warning, function(){ window.doGlobalActionConfirmed494(prompt); }, null, 'CONFERMA MODIFICA', 'ANNULLA');\n        } else if (window.confirm(String(warning).replace(\/<[^>]+>\/g, ' '))) {\n            window.doGlobalActionConfirmed494(prompt);\n        }\n        return false;\n    };\n    window.doGlobalAction.__tiUnblock494 = true;\n    function fixGlobalButton(){\n        var b = byId('global-action-btn');\n        if (b) b.onclick = function(ev){ if (ev) ev.preventDefault(); return window.doGlobalAction(); };\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fixGlobalButton);\n    setTimeout(fixGlobalButton, 0); setTimeout(fixGlobalButton, 500); setTimeout(fixGlobalButton, 1500);\n})();\n<\/script>\n\n\n<script id=\"ti-audio-auto-presence-497\">\n(function(){\n    \"use strict\";\n    if (window.__tiAudioAutoPresence497Installed) return;\n    window.__tiAudioAutoPresence497Installed = true;\n\n    var AUTO_STATE = 3;\n    var scanTimer = null;\n    var prevFrame = null;\n    var lastPresenceTs = 0;\n    var lastGreetTs = 0;\n    var motionHits = 0;\n    var canvas = null;\n    var ctx = null;\n\n    function byId(id){ return document.getElementById(id); }\n    function now(){ return Date.now ? Date.now() : (new Date()).getTime(); }\n    function isAuto(){ return parseInt(window.muteState, 10) === AUTO_STATE; }\n    function canPersistAudio(){\n        try { return !!(window.tiAudioPersistentAllowed716 && window.tiAudioPersistentAllowed716()); }\n        catch(e) { return false; }\n    }\n    function ensureAudioKey(){\n        try { return window.tiAudioStorageKey716 ? window.tiAudioStorageKey716() : ('ti_mute_state_' + location.host + '_' + (window.tiUser || 'guest')); }\n        catch(e) { return 'ti_mute_state_' + location.host + '_' + (window.tiUser || 'guest'); }\n    }\n    function videoEl(){ return byId('ti-video-feed'); }\n    function cameraActive(){\n        var v = videoEl();\n        try {\n            return !!(v && v.srcObject && v.videoWidth > 0 && v.videoHeight > 0 && (!window.stream || window.stream.getTracks().some(function(t){ return t.readyState === 'live'; })));\n        } catch(e) { return !!(v && v.srcObject); }\n    }\n    function autoLabels(){\n        return (String(window.currLang || 'it').toLowerCase() === 'en') ? {\n            autoOff:'\ud83c\udfa7 Auto OFF', autoOn:'\ud83c\udfa7 Auto ON', offSession:'\ud83d\udd07 OFF S', off:'\ud83d\udd07 OFF', on:'\ud83d\udd0a ON'\n        } : {\n            autoOff:'\ud83c\udfa7 Auto OFF', autoOn:'\ud83c\udfa7 Auto ON', offSession:'\ud83d\udd07 OFF S', off:'\ud83d\udd07 OFF', on:'\ud83d\udd0a ON'\n        };\n    }\n    function setButtonAutoStyle(btn, active){\n        if (!btn) return;\n        var lbl = autoLabels();\n        btn.innerText = active ? lbl.autoOn : lbl.autoOff;\n        btn.title = active ? 'Audio Auto: presenza rilevata, audio attivo.' : 'Audio Auto: in attesa di presenza rilevata dalla videocamera.';\n        btn.style.background = active ? '#047857' : '#334155';\n        btn.style.borderColor = active ? '#10b981' : '#475569';\n        btn.style.color = '#fff';\n    }\n    function updateAudioStateFromAuto(){\n        if (!isAuto()) return;\n        var active = !!window.tiAudioAutoPresenceActive;\n        window.isMuted = !active;\n        setButtonAutoStyle(byId('ti-mute-btn'), active);\n    }\n    function userDisplayName(){\n        try {\n            var u = String(window.tiUser || '').trim();\n            if (u && u !== 'Ospite' && u !== 'Guest') return u;\n        } catch(e) {}\n        return '';\n    }\n    function welcomeText(){\n        var name = userDisplayName();\n        if (String(window.currLang || 'it').toLowerCase() === 'en') return name ? ('Welcome ' + name + '. How can I help you?') : 'Welcome to Shop & Service. How can I help you?';\n        return name ? ('Benvenuto ' + name + '. Come posso aiutarti?') : 'Benvenuto in Shop & Service. Come posso aiutarti?';\n    }\n    function greetUser(){\n        if (!isAuto()) return;\n        var t = now();\n        if (t - lastGreetTs < 45000) return;\n        lastGreetTs = t;\n        try { if (window.speechSynthesis) window.speechSynthesis.cancel(); } catch(e) {}\n        try {\n            if (typeof window.speakText === 'function') {\n                window.isMuted = false;\n                window.speakText(welcomeText());\n            }\n        } catch(e) {}\n    }\n    function markPresence(score){\n        lastPresenceTs = now();\n        if (!window.tiAudioAutoPresenceActive) {\n            window.tiAudioAutoPresenceActive = true;\n            updateAudioStateFromAuto();\n            greetUser();\n        } else {\n            updateAudioStateFromAuto();\n        }\n    }\n    function markNoPresenceIfStale(){\n        if (!isAuto()) return;\n        if (window.tiAudioAutoPresenceActive && now() - lastPresenceTs > 25000) {\n            window.tiAudioAutoPresenceActive = false;\n            window.isMuted = true;\n            updateAudioStateFromAuto();\n            try { if (window.speechSynthesis) window.speechSynthesis.cancel(); } catch(e) {}\n        } else {\n            updateAudioStateFromAuto();\n        }\n    }\n    function ensureCanvas(){\n        if (!canvas) {\n            canvas = document.createElement('canvas');\n            canvas.width = 96;\n            canvas.height = 72;\n            ctx = canvas.getContext('2d', {willReadFrequently:true});\n        }\n        return !!ctx;\n    }\n    function sampleMotion(){\n        if (!isAuto()) { stopScan(false); return; }\n        if (!cameraActive() || !ensureCanvas()) { markNoPresenceIfStale(); return; }\n        var v = videoEl();\n        try {\n            ctx.drawImage(v, 0, 0, canvas.width, canvas.height);\n            var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n            if (!prevFrame) { prevFrame = new Uint8ClampedArray(data); return; }\n            var diff = 0, checked = 0;\n            for (var i = 0; i < data.length; i += 16) {\n                var d = Math.abs(data[i] - prevFrame[i]) + Math.abs(data[i+1] - prevFrame[i+1]) + Math.abs(data[i+2] - prevFrame[i+2]);\n                if (d > 45) diff++;\n                checked++;\n            }\n            prevFrame = new Uint8ClampedArray(data);\n            var score = checked ? (diff \/ checked) : 0;\n            if (score > 0.035) motionHits++; else motionHits = Math.max(0, motionHits - 1);\n            if (motionHits >= 2) markPresence(score); else markNoPresenceIfStale();\n        } catch(e) { markNoPresenceIfStale(); }\n    }\n    function startScan(){\n        if (!isAuto()) return;\n        window.tiAudioAutoPresenceActive = false;\n        window.isMuted = true;\n        updateAudioStateFromAuto();\n        if (scanTimer) return;\n        prevFrame = null;\n        motionHits = 0;\n        scanTimer = setInterval(sampleMotion, 850);\n        setTimeout(sampleMotion, 300);\n        setTimeout(sampleMotion, 1200);\n    }\n    function stopScan(clearPresence){\n        if (scanTimer) { clearInterval(scanTimer); scanTimer = null; }\n        prevFrame = null;\n        motionHits = 0;\n        if (clearPresence !== false) {\n            window.tiAudioAutoPresenceActive = false;\n            if (isAuto()) window.isMuted = true;\n            updateAudioStateFromAuto();\n        }\n    }\n    function installMuteStateOverride(){\n        var prevApply = window.applyMuteState;\n        if (typeof prevApply === 'function' && !prevApply.__tiAudioAuto497) {\n            window.applyMuteState = function(){\n                var btn = byId('ti-mute-btn');\n                var st = parseInt(window.muteState, 10);\n                var lbl = autoLabels();\n                if (st === AUTO_STATE) {\n                    window.isMuted = !window.tiAudioAutoPresenceActive;\n                    setButtonAutoStyle(btn, !!window.tiAudioAutoPresenceActive);\n                    startScan();\n                    return;\n                }\n                stopScan(true);\n                var ret = prevApply.apply(this, arguments);\n                if (btn) {\n                    if (st === 1) btn.innerText = lbl.offSession;\n                    else if (st === 2) btn.innerText = lbl.off;\n                    else if (st === 0) btn.innerText = lbl.on;\n                }\n                return ret;\n            };\n            window.applyMuteState.__tiAudioAuto497 = true;\n        }\n    }\n    function installMuteButton(){\n        var btn = byId('ti-mute-btn');\n        if (!btn || btn.__tiAudioAuto497) return;\n        btn.__tiAudioAuto497 = true;\n        btn.onclick = function(ev){\n            if (ev) { try { ev.preventDefault(); ev.stopPropagation(); } catch(e){} }\n            window.tiAudioKey = ensureAudioKey();\n            var persistent = canPersistAudio();\n            var st = parseInt(window.muteState, 10);\n            if (isNaN(st) || st < 0 || st > AUTO_STATE || (!persistent && st !== 1)) st = 0;\n            st = persistent ? ((st + 1) % 4) : (st === 1 ? 0 : 1);\n            window.muteState = st;\n            try {\n                if (persistent && (st === 2 || st === AUTO_STATE)) localStorage.setItem(window.tiAudioKey, String(st));\n                else localStorage.removeItem(window.tiAudioKey);\n            } catch(e) {}\n            if (typeof window.applyMuteState === 'function') window.applyMuteState();\n            if (st !== 0) { try { if (window.speechSynthesis) window.speechSynthesis.cancel(); } catch(e){} }\n            if (persistent && st === AUTO_STATE) startScan();\n            return false;\n        };\n    }\n    function readStoredState(){\n        try {\n            window.tiAudioKey = ensureAudioKey();\n            if (!canPersistAudio()) { localStorage.removeItem(window.tiAudioKey); if (parseInt(window.muteState, 10) !== 1) window.muteState = 0; return; }\n            var raw = localStorage.getItem(window.tiAudioKey);\n            if (raw === '3') window.muteState = AUTO_STATE;\n            else if (raw === '2') window.muteState = 2;\n        } catch(e) {}\n    }\n    function installCameraHooks(){\n        if (typeof window.openCamModal === 'function' && !window.openCamModal.__tiAudioAuto497) {\n            var prevOpen = window.openCamModal;\n            window.openCamModal = function(){\n                var ret = prevOpen.apply(this, arguments);\n                setTimeout(function(){ if (isAuto()) startScan(); }, 500);\n                setTimeout(function(){ if (isAuto()) startScan(); }, 1800);\n                return ret;\n            };\n            window.openCamModal.__tiAudioAuto497 = true;\n        }\n        if (typeof window.closeCamModal === 'function' && !window.closeCamModal.__tiAudioAuto497) {\n            var prevClose = window.closeCamModal;\n            window.closeCamModal = function(){\n                var ret = prevClose.apply(this, arguments);\n                if (isAuto()) stopScan(true);\n                return ret;\n            };\n            window.closeCamModal.__tiAudioAuto497 = true;\n        }\n    }\n    function boot(){\n        readStoredState();\n        installMuteStateOverride();\n        installMuteButton();\n        installCameraHooks();\n        if (typeof window.applyMuteState === 'function') window.applyMuteState();\n        if (isAuto()) startScan();\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);\n    setTimeout(boot, 0);\n    setTimeout(boot, 600);\n    setTimeout(boot, 1800);\n})();\n<\/script>\n\n\n\n<script id=\"ti-config-open-watchdog-501\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigOpenWatchdog501Installed) return;\n    window.__tiConfigOpenWatchdog501Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(s){ return String(s == null ? '' : s).replace(\/[&<>\"']\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];}); }\n    function overlay(){ return byId('ti-conf-ov'); }\n    function cnt(){ return byId('ti-conf-cnt'); }\n    function selectedDb(){\n        var s = byId('ti-ditta');\n        return s && s.value ? String(s.value) : String(window.currentDb || window.tiCurrentDb || window.__tiConfigLoadedDb || '');\n    }\n    function show(){\n        var ov = overlay(); if (!ov) return;\n        try { if (window.preparePluginModal) window.preparePluginModal(ov); } catch(e) {}\n        try { if (window.showPluginModal) window.showPluginModal(ov); else if (window.openModal) window.openModal('ti-conf-ov'); } catch(e) {}\n        try {\n            ov.style.setProperty('display','flex','important');\n            ov.style.setProperty('visibility','visible','important');\n            ov.style.setProperty('opacity','1','important');\n            ov.style.setProperty('pointer-events','auto','important');\n            ov.style.setProperty('z-index','2147483000','important');\n            ov.removeAttribute('aria-hidden');\n        } catch(e) {}\n    }\n    function hide(){\n        window.__tiConfigOpenCancelled501 = true;\n        window.__tiConfigOpenToken501 = '';\n        try { if (window.__tiConfigAbort501) window.__tiConfigAbort501.abort(); } catch(e) {}\n        try { if (window.__tiConfigAbort492) window.__tiConfigAbort492.abort(); } catch(e) {}\n        try { if (window.closeModal) window.closeModal('ti-conf-ov'); else { var o=overlay(); if(o) o.style.display='none'; } } catch(e) { var o=overlay(); if(o) o.style.display='none'; }\n    }\n    function retryButtons(){\n        return '<div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;\">'\n            + '<button type=\"button\" id=\"ti-config-retry-501\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;\">Riprova<\/button>'\n            + '<button type=\"button\" id=\"ti-config-cache-501\" class=\"ti-btn\" style=\"background:#0f766e;color:#fff;\">Apri dati in memoria<\/button>'\n            + '<button type=\"button\" id=\"ti-config-close-501\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\">Chiudi<\/button>'\n            + '<\/div>';\n    }\n    function bindActionButtons(){\n        var r=byId('ti-config-retry-501'); if(r) r.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation&&ev.stopPropagation();} return window.openConfigSafe501(ev,true); };\n        var c=byId('ti-config-cache-501'); if(c) c.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation&&ev.stopPropagation();} return window.openConfigSafe501(ev,false,true); };\n        var x=byId('ti-config-close-501'); if(x) x.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation&&ev.stopPropagation();} hide(); return false; };\n    }\n    function message(html,type){\n        show();\n        var c = cnt(); if(!c) return;\n        var border = type==='error' ? '#ef4444' : (type==='warn' ? '#f59e0b' : '#22c55e');\n        var bg = type==='error' ? '#450a0a' : (type==='warn' ? '#422006' : '#052e16');\n        var color = type==='error' ? '#fecaca' : (type==='warn' ? '#fde68a' : '#bbf7d0');\n        c.innerHTML = '<div style=\"margin:14px;padding:14px;border-radius:12px;border:1px solid '+border+';background:'+bg+';color:'+color+';font-size:14px;line-height:1.45;\">'+html+'<\/div>';\n        bindActionButtons();\n    }\n    function isLoading(){\n        var c=cnt(); if(!c) return false;\n        var h=String(c.innerHTML||'');\n        return \/Caricamento configurazione in corso|Configurazione non caricata|ancora in corso\/i.test(h);\n    }\n    function goodContent(){\n        var c=cnt(); if(!c) return false;\n        var h=String(c.innerHTML||'').trim();\n        return !!(h && !\/Caricamento configurazione in corso|Configurazione non caricata|ancora in corso\/i.test(h));\n    }\n    function cache(db){\n        try{\n            var d = window.currentDbData;\n            if(!d || !d.Tabelle) return null;\n            var known = String(d.__db_name || window.__tiCurrentDbDataDb || window.__tiConfigLoadedDb || window.currentDb || window.tiCurrentDb || '').trim();\n            if(known && db && known !== db) return null;\n            return d;\n        } catch(e) { return null; }\n    }\n    function prepare(data,db){\n        if(!data || !data.Tabelle) throw new Error('Database non valido: manca la sezione Tabelle.');\n        window.currentDbData = data;\n        try { data.__db_name = db; window.__tiCurrentDbDataDb = db; window.__tiConfigLoadedDb = db; window.currentDb = db; window.tiCurrentDb = db; } catch(e) {}\n        try { window.configOriginalDbData = JSON.parse(JSON.stringify(data)); } catch(e) { window.configOriginalDbData = data; }\n        try { window.configWasSaved = false; window.tiConfigDeletedRowsManifest = []; } catch(e) {}\n        try { if(window.modifiedFields && window.modifiedFields.clear) window.modifiedFields.clear(); } catch(e) {}\n    }\n    function render(source){\n        show();\n        if(typeof window.renderConfig !== 'function') throw new Error('renderConfig non disponibile. Possibile errore JavaScript precedente.');\n        try { window.configForceTop = false; window.renderConfig(); } catch(e) { throw new Error('Errore renderConfig: ' + (e && e.message ? e.message : e)); }\n        var c=cnt(); if(!c) throw new Error('Contenitore ti-conf-cnt non trovato.');\n        if(!String(c.innerHTML||'').trim() || isLoading()) throw new Error('Render non completato: contenuto configurazione assente o ancora in caricamento.');\n        window.__tiConfigLastGoodHtml501 = String(c.innerHTML||'');\n        window.__tiConfigLastGoodTime501 = Date.now();\n        window.__tiConfigRenderedOk501 = true;\n        try { if(window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        try { console.info('Shop & Service Configurazione aperta rescue 501: ' + source); } catch(e) {}\n        return true;\n    }\n    function makeFd(db){\n        var fd = null;\n        try { if(window.buildAjaxFormData) fd = window.buildAjaxFormData('ti_ai_get_db_data',{db:db,ti_config_open:'1',rescue:'501'}); } catch(e) {}\n        if(!fd){ fd = new FormData(); fd.append('action','ti_ai_get_db_data'); fd.append('ti_action','ti_ai_get_db_data'); fd.append('db',db); fd.append('ti_config_open','1'); fd.append('rescue','501'); }\n        try { if(!fd.has('action')) fd.append('action','ti_ai_get_db_data'); if(!fd.has('ti_action')) fd.append('ti_action','ti_ai_get_db_data'); } catch(e) {}\n        return fd;\n    }\n    function fetchDb(db, token){\n        var urls=[];\n        if(window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if(window.ajaxurl && urls.indexOf(window.ajaxurl)<0) urls.push(window.ajaxurl);\n        if(window.tiUrl && urls.indexOf(window.tiUrl)<0) urls.push(window.tiUrl);\n        if(!urls.length) urls.push(window.location.href.split('#')[0]);\n        function attempt(i){\n            if(window.__tiConfigOpenToken501 !== token || window.__tiConfigOpenCancelled501) return Promise.reject(new Error('Apertura annullata.'));\n            var ctrl = null, timer = null, done = false;\n            var opts = {method:'POST', body:makeFd(db), credentials:'same-origin', cache:'no-store'};\n            try { if(window.AbortController){ ctrl = new AbortController(); opts.signal = ctrl.signal; window.__tiConfigAbort501 = ctrl; } } catch(e) {}\n            return new Promise(function(resolve,reject){\n                timer = setTimeout(function(){ if(done) return; done = true; try{ if(ctrl) ctrl.abort(); }catch(e){} reject(new Error('Timeout lettura database da ' + urls[i])); }, 22000);\n                fetch(urls[i], opts).then(function(r){\n                    return r.text().then(function(raw){\n                        if(!r.ok) throw new Error('HTTP ' + r.status + ' da ' + urls[i] + ': ' + String(raw||'').slice(0,280));\n                        try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta non JSON da ' + urls[i] + ': ' + String(raw||'').slice(0,280)); }\n                    });\n                }).then(function(j){ if(done) return; done = true; resolve(j); }).catch(function(err){\n                    if(done) return; done = true;\n                    if(i+1 < urls.length) attempt(i+1).then(resolve).catch(reject); else reject(err);\n                }).finally(function(){ try{ clearTimeout(timer); }catch(e){} });\n            });\n        }\n        return attempt(0);\n    }\n    function restoreLastGood(){\n        var c=cnt();\n        if(c && window.__tiConfigLastGoodHtml501 && isLoading()) {\n            c.innerHTML = window.__tiConfigLastGoodHtml501;\n            try { console.warn('Shop & Service Config 501: ripristinato contenuto valido dopo sovrascrittura loader.'); } catch(e) {}\n            return true;\n        }\n        return false;\n    }\n    function fail(err,db){\n        if(goodContent()) { restoreLastGood(); return false; }\n        var cached = cache(db);\n        if(cached){\n            try { prepare(cached,db); render('cache dopo errore server'); return false; } catch(e) { err = new Error((err && err.message ? err.message : String(err||'')) + ' | Cache non utilizzabile: ' + (e && e.message ? e.message : e)); }\n        }\n        var m = err && err.message ? err.message : String(err || 'errore sconosciuto');\n        message('<b>Configurazione non caricata.<\/b><br>' + esc(m) + retryButtons() + '<br><span style=\"font-size:12px;color:#fecaca;\">Se il problema persiste, verificare permessi file, dimensione database, risposta admin-ajax e log PHP.<\/span>','error');\n        try { console.error('Shop & Service CONFIGURA rescue 501 error', err); } catch(e) {}\n        return false;\n    }\n    function startWatchdog(token,db){\n        setTimeout(function(){ if(window.__tiConfigOpenToken501 !== token || goodContent()) return; restoreLastGood(); if(!goodContent()) message('<b>Caricamento configurazione ancora in corso...<\/b><br>La risposta del server tarda. Puoi riprovare, aprire i dati in memoria o chiudere.' + retryButtons(),'warn'); }, 6000);\n        setTimeout(function(){ if(window.__tiConfigOpenToken501 !== token || goodContent()) return; var cached = cache(db); if(cached){ try{ prepare(cached,db); render('cache watchdog'); return; }catch(e){} } message('<b>Caricamento configurazione non concluso.<\/b><br>Il server non ha completato la risposta in tempo utile.' + retryButtons(),'warn'); }, 14000);\n    }\n    window.openConfigSafe501 = function(ev, forceReload, cacheOnly){\n        if(ev && ev.preventDefault) ev.preventDefault();\n        try { if(ev && ev.stopPropagation) ev.stopPropagation(); if(ev && ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        var db = selectedDb();\n        if(!db || db === 'NEW_DB'){ try { if(window.tiAlert) window.tiAlert('Seleziona prima una ditta valida.'); else alert('Seleziona prima una ditta valida.'); } catch(e) {} return false; }\n        try { if(window.__tiConfigAbort501) window.__tiConfigAbort501.abort(); } catch(e) {}\n        try { if(window.__tiConfigAbort492) window.__tiConfigAbort492.abort(); } catch(e) {}\n        window.__tiConfigOpenCancelled501 = false;\n        var token = 'cfg501_' + Date.now() + '_' + Math.random().toString(36).slice(2,8);\n        window.__tiConfigOpenToken501 = token;\n        window.__tiConfigRenderedOk501 = false;\n        show();\n        var cached = cache(db);\n        if(cached && !forceReload){\n            try { prepare(cached,db); render(cacheOnly ? 'cache richiesta' : 'cache immediata'); if(cacheOnly) return false; } catch(e) { try{ console.warn('Shop & Service cache config non utilizzabile 501',e); }catch(_){} }\n        }\n        if(cacheOnly){ message('<b>Dati in memoria non disponibili.<\/b><br>Premi Riprova per leggere il database dal server.' + retryButtons(), 'warn'); return false; }\n        if(!goodContent()) message('<b>Caricamento configurazione in corso...<\/b><br><span style=\"font-size:12px;\">Lettura database e apertura form.<\/span>' + retryButtons(),'ok');\n        startWatchdog(token,db);\n        fetchDb(db,token).then(function(res){\n            if(window.__tiConfigOpenToken501 !== token || window.__tiConfigOpenCancelled501) return false;\n            if(!res || !res.success || !res.data){ var m = res && res.data && res.data.message ? res.data.message : (res && res.message ? res.message : 'Risposta server non valida.'); throw new Error(m); }\n            prepare(res.data,db);\n            render('server');\n            setTimeout(restoreLastGood,120); setTimeout(restoreLastGood,700); setTimeout(restoreLastGood,1800);\n            return true;\n        }).catch(function(err){ if(window.__tiConfigOpenToken501 !== token || window.__tiConfigOpenCancelled501) return false; return fail(err,db); });\n        return false;\n    };\n    ['openConfigSafe492','openConfigSafe491','openConfigSafe490','openConfigSafe489','openConfigSafe488','openConfigSafe218'].forEach(function(n){ window[n] = window.openConfigSafe501; });\n    var prevClose = window.closeModal;\n    if(typeof prevClose === 'function' && !prevClose.__tiConfigCancel501){\n        window.closeModal = function(id){ if(id === 'ti-conf-ov'){ window.__tiConfigOpenCancelled501 = true; window.__tiConfigOpenToken501 = ''; try{ if(window.__tiConfigAbort501) window.__tiConfigAbort501.abort(); }catch(e){} } return prevClose.apply(this,arguments); };\n        window.closeModal.__tiConfigCancel501 = true;\n    }\n    function bind(){ var b=byId('ti-conf-toggle'); if(b){ b.onclick = window.openConfigSafe501; b.setAttribute('data-ti-config-open-rescue','501'); } bindActionButtons(); }\n    document.addEventListener('click',function(ev){\n        var t=ev && ev.target; if(!t || !t.closest) return;\n        var close=t.closest('#ti-config-close-501,#ti-config-close-492,#ti-config-close-491,#ti-config-close-490,#ti-config-close-489');\n        if(close){ try{ev.preventDefault();ev.stopPropagation();if(ev.stopImmediatePropagation)ev.stopImmediatePropagation();}catch(e){} hide(); return false; }\n        var b=t.closest('#ti-conf-toggle,#ti-config-retry-501,#ti-config-cache-501,#ti-config-retry-492,#ti-config-retry-491,#ti-config-retry-490,#ti-config-retry-489,#ti-config-rescue-488-retry');\n        if(!b) return;\n        try{ev.preventDefault();ev.stopPropagation();if(ev.stopImmediatePropagation)ev.stopImmediatePropagation();}catch(e){}\n        if(b.id === 'ti-config-cache-501') return window.openConfigSafe501(ev,false,true);\n        return window.openConfigSafe501(ev,b.id !== 'ti-conf-toggle');\n    },true);\n    if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded',bind); else bind();\n    setTimeout(bind,0); setTimeout(bind,250); setTimeout(bind,1000); setInterval(bind,2000);\n    setInterval(function(){ if(isLoading() && window.__tiConfigLastGoodHtml501) restoreLastGood(); },1800);\n})();\n<\/script>\n\n\n<script id=\"ti-report-attivita-fix-502\">\n(function(){\n    \"use strict\";\n    if (window.__tiReportAttivitaFix502Installed) return;\n    window.__tiReportAttivitaFix502Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function norm(v){ return String(v == null ? '' : v).trim(); }\n    function ensureState(){\n        if (!window.activityReportState) window.activityReportState = {};\n        if (!window.activityReportState.filters) window.activityReportState.filters = {};\n        if (!window.activityReportState.colFlags) window.activityReportState.colFlags = {};\n        if (!window.activityReportState.rowFlags) window.activityReportState.rowFlags = {};\n        if (!window.activityReportState.metricFlags) window.activityReportState.metricFlags = (typeof window.getDefaultActivityMetricFlags === 'function') ? window.getDefaultActivityMetricFlags() : {Prezzo:false,'Quantit\u00e0':false,Quantita:false,Totale:true};\n        if (!window.activityReportState.view) window.activityReportState.view = 'table';\n        if (!window.activityReportState.groupField) window.activityReportState.groupField = 'Username';\n    }\n    function cols(){\n        var c = Array.isArray(window.activityReportCols) ? window.activityReportCols.slice() : [];\n        if (!c.length) c = ['Username','Descrizione','Prezzo','Quantit\u00e0','Esito','Operatore','Dispositivo','Sito','Prodotto','Istruzioni','Durata','Data','Ora','Nota','Stato','Totale'];\n        return c;\n    }\n    function metrics(){\n        var c = cols();\n        var m = ['Prezzo','Quantit\u00e0','Quantita','Totale'].filter(function(x){ return c.indexOf(x) !== -1 || x === 'Totale'; });\n        return m.length ? m : ['Totale'];\n    }\n    function savePrefs(){ try { if (typeof window.saveActivityReportPrefs === 'function') window.saveActivityReportPrefs(); } catch(e){} }\n    function rerender(){ try { if (typeof window.renderActivityReport === 'function') window.renderActivityReport(); } catch(e){ try { console.warn('Shop & Service Report attivita render error 502', e); } catch(ignore){} } }\n    function getRows(){\n        try { if (typeof window.getFilteredActivityRows === 'function') return window.getFilteredActivityRows(false) || []; } catch(e){}\n        try { if (typeof window.getActivityRowsNormalized === 'function') return window.getActivityRowsNormalized() || []; } catch(e){}\n        return [];\n    }\n    function numberVal(v){\n        if (typeof window.parseReportNum === 'function') return window.parseReportNum(v, 0);\n        var s = String(v == null ? '' : v).replace(\/[^0-9,.-]\/g,'');\n        if (s.indexOf(',') >= 0 && s.indexOf('.') >= 0) s = s.replace(\/\\.\/g,'').replace(',','.');\n        else if (s.indexOf(',') >= 0) s = s.replace(',','.');\n        var n = parseFloat(s); return isNaN(n) ? 0 : n;\n    }\n    function selectedMetric(){\n        ensureState();\n        var mf = window.activityReportState.metricFlags || {};\n        var ms = metrics();\n        for (var i=0;i<ms.length;i++) if (mf[ms[i]]) return ms[i];\n        return ms.indexOf('Totale') !== -1 ? 'Totale' : ms[0];\n    }\n    function groupField(){\n        ensureState();\n        var c = cols();\n        var g = window.activityReportState.groupField || 'Username';\n        if (c.indexOf(g) === -1) g = c.indexOf('Esito') !== -1 ? 'Esito' : (c[0] || 'Username');\n        return g;\n    }\n    function aggregate(rows){\n        var g = groupField();\n        var m = selectedMetric();\n        var map = {};\n        (rows || []).forEach(function(r){\n            var key = norm(r && r[g]) || '(vuoto)';\n            if (!map[key]) map[key] = {key:key, count:0, value:0};\n            map[key].count++;\n            if (m === 'Quantit\u00e0' || m === 'Quantita') map[key].value += numberVal(r && (r['Quantit\u00e0'] != null ? r['Quantit\u00e0'] : r.Quantita));\n            else if (m === 'Prezzo') map[key].value += numberVal(r && r.Prezzo);\n            else map[key].value += numberVal(r && (r.Totale != null ? r.Totale : (numberVal(r && r.Prezzo) * (numberVal(r && (r['Quantit\u00e0'] != null ? r['Quantit\u00e0'] : r.Quantita)) || 1))));\n        });\n        return Object.keys(map).map(function(k){ return map[k]; }).sort(function(a,b){ return b.value - a.value; }).slice(0,12);\n    }\n    function drawFallback(canvasId, type){\n        var cv = byId(canvasId); if (!cv || !cv.getContext) return;\n        var ctx = cv.getContext('2d');\n        var w = cv.width || 900, h = cv.height || 360;\n        ctx.clearRect(0,0,w,h);\n        ctx.fillStyle = '#020617'; ctx.fillRect(0,0,w,h);\n        var data = aggregate(getRows());\n        ctx.fillStyle = '#e5e7eb'; ctx.font = '16px Arial';\n        ctx.fillText((type === 'trend' ? 'Andamento' : 'Grafico') + ' - ' + selectedMetric() + ' per ' + groupField(), 18, 26);\n        if (!data.length) { ctx.font='14px Arial'; ctx.fillText('Nessun dato disponibile', 18, 58); return; }\n        var max = Math.max.apply(null, data.map(function(d){ return Math.abs(d.value) || 1; }));\n        if (type === 'trend') {\n            var left=52, top=52, right=24, bottom=52, cw=w-left-right, ch=h-top-bottom;\n            ctx.strokeStyle='#334155'; ctx.beginPath(); ctx.moveTo(left,top); ctx.lineTo(left,top+ch); ctx.lineTo(left+cw,top+ch); ctx.stroke();\n            ctx.strokeStyle='#93c5fd'; ctx.lineWidth=3; ctx.beginPath();\n            data.forEach(function(d,i){ var x=left+(cw*(i\/(Math.max(1,data.length-1)))); var y=top+ch-(ch*(d.value\/max)); if(i===0) ctx.moveTo(x,y); else ctx.lineTo(x,y); });\n            ctx.stroke();\n            ctx.fillStyle='#bfdbfe';\n            data.forEach(function(d,i){ var x=left+(cw*(i\/(Math.max(1,data.length-1)))); var y=top+ch-(ch*(d.value\/max)); ctx.beginPath(); ctx.arc(x,y,4,0,Math.PI*2); ctx.fill(); ctx.save(); ctx.translate(x, top+ch+15); ctx.rotate(-0.45); ctx.fillStyle='#cbd5e1'; ctx.font='10px Arial'; ctx.fillText(String(d.key).slice(0,16),0,0); ctx.restore(); });\n        } else {\n            var bx=28, by=55, bw=w-56, bh=h-95, barH=Math.max(14, Math.floor(bh\/data.length)-5);\n            data.forEach(function(d,i){ var y=by+i*(barH+5); var ww=Math.max(2, Math.round((bw-190)*(d.value\/max))); ctx.fillStyle='#2563eb'; ctx.fillRect(bx+160,y,ww,barH); ctx.fillStyle='#e5e7eb'; ctx.font='12px Arial'; ctx.fillText(String(d.key).slice(0,22), bx, y+barH-3); ctx.fillText(String(Math.round(d.value*100)\/100), bx+165+ww, y+barH-3); });\n        }\n    }\n    function ensureStyle(){\n        if (byId('ti-report-attivita-fix-502-css')) return;\n        var st=document.createElement('style'); st.id='ti-report-attivita-fix-502-css';\n        st.textContent = '#ti-report-cnt .ti-report-502-panel{display:block!important;visibility:visible!important;opacity:1!important;position:relative!important;z-index:999!important;pointer-events:auto!important;background:#0f172a!important;border:1px solid #38bdf8!important;border-radius:12px!important;padding:10px!important;margin:10px 0!important;color:#e5e7eb!important;}'+\n        '#ti-report-cnt .ti-report-502-panel *{pointer-events:auto!important;}'+\n        '#ti-report-cnt .ti-report-502-row{display:flex!important;gap:8px!important;align-items:center!important;flex-wrap:wrap!important;margin:6px 0!important;}'+\n        '#ti-report-cnt .ti-report-502-btn{border:1px solid #475569!important;border-radius:8px!important;background:#1f2937!important;color:#fff!important;padding:7px 10px!important;font-weight:800!important;cursor:pointer!important;}'+\n        '#ti-report-cnt .ti-report-502-btn.is-active{background:#15803d!important;border-color:#86efac!important;}'+\n        '#ti-report-cnt .ti-report-502-chip{display:inline-flex!important;align-items:center!important;gap:5px!important;border:1px solid #334155!important;border-radius:999px!important;background:#111827!important;color:#e5e7eb!important;padding:5px 8px!important;font-size:12px!important;}'+\n        '#ti-report-cnt .ti-report-502-select{background:#111827!important;color:#fff!important;border:1px solid #475569!important;border-radius:8px!important;padding:6px 8px!important;}'+\n        '#ti-report-cnt .ti-chart-wrap{min-height:360px!important;display:block!important;visibility:visible!important;opacity:1!important;}'+\n        '#ti-report-cnt canvas{display:block!important;visibility:visible!important;opacity:1!important;max-width:100%!important;background:#020617!important;}';\n        document.head.appendChild(st);\n    }\n    function panelHtml(){\n        ensureState();\n        var c=cols(), view=window.activityReportState.view || 'table', cf=window.activityReportState.colFlags || {}, mf=window.activityReportState.metricFlags || {};\n        var html='<div id=\"ti-report-controls-502\" class=\"ti-report-502-panel\" data-ti-report-fix=\"502\">';\n        html+='<div class=\"ti-report-502-row\"><b>Vista report<\/b>';\n        [['table','Elenco dati'],['pie','Grafico torte'],['bar','Grafico barre'],['trend','Grafico andamento']].forEach(function(v){ html+='<button type=\"button\" class=\"ti-report-502-btn '+(view===v[0]?'is-active':'')+'\" data-ti-report-view=\"'+v[0]+'\">'+esc(v[1])+'<\/button>'; });\n        html+='<\/div><div class=\"ti-report-502-row\"><b>Selezione campi<\/b>';\n        c.forEach(function(col){ html+='<label class=\"ti-report-502-chip\"><input type=\"checkbox\" data-ti-report-col=\"'+esc(col)+'\" '+(!cf[col]?'checked':'')+'><span>'+esc(col)+'<\/span><\/label>'; });\n        html+='<\/div><div class=\"ti-report-502-row\"><b>Grafico<\/b><span>Raggruppa per<\/span><select class=\"ti-report-502-select\" data-ti-report-group>';\n        var visible = c.filter(function(x){ return !cf[x]; }); if (!visible.length) visible = c;\n        visible.forEach(function(col){ html+='<option value=\"'+esc(col)+'\" '+(groupField()===col?'selected':'')+'>'+esc(col)+'<\/option>'; });\n        html+='<\/select>';\n        metrics().forEach(function(m){ html+='<label class=\"ti-report-502-chip\"><input type=\"checkbox\" data-ti-report-metric=\"'+esc(m)+'\" '+(mf[m]?'checked':'')+'><span>'+esc(m)+'<\/span><\/label>'; });\n        html+='<\/div><\/div>';\n        return html;\n    }\n    function applyControls(){\n        var box=byId('ti-report-cnt'); if(!box) return;\n        ensureStyle(); ensureState();\n        \/\/ 30.9.1538: il renderer principale possiede gia Vista report, selezione campi e opzioni grafico.\n        \/\/ Il vecchio pannello 502 duplicava gli stessi controlli: viene rimosso e non reinserito.\n        var old=byId('ti-report-controls-502'); if(old) old.remove();\n        setTimeout(function(){ ensureDraw(); }, 40);\n    }\n    function ensureDraw(){\n        ensureState();\n        var view=window.activityReportState.view || 'table';\n        if(view === 'pie') {\n            var p=byId('ti-report-pie');\n            if(!p) { var box=byId('ti-report-cnt'); if(box) box.insertAdjacentHTML('beforeend','<div class=\"ti-chart-wrap\"><canvas id=\"ti-report-pie\" width=\"980\" height=\"380\"><\/canvas><\/div>'); }\n            try { if (typeof window.drawPie3D === 'function') window.drawPie3D('ti-report-pie', getRows()); else drawFallback('ti-report-pie','pie'); } catch(e) { drawFallback('ti-report-pie','pie'); }\n        }\n        if(view === 'bar') {\n            var b=byId('ti-report-bar');\n            if(!b) { var boxBar=byId('ti-report-cnt'); if(boxBar) boxBar.insertAdjacentHTML('beforeend','<div class=\"ti-chart-wrap\"><canvas id=\"ti-report-bar\" width=\"980\" height=\"380\"><\/canvas><\/div>'); }\n            try { if (typeof window.drawBar3D === 'function') window.drawBar3D('ti-report-bar', getRows()); else drawFallback('ti-report-bar','bar'); } catch(eBar) { drawFallback('ti-report-bar','bar'); }\n        }\n        if(view === 'trend') {\n            var t=byId('ti-report-trend');\n            if(!t) { var box2=byId('ti-report-cnt'); if(box2) box2.insertAdjacentHTML('beforeend','<div class=\"ti-chart-wrap\"><canvas id=\"ti-report-trend\" width=\"980\" height=\"380\"><\/canvas><\/div>'); }\n            try { if (typeof window.drawTrend3D === 'function') window.drawTrend3D('ti-report-trend', getRows()); else drawFallback('ti-report-trend','trend'); } catch(e2) { drawFallback('ti-report-trend','trend'); }\n        }\n    }\n    document.addEventListener('click', function(ev){\n        var b = ev.target && ev.target.closest ? ev.target.closest('[data-ti-report-view]') : null;\n        if(!b) return;\n        ev.preventDefault(); ev.stopPropagation();\n        ensureState(); window.activityReportState.view = b.getAttribute('data-ti-report-view') || 'table'; savePrefs(); rerender(); setTimeout(applyControls,30);\n    }, true);\n    document.addEventListener('change', function(ev){\n        var t=ev.target; if(!t) return;\n        if(t.hasAttribute('data-ti-report-col')) { ev.stopPropagation(); ensureState(); window.activityReportState.colFlags[t.getAttribute('data-ti-report-col')] = !t.checked; savePrefs(); rerender(); setTimeout(applyControls,30); return; }\n        if(t.hasAttribute('data-ti-report-metric')) { ev.stopPropagation(); ensureState(); var m=t.getAttribute('data-ti-report-metric'); window.activityReportState.metricFlags[m] = !!t.checked; var any=metrics().some(function(x){ return !!window.activityReportState.metricFlags[x]; }); if(!any) window.activityReportState.metricFlags[m] = true; savePrefs(); rerender(); setTimeout(applyControls,30); return; }\n        if(t.hasAttribute('data-ti-report-group')) { ev.stopPropagation(); ensureState(); window.activityReportState.groupField = t.value || 'Username'; savePrefs(); rerender(); setTimeout(applyControls,30); return; }\n    }, true);\n    function wrap(){\n        if(typeof window.renderActivityReport === 'function' && !window.renderActivityReport.__ti502){ var old=window.renderActivityReport; window.renderActivityReport=function(){ var r=old.apply(this,arguments); setTimeout(applyControls,0); setTimeout(applyControls,180); return r; }; window.renderActivityReport.__ti502=true; }\n        if(typeof window.openActivityReport === 'function' && !window.openActivityReport.__ti502){ var oo=window.openActivityReport; window.openActivityReport=function(){ var r=oo.apply(this,arguments); setTimeout(applyControls,120); setTimeout(applyControls,500); return r; }; window.openActivityReport.__ti502=true; }\n    }\n    wrap(); setTimeout(function(){ wrap(); applyControls(); }, 600); setTimeout(function(){ wrap(); applyControls(); }, 1800);\n})();\n<\/script>\n\n\n<script id=\"ti-config-read-wait-503\">\n(function(){\n    \"use strict\";\n    window.__tiConfigReadWait503Installed = true;\n    window.__tiConfigReadWait503Disabled549 = true;\n    window.__tiConfigReadWaitActive503 = false;\n})();\n<\/script>\n\n\n\n<script id=\"ti-company-switch-logout-config-reset-504\">\n(function(){\n    \"use strict\";\n    if (window.__tiCompanySwitchLogoutConfigReset504Installed) return;\n    window.__tiCompanySwitchLogoutConfigReset504Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function safe(fn){ try { return fn(); } catch(e) { return null; } }\n    function isConfigVisible(){\n        var ov = byId('ti-conf-ov');\n        if (!ov) return false;\n        var cs = window.getComputedStyle ? window.getComputedStyle(ov) : null;\n        return String(ov.style.display || '') !== 'none' && (!cs || cs.display !== 'none');\n    }\n    function hideElement(el){\n        if (!el) return;\n        safe(function(){ if (window.closeModal) window.closeModal(el.id || el); });\n        safe(function(){ el.style.setProperty('display','none','important'); });\n        safe(function(){ el.classList.remove('show','open','active','ti-modal-open'); });\n        safe(function(){ el.setAttribute('aria-hidden','true'); });\n    }\n    function hideProgress(reason){\n        safe(function(){ if (window.hideProgressPopup) window.hideProgressPopup(false, reason || 'Operazione interrotta', {notifyUser:false}); });\n        safe(function(){ if (window.clearLongAIProcess) window.clearLongAIProcess(); });\n        safe(function(){ if (window.cancelActiveConfigAiRequest434) window.cancelActiveConfigAiRequest434('company_switch_or_logout'); });\n        window.__tiConfigReadWaitActive503 = false;\n        window.__tiConfigReadWaitStarted503 = 0;\n    }\n    function resetConfigState(reason){\n        window.__tiCompanySwitchResetReason504 = reason || '';\n        window.__tiConfigClosedBySwitch504 = Date.now();\n        window.__tiConfigOpenToken501 = null;\n        window.__tiConfigOpenToken503 = null;\n        window.__tiConfigOpenToken492 = null;\n        window.__tiConfigOpenToken491 = null;\n        safe(function(){ window.currentDbData = null; });\n        safe(function(){ window.configOriginalDbData = null; });\n        safe(function(){ window.configWasSaved = true; });\n        safe(function(){ window.tiConfigDeletedRowsManifest = []; });\n        safe(function(){ if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); });\n        safe(function(){ window.tiConfigImportToken = null; });\n        safe(function(){ window.configBotFile = null; });\n        hideProgress(reason || 'Cambio contesto');\n    }\n    window.tiCloseConfigurationForContextChange504 = function(reason){\n        resetConfigState(reason || 'Cambio ditta');\n        hideElement(byId('ti-conf-ov'));\n        hideElement(byId('ti-file-manager-ov'));\n        hideElement(byId('ti-ai-gen-ov'));\n        hideElement(byId('ti-activity-report-ov'));\n        safe(function(){ if (window.closeDittaPopup) window.closeDittaPopup(); });\n        safe(function(){ if (window.hideOrderConfirmPanel) window.hideOrderConfirmPanel(); });\n        var cnt = byId('ti-conf-cnt');\n        if (cnt) cnt.innerHTML = '<div style=\"padding:14px;border-radius:12px;background:#111827;border:1px solid #334155;color:#e5e7eb;\">Configurazione chiusa per cambio ditta. Riapri Configura dopo il caricamento della nuova ditta.<\/div>';\n    };\n    window.tiCloseAllShopServiceUiForLogout504 = function(){\n        resetConfigState('Logoff');\n        var ids = ['ti-conf-ov','ti-login-ov','ti-profile-ov','ti-newdb-ov','ti-new-db-ov','ti-file-manager-ov','ti-ai-gen-ov','ti-activity-report-ov','ti-delete-company-ov','ti-progress-ov'];\n        ids.forEach(function(id){ hideElement(byId(id)); });\n        safe(function(){ document.querySelectorAll('.ti-modal-overlay,.ti-modal-backdrop').forEach(function(el){ hideElement(el); }); });\n        safe(function(){ if (window.closeDittaPopup) window.closeDittaPopup(); });\n        safe(function(){ if (window.hideOrderConfirmPanel) window.hideOrderConfirmPanel(); });\n        safe(function(){ var chat=byId('ti-chat-box'); if (chat) chat.innerHTML=''; });\n        safe(function(){ var msg=byId('ti-msg'); if (msg) msg.value=''; });\n        safe(function(){ var un=byId('ti-user-name'); if (un) un.textContent='Cliente\/Utente'; });\n        safe(function(){ var ur=byId('ti-user-role'); if (ur) ur.textContent=''; });\n        safe(function(){ var lb=byId('ti-login-btn'); if (lb) lb.style.display='inline-block'; });\n        safe(function(){ var ob=byId('ti-logout-btn'); if (ob) ob.style.display='none'; });\n        safe(function(){ document.cookie = 'ti_ai_ss_session=; Max-Age=0; path=\/; SameSite=Lax'; });\n        safe(function(){ if (window.tiResetLogoutLayout1589) window.tiResetLogoutLayout1589(); });\n    };\n    var lastDb = '';\n    function syncLastDb(){ var d=byId('ti-ditta'); if (d) lastDb = String(d.value || ''); }\n    syncLastDb();\n    document.addEventListener('DOMContentLoaded', syncLastDb, {once:true});\n    document.addEventListener('change', function(ev){\n        var t = ev && ev.target;\n        if (!t || t.id !== 'ti-ditta') return;\n        var newDb = String(t.value || '');\n        if (newDb === lastDb) return;\n        var oldDb = lastDb;\n        lastDb = newDb;\n        if (oldDb || isConfigVisible()) {\n            window.tiCloseConfigurationForContextChange504('Cambio ditta da ' + (oldDb || '-') + ' a ' + (newDb || '-'));\n        }\n        safe(function(){ var chat=byId('ti-chat-box'); if (chat) chat.innerHTML=''; });\n        safe(function(){ var msg=byId('ti-msg'); if (msg) msg.value=''; });\n        safe(function(){ window.tiCurrentSelectedDb = newDb; });\n        safe(function(){ if (newDb) localStorage.setItem('ti_saved_db', newDb); else localStorage.removeItem('ti_saved_db'); });\n    }, true);\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var logoutBtn = t.closest('#ti-logout-btn,[data-ti-logout],.ti-logout-btn');\n        if (logoutBtn) window.tiCloseAllShopServiceUiForLogout504();\n    }, true);\n    function wrapLogout(){\n        if (typeof window.doLogout === 'function' && !window.doLogout.__ti504) {\n            var oldLogout = window.doLogout;\n            window.doLogout = function(){\n                window.tiCloseAllShopServiceUiForLogout504();\n                return oldLogout.apply(this, arguments);\n            };\n            window.doLogout.__ti504 = true;\n        }\n        if (typeof window.forceSessionCloseNow === 'function' && !window.forceSessionCloseNow.__ti504) {\n            var oldForce = window.forceSessionCloseNow;\n            window.forceSessionCloseNow = function(){\n                window.tiCloseAllShopServiceUiForLogout504();\n                return oldForce.apply(this, arguments);\n            };\n            window.forceSessionCloseNow.__ti504 = true;\n        }\n    }\n    function wrapDittaRender(){\n        if (typeof window.renderDittePopup === 'function' && !window.renderDittePopup.__ti504) {\n            var oldRender = window.renderDittePopup;\n            window.renderDittePopup = function(){\n                var r = oldRender.apply(this, arguments);\n                safe(function(){\n                    document.querySelectorAll('#ti-ditta-popup .ti-ditta-row').forEach(function(row){\n                        if (row.__ti504Bound) return;\n                        row.__ti504Bound = true;\n                        row.addEventListener('click', function(){\n                            var d=byId('ti-ditta');\n                            var before=lastDb;\n                            setTimeout(function(){\n                                var after = d ? String(d.value || '') : '';\n                                if (after !== before) window.tiCloseConfigurationForContextChange504('Cambio ditta');\n                            }, 0);\n                        }, true);\n                    });\n                });\n                return r;\n            };\n            window.renderDittePopup.__ti504 = true;\n        }\n    }\n    wrapLogout(); wrapDittaRender();\n    setTimeout(function(){ syncLastDb(); wrapLogout(); wrapDittaRender(); }, 300);\n    setTimeout(function(){ wrapLogout(); wrapDittaRender(); }, 1200);\n    setInterval(function(){ wrapLogout(); wrapDittaRender(); }, 2500);\n})();\n<\/script>\n\n\n<script id=\"ti-logout-guest-guard-505\">\n(function(){\n    \"use strict\";\n    if (window.__tiLogoutGuestGuard505) return;\n    window.__tiLogoutGuestGuard505 = true;\n    function byId(id){ return document.getElementById(id); }\n    function safe(fn){ try { return fn(); } catch(e) {} }\n    function txt(v){ return String(v == null ? '' : v).trim(); }\n    function isLogged(){\n        var u = txt(window.tiUser || '');\n        if (u !== '') return true;\n        var name = byId('ti-user-name');\n        var nameTxt = name ? txt(name.textContent || '') : '';\n        if (nameTxt && !\/^(cliente\\\/utente|cliente|utente|guest|ospite)$\/i.test(nameTxt)) return true;\n        return false;\n    }\n    function logoutButtons(){\n        var sel = '#ti-logout-btn,[data-ti-logout],.ti-logout-btn';\n        return Array.prototype.slice.call(document.querySelectorAll(sel));\n    }\n    function hideGuestLogout(){\n        var logged = isLogged();\n        logoutButtons().forEach(function(btn){\n            if (!btn) return;\n            if (!logged) {\n                btn.style.setProperty('display','none','important');\n                btn.style.setProperty('visibility','hidden','important');\n                btn.style.setProperty('pointer-events','none','important');\n                btn.setAttribute('aria-hidden','true');\n                btn.dataset.tiGuestHidden505 = '1';\n            } else if (btn.dataset.tiGuestHidden505 === '1') {\n                btn.style.removeProperty('visibility');\n                btn.style.removeProperty('pointer-events');\n                btn.removeAttribute('aria-hidden');\n                btn.dataset.tiGuestHidden505 = '0';\n            }\n        });\n        var loginBtn = byId('ti-login-btn');\n        if (loginBtn && !logged) {\n            loginBtn.style.removeProperty('display');\n            loginBtn.style.setProperty('pointer-events','auto','important');\n        }\n    }\n    function isLogoutTarget(target){\n        if (!target || !target.closest) return null;\n        return target.closest('#ti-logout-btn,[data-ti-logout],.ti-logout-btn');\n    }\n    function blockGuestLogoutEvent(ev){\n        var btn = isLogoutTarget(ev && ev.target);\n        if (!btn) return;\n        if (isLogged()) return;\n        safe(function(){ ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); });\n        hideGuestLogout();\n        return false;\n    }\n    ['click','mousedown','mouseup','touchstart','touchend','pointerdown','pointerup'].forEach(function(evt){\n        try { window.addEventListener(evt, blockGuestLogoutEvent, true); } catch(e) {}\n    });\n    function wrapLogoutNoSession(){\n        if (typeof window.doLogout === 'function' && !window.doLogout.__tiGuestGuard505) {\n            var old = window.doLogout;\n            window.doLogout = function(){\n                if (!isLogged()) {\n                    hideGuestLogout();\n                    safe(function(){ if (window.closeModal) { window.closeModal('ti-conf-ov'); window.closeModal('ti-file-manager-ov'); } });\n                    safe(function(){ var fm = byId('ti-file-manager-ov'); if (fm) fm.style.display = 'none'; });\n                    return false;\n                }\n                return old.apply(this, arguments);\n            };\n            window.doLogout.__tiGuestGuard505 = true;\n        }\n    }\n    function resync(){ hideGuestLogout(); wrapLogoutNoSession(); }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', resync, {once:true});\n    resync();\n    setTimeout(resync, 100);\n    setTimeout(resync, 500);\n    setTimeout(resync, 1500);\n    \/\/ 30.9.1476: rimossi setInterval(resync, 2500) e il MutationObserver che pianificava resync ad ogni\n    \/\/ variazione di style\/class sull'intero documento - confermati come contributo significativo (383ms\n    \/\/ combinato con 506, 112.950 chiamate) al sovraccarico rilevato durante l'apertura di Configurazione. La\n    \/\/ cascata di setTimeout sopra e la delegazione globale eventi in 506 dovrebbero coprire i casi reali senza\n    \/\/ bisogno di sorveglianza continua.\n})();\n<\/script>\n\n\n\n<script id=\"ti-logout-immediate-safe-506\">\n(function(){\n    \"use strict\";\n    if (window.__tiLogoutImmediateSafe506) return;\n    window.__tiLogoutImmediateSafe506 = true;\n    function byId(id){ return document.getElementById(id); }\n    function safe(fn){ try { return fn(); } catch(e) {} }\n    function text(v){ return String(v == null ? '' : v).trim(); }\n    function hasLogin(){\n        var u = text(window.tiUser || '');\n        if (u) return true;\n        var nm = byId('ti-user-name');\n        var nt = nm ? text(nm.textContent || '') : '';\n        if (nt && !\/^(cliente\\\/?utente|cliente|utente|ospite|guest)$\/i.test(nt)) return true;\n        try { return \/(?:^|;\\s*)ti_ai_ss_session=\/.test(document.cookie || ''); } catch(e) { return false; }\n    }\n    function isLogoutElement(el){\n        if (!el || !el.closest) return null;\n        var btn = el.closest('#ti-logout-btn,[data-ti-logout],.ti-logout-btn');\n        if (btn) return btn;\n        \/\/ Fallback prudente: solo pulsanti reali visibili con testo Esci\/Logout, non dentro file manager o altri popup di chiusura.\n        var b = el.closest('button,input[type=\"button\"],a');\n        if (!b) return null;\n        var label = text(b.textContent || b.value || '').toLowerCase();\n        if (!\/^(esci|logout|logoff)$\/.test(label)) return null;\n        if (b.closest('#ti-file-manager-ov,#ti-ai-gen-ov,#ti-progress-ov,#ti-conf-ov,#ti-profile-ov,#ti-activity-report-ov')) return null;\n        return b;\n    }\n    function closeAllUi(){\n        var ids = ['ti-file-manager-ov','ti-ai-gen-ov','ti-conf-ov','ti-login-ov','ti-profile-ov','ti-newdb-ov','ti-new-db-ov','ti-activity-report-ov','ti-delete-company-ov','ti-progress-ov','ti-order-confirm-ov','ti-help-ov','ti-col-help-ov','ti-global-action-ov'];\n        ids.forEach(function(id){\n            var el = byId(id);\n            if (!el) return;\n            el.style.setProperty('display','none','important');\n            el.style.setProperty('visibility','hidden','important');\n            el.style.setProperty('opacity','0','important');\n            el.style.setProperty('pointer-events','none','important');\n            el.classList.add('ti-hidden');\n        });\n        safe(function(){ document.querySelectorAll('.ti-modal-overlay,.ti-modal-backdrop,.ti-ov').forEach(function(el){\n            if (el && el.id !== 'ti-ai-outer') {\n                el.style.setProperty('display','none','important');\n                el.style.setProperty('pointer-events','none','important');\n            }\n        }); });\n        safe(function(){ if (window.cancelActiveConfigAiRequest434) window.cancelActiveConfigAiRequest434('logout_506'); });\n        safe(function(){ if (window.clearLongAIProcess) window.clearLongAIProcess(); });\n        safe(function(){ if (window.hideProgressPopup) window.hideProgressPopup(false, 'Uscita in corso', {notifyUser:false}); });\n        safe(function(){ var chat=byId('ti-chat-box'); if (chat) chat.innerHTML=''; });\n        safe(function(){ var msg=byId('ti-msg'); if (msg) msg.value=''; });\n        safe(function(){ var un=byId('ti-user-name'); if (un) un.textContent='Cliente\/Utente'; });\n        safe(function(){ var ur=byId('ti-user-role'); if (ur) ur.textContent=''; });\n        safe(function(){ var lb=byId('ti-login-btn'); if (lb) lb.style.display='inline-block'; });\n        safe(function(){ var ob=byId('ti-logout-btn'); if (ob) ob.style.display='none'; });\n    }\n    function clearCookie(){\n        safe(function(){ document.cookie = 'ti_ai_ss_session=; Max-Age=0; path=\/; SameSite=Lax'; });\n        safe(function(){ document.cookie = 'ti_ai_ss_session=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=\/'; });\n    }\n    function logoutRequest(){\n        var fd = new FormData();\n        fd.append('ti_action','ti_ai_logout');\n        fd.append('action','ti_ai_logout');\n        fd.append('_ti_logout_immediate','506');\n        var urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) === -1) urls.push(window.tiUrl);\n        if (!urls.length) urls.push(window.location.href.split('#')[0]);\n        try {\n            if (navigator.sendBeacon) {\n                var qs = new URLSearchParams();\n                qs.append('ti_action','ti_ai_logout');\n                qs.append('action','ti_ai_logout');\n                qs.append('_ti_logout_immediate','506');\n                var blob = new Blob([qs.toString()], {type:'application\/x-www-form-urlencoded'});\n                navigator.sendBeacon(urls[0], blob);\n            }\n        } catch(e) {}\n        try { return fetch(urls[0], {method:'POST', body:fd, credentials:'same-origin', keepalive:true, cache:'no-store'}); } catch(e) { return Promise.resolve(); }\n    }\n    function reloadSoon(){\n        setTimeout(function(){ try { window.location.reload(); } catch(e) { window.location.href = window.location.href.split('#')[0]; } }, 120);\n    }\n    window.tiImmediateLogout506 = function(ev){\n        if (ev) safe(function(){ ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); });\n        if (window.__tiLogoutImmediateRunning506) return false;\n        window.__tiLogoutImmediateRunning506 = true;\n        \/\/ Se il pulsante Esci e' visibile senza sessione, non deve aprire nulla: lo nasconde e basta.\n        if (!hasLogin()) {\n            closeAllUi();\n            clearCookie();\n            window.__tiLogoutImmediateRunning506 = false;\n            return false;\n        }\n        closeAllUi();\n        clearCookie();\n        var fail = setTimeout(reloadSoon, 700);\n        Promise.resolve(logoutRequest()).catch(function(){}).finally(function(){ clearTimeout(fail); reloadSoon(); });\n        return false;\n    };\n    function intercept(ev){\n        \/\/ Dopo l'inizio del logout blocca qualunque evento successivo sul layout: evita il click-through verso Gestione File Associati.\n        if (window.__tiLogoutImmediateRunning506) {\n            if (ev) safe(function(){ ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); });\n            return false;\n        }\n        var btn = isLogoutElement(ev && ev.target);\n        if (!btn) return;\n        \/\/ Intercetto SEMPRE prima degli handler nativi: Esci non deve mai aprire Gestione File Associati o altre form.\n        if (ev) safe(function(){ ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); });\n        return window.tiImmediateLogout506(ev);\n    }\n    ['pointerdown','pointerup','mousedown','mouseup','click','touchstart','touchend','keydown'].forEach(function(evt){\n        safe(function(){ window.addEventListener(evt, function(ev){\n            if (evt === 'keydown') {\n                var k = ev && (ev.key || ev.code || '');\n                if (k !== 'Enter' && k !== ' ' && k !== 'Spacebar') return;\n            }\n            intercept(ev);\n        }, true); });\n        safe(function(){ document.addEventListener(evt, function(ev){\n            if (evt === 'keydown') {\n                var k = ev && (ev.key || ev.code || '');\n                if (k !== 'Enter' && k !== ' ' && k !== 'Spacebar') return;\n            }\n            intercept(ev);\n        }, true); });\n    });\n    function bindLogoutButtons(){\n        safe(function(){ document.querySelectorAll('#ti-logout-btn,[data-ti-logout],.ti-logout-btn').forEach(function(btn){\n            if (!btn) return;\n            btn.onclick = function(ev){ return window.tiImmediateLogout506(ev); };\n            btn.onmousedown = function(ev){ return window.tiImmediateLogout506(ev); };\n            btn.ontouchend = function(ev){ return window.tiImmediateLogout506(ev); };\n            if (!hasLogin()) {\n                btn.style.setProperty('display','none','important');\n                btn.style.setProperty('visibility','hidden','important');\n                btn.style.setProperty('pointer-events','none','important');\n            } else {\n                btn.style.removeProperty('visibility');\n                btn.style.setProperty('pointer-events','auto','important');\n            }\n        }); });\n        if (typeof window.doLogout === 'function' && !window.doLogout.__tiImmediate506) {\n            var prev = window.doLogout;\n            window.doLogout = function(){\n                return window.tiImmediateLogout506(null) || false;\n            };\n            window.doLogout.__tiImmediate506 = true;\n            window.doLogout.__prev506 = prev;\n        }\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bindLogoutButtons, {once:true});\n    bindLogoutButtons();\n    setTimeout(bindLogoutButtons, 100);\n    setTimeout(bindLogoutButtons, 500);\n    setTimeout(bindLogoutButtons, 1500);\n    \/\/ 30.9.1476: rimossi setInterval(bindLogoutButtons, 2000) e il MutationObserver che pianificava\n    \/\/ bindLogoutButtons ad ogni variazione di style\/class sull'intero documento - la delegazione globale\n    \/\/ eventi (poco sopra in questa stessa funzione) intercetta gia' i click sui pulsanti indipendentemente da\n    \/\/ un nuovo binding esplicito, rendendo la sorveglianza continua ridondante.\n})();\n<\/script>\n\n<script id=\"ti-config-fast-render-507\">\n(function(){\n    'use strict';\n    if (window.__tiConfigFastRender507Installed) return;\n    window.__tiConfigFastRender507Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(ch){\n            return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[ch];\n        });\n    }\n    function norm(v){\n        try { return String(v == null ? '' : v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/[^a-z0-9]+\/g,''); }\n        catch(e){ return String(v == null ? '' : v).toLowerCase().replace(\/[^a-z0-9]+\/g,''); }\n    }\n    function getDbName(){\n        var d = byId('ti-ditta');\n        return d ? String(d.value || '').trim() : '';\n    }\n    function getCnt(){ return byId('ti-conf-cnt'); }\n    function showOverlay(){\n        var ov = byId('ti-conf-ov');\n        try { if (window.showPluginModal) window.showPluginModal(ov || 'ti-conf-ov'); else if (window.openModal) window.openModal('ti-conf-ov'); }\n        catch(e){ if (ov) ov.style.display = 'flex'; }\n    }\n    function setTitle(txt){ var t=byId('ti-conf-title'); if(t) t.textContent = txt || 'Configurazione'; }\n    function showWait(msg){\n        showOverlay();\n        var c = getCnt();\n        if (!c) return;\n        c.innerHTML = '<div style=\"padding:18px;background:#0f172a;color:#e5e7eb;border:1px solid #334155;border-radius:12px;margin:12px;line-height:1.45;\">'\n            + '<b>Caricamento configurazione<\/b><br>'\n            + '<span style=\"font-size:13px;\">' + esc(msg || 'Lettura dati configurazione in corso...') + '<\/span><br><br>'\n            + '<button type=\"button\" id=\"ti-config-fast-cache-507\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;margin-right:8px;\">Apri dati in memoria<\/button>'\n            + '<button type=\"button\" id=\"ti-config-fast-retry-507\" class=\"ti-btn\" style=\"background:#10b981;color:#fff;margin-right:8px;\">Riprova<\/button>'\n            + '<button type=\"button\" id=\"ti-config-fast-close-507\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\">Chiudi<\/button>'\n            + '<\/div>';\n        bindWaitButtons();\n    }\n    function bindWaitButtons(){\n        var b=byId('ti-config-fast-cache-507'); if(b) b.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation();} return window.openConfigSafe507(ev,false,true); };\n        var r=byId('ti-config-fast-retry-507'); if(r) r.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation();} return window.openConfigSafe507(ev,true,false); };\n        var x=byId('ti-config-fast-close-507'); if(x) x.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation();} window.__tiConfigOpenToken507 = ''; try{ if(window.closeModal) window.closeModal('ti-conf-ov'); }catch(e){} return false; };\n    }\n    function clone(o){ try { return JSON.parse(JSON.stringify(o || {})); } catch(e){ return o || {}; } }\n    function getTables(db){ return (db && db.Tabelle && typeof db.Tabelle === 'object') ? db.Tabelle : {}; }\n    function tableRows(db, tbl){\n        var t = getTables(db)[tbl];\n        if (Array.isArray(t)) return t;\n        if (t && typeof t === 'object') return Object.values(t);\n        return [];\n    }\n    function tableKeys(rows){\n        var seen={}, keys=[];\n        (rows || []).forEach(function(row){\n            if(!row || typeof row !== 'object') return;\n            Object.keys(row).forEach(function(k){ if(!seen[k]){ seen[k]=true; keys.push(k); } });\n        });\n        keys.sort(function(a,b){\n            var pa = (a === 'ID' ? -3 : (\/^(prodotto|servizio|utente|descrizione|tipo|istruzione|username)$\/i.test(a) ? -2 : 0));\n            var pb = (b === 'ID' ? -3 : (\/^(prodotto|servizio|utente|descrizione|tipo|istruzione|username)$\/i.test(b) ? -2 : 0));\n            if(pa !== pb) return pa - pb;\n            return String(a).localeCompare(String(b),'it');\n        });\n        return keys;\n    }\n    function markChanged(tbl, idx, key, el){\n        if(!window.currentDbData || !window.currentDbData.Tabelle || !window.currentDbData.Tabelle[tbl] || !window.currentDbData.Tabelle[tbl][idx]) return;\n        window.currentDbData.Tabelle[tbl][idx][key] = el ? el.value : '';\n        if(!window.modifiedFields) window.modifiedFields = new Set();\n        try { window.modifiedFields.add(tbl + '-' + idx + '-' + key); } catch(e) {}\n        if(el){ el.style.setProperty('border-color','#fbbf24','important'); }\n        try { if(window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n    }\n    window.tiConfigFastMarkChanged507 = markChanged;\n\n    function addRow(tbl){\n        if(!window.currentDbData) window.currentDbData = {Tabelle:{}};\n        if(!window.currentDbData.Tabelle) window.currentDbData.Tabelle = {};\n        if(!Array.isArray(window.currentDbData.Tabelle[tbl])) window.currentDbData.Tabelle[tbl] = [];\n        var rows = window.currentDbData.Tabelle[tbl];\n        var vm1910 = window.currentDbData.__ti_virtual_tables_1698 && window.currentDbData.__ti_virtual_tables_1698[tbl] ? window.currentDbData.__ti_virtual_tables_1698[tbl] : null;\n        var logicalTotal1910 = vm1910 ? Math.max(0,parseInt(vm1910.total||0,10)||0) : rows.length;\n        if(rows.length < logicalTotal1910) rows.length = logicalTotal1910;\n        var keys = tableKeys(rows.filter(function(r){return r&&typeof r==='object';}).slice(0,200));\n        var row = {};\n        keys.forEach(function(k){ row[k] = (k === 'ID') ? (logicalTotal1910 + 1) : ''; });\n        if(!('ID' in row)) row.ID = logicalTotal1910 + 1;\n        var newIndex1910 = logicalTotal1910;\n        rows[newIndex1910] = row;\n        if(vm1910){\n            vm1910.total = logicalTotal1910 + 1;\n            vm1910.pages = Math.max(1,Math.ceil(vm1910.total\/100));\n            vm1910.current_page = vm1910.pages;\n            vm1910.loaded_pages = vm1910.loaded_pages || {};\n            vm1910.loaded_pages[vm1910.current_page] = true;\n            window.__tiFastConfigPages1715 = window.__tiFastConfigPages1715 || {};\n            window.__tiFastConfigPages1715[tbl] = vm1910.current_page;\n        }\n        try {\n            if(!window.tiConfigPendingNewRows1910) window.tiConfigPendingNewRows1910={};\n            if(!Array.isArray(window.tiConfigPendingNewRows1910[tbl])) window.tiConfigPendingNewRows1910[tbl]=[];\n            window.tiConfigPendingNewRows1910[tbl].push({index:newIndex1910});\n        } catch(e1910) {}\n        \/\/ 30.9.1907: una nuova riga e' una modifica strutturale. Non basta il confronto dei campi,\n        \/\/ perche' nello snapshot originale la riga non esiste e il salvataggio puntuale non puo' rappresentarla.\n        try {\n            if(!window.tiConfigStructuralChangedTables1907) window.tiConfigStructuralChangedTables1907 = new Set();\n            window.tiConfigStructuralChangedTables1907.add(tbl);\n            if(!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(tbl + '-' + newIndex1910 + '-__structural_1907');\n            window.modifiedFields.add(tbl + '-' + newIndex1910 + '-__structural_1910');\n        } catch(e) {}\n        renderTable(tbl);\n        try { if(window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n    }\n    window.tiConfigFastAddRow507 = addRow;\n\n    function deleteRow(tbl, idx){\n        if(!window.currentDbData || !window.currentDbData.Tabelle || !Array.isArray(window.currentDbData.Tabelle[tbl])) return;\n        if(!confirm('Eliminare la riga ' + (idx + 1) + ' della tabella ' + tbl + '?')) return;\n        window.currentDbData.Tabelle[tbl].splice(idx,1);\n        \/\/ 30.9.1907: anche la cancellazione modifica la struttura della tabella e richiede full-save compatto.\n        try {\n            if(!window.tiConfigStructuralChangedTables1907) window.tiConfigStructuralChangedTables1907 = new Set();\n            window.tiConfigStructuralChangedTables1907.add(tbl);\n            if(!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(tbl + '-0-__structural_1907');\n            window.modifiedFields.add(tbl + '-0-__structural_1909');\n        } catch(e) {}\n        renderTable(tbl);\n        try { if(window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n    }\n    window.tiConfigFastDeleteRow507 = deleteRow;\n\n    window.__tiFastConfigPages1715 = window.__tiFastConfigPages1715 || {};\n    function fastPageMeta1715(tbl, rows){\n        var vm = null;\n        try { vm = window.currentDbData && window.currentDbData.__ti_virtual_tables_1698 ? window.currentDbData.__ti_virtual_tables_1698[tbl] || null : null; } catch(e) {}\n        var total = vm ? Math.max(0, parseInt(vm.total || 0, 10) || 0) : (Array.isArray(rows) ? rows.length : 0);\n        var pageSize = 100;\n        var pages = Math.max(1, Math.ceil(total \/ pageSize));\n        var page = Math.max(1, Math.min(pages, parseInt(window.__tiFastConfigPages1715[tbl] || (vm && vm.current_page) || 1, 10) || 1));\n        window.__tiFastConfigPages1715[tbl] = page;\n        return {vm:vm,total:total,pageSize:pageSize,pages:pages,page:page};\n    }\n    function fastPager1715(tbl, info, where){\n        if(!info || info.pages <= 1) return '';\n        var from = info.total ? ((info.page - 1) * info.pageSize + 1) : 0;\n        var to = info.total ? Math.min(info.page * info.pageSize, info.total) : 0;\n        var prevDis = info.page <= 1 ? ' disabled' : '';\n        var nextDis = info.page >= info.pages ? ' disabled' : '';\n        var qtbl = esc(tbl).replace(\/&#39;\/g,'\\\\\\'');\n        var bstyle = 'display:inline-flex;align-items:center;justify-content:center;text-align:center;width:30px;min-width:30px;max-width:30px;height:26px;min-height:26px;padding:0;margin:0;border:1px solid #64748b;border-radius:6px;background:#334155;color:#fff;font:900 17px\/1 Arial,Helvetica,sans-serif;cursor:pointer;box-sizing:border-box;';\n        return '<div class=\"ti-fast-cfg-pager-1715\" data-pos=\"'+(where||'top')+'\" style=\"display:flex;align-items:center;justify-content:space-between;gap:8px;margin:6px 0;padding:5px 7px;min-height:30px;background:#172033;border:1px solid #475569;border-radius:7px;color:#fff;position:relative;z-index:50;box-sizing:border-box;\">'\n            + '<span style=\"font-size:10px;font-weight:800;line-height:1.1;white-space:nowrap;\">Righe '+from+'-'+to+' di '+info.total+' \u00b7 Pagina '+info.page+'\/'+info.pages+'<\/span>'\n            + '<span style=\"display:inline-flex;align-items:center;justify-content:center;gap:5px;flex:0 0 auto;\">'\n            + '<button type=\"button\"'+prevDis+' aria-label=\"Pagina precedente\" title=\"Pagina precedente\" style=\"'+bstyle+'\" onclick=\"event.preventDefault();event.stopPropagation();return window.tiConfigFastPage1715(\\''+qtbl+'\\',-1);\">&lt;<\/button>'\n            + '<button type=\"button\"'+nextDis+' aria-label=\"Pagina successiva\" title=\"Pagina successiva\" style=\"'+bstyle+'\" onclick=\"event.preventDefault();event.stopPropagation();return window.tiConfigFastPage1715(\\''+qtbl+'\\',1);\">&gt;<\/button>'\n            + '<\/span><\/div>';\n    }\n    function fastLoaded1715(info){\n        if(!info || !info.vm) return true;\n        if(info.vm.hydrated) return true;\n        var lp = info.vm.loaded_pages || {};\n        return !!(lp[info.page] || lp[String(info.page)]);\n    }\n    function fastRequestPage1715(tbl, info){\n        if(!info || !info.vm || fastLoaded1715(info)) return Promise.resolve(true);\n        if(typeof window.tiConfigPrefetchPage1696 !== 'function') return Promise.resolve(false);\n        try {\n            return Promise.resolve(window.tiConfigPrefetchPage1696(tbl, info.page)).then(function(v){\n                try { if(info.vm) info.vm.current_page = info.page; } catch(e) {}\n                return v !== false;\n            });\n        } catch(e) { return Promise.resolve(false); }\n    }\n    function renderTable(tbl){\n        var holder = byId('ti-config-fast-table-body-' + norm(tbl));\n        if(!holder || !window.currentDbData) return;\n        var rows = tableRows(window.currentDbData, tbl);\n        var info = fastPageMeta1715(tbl, rows);\n        if(info.pages > 1 && !fastLoaded1715(info)){\n            holder.innerHTML = fastPager1715(tbl, info, 'top')\n                + '<div style=\"padding:14px;background:#0f172a;color:#e5e7eb;border:1px solid #334155;border-radius:8px;\">Caricamento pagina <b>'+info.page+'<\/b> di <b>'+info.pages+'<\/b>...<\/div>'\n                + fastPager1715(tbl, info, 'bottom');\n            fastRequestPage1715(tbl, info).then(function(ok){\n                if(ok === false){\n                    holder.innerHTML = fastPager1715(tbl, info, 'top')\n                        + '<div style=\"padding:14px;background:#450a0a;color:#fee2e2;border:1px solid #ef4444;border-radius:8px;\">Pagina non caricata. Premi nuovamente &lt; o &gt; per riprovare.<\/div>'\n                        + fastPager1715(tbl, info, 'bottom');\n                    return;\n                }\n                renderTable(tbl);\n            });\n            return;\n        }\n        var startIdx = (info.page - 1) * info.pageSize;\n        var endIdx = Math.min(info.total, startIdx + info.pageSize);\n        var items = [];\n        for(var ri=startIdx; ri<endIdx; ri++){\n            var rr = rows[ri];\n            if(rr && typeof rr === 'object') items.push({row:rr,idx:ri});\n        }\n        var keyRows = items.map(function(x){return x.row;});\n        if(!keyRows.length){\n            for(var kr=0; kr<rows.length && keyRows.length<200; kr++) if(rows[kr] && typeof rows[kr] === 'object') keyRows.push(rows[kr]);\n        }\n        var keys = tableKeys(keyRows);\n        var html = '<div style=\"display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:8px 0 10px 0;\">'\n            + '<button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;\" onclick=\"window.tiConfigFastAddRow507(\\'' + esc(tbl).replace(\/&#39;\/g,'\\\\\\'') + '\\')\">+ Riga<\/button>'\n            + '<span style=\"font-size:12px;color:#9ca3af;\">' + info.total + ' righe, ' + keys.length + ' campi. Pagina ' + info.page + '\/' + info.pages + ' \u00b7 max 100 righe per pagina.<\/span>'\n            + '<\/div>';\n        if(info.pages > 1) html += fastPager1715(tbl, info, 'top');\n        if(!info.total){\n            html += '<div style=\"padding:10px;background:#111827;border:1px solid #374151;border-radius:8px;color:#cbd5e1;\">Tabella vuota. Usa + Riga per inserire il primo record.<\/div>';\n            holder.innerHTML = html;\n            return;\n        }\n        if(!items.length){\n            html += '<div style=\"padding:10px;background:#111827;border:1px solid #374151;border-radius:8px;color:#cbd5e1;\">Nessuna riga disponibile nella pagina corrente.<\/div>';\n            if(info.pages > 1) html += fastPager1715(tbl, info, 'bottom');\n            holder.innerHTML = html;\n            return;\n        }\n        html += '<div style=\"overflow:auto;max-height:62vh;border:1px solid #334155;border-radius:8px;background:#020617;\">';\n        html += '<table class=\"ti-cfg-table ti-config-fast-table-507\" style=\"border-collapse:collapse;width:max-content;min-width:100%;font-size:12px;\">';\n        html += '<thead><tr><th style=\"position:sticky;left:0;top:0;z-index:3;background:#1f2937;color:#fff;padding:6px;border:1px solid #374151;\">Riga<\/th>';\n        keys.forEach(function(k){ html += '<th style=\"position:sticky;top:0;z-index:2;background:#1f2937;color:#fff;padding:6px;border:1px solid #374151;white-space:nowrap;\">' + esc(k) + '<\/th>'; });\n        html += '<th style=\"position:sticky;right:0;top:0;z-index:3;background:#1f2937;color:#fff;padding:6px;border:1px solid #374151;\">Azioni<\/th><\/tr><\/thead><tbody>';\n        items.forEach(function(it){\n            var row=it.row, idx=it.idx;\n            html += '<tr><td style=\"position:sticky;left:0;z-index:2;background:#111827;color:#e5e7eb;padding:5px;border:1px solid #374151;text-align:center;\">' + (idx+1) + '<\/td>';\n            keys.forEach(function(k){\n                var val = row && row[k] != null ? row[k] : '';\n                var inputId = 'ti-fast-cfg-' + norm(tbl) + '-' + idx + '-' + norm(k);\n                var isLong = String(val).length > 55 || \/istruzioni|descrizione|nota|note|qr|link\/i.test(k);\n                var common = 'id=\"' + inputId + '\" data-tbl=\"' + esc(tbl) + '\" data-idx=\"' + idx + '\" data-key=\"' + esc(k) + '\" onchange=\"window.tiConfigFastMarkChanged507(\\'' + esc(tbl).replace(\/&#39;\/g,'\\\\\\'') + '\\',' + idx + ',\\'' + esc(k).replace(\/&#39;\/g,'\\\\\\'') + '\\',this)\" oninput=\"this.dataset.dirty=1\"';\n                html += '<td style=\"padding:4px;border:1px solid #1f2937;vertical-align:top;background:#0b1120;\">';\n                if(isLong) html += '<textarea ' + common + ' rows=\"2\" style=\"min-width:220px;max-width:360px;background:#111827;color:#fff;border:1px solid #374151;border-radius:5px;padding:5px;\">' + esc(val) + '<\/textarea>';\n                else html += '<input ' + common + ' value=\"' + esc(val) + '\" style=\"min-width:120px;background:#111827;color:#fff;border:1px solid #374151;border-radius:5px;padding:5px;\">';\n                html += '<\/td>';\n            });\n            html += '<td style=\"position:sticky;right:0;background:#111827;padding:5px;border:1px solid #374151;\"><button type=\"button\" class=\"ti-btn\" style=\"background:#991b1b;color:#fff;font-size:11px;padding:5px 7px;\" onclick=\"window.tiConfigFastDeleteRow507(\\'' + esc(tbl).replace(\/&#39;\/g,'\\\\\\'') + '\\',' + idx + ')\">Elimina<\/button><\/td>';\n            html += '<\/tr>';\n        });\n        html += '<\/tbody><\/table><\/div>';\n        if(info.pages > 1) html += fastPager1715(tbl, info, 'bottom');\n        holder.innerHTML = html;\n        try { if(info.vm) info.vm.current_page = info.page; } catch(e) {}\n        try { if (window.ensureAuthorizedConfigInputsEditable512) window.ensureAuthorizedConfigInputsEditable512(holder); } catch(e) {}\n        if(info.vm && info.page < info.pages){ try { setTimeout(function(){ window.tiConfigPrefetchPage1696 && window.tiConfigPrefetchPage1696(tbl, info.page + 1); }, 80); } catch(e) {} }\n    }\n    window.tiConfigFastRenderTable507 = renderTable;\n    window.tiConfigFastPage1715 = function(tbl, delta){\n        var rows = tableRows(window.currentDbData || {}, tbl), info = fastPageMeta1715(tbl, rows);\n        var next = Math.max(1, Math.min(info.pages, info.page + (parseInt(delta,10) || 0)));\n        if(next === info.page) return false;\n        window.__tiFastConfigPages1715[tbl] = next;\n        try { if(info.vm) info.vm.current_page = next; } catch(e) {}\n        renderTable(tbl);\n        return false;\n    };\n    try { console.info('[Shop-Service] Config pager 1715 pronto',{pageSize:100,insideTable:true,topAndBottom:true}); } catch(e) {}\n\n    function renderLite(sourceLabel){\n        var db = window.currentDbData || {Tabelle:{}};\n        var tables = Object.keys(getTables(db)).filter(function(t){ return t && t !== 'undefined'; });\n        setTitle('Impostazioni ' + (window.currentDittaName || getDbName() || 'Ditta') + ' - caricamento rapido');\n        var c = getCnt();\n        if(!c) return false;\n        var html = '<div id=\"ti-config-fast-507\" style=\"padding:12px;color:#e5e7eb;\">'\n            + '<div style=\"background:#082f49;border:1px solid #0284c7;border-radius:12px;padding:12px;margin-bottom:12px;line-height:1.45;\">'\n            + '<b>Configurazione caricata in modalit\u00e0 rapida<\/b><br>'\n            + '<span style=\"font-size:13px;\">Origine: ' + esc(sourceLabel || 'database') + '. Le tabelle vengono renderizzate solo quando vengono aperte, evitando blocchi della pagina.<\/span><br>'\n            + '<span style=\"font-size:12px;color:#bae6fd;\">Database: ' + esc((db && db.Database) || getDbName()) + ' - Tabelle: ' + tables.length + '<\/span>'\n            + '<\/div>'\n            + '<div style=\"background:#111827;border:1px solid #334155;border-radius:12px;padding:12px;margin-bottom:12px;\">'\n            + '<h4 style=\"margin:0 0 8px 0;color:#fff;\">Istruzioni AI configurazione<\/h4>'\n            + '<textarea id=\"ti-conf-ai-prompt\" class=\"ti-in\" rows=\"7\" placeholder=\"Scrivi qui la richiesta per la AI di configurazione.\" style=\"min-height:150px;line-height:1.45;width:100%;\"><\/textarea>'\n            + '<div id=\"ti-conf-ai-chat-actions\" style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;\">'\n            + '<button type=\"button\" id=\"ti-conf-ai-send\" class=\"ti-btn\" style=\"background:#10b981;color:#fff;font-weight:800;\" onclick=\"window.runConfigBot&&window.runConfigBot();return false;\">Invia<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;\" onclick=\"window.verifyInstructionsArchive&&window.verifyInstructionsArchive();return false;\">Verifica istruzioni<\/button>'\n            + '<button type=\"button\" class=\"ti-btn\" style=\"background:#1d4ed8;color:#fff;\" onclick=\"window.openActivityReport&&window.openActivityReport();return false;\">Report Attivit\u00e0<\/button>'\n            + '<\/div><div id=\"ti-conf-ai-reply\" style=\"display:none;\"><\/div><\/div>';\n        if(!tables.length){\n            html += '<div style=\"padding:14px;background:#111827;border:1px solid #374151;border-radius:10px;\">Nessuna tabella trovata nel database.<\/div>';\n        } else {\n            tables.forEach(function(t){\n                var rows = tableRows(db,t);\n                var vm1715 = db && db.__ti_virtual_tables_1698 ? db.__ti_virtual_tables_1698[t] || null : null;\n                var total1715 = vm1715 ? (parseInt(vm1715.total || 0,10) || rows.length) : rows.length;\n                html += '<details class=\"ti-cfg-details ti-config-fast-details-507\" data-tbl=\"' + esc(t) + '\" style=\"background:#111827;margin-bottom:8px;border-radius:10px;border:1px solid #334155;\">'\n                    + '<summary style=\"cursor:pointer;padding:10px 12px;color:#fff;font-weight:700;display:flex;justify-content:space-between;gap:10px;align-items:center;\">'\n                    + '<span>' + esc(t) + '<\/span><span style=\"font-size:12px;color:#93c5fd;\">' + total1715 + ' righe<\/span><\/summary>'\n                    + '<div id=\"ti-config-fast-table-body-' + norm(t) + '\" style=\"padding:8px 10px 12px 10px;\"><button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;\" onclick=\"window.tiConfigFastRenderTable507(\\'' + esc(t).replace(\/&#39;\/g,'\\\\\\'') + '\\')\">Apri tabella<\/button><\/div>'\n                    + '<\/details>';\n            });\n        }\n        html += '<\/div>';\n        c.innerHTML = html;\n        c.scrollTop = 0;\n        Array.prototype.slice.call(c.querySelectorAll('details.ti-config-fast-details-507')).forEach(function(det){\n            det.addEventListener('toggle', function(){ if(det.open){ var tbl = det.getAttribute('data-tbl') || ''; var body = byId('ti-config-fast-table-body-' + norm(tbl)); if(body && body.querySelector('button')) renderTable(tbl); } });\n        });\n        try { if(window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        try { if(window.syncConfiguratorOperationalTipsFlagUI) window.syncConfiguratorOperationalTipsFlagUI(); } catch(e) {}\n        window.__tiConfigRenderedOk507 = true;\n        return true;\n    }\n    window.tiConfigFastRender507 = renderLite;\n\n    function fetchDb(db, token){\n        var fd;\n        try { if(window.buildAjaxFormData) fd = window.buildAjaxFormData('ti_ai_get_db_data', {db:db, ti_config_open:'1', rescue:'507'}); } catch(e) {}\n        if(!fd){ fd = new FormData(); fd.append('action','ti_ai_get_db_data'); fd.append('ti_action','ti_ai_get_db_data'); fd.append('db',db); fd.append('ti_config_open','1'); fd.append('rescue','507'); }\n        try { if(!fd.has('action')) fd.append('action','ti_ai_get_db_data'); if(!fd.has('ti_action')) fd.append('ti_action','ti_ai_get_db_data'); } catch(e) {}\n        return fetch(window.tiUrl || location.href, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'}).then(function(r){ return r.text(); }).then(function(txt){\n            var res;\n            try { res = JSON.parse(txt); } catch(e){ throw new Error('Risposta non JSON durante lettura configurazione. Inizio risposta: ' + txt.slice(0,180)); }\n            if(!res || !res.success) throw new Error((res && res.data && (res.data.message || res.data)) || 'Lettura database non riuscita.');\n            if(window.__tiConfigOpenToken507 !== token) return false;\n            window.currentDbData = res.data || {Tabelle:{}};\n            window.configOriginalDbData = clone(window.currentDbData);\n            window.configWasSaved = false;\n            if(window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear();\n            try { localStorage.setItem('ti_config_cache_507_' + db, JSON.stringify(window.currentDbData)); } catch(e) {}\n            renderLite('server');\n            return true;\n        });\n    }\n\n    function cachedDb(db){\n        if (window.__tiForceDbRefreshNext1204) { window.__tiForceDbRefreshNext1204 = false; return null; }\n        if(window.currentDbData && window.currentDbData.Tabelle) return window.currentDbData;\n        try { var s = localStorage.getItem('ti_config_cache_507_' + db); if(s) return JSON.parse(s); } catch(e) {}\n        return null;\n    }\n\n    window.openConfigSafe507 = function(ev, forceReload, cacheOnly){\n        if(ev){ try { ev.preventDefault(); ev.stopPropagation(); } catch(e){} }\n        var db = getDbName();\n        if(!db){ try { if(window.tiAlert) window.tiAlert('Seleziona una ditta prima di aprire la configurazione.'); else alert('Seleziona una ditta prima di aprire la configurazione.'); } catch(e){} return false; }\n        var token = String(Date.now()) + '-' + Math.random();\n        window.__tiConfigOpenToken507 = token;\n        window.__tiConfigRenderedOk507 = false;\n        showWait('Lettura database della ditta ' + db + '.');\n        var cdb = cachedDb(db);\n        if(cacheOnly && cdb){ window.currentDbData = cdb; renderLite('dati in memoria'); return false; }\n        var slow = setTimeout(function(){\n            if(window.__tiConfigOpenToken507 !== token || window.__tiConfigRenderedOk507) return;\n            var cd = cachedDb(db);\n            if(cd){ window.currentDbData = cd; renderLite('cache mentre il server risponde'); }\n            else showWait('Il server sta impiegando piu del previsto. Puoi aprire dati in memoria, riprovare o chiudere.');\n        }, 1800);\n        fetchDb(db, token).catch(function(err){\n            if(window.__tiConfigOpenToken507 !== token) return;\n            var cd = cachedDb(db);\n            if(cd){ window.currentDbData = cd; renderLite('cache dopo errore server'); return; }\n            var c = getCnt();\n            if(c) c.innerHTML = '<div style=\"padding:18px;margin:12px;background:#450a0a;color:#fee2e2;border:1px solid #ef4444;border-radius:12px;line-height:1.45;\">'\n                + '<b>Configurazione non caricata.<\/b><br>' + esc(err && err.message ? err.message : err)\n                + '<br><br><button type=\"button\" class=\"ti-btn\" style=\"background:#2563eb;color:#fff;margin-right:8px;\" onclick=\"window.openConfigSafe507(event,true,false)\">Riprova<\/button>'\n                + '<button type=\"button\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\" onclick=\"window.closeModal&&window.closeModal(\\'ti-conf-ov\\')\">Chiudi<\/button><\/div>';\n        }).finally(function(){ clearTimeout(slow); try { window.__tiConfigReadWaitActive503 = false; } catch(e){} });\n        return false;\n    };\n\n    var previousRender = window.renderConfig;\n    window.renderConfigFullLegacy507 = previousRender;\n    window.renderConfig = function(){\n        try {\n            if(window.__tiPreferLegacyConfigRender507 && typeof previousRender === 'function') return previousRender.apply(this, arguments);\n        } catch(e) {}\n        try { return renderLite('render rapido'); }\n        catch(e) {\n            try { console.error('Shop & Service Config fast render 507 error', e); } catch(x) {}\n            if(typeof previousRender === 'function') return previousRender.apply(this, arguments);\n        }\n    };\n\n    ['openConfigSafe506','openConfigSafe505','openConfigSafe504','openConfigSafe503','openConfigSafe502','openConfigSafe501','openConfigSafe492','openConfigSafe491','openConfigSafe490','openConfigSafe489','openConfigSafe488','openConfigSafe218'].forEach(function(n){ window[n] = window.openConfigSafe507; });\n\n    function bind(){\n        var b = byId('ti-conf-toggle');\n        if(b){ b.onclick = window.openConfigSafe507; b.setAttribute('data-ti-config-open-rescue','507'); }\n    }\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if(!t || !t.closest) return;\n        var b = t.closest('#ti-conf-toggle, #ti-config-fast-retry-507, #ti-config-fast-cache-507');\n        if(!b) return;\n        ev.preventDefault(); ev.stopPropagation();\n        if(b.id === 'ti-config-fast-cache-507') return window.openConfigSafe507(ev,false,true);\n        return window.openConfigSafe507(ev, b.id !== 'ti-conf-toggle', false);\n    }, true);\n    if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bind); else bind();\n    setTimeout(bind, 300); setTimeout(bind, 1200);\n})();\n\n\nvar tiGlobalStorageStyle1639 = document.getElementById('ti-global-storage-style-1639');\nif (!tiGlobalStorageStyle1639) {\n    tiGlobalStorageStyle1639 = document.createElement('style');\n    tiGlobalStorageStyle1639.id = 'ti-global-storage-style-1639';\n    tiGlobalStorageStyle1639.textContent =\n        '#ti-ai-outer #ti-global-storage-stack-1639{display:flex;flex:1 1 0;min-width:0;flex-direction:column;gap:3px;align-items:stretch;justify-content:flex-start;box-sizing:border-box;}' +\n        '#ti-ai-outer #ti-global-storage-stack-1639>.ti-btn{width:100%!important;max-width:none!important;min-width:0!important;flex:0 0 auto!important;margin:0!important;}' +\n        '#ti-ai-outer #ti-global-storage-stack-1639[style*=\\\"display: none\\\"]{display:none!important;}';\n    document.head.appendChild(tiGlobalStorageStyle1639);\n}\n\n(function(){\n    if (window.__tiBottomButtonsCompact508) return;\n    window.__tiBottomButtonsCompact508 = true;\n    function byId(id){ return document.getElementById(id); }\n    function stripIcons(txt){\n        txt = String(txt || '').replace(\/<[^>]*>\/g, ' ');\n        txt = txt.replace(\/[\\u{1F300}-\\u{1FAFF}\\u{2600}-\\u{27BF}]\/gu, ' ');\n        txt = txt.replace(\/[\u2699\ufe0f\u26a1\ud83d\uded2\ud83e\uddf9\ud83d\uddd1\ud83e\ude84\ud83d\uddc2\ud83d\udcca\ud83d\udcc1\ud83e\udd16\ud83d\udd0a\ud83d\udd07\ud83c\udfa4\ud83d\udcf7]\/g, ' ');\n        return txt.replace(\/\\s+\/g, ' ').trim();\n    }\n    var labels = {\n        'ti-new':{it:'Nuova',en:'New'},\n        'ti-copy':{it:'Copia testo',en:'Copy text'},\n        'ti-file':{it:'File',en:'File'},\n        'ti-products-btn':{it:'Prodotti',en:'Products'},\n        'ti-services-btn':{it:'Servizi',en:'Services'},\n        'ti-activities-btn':{it:'Attivita',en:'Activities'},\n        'ti-kbd-btn':{it:'Tastiera',en:'Keyboard'},\n        'ti-mic':{it:'Mic',en:'Mic'},\n        'ti-cam':{it:'Cam',en:'Cam'},\n        'ti-mute-btn':{it:'Audio',en:'Audio'},\n        'ti-help-btn':{it:'?',en:'?'},\n        'ti-conf-toggle':{it:'Configura',en:'Configure'},\n        \/\/ 30.9.2018: ti-activation-toggle e dinamico (Attiva \/ Abbonati \/ Aggiungi AI).\n        \/\/ Non assegnare una label statica che sovrascriva lo stato commerciale reale.\n        'ti-purchase-toggle':{it:'Acquisizioni',en:'Acquisitions'},\n        'ti-clean-orphans-btn':{it:'Pulisci',en:'Clean'},\n        'ti-delete-company-toggle':{it:'Cancella',en:'Delete'},\n        'ti-global-action-toggle':{it:'Globale',en:'Global'},\n        'ti-shared-setup-toggle':{it:'Storage',en:'Storage'}\n    };\n    function labelFor508(id){\n        var item = labels[id];\n        if (!item) return '';\n        var lang = String(window.currLang || window.tiLang || 'it').toLowerCase();\n        return lang.indexOf('en') === 0 ? (item.en || item.it || '') : (item.it || item.en || '');\n    }\n    function setPlainButton(btn, label){\n        if (!btn) return;\n        var id = btn.id || '';\n        \/\/ 30.9.2018: il pulsante commerciale mantiene sempre la label calcolata\n        \/\/ da refreshShopServiceActivationButton (Attiva \/ Abbonati \/ Aggiungi AI).\n        var finalLabel = (id === 'ti-activation-toggle')\n            ? stripIcons(btn.textContent || btn.innerHTML || '')\n            : (label || labelFor508(id) || stripIcons(btn.textContent || btn.innerHTML || ''));\n        if (String(window.currLang || window.tiLang || 'it').toLowerCase().indexOf('en') === 0 && window.tiTranslateLayoutString) {\n            try { finalLabel = window.tiTranslateLayoutString(finalLabel); } catch(e) {}\n        }\n        if (!finalLabel) finalLabel = stripIcons(btn.getAttribute('aria-label') || btn.getAttribute('title') || id || '');\n        if (id === 'ti-mute-btn') {\n            var t = stripIcons(btn.textContent || '');\n            var en508 = String(window.currLang || window.tiLang || 'it').toLowerCase().indexOf('en') === 0;\n            if (\/auto\/i.test(t)) finalLabel = 'Audio Auto';\n            else if (\/off sessione|off session|off\\s*s\\b\/i.test(t)) finalLabel = 'OFF S';\n            else if (\/off\/i.test(t)) finalLabel = 'Audio OFF';\n            else if (\/on\/i.test(t)) finalLabel = 'Audio ON';\n            else finalLabel = en508 ? 'Audio' : 'Audio';\n        }\n        btn.textContent = finalLabel;\n        btn.setAttribute('data-ti-compact-508', '1');\n        btn.style.setProperty('font-size', id === 'ti-help-btn' ? '11px' : '9.5px', 'important');\n        btn.style.setProperty('height', '27px', 'important');\n        btn.style.setProperty('min-height', '27px', 'important');\n        btn.style.setProperty('padding', id === 'ti-help-btn' ? '0' : '3px 4px', 'important');\n        btn.style.setProperty('min-width', '0', 'important');\n        btn.style.setProperty('max-width', id === 'ti-help-btn' ? '28px' : 'none', 'important');\n        btn.style.setProperty('width', id === 'ti-help-btn' ? 'auto' : 'auto', 'important');\n        btn.style.setProperty('white-space', 'nowrap', 'important');\n        btn.style.setProperty('overflow', 'hidden', 'important');\n        btn.style.setProperty('text-overflow', 'ellipsis', 'important');\n        btn.style.setProperty('line-height', '1', 'important');\n        btn.style.setProperty('border-radius', '6px', 'important');\n        btn.style.setProperty('gap', '0', 'important');\n        btn.style.setProperty('display', btn.style.display === 'none' ? 'none' : 'flex', 'important');\n        btn.style.setProperty('align-items', 'center', 'important');\n        btn.style.setProperty('justify-content', 'center', 'important');\n        if (id === 'ti-help-btn') btn.style.setProperty('flex', '0 1 26px', 'important');\n        else btn.style.setProperty('flex', '1 1 0', 'important');\n    }\n    function compactRow(row){\n        if (!row) return;\n        row.style.setProperty('width', '100%', 'important');\n        row.style.setProperty('box-sizing', 'border-box', 'important');\n        row.style.setProperty('display', row.style.display === 'none' ? 'none' : 'flex', 'important');\n        row.style.setProperty('flex-direction', 'row', 'important');\n        row.style.setProperty('flex-wrap', 'nowrap', 'important');\n        row.style.setProperty('gap', '4px', 'important');\n        row.style.setProperty('overflow', 'hidden', 'important');\n        row.style.setProperty('align-items', 'stretch', 'important');\n        row.style.setProperty('justify-content', 'stretch', 'important');\n    }\n    window.tiCompactMainBottomButtons508 = function(){\n        try {\n            var adminRow = byId('ti-admin-actions-row');\n            compactRow(adminRow);\n            if (adminRow) Array.prototype.slice.call(adminRow.querySelectorAll('button,.ti-btn')).forEach(function(b){ setPlainButton(b); });\n        } catch(e) { try { console.warn('Shop & Service compact bottom buttons 508 error', e); } catch(x) {} }\n    };\n    var prevSetAdminUI = window.setAdminUI;\n    if (typeof prevSetAdminUI === 'function' && !prevSetAdminUI.__tiCompact508) {\n        window.setAdminUI = function(){\n            var r = prevSetAdminUI.apply(this, arguments);\n            setTimeout(window.tiCompactMainBottomButtons508, 0);\n            setTimeout(window.tiCompactMainBottomButtons508, 250);\n            return r;\n        };\n        window.setAdminUI.__tiCompact508 = true;\n    }\n    var prevApplyLayoutLang = window.applyLayoutLanguage;\n    if (typeof prevApplyLayoutLang === 'function' && !prevApplyLayoutLang.__tiCompact508) {\n        window.applyLayoutLanguage = function(){\n            var r = prevApplyLayoutLang.apply(this, arguments);\n            setTimeout(window.tiCompactMainBottomButtons508, 0);\n            return r;\n        };\n        window.applyLayoutLanguage.__tiCompact508 = true;\n    }\n    \/\/ 30.9.1484: rimosso observer globale 508; layout aggiornato dai wrapper UI e dai tentativi iniziali.\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', window.tiCompactMainBottomButtons508); else window.tiCompactMainBottomButtons508();\n    setTimeout(window.tiCompactMainBottomButtons508, 300);\n    setTimeout(window.tiCompactMainBottomButtons508, 1000);\n    setTimeout(window.tiCompactMainBottomButtons508, 2000);\n})();\n\n\n(function(){\n    'use strict';\n    if (window.__tiConfigFullMode509Installed) return;\n    window.__tiConfigFullMode509Installed = true;\n    window.__tiPreferLegacyConfigRender507 = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(ch){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[ch]; }); }\n    function clone(o){ try { return JSON.parse(JSON.stringify(o || {})); } catch(e){ return o || {}; } }\n    function getDbName(){ var d=byId('ti-ditta'); return d ? String(d.value || '').trim() : ''; }\n    function getCnt(){ return byId('ti-conf-cnt'); }\n    function showOverlay(){\n        var ov=byId('ti-conf-ov');\n        try { if (window.showPluginModal) window.showPluginModal(ov || 'ti-conf-ov'); else if (window.openModal) window.openModal('ti-conf-ov'); else if (ov) ov.style.display='flex'; }\n        catch(e){ if (ov) ov.style.display='flex'; }\n    }\n    function closeOverlay(){ try { if(window.closeModal) window.closeModal('ti-conf-ov'); } catch(e){} }\n    function setTitle(){ var t=byId('ti-conf-title'); if(t) t.textContent='Configurazione'; }\n    function setWait(msg){\n        showOverlay(); setTitle();\n        var c=getCnt(); if(!c) return;\n        \/\/ 30.9.1350: rimossi anche qui i pulsanti (Riprova\/Apri dati in memoria\/Esci\/Chiudi) - stessa causa gia'\n        \/\/ corretta in showError: apparivano visibili durante il normale caricamento, prima di essere sostituiti\n        \/\/ dal contenuto vero e proprio, risultando un inutile \"flash\" di pulsanti.\n        c.innerHTML = '<div style=\"padding:18px;background:#0f172a;color:#e5e7eb;border:1px solid #334155;border-radius:12px;margin:12px;line-height:1.45;\">'\n            + '<b>Caricamento configurazione completa<\/b><br>'\n            + '<span style=\"font-size:13px;\">' + esc(msg || 'Lettura dati e apertura tabelle complete in corso...') + '<\/span>'\n            + '<\/div>';\n    }\n    function bindWaitButtons(){\n        var r=byId('ti-config-full-retry-509'); if(r) r.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation();} return window.openConfigSafe509(ev,true,false); };\n        var b=byId('ti-config-full-cache-509'); if(b) b.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation();} return window.openConfigSafe509(ev,false,true); };\n        var e=byId('ti-config-full-exit-510'); if(e) e.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation();} if(window.tiExitConfigLoading510) return window.tiExitConfigLoading510('Caricamento configurazione interrotto. Ripeti l apertura della Configurazione.'); window.__tiConfigOpenToken509=''; closeOverlay(); return false; };\n        var x=byId('ti-config-full-close-509'); if(x) x.onclick=function(ev){ if(ev){ev.preventDefault(); ev.stopPropagation();} window.__tiConfigOpenToken509=''; closeOverlay(); return false; };\n    }\n    function legacyRenderer(){\n        var r = window.renderConfigFullLegacy507;\n        if (typeof r === 'function') return r;\n        if (window.renderConfig && window.renderConfig !== legacyRenderWrapper) return window.renderConfig;\n        return null;\n    }\n    function legacyRenderWrapper(){ return renderFull('wrapper'); }\n    function renderFull(source){\n        window.__tiPreferLegacyConfigRender507 = true;\n        showOverlay(); setTitle();\n        var r = legacyRenderer();\n        if (typeof r === 'function') {\n            try {\n                var ret = r.call(window);\n                setTimeout(function(){\n                    try { if (window.forceConfigAiUi) window.forceConfigAiUi(); } catch(e){}\n                    try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e){}\n                }, 60);\n                try { console.log('Shop & Service Configurazione completa aperta 509:', source || ''); } catch(e){}\n                return ret;\n            } catch(e) {\n                throw e;\n            }\n        }\n        throw new Error('Renderer configurazione completa non disponibile.');\n    }\n    function cachedDb(db){\n        try {\n            if (window.__tiForceDbRefreshNext1204) { window.__tiForceDbRefreshNext1204 = false; return null; }\n            if(window.currentDbData && window.currentDbData.Tabelle){\n                var curDb = String(window.currentDbData.Database || window.currentDbData.database || window.currentDbData.__db || '').replace(\/\\.json$\/i,'');\n                var reqDb = String(db || '').replace(\/\\.json$\/i,'');\n                if(!curDb || curDb === reqDb) return window.currentDbData;\n            }\n        } catch(e){}\n        try { var s = localStorage.getItem('ti_config_cache_507_' + db) || localStorage.getItem('ti_config_cache_509_' + db); if(s) return JSON.parse(s); } catch(e){}\n        return null;\n    }\n    function prepareData(data, db){\n        data = data || {Tabelle:{}};\n        try {\n            var vm=data.__ti_virtual_tables_1698||{}, tabs=data.Tabelle||{};\n            Object.keys(vm).forEach(function(tbl){\n                var m=vm[tbl]||{}, first=Array.isArray(tabs[tbl])?tabs[tbl]:[], total=Math.max(first.length,parseInt(m.total||0,10)||0), sparse=new Array(total);\n                first.forEach(function(row,i){ sparse[i]=row; });\n                tabs[tbl]=sparse; m.current_page=1; m.loaded_pages={1:true}; m.hydrated=(total<=first.length)?1:0; vm[tbl]=m;\n            });\n        } catch(e) { try{console.warn('[Shop-Service] virtual config prepare 1698',e);}catch(_e){} }\n        window.currentDbData = data;\n        window.configOriginalDbData = clone(window.currentDbData);\n        window.configWasSaved = false;\n        try { if(window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); } catch(e){}\n        try { if(typeof window.tiPrimeConfigPageCache1696==='function') window.tiPrimeConfigPageCache1696(window.currentDbData,db); } catch(e){}\n        try {\n            var totalRows1696=0, tabs1696=(window.currentDbData&&window.currentDbData.Tabelle)||{};\n            Object.keys(tabs1696).forEach(function(k){ if(Array.isArray(tabs1696[k])) totalRows1696+=tabs1696[k].length; });\n            if(totalRows1696<=1200){\n                var cacheText1696=JSON.stringify(window.currentDbData);\n                localStorage.setItem('ti_config_cache_509_' + db, cacheText1696);\n                localStorage.setItem('ti_config_cache_507_' + db, cacheText1696);\n            }\n        } catch(e){}\n    }\n    function buildFd(db){\n        var fd = null;\n        try { if(window.buildAjaxFormData) fd = window.buildAjaxFormData('ti_ai_get_db_data', {db:db, ti_config_open:'1', rescue:'509', full_config:'1', ti_config_fast_1696:'1', ti_config_virtual_1698:'1'}); } catch(e){}\n        if(!fd){ fd = new FormData(); fd.append('action','ti_ai_get_db_data'); fd.append('ti_action','ti_ai_get_db_data'); fd.append('db',db); fd.append('ti_config_open','1'); fd.append('rescue','509'); fd.append('full_config','1'); fd.append('ti_config_fast_1696','1'); fd.append('ti_config_virtual_1698','1'); }\n        try { if(!fd.has('action')) fd.append('action','ti_ai_get_db_data'); if(!fd.has('ti_action')) fd.append('ti_action','ti_ai_get_db_data'); if(!fd.has('ti_config_fast_1696')) fd.append('ti_config_fast_1696','1'); if(!fd.has('ti_config_virtual_1698')) fd.append('ti_config_virtual_1698','1'); } catch(e){}\n        return fd;\n    }\n    function fetchDb(db, token){\n        var url = location.href.split('?')[0]; \/\/ 30.9.1698: Configurazione virtuale usa sempre il router diretto della pagina, non admin-ajax.\n        var opts = {method:'POST', body:buildFd(db), credentials:'same-origin', cache:'no-store'};\n        try { if(window.__tiConfigOpenAbort510 && window.__tiConfigOpenAbort510.signal) opts.signal = window.__tiConfigOpenAbort510.signal; } catch(e){}\n        \/\/ 30.9.1341: timeout esplicito (in precedenza assente) - senza questo, se il server non risponde mai\n        \/\/ (non solo lentamente ma bloccato), la richiesta restava in attesa indefinita, senza alcun percorso\n        \/\/ per fallire e proporre un recupero (Riprova\/Apri dati in memoria) - coerente con l'aggravamento\n        \/\/ osservato (\"ancora bloccato anche dopo F5\"). Riusa lo STESSO controller gia' assegnato al segnale\n        \/\/ sopra (non uno separato, che verrebbe sovrascritto) - 25s di margine, oltre il tempo di risposta\n        \/\/ piu' lungo osservato finora (~10s).\n        var timer1341 = null;\n        var abortedByTimeout1341 = false;\n        try {\n            var ctl1341 = window.__tiConfigOpenAbort510;\n            if (ctl1341 && ctl1341.abort) timer1341 = setTimeout(function(){ abortedByTimeout1341 = true; try { ctl1341.abort(); } catch(e){} }, 75000);\n        } catch(e) {}\n        function logFetchDb1109(msg){\n            try {\n                var st = window.__tiNativeFileUploadState || {};\n                if (!st.uploadLogLines821) st.uploadLogLines821 = [];\n                var d = new Date();\n                var ts = d.toLocaleTimeString('it-IT',{hour12:false}) + '.' + String(d.getMilliseconds()).padStart(3,'0');\n                st.uploadLogLines821.push('[' + ts + '] fetchDb_1109 - ' + msg);\n                window.__tiNativeFileUploadState = st;\n            } catch(e) {}\n        }\n        logFetchDb1109('avvio lettura database completo db=' + db);\n        var t0_1109 = Date.now();\n        return fetch(url, opts).then(function(r){ try { clearTimeout(timer1341); } catch(e){} logFetchDb1109('risposta ricevuta dopo ' + (Date.now()-t0_1109) + 'ms, status=' + r.status); return r.text(); }).then(function(txt){\n            logFetchDb1109('corpo letto, len=' + txt.length + ' tempo totale=' + (Date.now()-t0_1109) + 'ms');\n            var res;\n            try { res = JSON.parse(txt); } catch(e){ throw new Error('Risposta non JSON durante lettura configurazione completa. Inizio risposta: ' + txt.slice(0,180)); }\n            if(!res || !res.success) throw new Error((res && res.data && (res.data.message || res.data)) || 'Lettura database non riuscita.');\n            try {\n                if (res.data && res.data.__timing_1342) {\n                    var tm = res.data.__timing_1342;\n                    var timingMsg = 'DIAGNOSTICA 1342 tempi server ti_ai_get_db_data: precheck=' + tm.precheck_ms + 'ms, lettura_db=' + tm.read_db_ms + 'ms, filtro_attivita=' + tm.filter_activities_ms + 'ms, lettura_template=' + tm.read_template_ms + 'ms, totale_server=' + tm.total_ms_so_far + 'ms, totale_rete_incl_trasferimento=' + (Date.now()-t0_1109) + 'ms';\n                    console.log(timingMsg);\n                    if (window.log1088) window.log1088(timingMsg);\n                }\n            } catch(eTm1342) {}\n            if(window.__tiConfigOpenToken509 !== token) return false;\n            prepareData(res.data || {Tabelle:{}}, db);\n            renderFull('server');\n            window.__tiConfigOpenToken509 = '';\n            try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'Configurazione caricata', {notifyUser:false}); } catch(e){}\n            try { if (window.closeProgressPopup) window.closeProgressPopup(); } catch(e){}\n            return true;\n        }).catch(function(err){\n            try { clearTimeout(timer1341); } catch(e){}\n            if (err && err.name === 'AbortError' && abortedByTimeout1341) {\n                logFetchDb1109('TIMEOUT dopo ' + (Date.now()-t0_1109) + 'ms (75s) - nessuna risposta dal server');\n                throw new Error('Il server non ha risposto entro 75 secondi. Riprova, oppure verifica la connessione.');\n            }\n            throw err;\n        });\n    }\n    window.openConfigSafe509 = function(ev, forceReload, cacheOnly){\n        if(ev){ try { ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e){} }\n        var db = getDbName();\n        if(!db){ try { if(window.tiAlert) window.tiAlert('Seleziona una ditta prima di aprire la configurazione.'); else alert('Seleziona una ditta prima di aprire la configurazione.'); } catch(e){} return false; }\n        \/\/ 30.9.1336: protezione contro chiamate multiple ravvicinate (da qualsiasi origine: click utente,\n        \/\/ riapertura automatica dopo salvataggio, click ripetuti su \"Riprova\", ecc.) - se una richiesta e' gia'\n        \/\/ in corso, non la interrompe per ripartire da capo: la lascia concludere, evitando la cascata di\n        \/\/ AbortError osservata con trigger ravvicinati. Finestra ampia (15s\/8s) perche' il server puo' impiegare\n        \/\/ anche piu' di 10 secondi a rispondere nei casi osservati - una finestra piu' breve non basterebbe.\n        var nowCall1335 = Date.now();\n        var guardWindow1336 = forceReload ? 8000 : 15000;\n        if (window.__tiConfigOpenToken509 && window.__tiConfigOpenLastCallAt1335 && (nowCall1335 - window.__tiConfigOpenLastCallAt1335) < guardWindow1336) {\n            if (window.tiShowConfigWaitOverlay1340) window.tiShowConfigWaitOverlay1340(guardWindow1336 + 2000);\n            return false;\n        }\n        window.__tiConfigOpenLastCallAt1335 = nowCall1335;\n        var token = String(Date.now()) + '-' + Math.random();\n        window.__tiConfigOpenToken509 = token;\n        try { if(window.__tiConfigOpenAbort510 && window.__tiConfigOpenAbort510.abort) window.__tiConfigOpenAbort510.abort(); } catch(e){}\n        try { window.__tiConfigOpenAbort510 = (typeof AbortController !== 'undefined') ? new AbortController() : null; } catch(e){ window.__tiConfigOpenAbort510 = null; }\n        window.__tiConfigRenderedOk507 = true;\n        window.__tiConfigFullModeActive509 = true;\n        try { window.__tiConfigReadWaitActive503 = false; } catch(e){}\n        try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'Configurazione caricata', {notifyUser:false}); } catch(e){}\n        try { if (window.closeProgressPopup) window.closeProgressPopup(); } catch(e){}\n\n        \/\/ 30.9.1731: il database fisico e la sorgente autorevole ad ogni apertura normale.\n        \/\/ currentDbData\/localStorage possono essere obsoleti in un altra scheda o dopo una modifica server-side:\n        \/\/ vengono usati esclusivamente quando l utente richiede esplicitamente i dati in memoria.\n        var immediateData = cachedDb(db);\n        if(cacheOnly){\n            if(immediateData){\n                try {\n                    prepareData(immediateData, db);\n                    renderFull('dati in memoria richiesti esplicitamente');\n                    window.__tiConfigOpenToken509 = '';\n                    return false;\n                } catch(e) { showError(e); return false; }\n            }\n            showError(new Error('Dati in memoria non disponibili per la ditta ' + db + '. Premi Riprova per rileggerli dal database.'));\n            return false;\n        }\n\n        setWait('Lettura database reale della ditta ' + db + '.');\n        var slow = setTimeout(function(){\n            if(window.__tiConfigOpenToken509 !== token) return;\n            setWait('La lettura richiede piu tempo del previsto. Puoi attendere, premere Riprova oppure Esci.');\n        }, 4500);\n        fetchDb(db, token).catch(function(err){\n            if(window.__tiConfigOpenToken509 !== token) return;\n            \/\/ 30.9.1731: mai sostituire automaticamente il database reale con una cache potenzialmente vecchia.\n            \/\/ Se il server non risponde, mostrare l errore rende evidente che i dati non sono stati verificati.\n            showError(err);\n        }).finally(function(){ clearTimeout(slow); try { window.__tiConfigReadWaitActive503 = false; } catch(e){} });\n        return false;\n    };\n    function showError(err){\n        try { if (window.log1088) window.log1088('DIAGNOSTICA 1348: showError invocata - messaggio=' + (err && err.message ? err.message : String(err))); } catch(eL348a){}\n        var c=getCnt(); showOverlay();\n        \/\/ 30.9.1349: rimossi i pulsanti (Riprova\/Apri dati in memoria\/Chiudi) - apparivano spesso solo per un\n        \/\/ istante prima di essere coperti da un tentativo piu' recente gia' in corso (overlay di attesa 1340),\n        \/\/ risultando inutili e confusi. Resta solo il messaggio informativo; il recupero avviene automaticamente\n        \/\/ tramite i meccanismi gia' presenti (timeout, overlay di attesa, nuovo tentativo al successivo cambio ditta).\n        if(c) c.innerHTML = '<div style=\"padding:18px;margin:12px;background:#450a0a;color:#fee2e2;border:1px solid #ef4444;border-radius:12px;line-height:1.45;\">'\n            + '<b>Configurazione completa non caricata.<\/b><br>' + esc(err && err.message ? err.message : err)\n            + '<\/div>';\n        try { console.error('Shop & Service Configurazione completa 509 error', err); } catch(e){}\n    }\n\n    \/\/ Ripristina il render completo come render principale e reindirizza tutti gli opener al flusso completo 509.\n    if (typeof window.renderConfigFullLegacy507 === 'function') {\n        window.renderConfig = function(){ return renderFull('renderConfig completo'); };\n    }\n    ['openConfigSafe508','openConfigSafe507','openConfigSafe506','openConfigSafe505','openConfigSafe504','openConfigSafe503','openConfigSafe502','openConfigSafe501','openConfigSafe492','openConfigSafe491','openConfigSafe490','openConfigSafe489','openConfigSafe488','openConfigSafe218'].forEach(function(n){ window[n] = window.openConfigSafe509; });\n    function bind(){ var b=byId('ti-conf-toggle'); if(b){ b.onclick=window.openConfigSafe509; b.setAttribute('data-ti-config-open-rescue','509-full'); } }\n    document.addEventListener('click', function(ev){\n        var t=ev && ev.target; if(!t || !t.closest) return;\n        var b=t.closest('#ti-conf-toggle,#ti-config-fast-retry-507,#ti-config-fast-cache-507,#ti-config-full-retry-509,#ti-config-full-cache-509');\n        if(!b) return;\n        ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n        if(b.id === 'ti-config-fast-cache-507' || b.id === 'ti-config-full-cache-509') return window.openConfigSafe509(ev,false,true);\n        return window.openConfigSafe509(ev, b.id !== 'ti-conf-toggle', false);\n    }, true);\n    if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bind); else bind();\n    setTimeout(bind, 200); setTimeout(bind, 900); setTimeout(bind, 1800);\n})();\n\n(function(){\n    'use strict';\n    if (window.__tiConfigExitWait510Installed) return;\n    window.__tiConfigExitWait510Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){ return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(ch){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[ch]; }); }\n    function closeConfigOverlay(){\n        try { if(window.closeModal) window.closeModal('ti-conf-ov'); } catch(e){}\n        var ov = byId('ti-conf-ov'); if(ov) { try { ov.style.display='none'; ov.classList.remove('ti-modal-open','open','show'); } catch(e){} }\n    }\n    window.tiExitConfigLoading510 = function(message){\n        window.__tiConfigOpenToken509 = '';\n        window.__tiConfigOpenToken501 = '';\n        window.__tiConfigOpenToken492 = '';\n        window.__tiConfigReadWaitActive503 = false;\n        try { if(window.__tiConfigOpenAbort510 && window.__tiConfigOpenAbort510.abort) window.__tiConfigOpenAbort510.abort(); } catch(e){}\n        try { if(window.hideProgressPopup) window.hideProgressPopup(); } catch(e){}\n        try { if(window.closeProgressPopup) window.closeProgressPopup(); } catch(e){}\n        closeConfigOverlay();\n        var msg = message || 'Caricamento configurazione interrotto. Ripeti l apertura della Configurazione.';\n        setTimeout(function(){\n            try { if(window.tiAlert) window.tiAlert(msg); else alert(msg); } catch(e){}\n        }, 80);\n        return false;\n    };\n    function addExitButtonToWait(){\n        var c = byId('ti-conf-cnt');\n        if (c && \/Caricamento configurazione|Lettura dati configurazione|Avanzamento stimato\/i.test(String(c.textContent || '')) && !byId('ti-config-full-exit-510')) {\n            var wrap = document.createElement('div');\n            wrap.style.marginTop = '10px';\n            wrap.innerHTML = '<button type=\"button\" id=\"ti-config-full-exit-510\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;margin-right:8px;\">Esci<\/button>';\n            c.appendChild(wrap);\n        }\n        var b = byId('ti-config-full-exit-510');\n        if (b && !b.__tiExit510Bound) {\n            b.__tiExit510Bound = true;\n            b.onclick = function(ev){ if(ev){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } return window.tiExitConfigLoading510(); };\n        }\n        var progressButtons = Array.prototype.slice.call(document.querySelectorAll('.ti-config-progress-exit-510'));\n        for (var pi=1; pi<progressButtons.length; pi++) { try { progressButtons[pi].remove(); } catch(e){} }\n        if (!document.querySelector('.ti-config-progress-exit-510')) {\n            var candidates = Array.prototype.slice.call(document.querySelectorAll('#ti-progress-ov .ti-modal,#ti-ai-loader-ov .ti-loader-box,.ti-loader-box,.ti-progress-box,[id*=\"progress\"],[id*=\"loader\"]'));\n            var target = null;\n            for (var i=0;i<candidates.length;i++) {\n                var n = candidates[i];\n                if (!n || !n.textContent) continue;\n                var tx = String(n.textContent || '');\n                if (\/Caricamento configurazione|Lettura dati configurazione\/i.test(tx) && \/Avanzamento stimato|%\/.test(tx)) { target = n; break; }\n            }\n            if (target) {\n                var btn = document.createElement('button');\n                btn.type = 'button';\n                btn.className = 'ti-btn ti-config-progress-exit-510';\n                btn.textContent = 'Esci';\n                btn.style.cssText = 'background:#dc2626;color:#fff;margin:8px 6px 0 0;position:relative;z-index:999999;';\n                btn.onclick = function(ev){ if(ev){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } return window.tiExitConfigLoading510(); };\n                try { target.appendChild(btn); } catch(e){}\n            }\n        }\n    }\n    var oldOpen = window.openConfigSafe509;\n    if (typeof oldOpen === 'function' && !oldOpen.__tiExit510Wrapped) {\n        window.openConfigSafe509 = function(){ setTimeout(addExitButtonToWait, 0); setTimeout(addExitButtonToWait, 350); setTimeout(addExitButtonToWait, 1000); return oldOpen.apply(this, arguments); };\n        window.openConfigSafe509.__tiExit510Wrapped = true;\n        ['openConfigSafe508','openConfigSafe507','openConfigSafe506','openConfigSafe505','openConfigSafe504','openConfigSafe503','openConfigSafe502','openConfigSafe501','openConfigSafe492','openConfigSafe491','openConfigSafe490','openConfigSafe489','openConfigSafe488','openConfigSafe218'].forEach(function(n){ window[n] = window.openConfigSafe509; });\n    }\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target; if(!t || !t.closest) return;\n        var b = t.closest('#ti-config-full-exit-510,.ti-config-progress-exit-510');\n        if(!b) return;\n        ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n        return window.tiExitConfigLoading510();\n    }, true);\n    if (typeof MutationObserver !== 'undefined') {\n        try { new MutationObserver(function(){ setTimeout(addExitButtonToWait, 40); }).observe(document.body || document.documentElement, {childList:true, subtree:true}); } catch(e){}\n    }\n    if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', addExitButtonToWait); else addExitButtonToWait();\n})();\n\n<\/script>\n\n<style id=\"ti-logout-dedupe-511-css\">\n    #ti-ai-outer .ti-header-right-controls > #ti-logout-btn { display:none; }\n    #ti-ai-outer .ti-config-progress-exit-510 + .ti-config-progress-exit-510 { display:none !important; }\n<\/style>\n<script id=\"ti-logout-dedupe-511\">\n(function(){\n    'use strict';\n    if (window.__tiLogoutDedupe511Installed) return;\n    window.__tiLogoutDedupe511Installed = true;\n    function safe(fn){ try { return fn(); } catch(e) {} }\n    function byId(id){ return document.getElementById(id); }\n    function text(el){ return String((el && (el.textContent || el.value)) || '').trim(); }\n    function hasLogin(){\n        var u = String(window.tiUser || '').trim();\n        if (u) return true;\n        var nm = byId('ti-user-name');\n        var nt = nm ? text(nm) : '';\n        if (nt && !\/^(cliente\\\/?utente|cliente|utente|ospite|guest)$\/i.test(nt)) return true;\n        try { return \/(?:^|;\\s*)ti_ai_ss_session=\/.test(document.cookie || ''); } catch(e) { return false; }\n    }\n    function canonicalLogout(){\n        var header = document.querySelector('#ti-ai-outer .ti-header-right-controls') || document.querySelector('.ti-header-right-controls');\n        var existing = Array.prototype.slice.call(document.querySelectorAll('#ti-logout-btn'));\n        var keep = existing.find(function(b){ return header && b.parentNode === header; }) || existing[0] || null;\n        if (!keep && header) {\n            keep = document.createElement('button');\n            keep.type = 'button';\n            keep.id = 'ti-logout-btn';\n            keep.className = 'ti-btn';\n            keep.textContent = 'Esci';\n            header.appendChild(keep);\n        }\n        existing.forEach(function(b){ if (b !== keep) safe(function(){ b.remove(); }); });\n        if (keep) {\n            keep.id = 'ti-logout-btn';\n            keep.type = 'button';\n            keep.classList.add('ti-btn');\n            keep.textContent = (String(window.currLang || 'it').toLowerCase() === 'en') ? 'Logout' : 'Esci';\n            keep.setAttribute('data-ti-logout','1');\n            keep.onclick = function(ev){ if(ev){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } if (window.tiImmediateLogout506) return window.tiImmediateLogout506(ev); if (window.doLogout) return window.doLogout(); return false; };\n            keep.onmousedown = keep.onclick;\n            keep.ontouchend = keep.onclick;\n            if (hasLogin()) {\n                keep.style.setProperty('display','inline-flex','important');\n                keep.style.setProperty('visibility','visible','important');\n                keep.style.setProperty('pointer-events','auto','important');\n            } else {\n                keep.style.setProperty('display','none','important');\n            }\n        }\n        Array.prototype.slice.call(document.querySelectorAll('[data-ti-logout],.ti-logout-btn')).forEach(function(b){\n            if (b === keep) return;\n            if (b.id === 'ti-logout-btn') return;\n            if (\/^(esci|logout|logoff)$\/i.test(text(b))) safe(function(){ b.remove(); });\n        });\n        var progress = Array.prototype.slice.call(document.querySelectorAll('.ti-config-progress-exit-510'));\n        progress.forEach(function(b, idx){ if (idx > 0) safe(function(){ b.remove(); }); });\n        var full = Array.prototype.slice.call(document.querySelectorAll('#ti-config-full-exit-510'));\n        full.forEach(function(b, idx){ if (idx > 0) safe(function(){ b.remove(); }); });\n    }\n    function run(){ safe(canonicalLogout); }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', run, {once:true});\n    run();\n    setTimeout(run, 100); setTimeout(run, 500); setTimeout(run, 1500);\n    setInterval(run, 2000);\n    if (typeof MutationObserver !== 'undefined') safe(function(){ new MutationObserver(function(){ setTimeout(run, 25); }).observe(document.documentElement, {childList:true, subtree:true}); });\n})();\n<\/script>\n<style id=\"ti-mobile-logout-filter-table-526\">\n#ti-ai-outer #ti-new-db-ov .ti-modal { max-height: calc(var(--ti-vh, 1vh) * 96) !important; overflow-y: auto !important; -webkit-overflow-scrolling: touch !important; }\n#ti-ai-outer #ti-new-db-ov .ti-new-db-info-top { color:#d1fae5 !important; }\n#ti-ai-outer #ti-new-db-ov .ti-new-db-manual-bottom { min-height:36px !important; line-height:1.15 !important; }\n#ti-ai-outer .ti-cfg-table-container,\n#ti-ai-outer .ti-import-table-container,\n#ti-ai-outer .ti-sync-hscroll-wrap,\n#ti-ai-outer .ti-table-wrap,\n#ti-ai-outer .ti-prod-table-wrap,\n#ti-ai-outer .ti-order-table-wrap { overflow-x:auto !important; overflow-y:auto !important; max-width:100% !important; -webkit-overflow-scrolling:touch !important; touch-action: pan-x pan-y !important; overscroll-behavior:auto !important; }\n#ti-ai-outer .ti-purchase-table-wrap { overflow-x:auto !important; overflow-y:visible !important; max-width:100% !important; -webkit-overflow-scrolling:touch !important; touch-action: pan-x pan-y !important; overscroll-behavior:auto !important; }\n#ti-ai-outer .ti-cfg-top-scroll,\n#ti-ai-outer .ti-cfg-bottom-scroll,\n#ti-ai-outer .ti-order-top-scroll,\n#ti-ai-outer .ti-order-bottom-scroll { overflow-x:auto !important; overflow-y:hidden !important; -webkit-overflow-scrolling:touch !important; touch-action: pan-x !important; }\n#ti-ai-outer .ti-cfg-table { width:max-content !important; min-width:100% !important; table-layout:auto !important; border-collapse:collapse !important; }\n#ti-ai-outer .ti-cfg-table th,\n#ti-ai-outer .ti-cfg-table td { white-space:nowrap !important; vertical-align:top !important; }\n#ti-ai-outer .ti-cfg-table textarea { white-space:pre-wrap !important; min-width:220px !important; }\n#ti-ai-outer #ti-conf-ov .ti-cfg-table input:not([type=\"checkbox\"]):not([type=\"radio\"]),\n#ti-ai-outer #ti-conf-ov .ti-cfg-table textarea,\n#ti-ai-outer #ti-conf-ov .ti-cfg-table select,\n#ti-ai-outer #ti-conf-ov .ti-cfg-filter { pointer-events:auto !important; user-select:text !important; -webkit-user-select:text !important; opacity:1 !important; caret-color:#fff !important; color:#fff !important; -webkit-text-fill-color:#fff !important; }\n#ti-ai-outer .ti-cfg-filter-wrap-526 { display:flex !important; align-items:center !important; gap:4px !important; width:100% !important; min-width:90px !important; }\n#ti-ai-outer .ti-cfg-filter-wrap-526 .ti-cfg-filter { flex:1 1 auto !important; min-width:58px !important; }\n#ti-ai-outer .ti-cfg-filter-lens-526 { flex:0 0 24px !important; width:24px !important; min-width:24px !important; height:24px !important; min-height:24px !important; padding:0 !important; border:1px solid #64748b !important; border-radius:7px !important; background:#1d4ed8 !important; color:#fff !important; cursor:pointer !important; display:inline-flex !important; align-items:center !important; justify-content:center !important; line-height:1 !important; font-size:13px !important; }\n#ti-ai-outer .ti-cfg-filter-lens-526.is-active { background:#f59e0b !important; color:#111827 !important; border-color:#fbbf24 !important; }\n#ti-ai-outer .ti-cfg-filter.has-manual-filter-526 { border-color:#f59e0b !important; box-shadow:0 0 0 1px rgba(245,158,11,.45) !important; }\n@media (max-width: 680px) {\n  #ti-ai-outer { max-width:100vw !important; padding:6px !important; overflow-x:hidden !important; --ti-font-base:12px; --ti-font-small:11px; --ti-font-xs:10px; }\n  #ti-ai-outer .ti-modal { width:96vw !important; max-width:96vw !important; padding:12px !important; }\n  #ti-ai-outer #ti-new-db-ov .ti-modal { width:96vw !important; max-width:96vw !important; }\n  #ti-ai-outer input, #ti-ai-outer textarea, #ti-ai-outer select { font-size:16px !important; }\n  #ti-ai-outer .ti-cfg-table input, #ti-ai-outer .ti-cfg-table textarea, #ti-ai-outer .ti-cfg-table select, #ti-ai-outer .ti-cfg-filter { font-size:12px !important; }\n  #ti-ai-outer .ti-conf-body { overflow:auto !important; -webkit-overflow-scrolling:touch !important; touch-action:pan-x pan-y !important; }\n  #ti-ai-outer .ti-header { padding:8px !important; gap:6px !important; }\n  #ti-ai-outer .ti-header-bottom, #ti-ai-outer .ti-header-left-controls, #ti-ai-outer .ti-header-right-controls { gap:4px !important; }\n}\n@media (max-width: 980px) and (orientation: landscape) {\n  #ti-ai-outer { width:100vw !important; max-width:100vw !important; padding:5px !important; --ti-font-base:11px; --ti-font-small:10px; --ti-font-xs:9px; --ti-btn-h:26px; --ti-input-h:28px; }\n  #ti-ai-outer .ti-header { min-height:0 !important; padding:6px !important; margin-bottom:5px !important; gap:4px !important; }\n  #ti-ai-outer #ti-company-name { font-size:1.35em !important; }\n  #ti-ai-outer #ti-company-sub { font-size:10px !important; }\n  #ti-ai-outer .ti-actions-row, #ti-ai-outer #ti-admin-actions-row { gap:3px !important; overflow-x:auto !important; }\n  #ti-ai-outer .ti-actions-row .ti-btn, #ti-ai-outer #ti-admin-actions-row .ti-btn { font-size:8.8px !important; min-height:24px !important; height:24px !important; padding:2px 3px !important; }\n  #ti-ai-outer #ti-conf-ov .ti-conf-window, #ti-ai-outer #ti-conf-ov .ti-modal { width:98vw !important; max-width:98vw !important; height:94vh !important; max-height:94vh !important; }\n  #ti-ai-outer .ti-conf-body { top:48px !important; bottom:52px !important; overflow:auto !important; touch-action:pan-x pan-y !important; }\n  #ti-ai-outer .ti-cfg-table th, #ti-ai-outer .ti-cfg-table td { font-size:10px !important; padding:3px !important; }\n  #ti-ai-outer .ti-cfg-table input, #ti-ai-outer .ti-cfg-table textarea, #ti-ai-outer .ti-cfg-table select, #ti-ai-outer .ti-cfg-filter { font-size:10px !important; min-height:24px !important; padding:2px 4px !important; }\n}\n<\/style>\n\n<script id=\"ti-mobile-logout-filter-table-526\">\n(function(){\n    'use strict';\n    if (window.__tiMobileLogoutFilterTable526) return;\n    window.__tiMobileLogoutFilterTable526 = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function trim(v){ return txt(v).trim(); }\n    function norm(v){ try { return trim(v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/[^a-z0-9]+\/g,''); } catch(e) { return trim(v).toLowerCase().replace(\/[^a-z0-9]+\/g,''); } }\n    function cssEsc(v){ try { return window.CSS && CSS.escape ? CSS.escape(String(v)) : String(v).replace(\/[^a-zA-Z0-9_-]\/g, function(ch){ return '\\\\' + ch; }); } catch(e){ return String(v).replace(\/[^a-zA-Z0-9_-]\/g,'_'); } }\n    function safe(fn){ try { return fn(); } catch(e) { return null; } }\n\n    function setupNewCompanyForm(){\n        var ov = byId('ti-new-db-ov'); if (!ov) return;\n        var modal = ov.querySelector('.ti-modal') || ov;\n        var h3 = modal.querySelector('h3');\n        if (h3 && !modal.querySelector('.ti-new-db-info-top')) {\n            var info = document.createElement('div');\n            info.className = 'ti-new-db-info-top';\n            info.style.cssText = 'font-size:12px;color:#d1fae5;text-align:left;line-height:1.45;background:#052e25;border:1px solid #065f46;border-radius:10px;padding:10px;margin:0 0 12px 0;';\n            info.innerHTML = '<p style=\"margin:0 0 8px 0;\">Alla fine del processo di creazione della ditta, verr\u00e0 generato l\\'archivio e farai l\\'accesso automatico a te riservato come configuratore.<\/p><p style=\"margin:0 0 8px 0;\">Il servizio sar\u00e0 <b>GRATUITO di prova per 30 giorni senza impegno<\/b>, poi potrai eventualmente attivare la ditta alle condizioni commerciali previste per il servizio Shop &amp; Service disponibili direttamente durante la configurazione ed il periodo di prova.<\/p><p style=\"margin:0;\">Trascorso il periodo di prova di 30 giorni, potrai comunque mantenere i dati in attesa del da farsi per ulteriori 30 giorni o cancellarli definitivamente.<\/p>';\n            h3.insertAdjacentElement('afterend', info);\n        }\n        var manualLinks = Array.prototype.slice.call(modal.querySelectorAll('a[href*=\"Shop-service\"],a[href*=\"Shop-Service\"],a[href*=\"Shop%20Service\"],a'))\n            .filter(function(a){ return \/manuale operativo\/i.test(trim(a.textContent || '')); });\n        var bottom = modal.querySelector('.ti-new-db-manual-bottom');\n        if (!bottom) {\n            bottom = manualLinks[0] || document.createElement('a');\n            bottom.className = ((bottom.className || '') + ' ti-new-db-manual-bottom ti-btn').trim();\n            bottom.textContent = 'Manuale operativo Shop & Service';\n            bottom.target = '_blank'; bottom.rel = 'noopener';\n            if (!bottom.getAttribute('href')) bottom.href = 'https:\/\/www.targetinformatica.it\/wp-content\/uploads\/AI-data\/AI-docs\/Shop-service\/';\n            var cancel = Array.prototype.slice.call(modal.querySelectorAll('button')).filter(function(b){ return \/annulla\/i.test(trim(b.textContent || '')); })[0];\n            if (cancel) cancel.insertAdjacentElement('beforebegin', bottom); else modal.appendChild(bottom);\n        }\n        manualLinks.forEach(function(a){ if (a !== bottom) safe(function(){ a.parentNode.removeChild(a); }); });\n    }\n\n    function hardLogout(ev){\n        try { if (typeof window.tiLogoutPlugin851 === 'function' && window.tiLogoutPlugin851 !== hardLogout) return window.tiLogoutPlugin851(ev || null); } catch(e1613) {}\n        if (ev) safe(function(){ ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); });\n        if (window.__tiHardLogoutRunning526) return false;\n        window.__tiHardLogoutRunning526 = true;\n        safe(function(){ if (window.clearIdleTimers) window.clearIdleTimers(); });\n        safe(function(){ window.idleForceClosing = true; });\n        ['ti-conf-ov','ti-file-manager-ov','ti-ai-gen-ov','ti-login-ov','ti-profile-ov','ti-new-db-ov','ti-newdb-ov','ti-activity-report-ov','ti-delete-company-ov','ti-progress-ov','ti-order-confirm-ov','ti-global-action-ov'].forEach(function(id){\n            var el = byId(id); if (!el) return;\n            el.style.setProperty('display','none','important');\n            el.style.setProperty('visibility','hidden','important');\n            el.style.setProperty('pointer-events','none','important');\n        });\n        safe(function(){ document.cookie = 'ti_ai_ss_session=; Max-Age=0; path=\/; SameSite=Lax'; });\n        safe(function(){ document.cookie = 'ti_ai_ss_session=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=\/'; });\n        safe(function(){ var b=byId('ti-logout-btn'); if(b) b.style.setProperty('display','none','important'); });\n        safe(function(){ var b=byId('ti-login-btn'); if(b) b.style.setProperty('display','inline-flex','important'); });\n        var fd = new FormData();\n        fd.append('action','ti_ai_logout'); fd.append('ti_action','ti_ai_logout'); fd.append('_ti_logout_526', String(Date.now()));\n        var urls = [];\n        if (window.tiAjaxUrl) urls.push(window.tiAjaxUrl);\n        if (window.tiUrl && urls.indexOf(window.tiUrl) < 0) urls.push(window.tiUrl);\n        urls.push(window.location.href.split('#')[0]);\n        function reload(){ setTimeout(function(){ try { window.location.href = window.location.href.split('#')[0]; } catch(e) { window.location.reload(); } }, 80); }\n        var done = false;\n        function finish(){ if (done) return; done = true; reload(); }\n        setTimeout(finish, 650);\n        safe(function(){ fetch(urls[0], {method:'POST', body:fd, credentials:'same-origin', keepalive:true, cache:'no-store'}).then(finish).catch(function(){ if(urls[1]) fetch(urls[1], {method:'POST', body:fd, credentials:'same-origin', keepalive:true, cache:'no-store'}).then(finish).catch(finish); else finish(); }); });\n        return false;\n    }\n    window.tiImmediateLogout526 = hardLogout;\n    window.tiImmediateLogout506 = hardLogout;\n    window.forceSessionCloseNow = hardLogout;\n    window.doLogout = hardLogout;\n    function isLogoutTarget(t){ return !!(t && t.closest && t.closest('#ti-logout-btn,[data-ti-logout],.ti-logout-btn')); }\n    ['pointerdown','click','touchend','keydown'].forEach(function(evt){\n        window.addEventListener(evt, function(ev){\n            if (evt === 'keydown') { var k = ev.key || ev.code || ''; if (k !== 'Enter' && k !== ' ' && k !== 'Spacebar') return; }\n            if (isLogoutTarget(ev.target)) return hardLogout(ev);\n        }, true);\n    });\n\n    function isProtected(el){\n        if (!el) return false;\n        if (window.tiAiSsIsDatabaseFullAdmin1562 && window.tiAiSsIsDatabaseFullAdmin1562()) return false;\n        var user = norm(window.tiUser || '');\n        if (user === 'ssglobaladmin') return false;\n        var tbl = norm(el.getAttribute('data-tbl') || '');\n        var key = norm(el.getAttribute('data-key') || '');\n        return tbl === 'config' && ['stato','datacreazione','dataattivazione','wcorderid','wcactivateid','activeid'].indexOf(key) >= 0;\n    }\n    function unlockInput(el){\n        if (!el || isProtected(el)) return;\n        safe(function(){ el.removeAttribute('readonly'); el.removeAttribute('disabled'); el.readOnly = false; el.disabled = false; });\n        safe(function(){ el.style.setProperty('pointer-events','auto','important'); el.style.setProperty('user-select','text','important'); el.style.setProperty('-webkit-user-select','text','important'); el.style.setProperty('opacity','1','important'); });\n    }\n    function syncField(el){\n        if (!el || !el.matches || !el.matches('#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]')) return;\n        if (isProtected(el)) return;\n        var tbl = el.getAttribute('data-tbl') || '', key = el.getAttribute('data-key') || '', idx = parseInt(el.getAttribute('data-idx') || '', 10);\n        if (!tbl || !key || isNaN(idx)) return;\n        safe(function(){\n            if (window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[tbl] && window.currentDbData.Tabelle[tbl][idx]) {\n                window.currentDbData.Tabelle[tbl][idx][key] = ('value' in el) ? el.value : el.textContent;\n                window.__configRelationSupportCache = null;\n                if (!window.modifiedFields) window.modifiedFields = new Set();\n                window.modifiedFields.add(tbl + '-' + idx + '-' + key);\n                if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            }\n        });\n    }\n    function unlockAll(root){\n        var scope = root || byId('ti-conf-ov') || document;\n        safe(function(){ scope.querySelectorAll('#ti-conf-ov .ti-cfg-table input,#ti-conf-ov .ti-cfg-table textarea,#ti-conf-ov .ti-cfg-table select,#ti-conf-ov .ti-cfg-filter').forEach(unlockInput); });\n    }\n    document.addEventListener('focusin', function(ev){ unlockInput(ev.target); }, true);\n    document.addEventListener('input', function(ev){ unlockInput(ev.target); syncField(ev.target); }, true);\n    document.addEventListener('change', function(ev){ unlockInput(ev.target); syncField(ev.target); }, true);\n\n    var filterState = window.__tiConfigManualFilters526 = window.__tiConfigManualFilters526 || {};\n    function tableNameFrom(el){ var d = el && el.closest ? el.closest('details.ti-cfg-details') : null; return d ? trim(d.getAttribute('data-tbl') || '') : ''; }\n    function getDetails(tbl, el){\n        var t = trim(tbl) || tableNameFrom(el);\n        if (el && el.closest) { var d = el.closest('details.ti-cfg-details'); if (d) return d; }\n        try { return document.querySelector('#ti-conf-ov details.ti-cfg-details[data-tbl=\"' + cssEsc(t) + '\"]'); } catch(e) { return null; }\n    }\n    function ensureFilterUi(root){\n        var scope = root || byId('ti-conf-ov') || document;\n        safe(function(){ scope.querySelectorAll('#ti-conf-ov .ti-cfg-filter[data-key]').forEach(function(inp){\n            unlockInput(inp);\n            var tbl = trim(inp.getAttribute('data-tbl') || '') || tableNameFrom(inp);\n            if (tbl) inp.setAttribute('data-tbl', tbl);\n            var wrap = inp.parentElement;\n            if (wrap) wrap.classList.add('ti-cfg-filter-wrap-526');\n            var btn = wrap ? wrap.querySelector('.ti-cfg-filter-lens-526') : null;\n            if (!btn) {\n                btn = document.createElement('button');\n                btn.type = 'button';\n                btn.textContent = '\ud83d\udd0d';\n                btn.className = 'ti-cfg-filter-lens-526 ti-no-i18n';\n                inp.insertAdjacentElement('afterend', btn);\n            }\n            btn.setAttribute('data-tbl', tbl);\n            btn.setAttribute('data-key', inp.getAttribute('data-key') || '');\n            refreshFilterControl(inp);\n        }); });\n    }\n    function refreshFilterControl(inp){\n        if (!inp) return;\n        var tbl = trim(inp.getAttribute('data-tbl') || '') || tableNameFrom(inp), key = trim(inp.getAttribute('data-key') || '');\n        var active = !!(filterState[tbl] && trim(filterState[tbl][key] || ''));\n        inp.classList.toggle('has-manual-filter-526', active);\n        var wrap = inp.parentElement;\n        var btn = wrap ? wrap.querySelector('.ti-cfg-filter-lens-526') : null;\n        if (btn) { btn.classList.toggle('is-active', active); btn.title = active ? 'Filtro attivo: clicca per rimuoverlo' : 'Applica filtro righe'; }\n    }\n    function cellTextFor(row, cellIndex){\n        var cell = (cellIndex >= 0 && row.cells && row.cells[cellIndex]) ? row.cells[cellIndex] : row;\n        try {\n            if (window.tiConfigCellText700) return trim(window.tiConfigCellText700(cell));\n            if (cell && cell.querySelectorAll) {\n                var parts = [];\n                cell.querySelectorAll('input,textarea,select').forEach(function(el){\n                    if (el.tagName && String(el.tagName).toLowerCase() === 'select') parts.push(Array.prototype.slice.call(el.selectedOptions || []).map(function(o){ return o.textContent || o.value || ''; }).join(' '));\n                    else if ('value' in el) parts.push(el.value);\n                });\n                var visible = trim(cell.innerText || cell.textContent || '');\n                if (visible) parts.push(visible);\n                var joined = parts.map(function(v){ return trim(v); }).filter(Boolean).join(' ');\n                if (joined) return joined;\n            }\n        } catch(e) {}\n        return trim(cell && (cell.innerText || cell.textContent) || '');\n    }\n    function matchesCell(textValue, filterValue){\n        try { if (window.configFilterMatches) return window.configFilterMatches(textValue, filterValue); } catch(e) {}\n        var hay = norm(textValue), needle = norm(filterValue);\n        if (!needle) return true;\n        return hay.indexOf(needle) >= 0;\n    }\n    function applyFilter(tbl, el){\n        var det = getDetails(tbl, el); if (!det) return false;\n        var t = trim(tbl) || trim(det.getAttribute('data-tbl') || '');\n        var active = filterState[t] || {};\n        var keys = Object.keys(active).filter(function(k){ return trim(active[k]); });\n        var colIndex = {};\n        keys.forEach(function(k){\n            var inp = det.querySelector('.ti-cfg-filter[data-key=\"' + cssEsc(k) + '\"]');\n            var th = inp ? inp.closest('th') : null;\n            colIndex[k] = th && typeof th.cellIndex === 'number' ? th.cellIndex : -1;\n        });\n        var visible = 0, total = 0;\n        Array.prototype.slice.call(det.querySelectorAll('tbody tr')).forEach(function(tr){\n            if (!tr.cells || !tr.cells.length) return;\n            total++;\n            var ok = true;\n            for (var i=0;i<keys.length;i++) {\n                var k = keys[i];\n                if (!matchesCell(cellTextFor(tr, colIndex[k]), active[k])) { ok = false; break; }\n            }\n            tr.style.display = ok ? '' : 'none';\n            if (ok) visible++;\n        });\n        det.setAttribute('data-ti-filter-visible-526', String(visible));\n        det.setAttribute('data-ti-filter-total-526', String(total));\n        det.querySelectorAll('.ti-cfg-filter[data-key]').forEach(refreshFilterControl);\n        syncHScroll(det);\n        return false;\n    }\n    function toggleFilter(inp, ev){\n        if (ev) safe(function(){ ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); });\n        if (!inp) return false;\n        unlockInput(inp);\n        var tbl = trim(inp.getAttribute('data-tbl') || '') || tableNameFrom(inp), key = trim(inp.getAttribute('data-key') || '');\n        if (!tbl || !key) return false;\n        filterState[tbl] = filterState[tbl] || {};\n        var st1675 = window.ensureConfigTableState ? window.ensureConfigTableState(tbl) : null;\n        var active1675 = st1675 && st1675.filters ? trim(st1675.filters[key] || '') : trim(filterState[tbl][key] || '');\n        if (active1675) {\n            filterState[tbl][key] = '';\n            if (st1675) { st1675.filters[key] = ''; st1675.filterDrafts[key] = ''; st1675.page = 1; }\n            inp.value = '';\n        } else {\n            var v1675 = trim(inp.value || '');\n            filterState[tbl][key] = v1675;\n            if (st1675) { st1675.filters[key] = v1675; st1675.filterDrafts[key] = v1675; st1675.page = 1; }\n        }\n        \/\/ 30.9.1675: il filtro deve essere applicato all intera tabella, non solo alle 100 righe della pagina DOM.\n        var oldAllow1675 = window.__tiAllowConfigRender520;\n        window.__tiAllowConfigRender520 = true;\n        try { if (typeof window.renderConfig === 'function') window.renderConfig(); else applyFilter(tbl, inp); }\n        finally { window.__tiAllowConfigRender520 = oldAllow1675; }\n        return false;\n    }\n    window.toggleConfigTableFilterManual526 = function(tbl,key,inputEl,buttonEl,ev){ return toggleFilter(inputEl || (buttonEl && buttonEl.parentNode ? buttonEl.parentNode.querySelector('.ti-cfg-filter') : null), ev); };\n    window.toggleConfigTableFilterManual525 = window.toggleConfigTableFilterManual526;\n    window.toggleConfigTableFilterManual524 = window.toggleConfigTableFilterManual526;\n    window.toggleConfigTableFilterManual522 = window.toggleConfigTableFilterManual526;\n    window.toggleConfigTableFilterManual521 = window.toggleConfigTableFilterManual526;\n    window.setConfigTableFilterDraftManual526 = function(tbl,key,value,inputEl){ if (inputEl) unlockInput(inputEl); return false; };\n    window.setConfigTableFilterDraftManual525 = window.setConfigTableFilterDraftManual526;\n    window.setConfigTableFilterDraftManual524 = window.setConfigTableFilterDraftManual526;\n    window.setConfigTableFilterDraftManual521 = window.setConfigTableFilterDraftManual526;\n    window.scheduleConfigTableFilter = function(){ return false; };\n    window.filterConfigTable = function(){ return false; };\n    window.applyConfigTableDomFilter526 = applyFilter;\n\n    window.addEventListener('click', function(ev){\n        var btn = ev.target && ev.target.closest ? ev.target.closest('.ti-cfg-filter-lens-526,.ti-cfg-filter-lens-525,.ti-cfg-filter-lens-524,.ti-cfg-filter-lens-522,.ti-cfg-filter-lens-521') : null;\n        if (!btn) return;\n        var inp = btn.previousElementSibling && btn.previousElementSibling.classList && btn.previousElementSibling.classList.contains('ti-cfg-filter') ? btn.previousElementSibling : (btn.parentNode ? btn.parentNode.querySelector('.ti-cfg-filter') : null);\n        return toggleFilter(inp, ev);\n    }, true);\n    window.addEventListener('keydown', function(ev){\n        var el = ev.target;\n        if (!el || !el.classList || !el.classList.contains('ti-cfg-filter') || ev.key !== 'Enter') return;\n        return toggleFilter(el, ev);\n    }, true);\n    window.addEventListener('input', function(ev){\n        var el = ev.target;\n        if (!el || !el.classList || !el.classList.contains('ti-cfg-filter')) return;\n        unlockInput(el);\n        return false;\n    }, true);\n\n    function syncHScroll(root){\n        \/\/ 30.9.1777: il vecchio sincronizzatore 526 non misura piu autonomamente le barre.\n        \/\/ Delega al motore unico che compensa anche la scrollbar verticale della tabella.\n        var scope = root || byId('ti-conf-ov') || document;\n        safe(function(){\n            if (typeof window.initConfigTopScrollbars === 'function') window.initConfigTopScrollbars(scope);\n        });\n    }\n    function bindScrollSync(){\n        \/\/ 30.9.1777: niente secondo set di listener scroll. I doppi handler 526 + corrente\n        \/\/ potevano rimbalzarsi scrollLeft sui layout WooCommerce e generare una deriva lenta.\n        safe(function(){ document.querySelectorAll('#ti-conf-ov details.ti-cfg-details').forEach(function(det){ det.__tiScrollSync526 = true; }); });\n        syncHScroll(byId('ti-conf-ov') || document);\n    }\n\n    function refreshAll(){ setupNewCompanyForm(); unlockAll(document); ensureFilterUi(document); bindScrollSync(); }\n    var oldRender = window.renderConfig;\n    if (typeof oldRender === 'function' && !oldRender.__tiFinal526) {\n        window.renderConfig = function(){ var r = oldRender.apply(this, arguments); setTimeout(refreshAll, 0); setTimeout(refreshAll, 150); return r; };\n        window.renderConfig.__tiFinal526 = true;\n    }\n    if (typeof MutationObserver !== 'undefined') safe(function(){ new MutationObserver(function(){ setTimeout(refreshAll, 40); }).observe(byId('ti-ai-outer') || document.body, {childList:true, subtree:true}); });\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', refreshAll, {once:true}); else refreshAll();\n    setTimeout(refreshAll, 300); setTimeout(refreshAll, 1000); setTimeout(refreshAll, 2200);\n})();\n<\/script>\n\n\n<script id=\"ti-newdb-company-switch-filemanager-guard-528\">\n(function(){\n    'use strict';\n    if (window.__tiNewDbCompanySwitchFileManagerGuard528) return;\n    window.__tiNewDbCompanySwitchFileManagerGuard528 = true;\n    function byId(id){ return document.getElementById(id); }\n    function safe(fn){ try { return fn(); } catch(e) { return null; } }\n    function setImp(el, prop, val){ safe(function(){ if (el && el.style) el.style.setProperty(prop, String(val), 'important'); }); }\n    function isFileManagerId(id){ return String(id || '') === 'ti-file-manager-ov'; }\n    function suppressFileManager(reason, ms){\n        var until = Date.now() + (ms || 7000);\n        window.tiSuppressFileManagerUntil = Math.max(window.tiSuppressFileManagerUntil || 0, until);\n        window.__tiFileManagerSuppressedReason528 = reason || 'context_change';\n        window.__tiAIGenReturnToFileManager455 = false;\n        safe(function(){ window.targetUploadContext = null; });\n        safe(function(){ window.tiLastUploadContext356 = null; });\n        safe(function(){ window.tiLastUploadContext471 = null; });\n        safe(function(){ sessionStorage.removeItem('tiLastUploadContext356'); });\n        hideFileManager();\n    }\n    function hideFileManager(){\n        var fm = byId('ti-file-manager-ov');\n        if (!fm) return;\n        setImp(fm, 'display', 'none');\n        setImp(fm, 'visibility', 'hidden');\n        setImp(fm, 'opacity', '0');\n        setImp(fm, 'pointer-events', 'none');\n        safe(function(){ fm.setAttribute('aria-hidden','true'); });\n        safe(function(){ fm.removeAttribute('data-ti-demoted-by-aigen455'); });\n        safe(function(){ fm.removeAttribute('data-ti-force-front'); });\n        safe(function(){ fm.removeAttribute('data-ti-config-child-modal'); });\n        safe(function(){ fm.dataset.tbl = ''; fm.dataset.idx = ''; fm.dataset.key = ''; });\n        safe(function(){ if (window.updatePluginScrollLock) window.updatePluginScrollLock(); });\n    }\n    function isSuppressed(){ return Date.now() < (window.tiSuppressFileManagerUntil || 0); }\n    function shouldBlockFileManagerOpen(){\n        if (isSuppressed()) return true;\n        var d = byId('ti-ditta');\n        var v = d ? String(d.value || '') : '';\n        if (!v || v === 'NEW_DB') return true;\n        return false;\n    }\n\n    var oldClose = window.closeModal;\n    if (typeof oldClose === 'function' && !oldClose.__tiNewDbGuard528) {\n        window.closeModal = function(id){\n            var sid = (typeof id === 'string') ? id : (id && id.id ? id.id : '');\n            if (sid === 'ti-new-db-ov' || sid === 'ti-newdb-ov') suppressFileManager('new_company_form_closed', 9000);\n            if (sid === 'ti-file-manager-ov') {\n                window.__tiAIGenReturnToFileManager455 = false;\n                safe(function(){ window.targetUploadContext = null; });\n                safe(function(){ window.tiLastUploadContext356 = null; sessionStorage.removeItem('tiLastUploadContext356'); });\n            }\n            var ret = oldClose.apply(this, arguments);\n            if (sid === 'ti-new-db-ov' || sid === 'ti-newdb-ov') setTimeout(hideFileManager, 0);\n            return ret;\n        };\n        window.closeModal.__tiNewDbGuard528 = true;\n    }\n\n    var oldOpen = window.openModal;\n    if (typeof oldOpen === 'function' && !oldOpen.__tiNewDbGuard528) {\n        window.openModal = function(id){\n            var sid = (typeof id === 'string') ? id : (id && id.id ? id.id : '');\n            if (isFileManagerId(sid) && shouldBlockFileManagerOpen()) { hideFileManager(); return false; }\n            return oldOpen.apply(this, arguments);\n        };\n        window.openModal.__tiNewDbGuard528 = true;\n    }\n\n    var oldShow = window.showPluginModal;\n    if (typeof oldShow === 'function' && !oldShow.__tiNewDbGuard528) {\n        window.showPluginModal = function(id){\n            var sid = (typeof id === 'string') ? id : (id && id.id ? id.id : '');\n            if (isFileManagerId(sid) && shouldBlockFileManagerOpen()) { hideFileManager(); return false; }\n            return oldShow.apply(this, arguments);\n        };\n        window.showPluginModal.__tiNewDbGuard528 = true;\n    }\n\n    var oldOpenFm = window.openFileManager;\n    if (typeof oldOpenFm === 'function' && !oldOpenFm.__tiNewDbGuard528) {\n        window.openFileManager = function(tbl, idx, key){\n            if (shouldBlockFileManagerOpen()) { hideFileManager(); return false; }\n            return oldOpenFm.apply(this, arguments);\n        };\n        window.openFileManager.__tiNewDbGuard528 = true;\n    }\n\n    document.addEventListener('change', function(ev){\n        var t = ev && ev.target;\n        if (!t || t.id !== 'ti-ditta') return;\n        suppressFileManager('company_select_changed', 9000);\n    }, true);\n\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        if (t.closest('#ti-new-db-ov .btn-close,#ti-new-db-ov button[onclick*=\"closeModal\"],#ti-newdb-ov .btn-close,#ti-newdb-ov button[onclick*=\"closeModal\"]')) {\n            suppressFileManager('new_company_cancel_clicked', 9000);\n        }\n        if (t.closest('#ti-ditta-popup .ti-ditta-row')) {\n            suppressFileManager('company_popup_row_clicked', 9000);\n        }\n    }, true);\n\n    setInterval(function(){ if (isSuppressed()) hideFileManager(); }, 250);\n})();\n<\/script>\n\n\n<script id=\"ti-new-db-close-fix-538\">\n(function(){\n    \"use strict\";\n    if (window.__tiNewDbCloseFix538Installed) return;\n    window.__tiNewDbCloseFix538Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function safe(fn){ try { return fn(); } catch(e) { return null; } }\n    function hide(el){\n        if (!el) return false;\n        el.classList.remove('ti-modal-open','ti-open','is-open','active');\n        el.style.setProperty('display','none','important');\n        el.style.removeProperty('visibility');\n        el.style.removeProperty('opacity');\n        el.style.removeProperty('pointer-events');\n        safe(function(){ el.setAttribute('aria-hidden','true'); });\n        return true;\n    }\n    function clearCtx(){\n        window.__tiAIGenReturnToFileManager455 = false;\n        window.__tiFileManagerSuppressedReason538 = 'new_company_form_closed';\n        window.tiSuppressFileManagerUntil = Math.max(window.tiSuppressFileManagerUntil || 0, Date.now() + 9000);\n        safe(function(){ window.targetUploadContext = null; });\n        safe(function(){ window.tiLastUploadContext356 = null; });\n        safe(function(){ window.tiLastUploadContext471 = null; });\n        safe(function(){ sessionStorage.removeItem('tiLastUploadContext356'); });\n        safe(function(){ sessionStorage.removeItem('tiNewDbOpen'); });\n        safe(function(){ sessionStorage.removeItem('tiPendingNewDb'); });\n        safe(function(){ window.__tiNewCompanyFlowActive1605=false; window.__tiNewCompanyUserClose2075=true; });\n        var fm = byId('ti-file-manager-ov');\n        if (fm) {\n            fm.style.setProperty('display','none','important');\n            fm.style.setProperty('visibility','hidden','important');\n            fm.style.setProperty('opacity','0','important');\n            fm.style.setProperty('pointer-events','none','important');\n            safe(function(){ fm.setAttribute('aria-hidden','true'); });\n            safe(function(){ fm.dataset.tbl = ''; fm.dataset.idx = ''; fm.dataset.key = ''; });\n        }\n    }\n    window.closeNewDbModal538 = function(ev){\n        if (ev) { safe(function(){ ev.preventDefault(); }); safe(function(){ ev.stopPropagation(); }); safe(function(){ if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); }); }\n        clearCtx();\n        hide(byId('ti-new-db-ov') || byId('ti-newdb-ov'));\n        var sel = byId('ti-ditta');\n        if (sel && String(sel.value || '') === 'NEW_DB') { sel.value = ''; safe(function(){ sel.selectedIndex = 0; }); }\n        safe(function(){ if (document.activeElement && document.activeElement.blur) document.activeElement.blur(); });\n        safe(function(){ if (window.updatePluginScrollLock) window.updatePluginScrollLock(); });\n        safe(function(){ if (window.tiMobileUnlockScroll) window.tiMobileUnlockScroll(); });\n        return false;\n    };\n    var prevClose = window.closeModal;\n    if (typeof prevClose === 'function' && !prevClose.__tiNewDb538) {\n        window.closeModal = function(id){\n            var sid = (typeof id === 'string') ? id : (id && id.id ? id.id : '');\n            if (sid === 'ti-new-db-ov' || sid === 'ti-newdb-ov') return window.closeNewDbModal538();\n            return prevClose.apply(this, arguments);\n        };\n        window.closeModal.__tiNewDb538 = true;\n    }\n    var prevPluginClose = window.closePluginFormModal;\n    if (typeof prevPluginClose === 'function' && !prevPluginClose.__tiNewDb538) {\n        window.closePluginFormModal = function(id){\n            var sid = (typeof id === 'string') ? id : (id && id.id ? id.id : '');\n            if (sid === 'ti-new-db-ov' || sid === 'ti-newdb-ov') return window.closeNewDbModal538();\n            return prevPluginClose.apply(this, arguments);\n        };\n        window.closePluginFormModal.__tiNewDb538 = true;\n    }\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var ov = t.closest('#ti-new-db-ov,#ti-newdb-ov');\n        if (!ov) return;\n        var btn = t.closest('button,a');\n        if (!btn) return;\n        var txt = String(btn.textContent || btn.value || '').trim().toLowerCase();\n        if (btn.classList.contains('btn-close') || btn.classList.contains('ti-modal-x-red') || \/^(x|\u00d7|chiudi|close|annulla|cancel)$\/i.test(txt) || \/\\b(chiudi|annulla|cancel)\\b\/i.test(txt)) {\n            return window.closeNewDbModal538(ev);\n        }\n    }, true);\n    document.addEventListener('keydown', function(ev){\n        if (!ev || ev.key !== 'Escape') return;\n        var ov = byId('ti-new-db-ov') || byId('ti-newdb-ov');\n        if (!ov) return;\n        var cs = safe(function(){ return window.getComputedStyle(ov); });\n        if (cs && cs.display !== 'none' && cs.visibility !== 'hidden') return window.closeNewDbModal538(ev);\n    }, true);\n})();\n<\/script>\n\n<script id=\"ti-global-reset-contacts-565\">\n(function(){\n    \"use strict\";\n    if (window.__tiGlobalResetContacts565Installed) return;\n    window.__tiGlobalResetContacts565Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function esc(s){\n        return String(s == null ? '' : s).replace(\/[&<>'\"]\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;',\"'\":'&#39;','\"':'&quot;'}[c]; });\n    }\n    function norm(s){\n        try { return String(s || '').toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/[^a-z0-9]+\/g,' ').trim(); }\n        catch(e){ return String(s || '').toLowerCase().replace(\/[^a-z0-9]+\/g,' ').trim(); }\n    }\n    function isResetContactsPrompt(prompt){\n        var n = norm(prompt);\n        if (!n) return false;\n        var hasReset = \/\\b(azzera|azzerare|reset|reimposta|imposta|porta|metti|svuota|cancella)\\b\/.test(n);\n        var hasContacts = \/\\b(totale contatti|contatti totali|contacts num|contact num|total contacts|contacts number|contact number)\\b\/.test(n);\n        return hasReset && hasContacts;\n    }\n    function setResult(html, color){\n        var box = byId('global-action-res');\n        if (!box) return;\n        box.style.display = 'block';\n        if (color) box.style.color = color;\n        box.innerHTML = html;\n    }\n    function resetBtn(){\n        var btn = byId('global-action-btn');\n        if (btn) { btn.disabled = false; btn.innerText = 'Esegui Modifica su Tutti i DB'; btn.style.pointerEvents = 'auto'; btn.style.opacity = '1'; }\n    }\n    function finish(success, msg){\n        try { if (window.finishGlobalActionProgress) window.finishGlobalActionProgress(!!success, msg || (success ? 'Operazione completata' : 'Operazione interrotta')); } catch(e) {}\n        resetBtn();\n        try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n    }\n\n    function safeUnlockResetContacts(reason){\n        try { if (window.finishGlobalActionProgress) window.finishGlobalActionProgress(false, reason || 'Operazione conclusa o interrotta'); } catch(e) {}\n        try { if (window.hideProgressPopup) window.hideProgressPopup(false, reason || 'Operazione conclusa o interrotta'); } catch(e) {}\n        try { var p=byId('ti-progress-ov'); if(p){ p.style.display='none'; p.setAttribute('aria-hidden','true'); p.classList.remove('active','show','ti-ov-active'); } } catch(e) {}\n        try { if (window.clearLongAIProcess) window.clearLongAIProcess(); } catch(e) {}\n        resetBtn();\n        try { document.body.classList.remove('ti-no-scroll'); document.documentElement.classList.remove('ti-no-scroll'); document.body.style.pointerEvents=''; } catch(e) {}\n    }\n    function postDirect(prompt){\n        var btn = byId('global-action-btn');\n        if (btn) { btn.disabled = true; btn.innerText = '\u23f3 Azzero totale contatti...'; }\n        try { if (window.startGlobalActionProgress) window.startGlobalActionProgress('Azzeramento totale contatti in corso...'); } catch(e) {}\n        try { if (window.setGlobalActionProgress) window.setGlobalActionProgress(12, 'Azzeramento Contacts_num\/Contact_num nei database ditte...'); } catch(e) {}\n        setResult('Azzero il totale contatti nei database ditte. Il template resta escluso. Attendere la risposta finale.', '#cbd5e1');\n        var __tiResetDone566 = false;\n        var __tiResetWatch566 = setTimeout(function(){\n            if (__tiResetDone566) return;\n            __tiResetDone566 = true;\n            safeUnlockResetContacts('Timeout server o risposta non ricevuta. Se il server ha comunque applicato la modifica, il layout resta sbloccato. Verifica il report o ricarica solo se necessario.');\n            setResult('<span style=\"color:#f59e0b;\">Timeout server o risposta non ricevuta. Il layout e stato sbloccato. La modifica potrebbe essere stata applicata: verifica il valore totale contatti o ripeti solo se necessario.<\/span>', '#f59e0b');\n        }, 45000);\n        var fd = new FormData();\n        fd.append('action', 'ti_ai_global_reset_contacts_total');\n        fd.append('ti_action', 'ti_ai_global_reset_contacts_total');\n        fd.append('prompt', prompt || 'azzera totale contatti');\n        fd.append('global_confirm', '1');\n        fd.append('reset_contacts_total', '1');\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        var url = window.tiUrl || window.ajaxurl || window.location.href;\n        fetch(url, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'}).then(function(r){\n            return r.text().then(function(raw){\n                if (!r.ok) throw new Error('HTTP ' + r.status + ': ' + String(raw || '').slice(0,300));\n                try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta server non JSON: ' + String(raw || '').slice(0,300)); }\n            });\n        }).then(function(d){\n            if (__tiResetDone566) return;\n            __tiResetDone566 = true; clearTimeout(__tiResetWatch566);\n            if (!d || !d.success) {\n                var m = d && d.data && (d.data.message || d.data.error) ? (d.data.message || d.data.error) : 'Errore azzeramento totale contatti.';\n                throw new Error(m);\n            }\n            var data = d.data || {};\n            var reply = data.reply || 'Azzeramento totale contatti completato.';\n            finish(true, 'Azzeramento totale contatti completato');\n            setResult('<pre style=\"white-space:pre-wrap;margin:0;color:#10b981;\">' + esc(reply) + '<\/pre>', '#10b981');\n        }).catch(function(err){\n            if (__tiResetDone566) return;\n            __tiResetDone566 = true; clearTimeout(__tiResetWatch566);\n            safeUnlockResetContacts('Errore o timeout azzeramento totale contatti');\n            finish(false, 'Errore azzeramento totale contatti');\n            setResult('<span style=\"color:#ef4444;\">Errore azzeramento totale contatti: ' + esc(err && err.message ? err.message : err) + '<\/span>', '#ef4444');\n            try { console.error('Shop & Service reset contacts 565 error', err); } catch(e) {}\n        });\n    }\n    window.tiAiSsGlobalResetContacts565 = postDirect;\n    var prevConfirmed = window.doGlobalActionConfirmed;\n    window.doGlobalActionConfirmed = function(prompt, previewToken, definitiveConfirm, tableScope){\n        if (!previewToken && !definitiveConfirm && !tableScope && isResetContactsPrompt(prompt)) {\n            postDirect(prompt);\n            return false;\n        }\n        if (typeof prevConfirmed === 'function') return prevConfirmed.apply(this, arguments);\n        return false;\n    };\n    window.doGlobalActionConfirmed.__tiResetContacts565 = true;\n    var prevDo = window.doGlobalAction;\n    window.doGlobalAction = function(){\n        var el = byId('global-action-prompt');\n        var prompt = el ? String(el.value || '').trim() : '';\n        if (isResetContactsPrompt(prompt)) {\n            var warning = '<b>Attenzione: azzeramento totale contatti<\/b><br><br>' +\n                'Saranno impostati a <b>0<\/b> i campi <b>Contacts_num \/ Contact_num<\/b> nella tabella <b>Config<\/b> dei database ditte.<br>' +\n                'Il template standard resta escluso e non verr\u00e0 modificata la struttura dei database.<br><br>' +\n                '<b>Operazione richiesta:<\/b><br><span style=\"color:#fbbf24;white-space:pre-wrap;display:block;margin-top:6px;\">' + esc(prompt) + '<\/span><br>' +\n                'Confermi di voler procedere?';\n            if (typeof window.tiConfirmYesNoAction === 'function') {\n                window.tiConfirmYesNoAction(warning, function(){ postDirect(prompt); }, null, 'CONFERMA AZZERAMENTO', 'ANNULLA');\n            } else if (window.confirm(String(warning).replace(\/<[^>]+>\/g, ' '))) {\n                postDirect(prompt);\n            }\n            return false;\n        }\n        if (typeof prevDo === 'function') return prevDo.apply(this, arguments);\n        return false;\n    };\n    function bindBtn(){\n        var b = byId('global-action-btn');\n        if (!b || b.__tiResetContacts565Bound) return;\n        b.__tiResetContacts565Bound = true;\n        b.addEventListener('click', function(ev){\n            var el = byId('global-action-prompt');\n            var prompt = el ? String(el.value || '').trim() : '';\n            if (!isResetContactsPrompt(prompt)) return;\n            ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n            window.doGlobalAction();\n            return false;\n        }, true);\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bindBtn, {once:true});\n    setTimeout(bindBtn, 0); setTimeout(bindBtn, 500);\n})();\n<\/script>\n<script id=\"ti-config-code-change-and-autocomplete-569\">\n(function(){\n    if (window.__tiConfigCodeChangeAutocomplete569Installed) return;\n    window.__tiConfigCodeChangeAutocomplete569Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function val(v){ return String(v == null ? '' : v); }\n    function esc(v){ return val(v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function norm(v){ try { return val(v).toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,''); } catch(e){ return val(v).toLowerCase(); } }\n    function roleCanSignal(){\n        var role = norm(window.tiRole || window.tiUserRole || window.currentUserRole || '');\n        var user = val(window.tiUser || '').toLowerCase();\n        return user === 'ssglobaladmin' || user === 'ssdemo' || role.indexOf('amministratore') >= 0 || role.indexOf('configuratore') >= 0 || role.indexOf('administrator') >= 0 || role.indexOf('configurator') >= 0;\n    }\n    function codeChangeNeeded(reply, prompt, data){\n        var txt = norm((reply || '') + '\\n' + (prompt || '') + '\\n' + JSON.stringify(data || {}));\n        if (!txt.trim()) return false;\n        var hasCode = \/(modifica|modificare|intervento|aggiornamento|patch|fix|svilupp|programmaz|implementaz|cambiare|variare)\/.test(txt) && \/(codice|plugin|php|javascript|funzion|sorgente|release|versione)\/.test(txt);\n        var cannotApply = \/(non posso|non e possibile|non \u00e8 possibile|non riesco|serve|necessar|richiede|richiesta|da fare|manuale|tecnico)\/.test(txt);\n        return !!(hasCode && cannotApply);\n    }\n    function ensureModal(){\n        var ov = byId('ti-code-change-email-ov-569');\n        if (ov) return ov;\n        ov = document.createElement('div');\n        ov.id = 'ti-code-change-email-ov-569';\n        ov.className = 'ti-ov ti-closable-ov';\n        ov.style.cssText = 'z-index:2147483600!important;';\n        ov.innerHTML = '<div class=\"ti-modal\" style=\"width:92%;max-width:640px;text-align:left;\">'\n            + '<h3 style=\"margin-top:0;color:#fff;border-bottom:1px solid #334155;padding-bottom:8px;\">Supporto Configurazione Shop & Service<\/h3>'\n            + '<div style=\"color:#dbeafe;font-size:14px;line-height:1.45;\">Le fonti disponibili non consentono una risposta sufficientemente certa oppure potrebbe servire un intervento tecnico sul plugin.<\/div>'\n            + '<div style=\"margin-top:10px;color:#cbd5e1;font-size:13px;line-height:1.45;\">Vuoi autorizzare l invio a <b>SSSupport@targetinformatica.it<\/b> della copia della tua richiesta e della risposta AI?<\/div>'\n            + '<div id=\"ti-code-change-email-preview-569\" style=\"margin-top:10px;max-height:180px;overflow:auto;background:#020617;border:1px solid #334155;border-radius:8px;padding:9px;color:#e5e7eb;font-size:12px;white-space:pre-wrap;\"><\/div>'\n            + '<div id=\"ti-code-change-email-status-569\" style=\"display:none;margin-top:10px;padding:8px;border-radius:8px;border:1px solid #334155;background:#020617;color:#bfdbfe;font-size:12px;\"><\/div>'\n            + '<div style=\"display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap;margin-top:14px;\">'\n            + '<button type=\"button\" class=\"ti-btn\" style=\"background:#4b5563;color:#fff;\" onclick=\"window.tiCloseCodeChangeEmailPopup569()\">Annulla<\/button>'\n            + '<button type=\"button\" id=\"ti-code-change-email-send-569\" class=\"ti-btn\" style=\"background:#dc2626;color:#fff;\" onclick=\"window.tiSendCodeChangeEmail569()\">Invia segnalazione<\/button>'\n            + '<\/div>'\n            + '<div style=\"margin-top:8px;display:flex;justify-content:stretch;\">'\n            + '<button type=\"button\" id=\"ti-code-change-email-copy-569\" class=\"ti-btn\" style=\"width:100%;background:#2563eb;color:#fff;\" onclick=\"window.tiCopyCodeChangeEmailText569(this)\">Copia testo<\/button>'\n            + '<\/div><\/div>';\n        document.body.appendChild(ov);\n        return ov;\n    }\n    window.tiBuildCodeChangeEmailCopyText569 = function(){\n        var payload = window.__tiCodeChangeEmailPayload569 || {};\n        var st = byId('ti-code-change-email-status-569');\n        var status = st && st.style.display !== 'none' ? val(st.textContent || '') : '';\n        var preview = byId('ti-code-change-email-preview-569');\n        var previewText = preview ? val(preview.textContent || preview.innerText || '') : '';\n        var txt = previewText || ('Richiesta modifica codice plugin\\n\\nRichiesta:\\n' + val(payload.prompt || '') + '\\n\\nRisposta AI \/ motivo:\\n' + val(payload.reply || ''));\n        if (status) txt += '\\n\\nStato invio:\\n' + status;\n        return txt.trim();\n    };\n    window.tiCopyCodeChangeEmailText569 = function(btn){\n        var text = window.tiBuildCodeChangeEmailCopyText569 ? window.tiBuildCodeChangeEmailCopyText569() : '';\n        function done(ok){\n            try {\n                if (btn) {\n                    var old = btn.getAttribute('data-old-label') || btn.textContent || 'Copia testo';\n                    btn.setAttribute('data-old-label', old);\n                    btn.textContent = ok ? 'Testo copiato' : 'Copia manuale';\n                    setTimeout(function(){ try { btn.textContent = old || 'Copia testo'; } catch(e){} }, 1400);\n                }\n            } catch(e) {}\n        }\n        if (!text) { done(false); return false; }\n        try {\n            if (navigator.clipboard && window.isSecureContext) {\n                navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){\n                    try {\n                        var ta = document.createElement('textarea'); ta.value = text; ta.style.position='fixed'; ta.style.left='-9999px'; document.body.appendChild(ta); ta.focus(); ta.select(); var ok = document.execCommand('copy'); document.body.removeChild(ta); done(ok);\n                    } catch(e2){ done(false); }\n                });\n                return false;\n            }\n        } catch(e) {}\n        try {\n            var ta = document.createElement('textarea'); ta.value = text; ta.style.position='fixed'; ta.style.left='-9999px'; document.body.appendChild(ta); ta.focus(); ta.select(); var ok = document.execCommand('copy'); document.body.removeChild(ta); done(ok); return false;\n        } catch(e) { done(false); return false; }\n    };\n    window.tiCloseCodeChangeEmailPopup569 = function(){ var ov = byId('ti-code-change-email-ov-569'); if (ov) ov.style.display = 'none'; };\n    window.tiOfferCodeChangeEmail569 = function(prompt, reply, opts){\n        if (!roleCanSignal()) return false;\n        prompt = val(prompt).trim(); reply = val(reply).trim(); opts = opts || {};\n        if (!opts.force && !codeChangeNeeded(reply, prompt, null)) return false;\n        var key = norm(prompt + '|' + reply).slice(0, 500);\n        if (window.__tiLastCodeChangeOffer569 === key) return false;\n        window.__tiLastCodeChangeOffer569 = key;\n        window.__tiCodeChangeEmailPayload569 = {prompt:prompt, reply:reply, reason:val(opts.reason || '')};\n        var ov = ensureModal();\n        var preview = byId('ti-code-change-email-preview-569');\n        if (preview) preview.innerHTML = esc('Richiesta:\\n' + prompt + '\\n\\nRisposta AI \/ motivo:\\n' + reply);\n        var st = byId('ti-code-change-email-status-569'); if (st) { st.style.display='none'; st.textContent=''; }\n        ov.style.display = 'flex';\n        return true;\n    };\n    window.tiSendCodeChangeEmail569 = function(){\n        var payload = window.__tiCodeChangeEmailPayload569 || {};\n        var st = byId('ti-code-change-email-status-569');\n        var btn = byId('ti-code-change-email-send-569');\n        if (st) { st.style.display='block'; st.style.borderColor='#2563eb'; st.style.color='#bfdbfe'; st.textContent='Invio segnalazione in corso...'; }\n        if (btn) btn.disabled = true;\n        var db = (byId('ti-ditta') && byId('ti-ditta').value) || window.tiCurrentSelectedDb || window.tiForced || window.tiSessionDb || '';\n        var fd = new FormData();\n        fd.append('ti_action','ti_ai_ss_code_change_request_email');\n        fd.append('action','ti_ai_ss_code_change_request_email');\n        fd.append('db', db);\n        fd.append('prompt', val(payload.prompt || ''));\n        fd.append('reply', val(payload.reply || ''));\n        fd.append('chat_copy', 'Copia chat richiesta da parte dell\\'utente\\n\\nRichiesta:\\n' + val(payload.prompt || '') + '\\n\\nRisposta AI \/ motivo mancata applicazione:\\n' + val(payload.reply || ''));\n        fetch(window.tiUrl || window.location.href, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'}).then(function(r){ return r.text().then(function(t){ try { return JSON.parse(t); } catch(e){ throw new Error(t.slice(0,220) || 'Risposta non valida'); } }); }).then(function(res){\n            if (!res || !res.success) throw new Error(res && res.data && res.data.message ? res.data.message : 'Invio non riuscito');\n            var sentMsg2031 = (res.data && res.data.reply) ? res.data.reply : 'Email inviata a SSSupport@targetinformatica.it.';\n            if (st) { st.style.borderColor='#22c55e'; st.style.color='#bbf7d0'; st.textContent=sentMsg2031 + ' Puoi usare Copia testo per copiare richiesta, risposta e stato invio.'; }\n            var rb2031 = byId('ti-conf-ai-reply');\n            if (rb2031) {\n                rb2031.style.display='block'; rb2031.removeAttribute('aria-hidden'); rb2031.setAttribute('data-ti-config-ai-persistent-2031','1');\n                var old2031 = byId('ti-config-support-sent-2031'); if (old2031) old2031.remove();\n                var note2031 = document.createElement('div'); note2031.id='ti-config-support-sent-2031';\n                note2031.style.cssText='margin-top:10px;padding:8px 10px;border:1px solid #22c55e;border-radius:8px;background:#052e16;color:#bbf7d0;font-weight:700;';\n                note2031.textContent = sentMsg2031;\n                rb2031.appendChild(note2031);\n            }\n        }).catch(function(e){\n            if (st) { st.style.borderColor='#ef4444'; st.style.color='#fecaca'; st.textContent='Errore invio segnalazione: ' + (e && e.message ? e.message : 'errore'); }\n        }).finally(function(){ if (btn) btn.disabled = false; });\n    };\n\n    \/\/ Sincronizzazione leggera dei campi tabellari: native autocomplete\/suggerimenti salvati, select relazionali e blur.\n    var lastValue = new WeakMap();\n    function syncField(el){\n        if (!el || !el.dataset) return;\n        var tbl = el.dataset.tbl || '', idx = el.dataset.idx, key = el.dataset.key || '';\n        if (!tbl || idx === undefined || idx === null || key === '') return;\n        var v = (el.tagName === 'SELECT') ? Array.prototype.map.call(el.selectedOptions || [], function(o){return o.value;}).join(', ') : val(el.value);\n        if (lastValue.get(el) === v) return;\n        lastValue.set(el, v);\n        try {\n            if (el.classList && el.classList.contains('ti-rel-select') && typeof window.updateMemFieldFromRelationSelect === 'function') {\n                window.updateMemFieldFromRelationSelect(tbl, parseInt(idx,10), key, el);\n            } else if (typeof window.updateMemField === 'function') {\n                window.updateMemField(tbl, parseInt(idx,10), key, el);\n            }\n        } catch(e) {}\n    }\n    ['input','change','blur','compositionend'].forEach(function(evt){\n        document.addEventListener(evt, function(e){\n            var el = e.target;\n            if (!el || !el.matches) return;\n            if (!el.matches('#ti-conf-ov .ti-cfg-table input[data-tbl][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-key]')) return;\n            \/\/ Eseguito sul singolo campo: nessuna scansione tabella e nessun re-render.\n            setTimeout(function(){ syncField(el); }, evt === 'blur' ? 0 : 20);\n        }, true);\n    });\n    if (typeof window.setConfigAiReplyHtml === 'function' && !window.setConfigAiReplyHtml.__ti569Wrapped) {\n        var prevSetReply = window.setConfigAiReplyHtml;\n        window.setConfigAiReplyHtml = function(box, html, raw){\n            var ret = prevSetReply.apply(this, arguments);\n            try {\n                var isConfigReply = box && box.id === 'ti-conf-ai-reply';\n                if (isConfigReply) {\n                    var active = window.tiActiveConfigAiRequest434 || {};\n                    var prompt = active.prompt || (byId('ti-conf-ai-prompt') ? byId('ti-conf-ai-prompt').value : '');\n                    var reply = raw || (box.textContent || box.innerText || html || '');\n                    setTimeout(function(){ window.tiOfferCodeChangeEmail569(prompt, reply); }, 80);\n                }\n            } catch(e) {}\n            return ret;\n        };\n        window.setConfigAiReplyHtml.__ti569Wrapped = true;\n    }\n})();\n<\/script>\n\n\n\n<script>\n(function(){\n    \"use strict\";\n    if (window.__tiCopyTextGlobal579Installed) return;\n    window.__tiCopyTextGlobal579Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function str(v){ return String(v == null ? '' : v); }\n    function isHidden(el){\n        try {\n            if (!el) return true;\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return true;\n            var r = el.getBoundingClientRect ? el.getBoundingClientRect() : null;\n            if (r && r.width === 0 && r.height === 0) return true;\n        } catch(e) {}\n        return false;\n    }\n    function plainText(root){\n        if (!root) return '';\n        try {\n            if (root.getAttribute && root.getAttribute('data-copy-text')) return str(root.getAttribute('data-copy-text')).trim();\n            if ('value' in root && !isHidden(root)) return str(root.value).trim();\n            var clone = root.cloneNode(true);\n            try {\n                clone.querySelectorAll('button,.ti-btn,script,style,noscript,input,select,textarea').forEach(function(el){ el.remove(); });\n            } catch(e) {}\n            return str(clone.innerText || clone.textContent || '')\n                .replace(\/\\r\/g, '')\n                .replace(\/[ \\t]+\\n\/g, '\\n')\n                .replace(\/\\n{3,}\/g, '\\n\\n')\n                .trim();\n        } catch(e) {\n            try { return str(root.innerText || root.textContent || '').trim(); } catch(x) {}\n        }\n        return '';\n    }\n    function resetState(){\n        try {\n            [\n                '__tiFileManagerBusy','__tiAiFileBusy','__tiAiGenBusy','__tiMediaUploadBusy','__tiUploadBusy',\n                '__tiPreventConfigClose','__tiFilePcBusy','__tiFileAttachBusy'\n            ].forEach(function(k){ try { window[k] = false; } catch(e) {} });\n            if (document.body && document.body.classList) {\n                ['ti-busy','ti-loading','ti-modal-blocked','ti-uploading','ti-file-busy','ti-no-click'].forEach(function(c){\n                    try { document.body.classList.remove(c); } catch(e) {}\n                });\n            }\n            document.querySelectorAll('.ti-ov,.ti-modal-backdrop,.ti-loader,.ti-config-loader').forEach(function(el){\n                try {\n                    var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n                    if (cs && (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')) el.style.pointerEvents = 'none';\n                } catch(e) {}\n            });\n            document.querySelectorAll('#ti-alert-copy,#ti-admin-comm-copy,#ti-col-help-copy,.ti-conf-ai-copy-btn,[data-copy-target],[data-ti-copy-text]').forEach(function(btn){\n                try { btn.disabled = false; btn.removeAttribute('disabled'); btn.style.pointerEvents = 'auto'; } catch(e) {}\n            });\n        } catch(e) {}\n    }\n    window.tiResetFileAndCopyBlockedState579 = resetState;\n\n    function fallbackCopy(text){\n        var ta = null;\n        try {\n            ta = document.createElement('textarea');\n            ta.value = text;\n            ta.setAttribute('readonly', 'readonly');\n            ta.style.position = 'fixed';\n            ta.style.left = '-9999px';\n            ta.style.top = '0';\n            ta.style.width = '2px';\n            ta.style.height = '2px';\n            ta.style.opacity = '0';\n            ta.style.zIndex = '2147483647';\n            document.body.appendChild(ta);\n            ta.focus();\n            ta.select();\n            ta.setSelectionRange(0, ta.value.length);\n            return !!document.execCommand('copy');\n        } catch(e) {\n            return false;\n        } finally {\n            try { if (ta && ta.parentNode) ta.parentNode.removeChild(ta); } catch(e) {}\n        }\n    }\n    function setButtonResult(btn, ok){\n        try {\n            if (!btn) return;\n            var old = btn.getAttribute('data-old-label') || btn.innerText || btn.textContent || 'Copia testo';\n            if (!btn.getAttribute('data-old-label')) btn.setAttribute('data-old-label', old);\n            btn.disabled = false;\n            btn.removeAttribute('disabled');\n            btn.innerText = ok ? 'Testo copiato' : 'Copia manuale';\n            setTimeout(function(){ try { btn.innerText = old || 'Copia testo'; } catch(e) {} }, 1300);\n        } catch(e) {}\n    }\n    function safeCopy(text, btn, sourceEl, statusCb){\n        resetState();\n        text = str(text).trim();\n        if (!text && sourceEl) text = plainText(sourceEl);\n        function done(ok){\n            setButtonResult(btn, ok);\n            try { if (typeof statusCb === 'function') statusCb(!!ok); } catch(e) {}\n            return !!ok;\n        }\n        if (!text) return done(false);\n        if (fallbackCopy(text)) return done(true);\n        try {\n            if (navigator.clipboard && navigator.clipboard.writeText) {\n                navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){\n                    try { window.prompt('Copia il testo:', text); } catch(e) {}\n                    done(false);\n                });\n                return true;\n            }\n        } catch(e) {}\n        try { window.prompt('Copia il testo:', text); } catch(e) {}\n        return done(false);\n    }\n    window.tiAiSafeCopyText579 = safeCopy;\n    window.tiCopyTextReliable = function(text, sourceEl, statusCb){ return safeCopy(text, null, sourceEl, statusCb); };\n    window.tiCopyTextToClipboard = function(text, btn){ return safeCopy(text, btn, null, null); };\n\n    function columnHelpText(){\n        try { if (window.tiSanitizeColumnHelpBox579) window.tiSanitizeColumnHelpBox579(); } catch(e) {}\n        try { if (window.tiSanitizeColumnHelpText357 && byId('col-help-content')) byId('col-help-content').innerHTML = byId('col-help-content').innerHTML; } catch(e) {}\n        var parts = [];\n        ['col-help-title','col-help-company','col-help-content'].forEach(function(id){\n            var t = plainText(byId(id));\n            if (t) parts.push(t);\n        });\n        var text = parts.join('\\n\\n').trim();\n        if (!text) text = plainText(document.querySelector('#ti-col-help-ov .ti-modal'));\n        return text;\n    }\n    function alertText(){\n        var current = plainText(byId('ti-alert-msg'));\n        if (current) return current;\n        if (window.lastOrphanCleanupReportText) return str(window.lastOrphanCleanupReportText).trim();\n        try { if (window.getAlertPlainText) return str(window.getAlertPlainText()).trim(); } catch(e) {}\n        return '';\n    }\n    function pickRoot(btn){\n        if (!btn) return null;\n        if (btn.getAttribute && btn.getAttribute('data-copy-target')) {\n            try { return document.querySelector(btn.getAttribute('data-copy-target')); } catch(e) {}\n        }\n        return btn.closest ? btn.closest('.ti-modal,.ti-ov,.ti-popup,.ti-maintenance-box,.ti-conf-ai-copy-box,.ti-admin-comm-box') : null;\n    }\n    function pickText(btn){\n        if (!btn) return '';\n        try {\n            if (btn.getAttribute && btn.getAttribute('data-ti-copy-text')) return str(btn.getAttribute('data-ti-copy-text')).trim();\n            if (btn.id === 'ti-col-help-copy') return columnHelpText();\n            if (btn.id === 'ti-alert-copy') return alertText();\n            if (btn.id === 'ti-admin-comm-copy') return plainText(byId('ti-admin-comm-msg'));\n            if (btn.id === 'ti-maint-copy') return plainText(byId('ti-maint-msg')) || plainText(btn.closest('.ti-modal'));\n            if (btn.id === 'ti-maint-runtime-copy-573') return plainText(byId('ti-maint-runtime-detail-573')) || plainText(btn.closest('.ti-modal'));\n            var root = pickRoot(btn);\n            if (!root) root = byId('ti-alert-msg') || document.body;\n            var attr = root.querySelector ? root.querySelector('[data-copy-text]') : null;\n            if (attr) {\n                var at = attr.getAttribute('data-copy-text');\n                if (at) return str(at).trim();\n            }\n            var selectors = [\n                '#ti-file-pc-diag-log-578','#ti-file-pc-diag-log-576','pre:not([aria-hidden=\"true\"])',\n                '.ti-copy-text','.ti-report-text','.ti-maintenance-detail','.ti-ai-msg','.ti-alert-text','#ti-alert-msg','#ti-admin-comm-msg'\n            ];\n            for (var i=0; i<selectors.length; i++) {\n                var el = null;\n                try { el = root.querySelector ? root.querySelector(selectors[i]) : null; } catch(e) {}\n                var t = plainText(el);\n                if (t) return t;\n            }\n            return plainText(root);\n        } catch(e) { return ''; }\n    }\n    function isCopyButton(btn){\n        if (!btn) return false;\n        \/\/ 30.9.1608: la scheda dettaglio Configurazione possiede un copier specializzato che deve\n        \/\/ leggere i valori degli input. Il copier globale 579, eseguito in capture, altrimenti lo\n        \/\/ precede e copia soltanto il testo grafico del drawer.\n        try { if ((btn.id && btn.id === 'ti-config-row-copy-1609') || (btn.closest && btn.closest('#ti-config-row-drawer-1590'))) return false; } catch(e) {}\n        var id = btn.id || '';\n        if (\/^(ti-alert-copy|ti-admin-comm-copy|ti-col-help-copy|ti-maint-copy|ti-maint-runtime-copy-573)$\/.test(id)) return true;\n        if (btn.getAttribute && (btn.getAttribute('data-copy-target') || btn.getAttribute('data-ti-copy-text'))) return true;\n        if (btn.classList && btn.classList.contains('ti-conf-ai-copy-btn')) return true;\n        var label = str(btn.innerText || btn.textContent).replace(\/\\s+\/g, ' ').trim().toLowerCase();\n        return label === 'copia testo' || label === 'copy text' || label === 'copia' || label.indexOf('copia testo') >= 0 || label.indexOf('copy text') >= 0;\n    }\n\n    window.copyColumnHelpText357 = function(){ return safeCopy(columnHelpText(), byId('ti-col-help-copy'), byId('col-help-content'), null); };\n    window.copyAlertText = function(){ return safeCopy(alertText(), byId('ti-alert-copy'), byId('ti-alert-msg'), null); };\n\n    document.addEventListener('click', function(ev){\n        var btn = ev.target && ev.target.closest ? ev.target.closest('button,a,[role=\"button\"]') : null;\n        if (!isCopyButton(btn)) return;\n        resetState();\n        var text = pickText(btn);\n        if (!text) return;\n        try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {}\n        safeCopy(text, btn, pickRoot(btn), null);\n    }, true);\n})();\n<\/script>\n\n\n\n\n\n<script>\n(function(){\n    \"use strict\";\n    if (window.__tiInvalidPathConfigPopup583) return;\n    window.__tiInvalidPathConfigPopup583 = true;\n    function byId(id){ return document.getElementById(id); }\n    function s(v){ return v == null ? '' : String(v); }\n    function dbName(){ var el=byId('ti-ditta'); return el ? s(el.value).trim() : ''; }\n    function canLocal(){ try { return window.canRunLocalOrphanCleanup && window.canRunLocalOrphanCleanup(); } catch(e){ return false; } }\n    function canGlobal(){ try { return window.canRunGlobalOrphanCleanup && window.canRunGlobalOrphanCleanup(); } catch(e){ return false; } }\n    function esc(x){ return s(x).replace(\/[&<>\"]\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;'}[c];}); }\n    function currentConfigOpen(){ var ov=byId('ti-conf-ov'); return !!(ov && ov.style && ov.style.display !== 'none'); }\n    function scanInvalidPaths(db){\n        var fd = new FormData();\n        fd.append('ti_action','ti_ai_scan_orphan_files');\n        fd.append('db', db);\n        fd.append('invalid_only','1');\n        fd.append('preview','1');\n        return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true}).then(function(res){\n            if (!res || !res.success) return [];\n            return (res.data && Array.isArray(res.data.files)) ? res.data.files : [];\n        }).catch(function(){ return []; });\n    }\n    window.tiCheckInvalidFilePathsOnConfig583 = function(force){\n        if (!canLocal()) return;\n        var db = dbName();\n        if (!db || db === 'Global' || db === 'NEW_DB') return;\n        var key = 'ti-invalid-file-path-popup-583-' + db;\n        try { if (!force && sessionStorage.getItem(key) === '1') return; sessionStorage.setItem(key, '1'); } catch(e) {}\n        setTimeout(function(){\n            if (!currentConfigOpen()) return;\n            scanInvalidPaths(db).then(function(files){\n                if (!files || !files.length) return;\n                var first = files[0] || {};\n                var html = '<div style=\"text-align:left;line-height:1.4;\">'\n                    + '<b>Path file da verificare<\/b><br><br>'\n                    + 'Sono stati rilevati file o cartelle in path non valide o non associabili per la ditta corrente. '\n                    + 'Esempio rilevato:<br><code style=\"font-size:11px;word-break:break-all;\">' + esc(first.relative_path || first.path || '') + '<\/code><br><br>'\n                    + 'Usa <b>Pulisci file non associati<\/b> per la ditta. La pulizia ora include anche path non valide come <code>Informazioni\/informazioni<\/code>: se un file risulta gi\u00e0 associato, viene spostato nella path ufficiale della tabella quando possibile; altrimenti viene eliminato come non associabile.';\n                html += '<div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;\">'\n                    + '<button type=\"button\" class=\"ti-btn\" style=\"background:#7c2d12;color:#fff;\" onclick=\"if(window.runOrphanFileCleanup)window.runOrphanFileCleanup();\">Pulisci file non associati<\/button>';\n                if (canGlobal()) html += '<button type=\"button\" class=\"ti-btn\" style=\"background:#991b1b;color:#fff;\" onclick=\"if(window.runGlobalOrphanFileCleanup)window.runGlobalOrphanFileCleanup();\">Pulisci globale<\/button>';\n                html += '<\/div><\/div>';\n                if (window.tiAlert) window.tiAlert(html); else alert(html.replace(\/<[^>]+>\/g,' '));\n            });\n        }, 1200);\n    };\n    function schedule(){ try { window.tiCheckInvalidFilePathsOnConfig583(false); } catch(e){} }\n    var oldOpenModal = window.openModal;\n    if (typeof oldOpenModal === 'function' && !oldOpenModal.__tiInvalidPath583) {\n        window.openModal = function(id){ var r = oldOpenModal.apply(this, arguments); if (s(id) === 'ti-conf-ov') setTimeout(schedule, 800); return r; };\n        window.openModal.__tiInvalidPath583 = true;\n    }\n    ['openConfigSafe509','openConfigSafe508','openConfigSafe507','openConfigSafe501','openConfigSafe492','openConfigSafe218'].forEach(function(name){\n        var fn = window[name];\n        if (typeof fn === 'function' && !fn.__tiInvalidPath583) {\n            window[name] = function(){ var r = fn.apply(this, arguments); setTimeout(schedule, 1800); return r; };\n            window[name].__tiInvalidPath583 = true;\n        }\n    });\n    var oldRender = window.renderConfig;\n    if (typeof oldRender === 'function' && !oldRender.__tiInvalidPath583) {\n        window.renderConfig = function(){ var r = oldRender.apply(this, arguments); setTimeout(schedule, 1600); return r; };\n        window.renderConfig.__tiInvalidPath583 = true;\n    }\n})();\n<\/script>\n\n\n\n\n\n\n\n\n\n\n\n<script id=\"ti-config-image-throttle-596\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigImageThrottle596Installed) return;\n    window.__tiConfigImageThrottle596Installed = true;\n    var maxActive = 3, active = 0, queue = [];\n    function isTiImg(url){ return \/ti_action=ti_ai_get_image\/i.test(String(url || '')); }\n    function next(){\n        while (active < maxActive && queue.length) {\n            var img = queue.shift();\n            if (!img || img.getAttribute('data-ti-img-loaded-596') === '1') continue;\n            var src = img.getAttribute('data-ti-src-596');\n            if (!src) continue;\n            active++;\n            img.setAttribute('data-ti-img-loaded-596','1');\n            img.onload = img.onerror = function(){ active = Math.max(0, active - 1); setTimeout(next, 30); };\n            img.src = src;\n        }\n    }\n    function process(root){\n        root = root || document;\n        try {\n            root.querySelectorAll('img').forEach(function(img){\n                var src = img.getAttribute('src') || '';\n                if (!isTiImg(src) || img.getAttribute('data-ti-img-queued-596') === '1') return;\n                img.setAttribute('data-ti-src-596', src);\n                img.setAttribute('data-ti-img-queued-596','1');\n                img.removeAttribute('src');\n                img.loading = 'lazy';\n                img.decoding = 'async';\n                queue.push(img);\n            });\n            next();\n        } catch(e) {}\n    }\n    var prevRender = window.renderConfig;\n    if (typeof prevRender === 'function' && !prevRender.__tiImageThrottle596) {\n        window.renderConfig = function(){\n            var ret = prevRender.apply(this, arguments);\n            setTimeout(function(){ process(document); }, 0);\n            return ret;\n        };\n        window.renderConfig.__tiImageThrottle596 = true;\n    }\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ process(document); });\n    else setTimeout(function(){ process(document); }, 0);\n})();\n<\/script>\n\n\n\n\n<script id=\"ti-config-login-help-600\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigLoginHelp600Installed) return;\n    window.__tiConfigLoginHelp600Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function norm(v){ return txt(v).trim().toLowerCase(); }\n    function visible(el){\n        try {\n            if (!el) return false;\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            return !(cs && (cs.display === 'none' || cs.visibility === 'hidden'));\n        } catch(e) { return !!el; }\n    }\n    function isPluginLogged(){\n        try {\n            var u = norm(window.tiUser || window.currentUser || '');\n            if (u && u !== 'cliente\/utente' && u !== 'cliente' && u !== 'utente' && u !== 'guest' && u !== 'ospite') return true;\n            var name = norm((byId('ti-user-name') || {}).textContent || '');\n            var role = norm((byId('ti-user-role') || {}).textContent || '');\n            if (name && name !== 'cliente\/utente' && name !== 'cliente' && name !== 'utente' && name !== 'ospite') return true;\n            if (role && role !== '-') return true;\n            var area = byId('ti-user-area');\n            if (visible(area) && (name || role) && name !== 'cliente\/utente') return true;\n            var logout = byId('ti-logout-btn');\n            if (visible(logout)) return true;\n        } catch(e) {}\n        return false;\n    }\n    function applyLoginButtons(){\n        var login = byId('ti-login-btn');\n        var logout = byId('ti-logout-btn');\n        if (isPluginLogged()) {\n            if (login) login.style.setProperty('display','none','important');\n            if (logout) logout.style.setProperty('display','inline-flex','important');\n            var direct = byId('ti-mobile-direct-login');\n            if (direct) direct.classList.remove('ti-direct-login-visible');\n        }\n    }\n    function ensureConfigHelp(){\n        var right = document.querySelector('#ti-conf-ov .ti-conf-header-right');\n        if (!right || byId('ti-conf-help-btn')) return;\n        var btn = document.createElement('button');\n        btn.type = 'button';\n        btn.id = 'ti-conf-help-btn';\n        btn.className = 'ti-header-help-btn ti-conf-help-btn';\n        btn.title = 'Aiuto configurazione';\n        btn.setAttribute('aria-label','Aiuto configurazione');\n        btn.textContent = '?';\n        btn.style.cssText = 'display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;min-width:24px;min-height:24px;padding:0;border-radius:999px;background:#374151;color:#fff;border:1px solid #4b5563;font-size:14px;font-weight:900;line-height:1;cursor:pointer;margin-right:6px;';\n        btn.addEventListener('click', function(ev){\n            try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {}\n            if (typeof window.openHelpModal === 'function') window.openHelpModal();\n            else {\n                var hb = byId('ti-help-btn');\n                if (hb) hb.click();\n            }\n            return false;\n        }, true);\n        var global = byId('ti-conf-global-btn');\n        if (global && global.parentNode === right) right.insertBefore(btn, global);\n        else right.insertBefore(btn, right.firstChild);\n    }\n    function apply(){ applyLoginButtons(); ensureConfigHelp(); }\n    var prevSetAdmin = window.setAdminUI;\n    if (typeof prevSetAdmin === 'function' && !prevSetAdmin.__ti600) {\n        window.setAdminUI = function(){ var r = prevSetAdmin.apply(this, arguments); setTimeout(apply, 0); return r; };\n        window.setAdminUI.__ti600 = true;\n    }\n    var prevOpenModal = window.openModal;\n    if (typeof prevOpenModal === 'function' && !prevOpenModal.__ti600) {\n        window.openModal = function(id){ var r = prevOpenModal.apply(this, arguments); if (id === 'ti-conf-ov') setTimeout(ensureConfigHelp, 0); setTimeout(applyLoginButtons, 0); return r; };\n        window.openModal.__ti600 = true;\n    }\n    ['DOMContentLoaded','ti:login','ti:config-opened'].forEach(function(evt){ document.addEventListener(evt, apply, true); });\n    setTimeout(apply, 0); setTimeout(apply, 500); setTimeout(apply, 1500);\n})();\n<\/script>\n\n\n\n\n\n\n\n\n<style id=\"ti-native-file-upload-621-css\">\n.ti-native-upload-617{background:#0f172a;border:1px solid #334155;border-radius:10px;padding:10px;box-sizing:border-box;text-align:left;}\n.ti-native-upload-row-617{display:flex;gap:8px;align-items:stretch;flex-wrap:wrap;}\n.ti-native-file-617{position:fixed!important;left:-9999px!important;top:-9999px!important;width:1px!important;height:1px!important;opacity:0!important;pointer-events:none!important;}\n.ti-native-upload-row-617 .ti-btn{flex:1;min-width:145px;}\n.ti-native-status-617{margin-top:8px;font-size:12px;line-height:1.35;color:#bfdbfe;text-align:center;white-space:normal;word-break:break-word;}\n.ti-native-status-617.ti-upload-error-617{color:#fecaca;}\n#ti-direct-upload-ov-621{position:fixed;inset:0;z-index:2147483600;display:none;align-items:center;justify-content:center;background:rgba(0,0,0,.72);padding:14px;box-sizing:border-box;}\n#ti-direct-upload-ov-621 .ti-direct-upload-box-621{width:min(94vw,720px);max-height:94vh;overflow:auto;background:#111827;border:1px solid #374151;border-radius:14px;box-shadow:0 24px 70px rgba(0,0,0,.55);color:#e5e7eb;padding:16px;box-sizing:border-box;text-align:left;}\n#ti-direct-upload-ov-621 h3{color:#fff;margin:0 0 10px 0;font-size:17px;line-height:1.25;}\n#ti-direct-upload-ov-621 .ti-direct-upload-text-621{font-size:13px;line-height:1.45;color:#cbd5e1;margin:8px 0 12px 0;}\n#ti-direct-upload-ov-621 .ti-direct-upload-file-621{font-size:12px;color:#bfdbfe;word-break:break-word;margin:6px 0 10px 0;display:none;}\n#ti-direct-upload-ov-621 .ti-direct-upload-preview-1526{display:none;margin:8px 0 12px 0;padding:8px;border:1px solid #334155;border-radius:10px;background:#020617;color:#e5e7eb;max-height:42vh;overflow:auto;box-sizing:border-box;}\n#ti-direct-upload-ov-621 .ti-direct-upload-preview-1526 iframe{display:block;width:100%;height:min(34vh,320px);border:0;border-radius:7px;background:#fff;}\n#ti-direct-upload-ov-621 .ti-direct-upload-preview-1526 img{display:block;max-width:100%;max-height:34vh;margin:0 auto;border-radius:7px;object-fit:contain;background:#fff;}\n#ti-direct-upload-ov-621 .ti-direct-upload-preview-1526 pre{margin:0;white-space:pre-wrap;word-break:break-word;max-height:32vh;overflow:auto;color:#dbeafe;font-size:10px;line-height:1.35;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;}\n#ti-direct-upload-ov-621 .ti-direct-progress-wrap-621{display:none;margin:12px 0 10px 0;}\n#ti-direct-upload-ov-621 .ti-direct-progress-shell-621{height:14px;background:#020617;border:1px solid #334155;border-radius:999px;overflow:hidden;}\n#ti-direct-upload-ov-621 .ti-direct-progress-bar-621{width:0%;height:100%;background:linear-gradient(90deg,#2563eb,#22c55e);transition:width .16s linear;}\n#ti-direct-upload-ov-621 .ti-direct-progress-label-621{margin-top:6px;font-size:12px;color:#dbeafe;text-align:center;}\n#ti-direct-upload-ov-621 .ti-direct-upload-log-821{display:none;margin:10px 0 8px 0;border:1px solid #475569;border-radius:10px;background:#020617;padding:8px;}\n#ti-direct-upload-ov-621 .ti-direct-upload-log-head-821{display:block;margin-bottom:6px;color:#e0f2fe;font-size:12px;font-weight:700;}\n#ti-direct-upload-ov-621 .ti-direct-upload-log-text-821{width:100%;min-height:150px;max-height:28vh;resize:vertical;box-sizing:border-box;border:1px solid #334155;border-radius:8px;background:#000;color:#d1fae5;font-family:Consolas,Monaco,monospace;font-size:11px;line-height:1.35;padding:8px;white-space:pre;overflow:auto;}\n#ti-direct-upload-ov-621 .ti-direct-upload-log-copy-821{display:block;width:100%;margin-top:8px;min-width:96px!important;padding:7px 10px!important;font-size:12px!important;background:#065f46!important;}\n#ti-direct-upload-ov-621 .ti-direct-upload-actions-621{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;}\n#ti-direct-upload-ov-621 .ti-btn{flex:1;min-width:130px;}\n#ti-direct-upload-ov-621 .ti-direct-exit-621{background:#4b5563!important;}\n#ti-direct-upload-ov-621 .ti-direct-start-621{background:#2563eb!important;}\n#ti-direct-upload-ov-621 .ti-direct-error-621{color:#fecaca!important;}\n#ti-direct-upload-ov-621 .ti-direct-source-map-629{display:none;margin:10px 0 8px 0;padding:10px;border:1px solid #334155;border-radius:10px;background:#000!important;color:#fff!important;font-size:12px;line-height:1.35;}\n#ti-direct-upload-ov-621 .ti-direct-source-map-629 label{display:flex;gap:7px;align-items:flex-start;margin-bottom:7px;background:#000!important;color:#fff!important;}\n#ti-direct-upload-ov-621 .ti-direct-source-map-629 label span,#ti-direct-upload-ov-621 #ti-direct-upload-map-label-text-629{background:#000!important;color:#fff!important;}\n#ti-direct-upload-ov-621 .ti-direct-source-map-629 input[type=checkbox]{accent-color:#111827;}\n#ti-direct-upload-ov-621 .ti-direct-source-map-629 input[type=text]{width:100%;box-sizing:border-box;border:1px solid #475569;border-radius:8px;background:#000!important;color:#fff!important;padding:8px;font-size:13px;}\n#ti-direct-upload-ov-621 .ti-direct-source-map-629 input[type=text]::placeholder{color:#e5e7eb!important;opacity:.85;}\n@media (max-width:640px){#ti-direct-upload-ov-621 .ti-direct-upload-box-621{width:96vw}.ti-native-upload-row-617{display:block}.ti-native-upload-row-617 .ti-btn{width:100%;margin-top:8px}}\n<\/style>\n<script id=\"ti-native-file-upload-651\">\n\n(function(){\n    \"use strict\";\n    if (window.__tiNativeFileUpload651Installed) return;\n    window.__tiNativeFileUpload651Installed = true;\n    window.__tiNativeFileUpload646Installed = true;\n    window.__tiNativeFileUpload645Installed = true;\n    window.__tiNativeFileUpload644Installed = true;\n    window.__tiNativeFileUpload643Installed = true;\n    window.__tiNativeFileUpload642Installed = true;\n    window.__tiNativeFileUpload641Installed = true;\n    window.__tiNativeFileUpload636Installed = true;\n    window.__tiNativeFileUpload634Installed = true;\n    window.__tiNativeFileUpload633Installed = true;\n    window.__tiNativeFileUpload632Installed = true;\n    window.__tiNativeFileUpload630Installed = true;\n    window.__tiNativeFileUpload629Installed = true;\n    window.__tiNativeFileUpload626Installed = true;\n    window.__tiNativeFileUpload625Installed = true;\n    window.__tiNativeFileUpload621Installed = true;\n    window.__tiNativeFileUpload624Installed = true;\n    window.__tiNativeFileUpload623Installed = true;\n    window.__tiNativeFileUpload622Installed = true;\n    window.__tiNativeFileUpload620Installed = true;\n    window.__tiNativeFileUpload617Installed = true;\n\n    var state = {kind:'main', target:'chat', xhr:null, busy:false, file:null, ctx:null, confirmingPath:false, confirmingUpload:false, serverAuthorizedPath659:'', serverCompanyLabel659:'', cancelRequested808:false, exitReason808:'', suppressStartClickUntil849:0, nativePickerArmedAt849:0, savedUploads859:[], uploadCleanupToken859:'', previousCleanupTokens859:[], preserveConfigFile1526:false, completedOk1528:false, managerAssociationPending1596:false};\n    try { window.__tiNativeFileUploadState = state; } catch(e823state) {}\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function trim(v){ return txt(v).trim(); }\n    function esc(v){ return txt(v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function dbName(){\n        var ids = ['ti-ditta','ti-db','ti-current-db','ti-selected-db'];\n        for (var i=0;i<ids.length;i++){ var el = byId(ids[i]); if (el && el.value) return el.value; }\n        try { if (window.currentDbName) return window.currentDbName; } catch(e) {}\n        try { if (window.tiCurrentDb) return window.tiCurrentDb; } catch(e2) {}\n        try { if (window.tiSelectedDb) return window.tiSelectedDb; } catch(e3) {}\n        try { if (window.currentDbData && window.currentDbData.__db_name) return window.currentDbData.__db_name; } catch(e4) {}\n        return 'Global';\n    }\n    function validCtx(ctx){ return !!(ctx && typeof ctx === 'object' && ctx.tbl && ctx.key && ctx.idx !== undefined && ctx.idx !== null && ctx.idx !== ''); }\n    function cloneCtx(ctx){ return validCtx(ctx) ? {tbl:txt(ctx.tbl), idx:ctx.idx, key:txt(ctx.key), id:ctx.id || ''} : null; }\n    function roleText(){\n        var r = trim(window.tiRole || window.tiUserRole || window.currentUserRole || '');\n        if (!r) {\n            var el = byId('ti-user-role');\n            r = trim(el ? el.textContent : '');\n        }\n        return r.toLowerCase();\n    }\n    function isPrivilegedUploadUser(){\n        var r = roleText();\n        var u = trim(window.tiUser || window.currentUser || window.tiCurrentUser || window.tiUsername || '').toLowerCase();\n        if (window.tiIsPrivilegedUploadUser === true || String(window.tiIsPrivilegedUploadUser || '').toLowerCase() === 'true') return true;\n        if (window.__tiPrivilegedUploadUser === true || window.tiCanCleanupOrphanFiles === true || window.tiConfigCanEditData === true) return true;\n        if (u === 'ssglobaladmin' || u === 'targetai') return true;\n        if (\/amministratore|administrator|configuratore|configurator|responsabile|responsible|globaladmin|global admin|globale|sysadmin\/.test(r)) return true;\n        try { if (typeof window.tiAiSsConfigCanEditData517 === 'function' && window.tiAiSsConfigCanEditData517()) return true; } catch(e) {}\n        try { if (typeof window.isAdminConfiguratorUser === 'function' && window.isAdminConfiguratorUser()) return true; } catch(e) {}\n        return false;\n    }\n    function isBasicUploadUser(){ return !isPrivilegedUploadUser(); }\n    function sanitizeNonPrivilegedMessage634(message){\n        var out = txt(message);\n        out = out.replace(\/Errore\\s+aggiunta\\s+file\\s+da\\s+PC\\s*:\\s*Upload\\s+file\\s+disponibile\\s+solo\\s+per[^\\r\\n.<]*\/gi, \"Errore upload file: Upload file non disponibile con il profilo corrente. Usa la procedura guidata prevista oppure richiedi l'abilitazione della sorgente file.\");\n        out = out.replace(\/Errore[^:\\r\\n<]*aggiunta[^:\\r\\n<]*file[^:\\r\\n<]*(?:PC|dispositivo)[^:\\r\\n<]*:\\s*Upload[^\\r\\n<]*(?:amministratore|administrator|configuratore|responsabile|globaladmin|global\\s*admin|SSGlobalAdmin)[^\\r\\n<]*\/gi, \"Errore upload file: Upload file non disponibile con il profilo corrente. Usa la procedura guidata prevista oppure richiedi l'abilitazione della sorgente file.\");\n        out = out.replace(new RegExp(['Upload file disponibile',' solo per'].join('') + '[^\\\\r\\\\n.]*', 'gi'), \"Upload file non disponibile con il profilo corrente. Usa la procedura guidata prevista oppure richiedi l'abilitazione della sorgente file.\");\n        out = out.replace(new RegExp(['Upload e associazione file disponibili',' solo per'].join('') + '[^\\\\r\\\\n.]*', 'gi'), \"Upload e associazione file non disponibili con il profilo corrente. Usa la procedura guidata prevista oppure richiedi l'abilitazione della sorgente file.\");\n        out = out.replace(new RegExp(['Associazione file disponibile',' solo per'].join('') + '[^\\\\r\\\\n.]*', 'gi'), \"Associazione file non disponibile con il profilo corrente.\");\n        out = out.replace(\/Funzione disponibile solo per[^\\r\\n.]*\/gi, \"Funzione non disponibile con il profilo corrente.\");\n        out = out.replace(\/Funzione globale disponibile solo per[^\\r\\n.]*\/gi, \"Funzione globale non disponibile con il profilo corrente.\");\n        out = out.replace(\/Accesso negato\\.\\s*Operazione disponibile solo per[^\\r\\n.]*\/gi, \"Accesso negato. Operazione non disponibile con il profilo corrente.\");\n        out = out.replace(\/\\bSSGlobalAdmin\\b|\\bglobal\\s*admin\\b|\\bglobaladmin\\b\/gi, 'profilo abilitato');\n        out = out.replace(\/\\bamministratore\\b|\\bamministratori\\b|\\badministrator\\b|\\bconfiguratore\\b|\\bconfiguratori\\b|\\bresponsabile\\b|\\bresponsabili\\b\/gi, 'profilo abilitato');\n        out = out.replace(\/profilo abilitato\\s*,\\s*profilo abilitato\\s*,\\s*profilo abilitato\\s*o\\s*profilo abilitato\/gi, 'profilo abilitato');\n        out = out.replace(\/profili abilitati\\s*,\\s*profili abilitati\/gi, 'profili abilitati');\n        return out;\n    }\n    function installUploadAlertSanitizer634(){\n        try {\n            var prev = window.tiAlert;\n            if (typeof prev === 'function' && !prev.__tiUploadSanitizer644) {\n                window.tiAlert = function(message){\n                    var args = Array.prototype.slice.call(arguments);\n                    args[0] = sanitizeNonPrivilegedMessage634(args[0]);\n                    return prev.apply(this, args);\n                };\n                window.tiAlert.__tiUploadSanitizer644 = true;\n                window.tiAlert.__tiUploadSanitizer634 = true;\n            }\n            var nativeAlert = window.alert;\n            if (typeof nativeAlert === 'function' && !nativeAlert.__tiUploadSanitizer644) {\n                window.alert = function(message){ return nativeAlert.call(window, sanitizeNonPrivilegedMessage634(message)); };\n                window.alert.__tiUploadSanitizer644 = true;\n            }\n        } catch(e) {}\n    }\n    function isMobileUploadDevice(){\n        try {\n            if (navigator.userAgentData && navigator.userAgentData.mobile) return true;\n        } catch(e) {}\n        var ua = trim((navigator && navigator.userAgent) || '').toLowerCase();\n        if (\/android|iphone|ipad|ipod|windows phone|mobile|tablet|kindle|silk|opera mini\/.test(ua)) return true;\n        try {\n            if (navigator.maxTouchPoints > 1 && \/macintosh|mac os\/.test(ua)) return true; \/\/ iPadOS in modalita desktop.\n        } catch(e2) {}\n        try {\n            if (window.matchMedia && window.matchMedia('(pointer: coarse)').matches && Math.min(window.innerWidth || 0, window.innerHeight || 0) <= 900) return true;\n        } catch(e3) {}\n        return false;\n    }\n    function basicDesktopUploadBlocked(){ return false; }\n    function removableNoticeText(kind){\n        if (isBasicUploadUser()) {\n            var p = firstAuthorizedSourcePath642();\n            if (p) return 'Il caricamento \u00e8 consentito solo dall\\'origine\/path autorizzata dalla ditta:<br><b>' + esc(p) + '<\/b><br><br>Non usare disco fisso o path di sistema generici. Inserisci eventualmente il supporto corretto, poi premi <b>Apri scelta file<\/b> e scegli il file da tale origine.<br><br>Nota tecnica: per sicurezza il browser non comunica sempre a Shop & Service il percorso locale reale del dispositivo; il plugin usa la prima origine\/path autorizzata presente nelle istruzioni della ditta.';\n            return 'Nessuna origine\/path file risulta disponibile per la ditta ' + esc(displayDittaLabel658(companyLabel642())) + '.';\n        }\n        var base2 = 'Prima di avviare la scelta del file, inserisci se necessario la chiavetta USB, il CD, il DVD o altro supporto esterno che contiene il documento.';\n        base2 += '<br><br>Per sicurezza del browser, Shop & Service non pu\u00f2 leggere o monitorare automaticamente l\\'elenco dei dischi\/supporti removibili collegati. La scelta avviene nella finestra nativa del sistema, dove potrai selezionare anche file presenti su USB, CD, DVD o altro supporto disponibile.';\n        if (window.__tiEnablePrivilegedUploadSourceMapping === true) base2 += '<br><br>Se questa \u00e8 una nuova origine da rendere disponibile agli utenti standard, puoi salvarla come istruzione: la AI user\u00e0 tale regola per consentire il caricamento guidato dalla path\/origine dichiarata.';\n        if (kind === 'manager') base2 += '<br><br>Il file selezionato verr\u00e0 caricato e associato al campo corrente.';\n        else base2 += '<br><br>Il file selezionato verr\u00e0 caricato e poi interpretato dalla AI quando possibile.';\n        return base2;\n    }\n    function isManager(kind){ return kind === 'manager'; }\n    function statusEl(kind){ return byId(isManager(kind) ? 'ti-fm-native-status-617' : 'ti-main-native-status-617'); }\n    function setInlineStatus(kind, msg, err){ var el = statusEl(kind); if (!el) return; el.className = 'ti-native-status-617' + (err ? ' ti-upload-error-617' : ''); el.innerHTML = msg ? esc(msg) : ''; }\n\n    function cleanupUrl859(){ return \"https:\/\/www.tisoft.it\/en\/?ti_action=ti_ai_ss_upload_cleanup_859\"; }\n    function makeUploadCleanupToken859(){ return 'u859_' + Date.now() + '_' + Math.random().toString(36).slice(2, 11); }\n    function currentUploadCleanupToken859(create){\n        if (!state.uploadCleanupToken859 && create !== false) state.uploadCleanupToken859 = makeUploadCleanupToken859();\n        return state.uploadCleanupToken859 || '';\n    }\n    function aiUploadTarget859(target){ target = trim(target || state.target || ''); return \/^(config-bot-file|chat|purchase-import-file)$\/.test(target); }\n    function dbForCleanup859(){ try { return dbName(); } catch(e) { return 'Global'; } }\n    function clearFileAiStorage859(removeMessages){\n        try { window.configBotFile = ''; window.lastUploadedFile = ''; window.__tiConfigBotFile798 = ''; window.__tiConfigBotFile847 = null; window.__tiLastFileAi799 = null; window.__tiLastFileAi798 = null; window.__tiLastAutoConfigFile795 = ''; window.__tiAutoFileImportRunning795 = false; } catch(e) {}\n        try { if (window.lastFileContext) { window.lastFileContext.url = ''; window.lastFileContext.active = false; window.lastFileContext.awaitingAction799 = false; } } catch(e2) {}\n        try {\n            [sessionStorage, localStorage].forEach(function(st){\n                if (!st) return;\n                var keys = [];\n                for (var i = 0; i < st.length; i++) { var k = st.key(i) || ''; if (\/^tiFileAI(798|799)::\/.test(k)) keys.push(k); }\n                keys.forEach(function(k){ try { st.removeItem(k); } catch(e) {} });\n            });\n        } catch(e3) {}\n        if (!removeMessages) return;\n        try { var fb = byId('ti-conf-ai-file'); if (fb) { fb.innerHTML = ''; fb.style.display = 'none'; } } catch(e4) {}\n        try {\n            var r = byId('ti-conf-ai-reply');\n            var rt = trim(r ? (r.textContent || '') : '');\n            if (r && \/file\\s+(caricato|disponibile|scelto)|cosa\\s+vuoi\\s+fare\\s+con\\s+questo\\s+file|anteprima\\s+import\\s+dal\\s+file|ANNULLA FILE|CARICA PRODOTTI E SERVIZI\/i.test(rt)) {\n                r.innerHTML = '';\n                r.style.display = 'none';\n            }\n        } catch(e5) {}\n        try {\n            var p = byId('ti-conf-ai-prompt');\n            if (p && \/ho\\s+caricato\\s+un\\s+file\\s+per\\s+la\\s+ai|aggiungi\\s+servizi\\s+e\\s+prodotti\\s+dal\\s+file\/i.test(p.value || '')) p.value = '';\n        } catch(e6) {}\n        try {\n            var bubbles = document.querySelectorAll('#ti-chat .ti-bubble.ai');\n            Array.prototype.forEach.call(bubbles, function(b){\n                var bt = trim(b.textContent || '');\n                if (\/file\\s+(caricato|disponibile|scelto)|cosa\\s+vuoi\\s+fare\\s+con\\s+questo\\s+file|CARICA PRODOTTI E SERVIZI|ANNULLA FILE\/i.test(bt)) {\n                    try { b.parentNode.removeChild(b); } catch(e) {}\n                }\n            });\n        } catch(e7) {}\n    }\n    function registerSavedUpload859(data, kind, target, file){\n        try {\n            if (!data) return;\n            var name = trim(data.name || data.filename || '');\n            var url = trim(data.url || '');\n            var path = trim(data.path || data.stored_path || '');\n            if (!name && url) { try { name = decodeURIComponent(url).split(\/[?#]\/)[0].split('\/').pop() || ''; } catch(e) {} }\n            if (!name && path) name = path.split(\/[\\\\\/]\/).pop() || '';\n            if (!name || !\/^\\d{14}_\\d{4}\\.[a-z0-9]{1,16}$\/i.test(name)) return;\n            var realTbl1526 = data.stored_table || data.tbl || (\/^config-bot-file\/i.test(String(target||'')) ? 'Config' : (target === 'chat' ? 'Chat' : 'Config'));\n            var mode1528 = trim(data.mode || ''); if (!mode1528) mode1528 = isManager(kind) ? 'attach' : 'plain';\n            var item = {name:name, filename:name, url:url, path:path, db:dbForCleanup859(), tbl:realTbl1526, record:(data.record_label || ''), mode:mode1528, kind:(kind || state.kind || 'main'), target:(target || state.target || ''), token:currentUploadCleanupToken859(false), original:(file && file.name ? file.name : '')};\n            state.savedUploads859 = state.savedUploads859 || [];\n            state.savedUploads859.push(item);\n            try { window.__tiGuidedUploadSaved859 = state.savedUploads859.slice(0); } catch(e2) {}\n        } catch(e3) {}\n    }\n    function cleanupRequest859(item, reason, token){\n        try {\n            var fd = new FormData();\n            fd.append('action', 'ti_ai_ss_upload_cleanup_859');\n            fd.append('ti_action', 'ti_ai_ss_upload_cleanup_859');\n            fd.append('reason', reason || 'reset_upload');\n            fd.append('cleanup_token', token || (item && item.token) || currentUploadCleanupToken859(false) || '');\n            fd.append('upload_cleanup_token', token || (item && item.token) || currentUploadCleanupToken859(false) || '');\n            fd.append('db', (item && item.db) || dbForCleanup859());\n            fd.append('tbl', (item && item.tbl) || 'Chat');\n            fd.append('record_label', (item && item.record) || '');\n            fd.append('file', (item && (item.name || item.filename)) || '');\n            fd.append('file_url', (item && item.url) || '');\n            fd.append('stored_path', (item && item.path) || '');\n            fd.append('mode', (item && item.mode) || 'plain');\n            fd.append('guided_upload_target', (item && item.target) || state.target || '');\n            return fetch(cleanupUrl859(), {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'}).then(function(r){ return r.text(); }).catch(function(){ return ''; });\n        } catch(e) { return Promise.resolve(''); }\n    }\n    function commitSavedUploads859(reason){\n        \/\/ 30.9.1526: un file Config\/Docs verificato non e piu temporaneo. Rimuove solo il registro cleanup, non il file.\n        var token=currentUploadCleanupToken859(false);\n        if(!token){ state.savedUploads859=[]; try{window.__tiGuidedUploadSaved859=[];}catch(e0){} return Promise.resolve(''); }\n        try{\n            var fd=new FormData();\n            fd.append('action','ti_ai_ss_upload_cleanup_859'); fd.append('ti_action','ti_ai_ss_upload_cleanup_859');\n            fd.append('upload_cleanup_token',token); fd.append('cleanup_token',token); fd.append('commit_keep_files','1');\n            fd.append('reason',reason||'commit_config_file_1526'); fd.append('db',dbForCleanup859()); fd.append('tbl','Config'); fd.append('guided_upload_target','config-bot-file');\n            state.savedUploads859=[]; try{window.__tiGuidedUploadSaved859=[];}catch(e1){} state.uploadCleanupToken859='';\n            return fetch(cleanupUrl859(),{method:'POST',body:fd,credentials:'same-origin',cache:'no-store'}).then(function(r){return r.text();}).catch(function(){return '';});\n        }catch(e){ state.uploadCleanupToken859=''; return Promise.resolve(''); }\n    }\n    function cleanupSavedUploads859(reason, removeMessages, keepToken){\n        var list = [];\n        try { if (state.savedUploads859 && state.savedUploads859.length) list = list.concat(state.savedUploads859); } catch(e) {}\n        try { if (window.__tiGuidedUploadSaved859 && window.__tiGuidedUploadSaved859.length) list = list.concat(window.__tiGuidedUploadSaved859); } catch(e2) {}\n        var token = currentUploadCleanupToken859(false);\n        var seen = {}, dedup = [];\n        list.forEach(function(it){ var k = (it && (it.path || it.url || it.name || it.filename) || '') + '|' + (it && it.token || token || ''); if (k && !seen[k]) { seen[k] = true; dedup.push(it); } });\n        state.savedUploads859 = [];\n        try { window.__tiGuidedUploadSaved859 = []; } catch(e3) {}\n        if (removeMessages) clearFileAiStorage859(true);\n        var jobs = [];\n        if (token) jobs.push(cleanupRequest859(null, reason || 'reset_upload', token));\n        dedup.forEach(function(it){ jobs.push(cleanupRequest859(it, reason || 'reset_upload', it && it.token ? it.token : token)); });\n        if (!keepToken) state.uploadCleanupToken859 = '';\n        if (!jobs.length) return Promise.resolve([]);\n        return Promise.all(jobs.map(function(p){ return p.catch(function(){ return ''; }); }));\n    }\n    function scheduleCleanup859(reason, removeMessages, token){\n        try { cleanupSavedUploads859(reason, removeMessages, true); } catch(e) {}\n        [1200, 4500, 12000].forEach(function(ms){ setTimeout(function(){ try { if (token) cleanupRequest859(null, reason || 'delayed_cleanup', token); } catch(e) {} }, ms); });\n    }\n    function hardResetUploadForReopen859(reason, removeMessages){\n        var token = currentUploadCleanupToken859(false);\n        try { if (state.xhr && state.xhr.readyState !== 4) state.xhr.abort(); } catch(e) {}\n        try { if (state.currentUploadAbort821) state.currentUploadAbort821.abort(); } catch(e2) {}\n        try { clearUploadWatchdog812(); } catch(e3) {}\n        try { removePendingNativeInputs808(); } catch(e4) {}\n        try { forceHideUploadProgress808(reason || 'reopen'); } catch(e5) {}\n        try { document.body.classList.remove('ti-upload-busy','ti-ai-upload-busy','ti-loader-active','ti-modal-open'); } catch(e6) {}\n        try { cleanupSavedUploads859(reason || 'riapertura_caricamento_file_ai', !!removeMessages, false); } catch(e7) {}\n        if (token) { [1500, 6000].forEach(function(ms){ setTimeout(function(){ cleanupRequest859(null, reason || 'riapertura_caricamento_file_ai', token); }, ms); }); }\n        state.busy = false; state.xhr = null; state.currentUploadAbort821 = null; state.file = null; state.confirmingPath = false; state.confirmingUpload = false; state.cancelRequested808 = false; state.timeoutRequested812 = false; state.uploadStartedAt812 = 0; state.uploadLastProgressAt812 = 0; state.popupClosedAfterSelect791 = false; state.autoCloseUploadModalAfterSelect791 = false; state.uploadCleanupToken859 = ''; state.preserveConfigFile1526 = false;\n        try { window.__tiGuidedUploadBusy810 = false; window.__tiComplexProcessActive845 = false; window.__tiGuidedUploadSelectedFile810 = null; window.__tiGuidedUploadCancelled808 = 0; } catch(e8) {}\n    }\n\n    function saveCtx(ctx){\n        var c = cloneCtx(ctx);\n        if (!c) return null;\n        window.targetUploadContext = c;\n        window.__tiNativeUploadCtx621 = c;\n        window.__tiNativeUploadCtx620 = c;\n        window.__tiNativeUploadCtx617 = c;\n        window.__tiLastDirectUploadCtx616 = c;\n        window.__tiLastFileManagerCtx471 = c;\n        window.__tiLastFileManagerCtx455 = c;\n        try { sessionStorage.setItem('tiNativeUploadCtx621', JSON.stringify(c)); } catch(e) {}\n        try { sessionStorage.setItem('tiNativeUploadCtx620', JSON.stringify(c)); } catch(e) {}\n        try { sessionStorage.setItem('tiNativeUploadCtx617', JSON.stringify(c)); } catch(e) {}\n        return c;\n    }\n    function readCtx(){\n        var c = cloneCtx(window.__tiNativeUploadCtx621 || window.__tiNativeUploadCtx620 || window.__tiNativeUploadCtx617 || window.targetUploadContext || window.__tiLastDirectUploadCtx616 || window.__tiLastFileManagerCtx471 || window.__tiLastFileManagerCtx455 || window.__tiLastFileManagerCtx360 || window.__tiLastFileAiCtx358 || window.__tiLastUploadContext356);\n        if (c) return saveCtx(c);\n        var fm = byId('ti-file-manager-ov');\n        if (fm) {\n            c = cloneCtx({tbl:fm.dataset ? (fm.dataset.tbl || fm.dataset.table || '') : '', idx:fm.dataset ? (fm.dataset.idx || fm.dataset.row || '') : '', key:fm.dataset ? (fm.dataset.key || fm.dataset.field || '') : '', id:fm.dataset ? (fm.dataset.id || '') : ''});\n            if (c) return saveCtx(c);\n            c = cloneCtx({tbl:fm.getAttribute('data-ti-context-table') || '', idx:fm.getAttribute('data-ti-context-row') || '', key:fm.getAttribute('data-ti-context-field') || '', id:fm.getAttribute('data-ti-context-id') || ''});\n            if (c) return saveCtx(c);\n        }\n        try {\n            var raw = sessionStorage.getItem('tiNativeUploadCtx621') || sessionStorage.getItem('tiNativeUploadCtx620') || sessionStorage.getItem('tiNativeUploadCtx617') || sessionStorage.getItem('tiLastDirectUploadCtx616') || sessionStorage.getItem('tiLastFileManagerCtx471') || sessionStorage.getItem('tiLastFileManagerCtx455');\n            if (raw) { c = cloneCtx(JSON.parse(raw)); if (c) return saveCtx(c); }\n        } catch(e) {}\n        return null;\n    }\n    function rowFor(ctx){\n        try { return (ctx && window.currentDbData && window.currentDbData.Tabelle && window.currentDbData.Tabelle[ctx.tbl]) ? (window.currentDbData.Tabelle[ctx.tbl][ctx.idx] || null) : null; }\n        catch(e) { return null; }\n    }\n    function recordLabel(ctx){\n        try { if (window.getRecordLabelForUpload) return window.getRecordLabelForUpload(ctx.tbl, rowFor(ctx), ctx.tbl); } catch(e) {}\n        return ctx && ctx.tbl ? ctx.tbl : '';\n    }\n    function startButtonWantsNativePicker849(btn){\n        if (!btn || state.busy || state.confirmingPath || state.confirmingUpload || state.file) return false;\n        var label = trim((btn.textContent || btn.value || btn.getAttribute('aria-label') || ''));\n        return \/scegli|ripeti|selezione\\s+file|apri\\s+selezione|apri\\s+scelta|caricamento\/i.test(label);\n    }\n    function handleStartPointerNativePicker849(ev){\n        try {\n            var btn = ev && ev.currentTarget ? ev.currentTarget : byId('ti-direct-upload-start-621');\n            if (!startButtonWantsNativePicker849(btn)) return;\n            var now = Date.now();\n            if (state.nativePickerArmedAt849 && (now - state.nativePickerArmedAt849) < 900) {\n                if (ev.preventDefault) ev.preventDefault();\n                if (ev.stopPropagation) ev.stopPropagation();\n                if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                return false;\n            }\n            state.nativePickerArmedAt849 = now;\n            state.suppressStartClickUntil849 = Date.now() + 650;\n            setTimeout(function(){ try { if (state.suppressStartClickUntil849 && Date.now() >= state.suppressStartClickUntil849) state.suppressStartClickUntil849 = 0; } catch(e849t) {} }, 750);\n            if (ev.preventDefault) ev.preventDefault();\n            if (ev.stopPropagation) ev.stopPropagation();\n            if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n            try { if (aiUploadTarget859(state.target)) cleanupSavedUploads859('ripeti_scelta_file_ai', true, false); } catch(e859rp) {}\n            state.file = null;\n            state.confirmingUpload = false;\n            state.confirmingPath = false;\n            removePendingNativeInputs808();\n            chooseFileNow();\n            return false;\n        } catch(e) { return false; }\n    }\n    function ensureModal(){\n        var ov = byId('ti-direct-upload-ov-621');\n        if (ov) return ov;\n        ov = document.createElement('div');\n        ov.id = 'ti-direct-upload-ov-621';\n        ov.innerHTML = '<div class=\"ti-direct-upload-box-621\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"ti-direct-upload-title-621\">'\n            + '<h3 id=\"ti-direct-upload-title-621\">Caricamento guidato file<\/h3>'\n            + '<div id=\"ti-direct-upload-text-621\" class=\"ti-direct-upload-text-621\"><\/div>'\n            + '<div id=\"ti-direct-upload-file-621\" class=\"ti-direct-upload-file-621\"><\/div>'\n            + '<div id=\"ti-direct-upload-preview-1526\" class=\"ti-direct-upload-preview-1526\"><\/div>'\n            + '<div id=\"ti-direct-upload-map-629\" class=\"ti-direct-source-map-629\" style=\"background:#000!important;color:#fff!important;\"><label id=\"ti-direct-upload-map-label-629\" style=\"background:#000!important;color:#fff!important;\"><input type=\"checkbox\" id=\"ti-direct-upload-map-check-629\"> <span id=\"ti-direct-upload-map-label-text-629\" style=\"background:#000!important;color:#fff!important;\">Salva questa origine\/path come istruzione di caricamento consentita<\/span><\/label><input type=\"text\" id=\"ti-direct-upload-source-label-629\" style=\"background:#000!important;color:#fff!important;\" placeholder=\"Origine\/path autorizzata prevista nelle istruzioni della ditta\"><\/div>'\n            + '<div id=\"ti-direct-progress-wrap-621\" class=\"ti-direct-progress-wrap-621\"><div class=\"ti-direct-progress-shell-621\"><div id=\"ti-direct-progress-bar-621\" class=\"ti-direct-progress-bar-621\"><\/div><\/div><div id=\"ti-direct-progress-label-621\" class=\"ti-direct-progress-label-621\">0%<\/div><\/div>'\n            + '<div id=\"ti-direct-upload-log-821\" class=\"ti-direct-upload-log-821\"><div class=\"ti-direct-upload-log-head-821\"><span>Log tecnico caricamento<\/span><\/div><textarea id=\"ti-direct-upload-log-text-821\" class=\"ti-direct-upload-log-text-821\" readonly><\/textarea><button type=\"button\" id=\"ti-direct-upload-log-copy-821\" class=\"ti-btn ti-direct-upload-log-copy-821\">Copia testo<\/button><\/div>'\n            + '<div class=\"ti-direct-upload-actions-621\"><button type=\"button\" id=\"ti-direct-upload-pick-path-655\" class=\"ti-btn ti-direct-pick-path-655\" style=\"display:none;\">Individua path<\/button><button type=\"button\" id=\"ti-direct-upload-save-source-651\" class=\"ti-btn ti-direct-save-source-651\" style=\"display:none;\">Salva origine\/path<\/button><button type=\"button\" id=\"ti-direct-upload-start-621\" class=\"ti-btn ti-direct-start-621\">Avvia caricamento<\/button><button type=\"button\" id=\"ti-direct-upload-exit-621\" class=\"ti-btn ti-direct-exit-621\">Chiudi<\/button><\/div>'\n            + '<\/div>';\n        document.body.appendChild(ov);\n        try { if (window.tiRefreshUploadUi823) window.tiRefreshUploadUi823(ov); } catch(e823) {}\n        try { if (window.tiNormalizeStableButtons828) window.tiNormalizeStableButtons828(ov); } catch(e828) {}\n        byId('ti-direct-upload-start-621').addEventListener('click', function(ev){\n            try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {}\n            if (state.suppressStartClickUntil849 && Date.now() < state.suppressStartClickUntil849) {\n                try { if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e849) {}\n                return false;\n            }\n            state.suppressStartClickUntil849 = 0;\n            var btn = byId('ti-direct-upload-start-621');\n            var label = trim((btn && btn.textContent) || '');\n            clearStaleUploadLock810('start_button');\n            if (state.busy) {\n                setModalText('Caricamento file ancora in corso. Puoi attendere oppure premere <b>Chiudi<\/b> per annullare. Se il tempo supera il limite, il plugin sblocca automaticamente la form.', true);\n                return false;\n            }\n            if (\/ripeti|scegli\/i.test(label) && !state.confirmingPath && !state.confirmingUpload) {\n                try { if (aiUploadTarget859(state.target)) cleanupSavedUploads859('ripeti_scelta_file_ai', true, false); } catch(e859pick) {}\n                state.file = null;\n                state.confirmingUpload = false;\n                state.confirmingPath = false;\n                removePendingNativeInputs808();\n                chooseFileNow();\n                return false;\n            }\n            if (state.confirmingPath && state.file) { var f = state.file; state.confirmingPath = false; state.confirmingUpload = false; state.autoCloseUploadModalAfterSelect791 = false; setModalText('Conferma ricevuta. Avvio caricamento file...', false); startUpload(state.kind, state.target, f); return false; }\n            if (state.confirmingUpload && state.file) { var f2 = state.file; if (\/riprova\/i.test(label)) { try { cleanupSavedUploads859('riprova_stesso_file_ai', true, false); } catch(e859retry) {} } state.confirmingUpload = false; state.autoCloseUploadModalAfterSelect791 = false; setModalText('Conferma ricevuta. Avvio caricamento file...', false); startUpload(state.kind, state.target, f2); return false; }\n            if (state.file) { state.confirmingUpload = true; showStartButton(true, 'Conferma e carica file'); setModalText('File gia scelto. Premi <b>Conferma e carica file<\/b> per avviare il caricamento.', false); return false; }\n            chooseFileNow(); return false;\n        }, true);\n        var pickPath655 = byId('ti-direct-upload-pick-path-655');\n        if (pickPath655) pickPath655.addEventListener('click', function(ev){ try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {} locateAuthorizedPathOnly655(); return false; }, true);\n        var saveSrc651 = byId('ti-direct-upload-save-source-651');\n        if (saveSrc651) saveSrc651.addEventListener('click', function(ev){ try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {} saveAuthorizedSourceOnly651(); return false; }, true);\n        byId('ti-direct-upload-exit-621').addEventListener('click', function(ev){ try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {} exitUpload(); return false; }, true);\n        var copyLog821 = byId('ti-direct-upload-log-copy-821');\n        if (copyLog821) copyLog821.addEventListener('click', function(ev){\n            try { ev.preventDefault(); ev.stopPropagation(); } catch(e) {}\n            copyUploadLog821();\n            return false;\n        }, true);\n        return ov;\n    }\n    function isUploadLogAllowed821(){\n        return window.tiStrictAdminLog1488 === true;\n    }\n    function uploadLogTime821(){\n        try { var d = new Date(); return d.toLocaleTimeString('it-IT', {hour12:false}) + '.' + String(d.getMilliseconds()).padStart(3,'0'); } catch(e) { return String(Date.now()); }\n    }\n    function uploadLogContext821(){\n        var parts = [];\n        try { parts.push('db=' + (dbName() || '')); } catch(e) {}\n        try { parts.push('kind=' + (state.kind || '')); } catch(e) {}\n        try { parts.push('target=' + (state.target || '')); } catch(e) {}\n        try { parts.push('busy=' + (!!state.busy)); } catch(e) {}\n        try { parts.push('pct=' + (state.progressPercent814 || 0)); } catch(e) {}\n        try { if (state.uploadEndpoint817) parts.push('endpoint=' + state.uploadEndpoint817); } catch(e) {}\n        return parts.join(' | ');\n    }\n    function updateUploadLogPanel821(){\n        try {\n            var allowed822 = isUploadLogAllowed821();\n            var wrap = byId('ti-direct-upload-log-821');\n            var ta = byId('ti-direct-upload-log-text-821');\n            if (wrap) wrap.style.display = allowed822 ? 'block' : 'none';\n            if (!allowed822) { if (ta) ta.value = ''; return; }\n            if (ta) {\n                ta.value = (state.uploadLogLines821 || []).join('\\n');\n                ta.scrollTop = ta.scrollHeight;\n            }\n        } catch(e) {}\n    }\n    function uploadLog821(phase, detail, extra){\n        try {\n            if (!isUploadLogAllowed821()) return;\n            if (!state.uploadLogLines821) state.uploadLogLines821 = [];\n            var msg = '[' + uploadLogTime821() + '] ' + (phase || 'fase') + ' - ' + (detail || '');\n            var ctx = uploadLogContext821();\n            if (ctx) msg += ' | ' + ctx;\n            if (extra) msg += ' | ' + String(extra).replace(\/\\s+\/g, ' ').slice(0, 700);\n            state.uploadLogLines821.push(msg);\n            if (state.uploadLogLines821.length > 500) state.uploadLogLines821 = state.uploadLogLines821.slice(-500);\n            updateUploadLogPanel821();\n        } catch(e) {}\n    }\n    function initUploadLog821(reason, kind, target, file){\n        try {\n            state.uploadLogLines821 = [];\n            state.uploadEndpoint817 = '';\n            state.currentUploadAbort821 = null;\n            var wrap = byId('ti-direct-upload-log-821');\n            if (wrap) wrap.style.display = isUploadLogAllowed821() ? 'block' : 'none';\n            var ta = byId('ti-direct-upload-log-text-821');\n            if (ta) ta.value = '';\n            var f = file ? ((file.name || 'file') + ' size=' + (file.size || 0) + ' type=' + (file.type || '')) : 'file=non ancora scelto';\n            uploadLog821('init', reason || 'apertura flusso upload', 'user=' + (window.tiUser || '') + ' role=' + (window.tiRole || roleText()) + ' | ' + f + ' | ua=' + (navigator.userAgent || ''));\n        } catch(e) {}\n    }\n    function copyUploadLog821(){\n        try {\n            var btn = byId('ti-direct-upload-log-copy-821');\n            function done(ok){ if (btn) { var old = btn.getAttribute('data-old-label') || btn.textContent || 'Copia testo'; btn.setAttribute('data-old-label', old); btn.textContent = ok ? 'Testo copiato' : 'Copia manuale'; setTimeout(function(){ try { btn.textContent = old || 'Copia testo'; } catch(e) {} }, ok ? 1800 : 2600); } }\n            if (!isUploadLogAllowed821()) { done(false); return false; }\n            var ta = byId('ti-direct-upload-log-text-821');\n            var fromState = (state.uploadLogLines821 || []).join('\\n');\n            var fromTextArea = ta ? String(ta.value || '') : '';\n            var text = (fromState && fromState.length >= fromTextArea.length) ? fromState : fromTextArea;\n            if (!text) text = 'Log caricamento vuoto.';\n            function fallbackCopy(){\n                try {\n                    var h = document.createElement('textarea');\n                    h.value = text;\n                    h.setAttribute('readonly','readonly');\n                    h.style.position = 'fixed'; h.style.left = '-10000px'; h.style.top = '0'; h.style.opacity = '0';\n                    document.body.appendChild(h); h.focus(); h.select(); h.setSelectionRange(0, h.value.length);\n                    var ok = false; try { ok = document.execCommand('copy'); } catch(e) { ok = false; }\n                    document.body.removeChild(h);\n                    if (!ok && ta) { try { ta.focus(); ta.select(); ok = document.execCommand('copy'); } catch(e2) {} }\n                    done(!!ok); return !!ok;\n                } catch(e3) { done(false); return false; }\n            }\n            if (navigator.clipboard && navigator.clipboard.writeText && window.isSecureContext) {\n                navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){ fallbackCopy(); });\n            } else {\n                fallbackCopy();\n            }\n            return false;\n        } catch(e) { return false; }\n    }\n    function setProgress(p, label){\n        p = Math.max(0, Math.min(100, parseInt(p,10) || 0));\n        try {\n            var cur817 = parseInt(state.progressPercent814 || 0, 10) || 0;\n            var forceReset817 = \/timeout|errore|annull|pronto per riprova|in attesa\/i.test(String(label || ''));\n            if (state.busy && p > 0 && p < 100 && cur817 > p && cur817 < 100 && !forceReset817) p = cur817;\n        } catch(e817np) {}\n        try { state.progressPercent814 = p; state.progressLabel814 = label || (p + '%'); state.progressLastAt814 = Date.now(); } catch(e814p) {}\n        try { uploadLog821('progress', label || (p + '%')); } catch(e821pl) {}\n        var bar = byId('ti-direct-progress-bar-621'), lab = byId('ti-direct-progress-label-621'), wrap = byId('ti-direct-progress-wrap-621');\n        if (wrap) wrap.style.display = 'block';\n        if (bar) bar.style.width = p + '%';\n        if (lab) {\n            lab.textContent = p + '%';\n            try { lab.setAttribute('title', label || (p + '%')); lab.setAttribute('aria-label', label || (p + '%')); } catch(e861lab) {}\n        }\n    }\n    function setUploadActivity814(p, label, title, subtitle, file){\n        setProgress(p, label);\n        try { state.uploadLastProgressAt812 = Date.now(); } catch(e812p) {}\n        try { updateUploadWaitPopup792(p, title || 'Caricamento file', subtitle || label || 'Avanzamento caricamento.', file && file.name ? file.name : 'file'); } catch(e814u) {}\n    }\n    function bumpUploadActivity814(minPct, maxPct, label, title, subtitle, file){\n        var cur = 0;\n        try { cur = parseInt(state.progressPercent814 || 0, 10) || 0; } catch(e814b) { cur = 0; }\n        var next = Math.max(minPct || 0, cur);\n        if (maxPct !== undefined && maxPct !== null) next = Math.min(maxPct, next);\n        setUploadActivity814(next, label, title, subtitle, file);\n    }\n    function uploadUrlListB64818(){\n        var urls = [];\n        var hardAjax818 = \"https:\/\/www.tisoft.it\/wp-admin\/admin-ajax.php\";\n        var hardDirect818 = \"https:\/\/www.tisoft.it\/en\/?ti_action=ti_ai_ss_b64_upload_818\";\n        function add(u){ u = trim(u || ''); if (!u) return; try { u = u.replace(\/#.*$\/, ''); } catch(e) {} if (urls.indexOf(u) === -1) urls.push(u); }\n        add(hardAjax818); add(hardDirect818); add(window.ajaxurl); add(window.tiAjaxUrl);\n        return urls;\n    }\n    function bytesToBase64820(bytes){\n        var binary = '';\n        var chunk = 0x8000;\n        for (var i = 0; i < bytes.length; i += chunk) {\n            var sub = bytes.subarray(i, i + chunk);\n            binary += String.fromCharCode.apply(null, sub);\n        }\n        return btoa(binary);\n    }\n    function readFileAsBase64818(file){\n        return new Promise(function(resolve, reject){\n            if (!file) { reject(new Error('Lettura locale file: file assente.')); return; }\n            var done = false;\n            var timer = null;\n            var heartbeat823 = null;\n            var hbStep823 = 0;\n            function stopHeartbeat823(){ try { if (heartbeat823) clearInterval(heartbeat823); } catch(e) {} heartbeat823 = null; }\n            function startHeartbeat823(){\n                stopHeartbeat823();\n                heartbeat823 = setInterval(function(){\n                    if (done) { stopHeartbeat823(); return; }\n                    hbStep823++;\n                    var pct823 = Math.min(24, 15 + hbStep823);\n                    try { uploadLog821('local_read_heartbeat_823', 'Lettura locale ancora in corso', 'step=' + hbStep823 + ' pct=' + pct823 + ' file=' + (file && file.name ? file.name : '')); } catch(e) {}\n                    try { setUploadActivity814(pct823, pct823 + '% - Lettura locale in corso', 'Caricamento file', 'Sto leggendo il file nel browser. Se non arriva risposta passo automaticamente al metodo alternativo.', file); } catch(e2) {}\n                }, 1200);\n            }\n            function finish(fn, val){\n                if (done) return;\n                done = true;\n                try { if (timer) clearTimeout(timer); } catch(e) {}\n                stopHeartbeat823();\n                fn(val);\n            }\n            function tryArrayBufferFallback(reason){\n                if (done) return;\n                if (!file.arrayBuffer) { finish(reject, new Error(reason || 'Lettura locale file non riuscita.')); return; }\n                try { setUploadActivity814(26, '26% - Lettura locale alternativa', 'Caricamento file', 'Il primo metodo di lettura non ha risposto. Uso lettura alternativa del browser.', file); } catch(e) {}\n                var abDone = false;\n                var abTimer = setTimeout(function(){ if (!abDone) finish(reject, new Error('Lettura locale file in timeout. Riprova oppure carica una versione TXT\/CSV\/XLSX.')); }, 12000);\n                file.arrayBuffer().then(function(buf){\n                    if (done) return;\n                    abDone = true;\n                    try { clearTimeout(abTimer); } catch(e) {}\n                    try { setUploadActivity814(31, '31% - File letto localmente', 'Caricamento file', 'File letto nel browser. Preparo invio diretto.', file); } catch(e) {}\n                    var b64 = bytesToBase64820(new Uint8Array(buf));\n                    finish(resolve, b64);\n                }).catch(function(err){\n                    if (done) return;\n                    abDone = true;\n                    try { clearTimeout(abTimer); } catch(e) {}\n                    finish(reject, new Error('Lettura locale file non riuscita: ' + (err && err.message ? err.message : (reason || err))));\n                });\n            }\n            try {\n                var fr = new FileReader();\n                startHeartbeat823();\n                timer = setTimeout(function(){\n                    try { uploadLog821('local_read_timeout_823', 'FileReader fermo: avvio fallback arrayBuffer', 'file=' + (file && file.name ? file.name : '')); } catch(e) {}\n                    try { fr.abort(); } catch(e) {}\n                    tryArrayBufferFallback('Lettura locale file ferma al 15%.');\n                }, 5000);\n                fr.onerror = function(){ tryArrayBufferFallback('Lettura locale file non riuscita.'); };\n                fr.onabort = function(){ if (!done) tryArrayBufferFallback('Lettura locale file interrotta.'); };\n                fr.onprogress = function(ev){\n                    try {\n                        if (ev && ev.lengthComputable && ev.total > 0) {\n                            var pct = Math.max(16, Math.min(24, Math.round(16 + (ev.loaded \/ ev.total) * 8)));\n                            setUploadActivity814(pct, pct + '% - Lettura locale file (' + Math.round((ev.loaded||0)\/1024) + '\/' + Math.round((ev.total||0)\/1024) + ' KB)', 'Caricamento file', 'Il browser sta leggendo il file prima dell invio diretto.', file);\n                        } else {\n                            setUploadActivity814(18, '18% - Lettura locale in corso', 'Caricamento file', 'Il browser sta leggendo il file prima dell invio diretto.', file);\n                        }\n                    } catch(e) {}\n                };\n                fr.onload = function(){\n                    if (done) return;\n                    var s = String(fr.result || '');\n                    if (!s) { tryArrayBufferFallback('Lettura locale file vuota.'); return; }\n                    var p = s.indexOf(',');\n                    try { setUploadActivity814(30, '30% - File letto localmente', 'Caricamento file', 'File letto nel browser. Preparo invio diretto.', file); } catch(e) {}\n                    finish(resolve, p >= 0 ? s.slice(p + 1) : s);\n                };\n                fr.readAsDataURL(file);\n            } catch(e) { tryArrayBufferFallback(e && e.message ? e.message : e); }\n        });\n    }\n    function uploadUrlListChunk825(){\n        var urls = [];\n        var direct825 = \"https:\/\/www.tisoft.it\/en\/?ti_action=ti_ai_ss_b64_chunk_upload_825\";\n        var ajax825 = \"https:\/\/www.tisoft.it\/wp-admin\/admin-ajax.php\";\n        function add(u){ u = trim(u || ''); if (!u) return; try { u = u.replace(\/#.*$\/, ''); } catch(e) {} if (urls.indexOf(u) === -1) urls.push(u); }\n        add(direct825); add(ajax825);\n        return urls;\n    }\n    function readSliceBase64825(blob, label, timeoutMs){\n        return new Promise(function(resolve, reject){\n            var done = false;\n            var timer = setTimeout(function(){\n                if (done) return;\n                done = true;\n                try { uploadLog821('chunk_read_timeout_829', 'Timeout lettura chunk locale', 'label=' + label + ' ms=' + (timeoutMs || 7000)); } catch(e829rt) {}\n                reject(new Error('Timeout lettura chunk locale: ' + label));\n            }, timeoutMs || 7000);\n            function finish(fn, val){\n                if (done) return;\n                done = true;\n                try { clearTimeout(timer); } catch(e) {}\n                fn(val);\n            }\n            try {\n                if (blob && blob.arrayBuffer) {\n                    blob.arrayBuffer().then(function(buf){\n                        finish(resolve, bytesToBase64820(new Uint8Array(buf)));\n                    }).catch(function(err){\n                        finish(reject, new Error('Errore lettura chunk: ' + (err && err.message ? err.message : err)));\n                    });\n                    return;\n                }\n                var fr = new FileReader();\n                fr.onerror = function(){ finish(reject, new Error('Errore FileReader chunk: ' + label)); };\n                fr.onabort = function(){ finish(reject, new Error('FileReader chunk interrotto: ' + label)); };\n                fr.onload = function(){\n                    var s = String(fr.result || '');\n                    var p = s.indexOf(',');\n                    finish(resolve, p >= 0 ? s.slice(p + 1) : s);\n                };\n                fr.readAsDataURL(blob);\n            } catch(e) {\n                finish(reject, new Error('Lettura chunk non avviata: ' + (e && e.message ? e.message : e)));\n            }\n        });\n    }\n    function postChunkPayload825(url, params, chunkIndex){\n        uploadLog821('chunk_post_prepare_825', 'Preparo invio chunk', 'chunk=' + chunkIndex + ' url=' + url);\n        var body = '';\n        try {\n            body = Object.keys(params || {}).map(function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(params[k] == null ? '' : String(params[k])); }).join('&');\n        } catch(e) {\n            uploadLog821('chunk_body_error_825', 'Errore codifica chunk', e && e.message ? e.message : e);\n            return Promise.reject(new Error('Errore codifica chunk: ' + (e && e.message ? e.message : e)));\n        }\n        var controller = null;\n        var timeoutId = null;\n        try { if (window.AbortController) { controller = new AbortController(); state.currentUploadAbort821 = controller; } } catch(e) { controller = null; }\n        var timeoutPromise = new Promise(function(_, reject){\n            timeoutId = setTimeout(function(){\n                try { uploadLog821('chunk_post_timeout_825', 'Timeout invio chunk', 'chunk=' + chunkIndex + ' url=' + url); } catch(e) {}\n                try { if (controller) controller.abort(); } catch(e) {}\n                reject(new Error('Timeout invio chunk ' + (chunkIndex + 1) + ': server non risponde.'));\n            }, 9000);\n        });\n        var fetchPromise = fetch(url, {method:'POST', credentials:'same-origin', cache:'no-store', headers:{'Content-Type':'application\/x-www-form-urlencoded; charset=UTF-8'}, body:body, signal: controller ? controller.signal : undefined}).then(function(resp){\n            return resp.text().then(function(raw){\n                uploadLog821('chunk_response_825', 'Risposta chunk', 'chunk=' + chunkIndex + ' status=' + resp.status + ' chars=' + String(raw || '').length + ' preview=' + String(raw || '').slice(0,160));\n                if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + String(raw || '').slice(0, 180));\n                var res = null; try { res = JSON.parse(raw); } catch(e) { throw new Error(raw && raw.trim() ? ('Risposta chunk non JSON: ' + raw.slice(0,180)) : 'Risposta chunk vuota.'); }\n                if (!res || !res.success) throw new Error(res && res.data && res.data.message ? res.data.message : 'Chunk non accettato dal server.');\n                return res.data || {};\n            });\n        });\n        return Promise.race([fetchPromise, timeoutPromise]).then(function(data){\n            try { if (timeoutId) clearTimeout(timeoutId); } catch(e) {}\n            try { if (state.currentUploadAbort821 === controller) state.currentUploadAbort821 = null; } catch(e) {}\n            return data;\n        }).catch(function(err){\n            try { if (timeoutId) clearTimeout(timeoutId); } catch(e) {}\n            try { if (state.currentUploadAbort821 === controller) state.currentUploadAbort821 = null; } catch(e) {}\n            var m = err && err.name === 'AbortError' ? 'Timeout invio chunk: il server non ha risposto.' : (err && err.message ? err.message : String(err));\n            uploadLog821('chunk_error_825', 'Errore chunk', 'chunk=' + chunkIndex + ' ' + m);\n            throw new Error(m);\n        });\n    }\n    function uploadChunkedDirect825(data, file, previousError){\n        if (!file || !(file instanceof File)) return Promise.reject(previousError || new Error('File non disponibile per upload a blocchi.'));\n        if (file.size && file.size > 25 * 1024 * 1024) return Promise.reject(previousError || new Error('File troppo grande per upload a blocchi.'));\n        if (state.cancelRequested808 || (window.__tiUploadClaim952 && window.__tiUploadClaim952.owner === '931')) return Promise.reject(new Error('Caricamento annullato.'));\n        var chunkSize = 32 * 1024;\n        var total = Math.max(1, Math.ceil((file.size || 0) \/ chunkSize));\n        var uploadId = 'u' + Date.now() + '_' + Math.random().toString(36).slice(2, 10);\n        var urls = uploadUrlListChunk825();\n        var endpoint = urls[0] || '';\n        uploadLog821('chunk_start_825', 'Avvio upload diretto a blocchi', 'chunkSize=' + chunkSize + ' total=' + total + ' endpoint=' + endpoint);\n        setUploadActivity814(12, '12% - Avvio upload a blocchi', 'Caricamento file', 'Invio il file a blocchi piccoli per evitare timeout e blocchi del browser.', file);\n        var baseParams = {};\n        Object.keys(data || {}).forEach(function(k){ baseParams[k] = data[k] == null ? '' : data[k]; });\n        baseParams.action = 'ti_ai_ss_b64_chunk_upload_825';\n        baseParams.ti_action = 'ti_ai_ss_b64_chunk_upload_825';\n        baseParams.upload_id = uploadId;\n        baseParams.file_name = file.name || 'upload.bin';\n        baseParams.file_type = file.type || '';\n        baseParams.file_size = String(file.size || 0);\n        baseParams.upload_cleanup_token = currentUploadCleanupToken859(true);\n        baseParams.guided_upload_target = state.target || '';\n        try {\n            if (isBasicUploadUser()) {\n                baseParams.source_policy = 'basic_authorized_path';\n                baseParams.source_label = sourceLabelForPayload(file);\n                baseParams.client_path_unavailable = '1';\n                baseParams.client_relative_path = clientRelativePath(file);\n                baseParams.authorized_path = sourceLabelForPayload(file);\n            } else {\n                baseParams.source_policy = 'privileged_upload';\n                baseParams.source_label = sourceLabelForPayload(file);\n                baseParams.client_path_unavailable = clientRelativePath(file) ? '0' : '1';\n                baseParams.client_relative_path = clientRelativePath(file);\n                baseParams.authorized_path = sourceLabelForPayload(file);\n            }\n        } catch(e) {}\n        function sendOne(i){\n            if (state.cancelRequested808 || (window.__tiUploadClaim952 && window.__tiUploadClaim952.owner === '931')) return Promise.reject(new Error('Caricamento annullato.'));\n            if (i >= total) return Promise.reject(new Error('Indice chunk oltre limite.'));\n            var start = i * chunkSize;\n            var end = Math.min(file.size || 0, start + chunkSize);\n            var blob = file.slice(start, end);\n            var pctRead = Math.max(15, Math.min(75, Math.round(15 + (i \/ total) * 60)));\n            setUploadActivity814(pctRead, pctRead + '% - Lettura chunk ' + (i + 1) + '\/' + total, 'Caricamento file', 'Lettura e invio del file a blocchi. Non chiudere la pagina.', file);\n            uploadLog821('chunk_read_start_825', 'Lettura chunk', 'chunk=' + i + '\/' + total + ' bytes=' + start + '-' + end);\n            return readSliceBase64825(blob, (i + 1) + '\/' + total, 7000).then(function(chunkB64){\n                var pctSend = Math.max(20, Math.min(82, Math.round(20 + (i \/ total) * 62)));\n                setUploadActivity814(pctSend, pctSend + '% - Invio chunk ' + (i + 1) + '\/' + total, 'Caricamento file', 'Invio chunk al server. Attendo conferma immediata.', file);\n                var params = {};\n                Object.keys(baseParams).forEach(function(k){ params[k] = baseParams[k]; });\n                params.chunk_index = String(i);\n                params.chunk_total = String(total);\n                params.chunk_b64 = chunkB64;\n                function tryEndpoint(ei){\n                    if (ei >= urls.length) return Promise.reject(new Error('Nessun endpoint upload chunk disponibile.'));\n                    return postChunkPayload825(urls[ei], params, i).catch(function(err){\n                        uploadLog821('chunk_endpoint_error_825', 'Endpoint chunk fallito', 'chunk=' + i + ' endpoint=' + ei + ' ' + (err && err.message ? err.message : err));\n                        if (ei + 1 < urls.length) return tryEndpoint(ei + 1);\n                        throw err;\n                    });\n                }\n                return tryEndpoint(0).then(function(res){\n                    uploadLog821('chunk_ok_825', 'Chunk confermato dal server', 'chunk=' + i + ' partial=' + (res && res.partial ? 1 : 0) + ' received=' + (res && res.received ? res.received : ''));\n                    if (i + 1 >= total) {\n                        setUploadActivity814(92, '92% - File ricevuto dal server', 'Caricamento file', 'File assemblato dal server. Preparo risposta AI\/opzioni.', file);\n                        return res || {};\n                    }\n                    return sendOne(i + 1);\n                });\n            });\n        }\n        return sendOne(0).catch(function(err){\n            uploadLog821('chunk_upload_failed_825', 'Upload a blocchi fallito', err && err.message ? err.message : err);\n            throw err;\n        });\n    }\n    function postB64Payload818(url, params){\n        uploadLog821('post_prepare', 'Preparazione richiesta HTTP diretta', 'url=' + url + ' keys=' + Object.keys(params || {}).join(','));\n        var body = '';\n        try {\n            var t0 = Date.now();\n            body = Object.keys(params || {}).map(function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(params[k] == null ? '' : String(params[k])); }).join('&');\n            uploadLog821('post_body_ready', 'Payload codificato', 'chars=' + body.length + ' ms=' + (Date.now() - t0));\n        } catch(e821body) {\n            uploadLog821('post_body_error', 'Errore codifica payload', e821body && e821body.message ? e821body.message : e821body);\n            return Promise.reject(new Error('Errore preparazione invio diretto: ' + (e821body && e821body.message ? e821body.message : e821body)));\n        }\n        var controller = null;\n        var timeoutId = null;\n        var hardReject = null;\n        try { if (window.AbortController) { controller = new AbortController(); state.currentUploadAbort821 = controller; } } catch(e) { controller = null; }\n        var timeoutPromise = new Promise(function(_, reject){\n            hardReject = reject;\n            timeoutId = setTimeout(function(){\n                try { uploadLog821('post_timeout', 'Timeout reale invio diretto', 'url=' + url); } catch(e) {}\n                try { if (controller) controller.abort(); } catch(e) {}\n                reject(new Error('Timeout invio diretto: nessuna risposta dal server entro 24 secondi. Endpoint: ' + url));\n            }, 24000);\n        });\n        setUploadActivity814(Math.max(20, parseInt(state.progressPercent814 || 0, 10) || 0), '20% - Invio diretto in corso', 'Caricamento file', 'Richiesta inviata al server. Attendo risposta con timeout reale.', state.file || null);\n        var fetchPromise = fetch(url, {method:'POST', credentials:'same-origin', cache:'no-store', headers:{'Content-Type':'application\/x-www-form-urlencoded; charset=UTF-8'}, body:body, signal: controller ? controller.signal : undefined}).then(function(resp){\n            uploadLog821('post_response_headers', 'Risposta HTTP ricevuta', 'status=' + resp.status + ' ok=' + resp.ok + ' url=' + url);\n            return resp.text().then(function(raw){\n                uploadLog821('post_response_text', 'Testo risposta letto', 'chars=' + String(raw || '').length + ' preview=' + String(raw || '').slice(0,220));\n                if (!resp.ok) throw new Error('HTTP ' + resp.status + ': ' + String(raw || '').slice(0, 220));\n                var res = null; try { res = JSON.parse(raw); } catch(e) { throw new Error(raw && raw.trim() ? ('Risposta server non JSON canale alternativo: ' + raw.slice(0, 220)) : 'Risposta server vuota canale alternativo.'); }\n                if (!res || !res.success) throw new Error(res && res.data && res.data.message ? res.data.message : 'Upload alternativo non riuscito.');\n                uploadLog821('post_json_ok', 'JSON upload valido', 'campi=' + Object.keys(res.data || {}).join(','));\n                return res.data || {};\n            });\n        });\n        return Promise.race([fetchPromise, timeoutPromise]).then(function(data){\n            try { if (timeoutId) clearTimeout(timeoutId); } catch(e) {}\n            try { if (state.currentUploadAbort821 === controller) state.currentUploadAbort821 = null; } catch(e) {}\n            return data;\n        }).catch(function(err){\n            try { if (timeoutId) clearTimeout(timeoutId); } catch(e) {}\n            try { if (state.currentUploadAbort821 === controller) state.currentUploadAbort821 = null; } catch(e) {}\n            var m = err && err.name === 'AbortError' ? 'Timeout invio diretto: il server non ha risposto al canale anti-blocco.' : (err && err.message ? err.message : String(err));\n            uploadLog821('post_error', 'Errore invio diretto', m);\n            throw new Error(m);\n        });\n    }\n    function b64UploadDirect818(data, file, previousError){\n        if (!file || !(file instanceof File)) return Promise.reject(previousError || new Error('File non disponibile per canale alternativo.'));\n        if (file.size && file.size > 25 * 1024 * 1024) return Promise.reject(previousError || new Error('File troppo grande per canale alternativo anti-timeout.'));\n        if (state.cancelRequested808 || (window.__tiUploadClaim952 && window.__tiUploadClaim952.owner === '931')) return Promise.reject(new Error('Caricamento annullato.'));\n        uploadLog821('b64_start', 'Avvio canale diretto anti-blocco', 'fileSize=' + (file && file.size ? file.size : 0));\n        setUploadActivity814(10, '10% - Preparo upload a blocchi', 'Caricamento file', 'Uso il canale a blocchi: ogni blocco deve avere risposta server immediata.', file);\n        return uploadChunkedDirect825(data, file, previousError).catch(function(chunkErr){\n            uploadLog821('b64_fallback_full_825', 'Fallback al canale base64 completo', chunkErr && chunkErr.message ? chunkErr.message : chunkErr);\n            setUploadActivity814(15, '15% - Fallback lettura file locale completa', 'Caricamento file', 'Il canale a blocchi non ha risposto. Provo il metodo alternativo completo.', file);\n            return readFileAsBase64818(file).then(function(b64){\n            uploadLog821('local_read_ok', 'File letto localmente', 'base64_chars=' + (b64 ? String(b64.length) : 0));\n            var params = {};\n            Object.keys(data || {}).forEach(function(k){ params[k] = data[k] == null ? '' : data[k]; });\n            params.action = 'ti_ai_ss_b64_upload_818';\n            params.ti_action = 'ti_ai_ss_b64_upload_818';\n            params.file_name = file.name || 'upload.bin';\n            params.file_type = file.type || '';\n            params.file_size = String(file.size || 0);\n            params.upload_cleanup_token = currentUploadCleanupToken859(true);\n            params.guided_upload_target = state.target || '';\n            params.file_b64 = b64;\n            try {\n                if (isBasicUploadUser()) {\n                    params.source_policy = 'basic_authorized_path';\n                    params.source_label = sourceLabelForPayload(file);\n                    params.client_path_unavailable = '1';\n                    params.client_relative_path = clientRelativePath(file);\n                    params.authorized_path = sourceLabelForPayload(file);\n                } else {\n                    params.source_policy = 'privileged_upload';\n                    params.source_label = sourceLabelForPayload(file);\n                    params.client_path_unavailable = clientRelativePath(file) ? '0' : '1';\n                    params.client_relative_path = clientRelativePath(file);\n                    params.authorized_path = sourceLabelForPayload(file);\n                }\n            } catch(e) {}\n            var urls = uploadUrlListB64818();\n            function attemptB64(i){\n                if (i >= urls.length) return Promise.reject(previousError || new Error('Canale alternativo non disponibile.'));\n                state.uploadEndpoint817 = urls[i] || '';\n                uploadLog821('endpoint_attempt', 'Tentativo endpoint upload diretto', 'index=' + i + ' url=' + (urls[i] || ''));\n                setUploadActivity814(Math.min(55, 20 + i * 8), (20 + i * 8) + '% - Invio diretto file', 'Caricamento file', 'Invio diretto al server. Attendi risposta AI.', file);\n                return postB64Payload818(urls[i], params).catch(function(err){ uploadLog821('endpoint_error', 'Endpoint fallito', (err && err.message ? err.message : err)); if (i + 1 < urls.length) return attemptB64(i + 1); throw err; });\n            }\n            return attemptB64(0).then(function(res){\n                setUploadActivity814(92, '92% - File ricevuto dal server', 'Caricamento file', 'File ricevuto. Preparo risposta AI\/opzioni utente.', file);\n                return res;\n            });\n        });\n        });\n    }\n    var guidedModalPreview1526 = {url:'', reader:null, file:null};\n    function clearGuidedModalPreview1526(){\n        try { if (guidedModalPreview1526.reader && guidedModalPreview1526.reader.readyState === 1) guidedModalPreview1526.reader.abort(); } catch(e) {}\n        guidedModalPreview1526.reader = null; guidedModalPreview1526.file = null;\n        try { if (guidedModalPreview1526.url) URL.revokeObjectURL(guidedModalPreview1526.url); } catch(e2) {}\n        guidedModalPreview1526.url = '';\n        var host = byId('ti-direct-upload-preview-1526');\n        if (host) { host.innerHTML=''; host.style.display='none'; }\n    }\n    function guidedPreviewSize1526(n){ n=Number(n||0); if(!isFinite(n)||n<0)n=0; if(n<1024)return n+' B'; if(n<1048576)return (n\/1024).toFixed(n<10240?1:0)+' KB'; return (n\/1048576).toFixed(2)+' MB'; }\n    function renderGuidedModalPreview1526(file){\n        if (!file) return;\n        clearGuidedModalPreview1526();\n        guidedModalPreview1526.file = file;\n        try { window.__tiGuidedFilePreviewFile1526 = file; } catch(e0) {}\n        var host = byId('ti-direct-upload-preview-1526'); if(!host) return;\n        var name=String(file.name||'file'), mm=name.match(\/\\.([a-z0-9]+)$\/i), ext=mm?mm[1].toLowerCase():'', mime=String(file.type||'');\n        var head=document.createElement('div'); head.style.cssText='display:flex;justify-content:space-between;gap:8px;align-items:flex-start;margin-bottom:7px;font-size:11px;line-height:1.35;color:#e2e8f0;';\n        var left=document.createElement('div'); left.style.cssText='min-width:0;word-break:break-word;'; var b=document.createElement('b'); b.textContent=name; left.appendChild(b);\n        var meta=document.createElement('div'); meta.style.cssText='color:#94a3b8;margin-top:2px;'; meta.textContent=(ext?ext.toUpperCase():(mime||'FILE'))+' \u00b7 '+guidedPreviewSize1526(file.size||0)+' \u00b7 preview disponibile fino a Chiudi'; left.appendChild(meta); head.appendChild(left); host.appendChild(head);\n        var isImg=\/^image\\\/\/i.test(mime)||\/^(png|jpe?g|gif|webp|bmp)$\/i.test(ext), isPdf=mime==='application\/pdf'||ext==='pdf', isText=\/^text\\\/\/i.test(mime)||\/^(txt|csv|json|xml|log|md|tsv)$\/i.test(ext);\n        if(isImg||isPdf){\n            try { guidedModalPreview1526.url=URL.createObjectURL(file); if(isImg){var im=document.createElement('img');im.src=guidedModalPreview1526.url;im.alt='Anteprima '+name;host.appendChild(im);} else {var fr=document.createElement('iframe');fr.src=guidedModalPreview1526.url+'#toolbar=0&navpanes=0&view=FitH';fr.title='Anteprima PDF '+name;host.appendChild(fr);} } catch(e1) { var er=document.createElement('div');er.textContent='Anteprima grafica non disponibile; il file resta selezionato.';er.style.cssText='font-size:11px;color:#fca5a5;';host.appendChild(er); }\n        } else if(isText && typeof FileReader!=='undefined'){\n            var pre=document.createElement('pre');pre.textContent='Lettura anteprima...';host.appendChild(pre);var r=new FileReader();guidedModalPreview1526.reader=r;r.onload=function(){var t=String(r.result||'');pre.textContent=t.slice(0,8000)+(t.length>8000?'\\n\\n\u2026 anteprima limitata ai primi 8000 caratteri \u2026':'');};r.onerror=function(){pre.textContent='Anteprima testuale non disponibile; il file resta selezionato.';};r.readAsText(file);\n        } else {\n            var info=document.createElement('div');info.style.cssText='padding:14px 8px;text-align:center;color:#cbd5e1;font-size:11px;line-height:1.45;';info.innerHTML='<div style=\"font-size:30px;margin-bottom:6px\">\ud83d\udcc4<\/div><b>File selezionato correttamente<\/b><br><span style=\"color:#94a3b8\">Per questo formato il browser mostra i metadati; il contenuto verra interpretato durante l analisi AI.<\/span>';host.appendChild(info);\n        }\n        host.style.display='block';\n        try { if(typeof window.tiRenderPersistentFilePreview1520==='function') window.tiRenderPersistentFilePreview1520(file); } catch(e2) {}\n        try { uploadLog821('preview_1526','Preview file visualizzata e mantenuta nel popup','name='+name+' size='+(file.size||0)+' type='+mime); } catch(e3) {}\n    }\n    window.tiRenderGuidedModalPreview1526 = renderGuidedModalPreview1526;\n    window.tiClearGuidedModalPreview1526 = clearGuidedModalPreview1526;\n\n    function setModalText(html, err){\n        var el = byId('ti-direct-upload-text-621');\n        if (!el) return;\n        el.className = 'ti-direct-upload-text-621' + (err ? ' ti-direct-error-621' : '');\n        el.innerHTML = html || '';\n    }\n    function setFileLine(file){\n        var el = byId('ti-direct-upload-file-621');\n        if (!el) return;\n        if (!file) { el.style.display = 'none'; el.innerHTML = ''; return; }\n        var size = file.size ? (' - ' + Math.round(file.size \/ 1024) + ' KB') : '';\n        el.style.display = 'block';\n        el.innerHTML = '<b>File:<\/b> ' + esc(file.name || 'upload') + esc(size);\n        try { if (typeof File !== 'undefined' && file instanceof File) renderGuidedModalPreview1526(file); } catch(e1526) {}\n    }\n    function currentDb642(){ return (window.currentDbData && typeof window.currentDbData === 'object') ? window.currentDbData : {}; }\n    function configValue642(keys, def){\n        var data = currentDb642(), cfg = null;\n        try { cfg = data && data.Tabelle ? data.Tabelle.Config : null; } catch(e) { cfg = null; }\n        var list = Array.isArray(cfg) ? cfg : (cfg && typeof cfg === 'object' ? [cfg] : []);\n        keys = keys || [];\n        for (var i=0;i<list.length;i++) {\n            var row = list[i] || {};\n            for (var k=0;k<keys.length;k++) { if (row[keys[k]] !== undefined && trim(row[keys[k]]) !== '') return trim(row[keys[k]]); }\n        }\n        return def || '';\n    }\n    function friendlyCompanyFallback658(){\n        var v = trim(dbName() || 'corrente');\n        v = v.replace(\/\\.json$\/i, '').replace(\/[_\\-]+\/g, ' ').trim();\n        return v || 'corrente';\n    }\n    function companyLabel642(){ return state.serverCompanyLabel659 || configValue642(['Ditta','Ragione sociale','Ragione Sociale','Azienda','Nome ditta','Nome'], friendlyCompanyFallback658()); }\n    function instructionRows642(){\n        var out = [], seen = {};\n        function addRow(r){\n            if (!r || typeof r !== 'object') return;\n            var t = rowTxt642(r);\n            var p = extractAuthorizedPath642(r);\n            if (!p && !\/(Origine\\\/path file autorizzata|Path\\s+assoluta\\s+autorizzata|Path\\s+autorizzata|Origine\\s+autorizzata|caricamento file utenti generici|utenti generici\\\/base)\/i.test(t)) return;\n            var sig = ''; try { sig = JSON.stringify(r); } catch(e) { sig = String(out.length); }\n            if (seen[sig]) return; seen[sig] = true; out.push(r);\n        }\n        function pushRows(rows){\n            if (!rows || typeof rows !== 'object') return;\n            var wraps = ['Righe','Rows','records','Records','Dati','Valori'];\n            for (var w=0; w<wraps.length; w++) { if (rows[wraps[w]] && typeof rows[wraps[w]] === 'object') { pushRows(rows[wraps[w]]); return; } }\n            if (Array.isArray(rows)) { rows.forEach(function(r){ if (r && typeof r === 'object') addRow(r); }); return; }\n            addRow(rows); Object.keys(rows).forEach(function(k){ if (rows[k] && typeof rows[k] === 'object') addRow(rows[k]); });\n        }\n        try {\n            var data = currentDb642() || {};\n            var tabelle = data.Tabelle || {};\n            Object.keys(tabelle).forEach(function(name){\n                var norm = String(name || '').toLowerCase().replace(\/[\\s_\\-]\/g, '');\n                if (norm === 'istruzioni' || norm === 'istruzione') pushRows(tabelle[name]);\n            });\n            ['Istruzioni','istruzioni','Istruzione','istruzione'].forEach(function(k){ if (data[k]) pushRows(data[k]); });\n            (function walk(n, depth){ if (!n || typeof n !== 'object' || depth > 7) return; addRow(n); Object.keys(n).forEach(function(k){ if (n[k] && typeof n[k] === 'object') walk(n[k], depth+1); }); })(data,0);\n        } catch(e) {}\n        return out;\n    }\n    function rowTxt642(row){\n        var keys = ['Istruzione','Istruzioni','Testo','Regola','Descrizione','Nota','Path assoluta autorizzata','Path autorizzata','Origine autorizzata','Path','Origine','Sorgente'];\n        var out = '';\n        row = row || {};\n        keys.forEach(function(k){ if (row[k] !== undefined && trim(row[k]) !== '') out += ' ' + trim(row[k]); });\n        return out;\n    }\n    function extractAbsoluteUploadPath657(v){\n        v = trim(v || '').replace(\/[\\u0000-\\u001F\\u007F]+\/g, ' ').replace(\/^[\\'\\\"]+|[\\'\\\"]+$\/g, '').trim();\n        if (!v) return '';\n        var probe = v.replace(\/\\\\\\\\\/g, '\\\\').replace(\/\\\\\/g, '\\\\').replace(\/\\\/\\\/\/g, '\/');\n        var m = probe.match(\/(?:^|[^A-Za-z0-9])([A-Za-z])\\s*:\\s*[\\\\\\\/]*(?:$|[\\s\\.;,\\)\\]\\}])\/);\n        if (m && m[1]) return m[1].toUpperCase() + ':\\\\';\n        m = probe.match(\/(?:^|[^A-Za-z0-9])([A-Za-z])\\s*:\\s*[\\\\\\\/]([^\\r\\n;]*)\/);\n        if (m && m[1]) {\n            var rest = String(m[2] || '').replace(\/[\\s\\.;,\\)\\]\\}]+$\/g, '').trim();\n            return m[1].toUpperCase() + ':\\\\' + rest.replace(\/\\\/\/g, '\\\\').replace(\/^\\\\+\/, '');\n        }\n        m = v.match(\/(\\\/Volumes\\\/[^\\r\\n;<>]+)\/);\n        if (m && m[1]) return String(m[1]).replace(\/[\\s\\.;,\\)\\]\\}]+$\/g, '').trim();\n        return '';\n    }\n    function cleanUploadPath653(v){\n        v = trim(v || '');\n        v = v.replace(\/[\\u0000-\\u001F\\u007F]+\/g, ' ').replace(\/^[\\'\\\"]+|[\\'\\\"]+$\/g, '').trim();\n        var extracted = extractAbsoluteUploadPath657(v);\n        if (extracted) return extracted;\n        for (var i=0; i<4; i++) {\n            var old = v;\n            v = v.replace(\/^[\\\\\\\/]+([A-Za-z]:[\\\\\\\/]?)\/, '$1');\n            v = v.replace(\/^([A-Za-z]):[\\\\\\\/]+$\/, function(_, d){ return d.toUpperCase() + ':\\\\'; });\n            v = v.replace(\/^([A-Za-z]):$\/, function(_, d){ return d.toUpperCase() + ':\\\\'; });\n            if (v === old) break;\n        }\n        v = v.replace(\/^([A-Za-z]):[\\\\\\\/]?(.*)$\/, function(_, d, rest){ return d.toUpperCase() + ':\\\\' + String(rest || '').replace(\/\\\/\/g, '\\\\').replace(\/^\\\\+\/, ''); });\n        return v;\n    }\n    function extractAuthorizedPath642(row){\n        row = row || {};\n        var keys = ['Path assoluta autorizzata','Path Assoluta Autorizzata','Percorso assoluto autorizzato','Percorso Assoluto Autorizzato','Path autorizzata','Path Autorizzata','Origine autorizzata','Origine Autorizzata','Path','Origine','Sorgente','authorized_path','source_label','absolute_path'];\n        for (var i=0;i<keys.length;i++) { if (row[keys[i]] !== undefined && trim(row[keys[i]]) !== '') return cleanUploadPath653(trim(row[keys[i]])); }\n        var t = rowTxt642(row), m = t.match(\/(?:Path\\s+assoluta|Percorso\\s+assoluto|Path|Origine|Sorgente)\\s+autorizzat[ao]\\s*:\\s*([^.;\\r\\n]+)\/i);\n        return m && m[1] ? cleanUploadPath653(trim(m[1])).slice(0,240) : '';\n    }\n    function isSysUploadRule642(row){\n        row = row || {};\n        var t = rowTxt642(row);\n        var p = extractAuthorizedPath642(row);\n        var isUpload = !!p || \/Origini\\\/path file consentite utenti generici\\\/base|Origini file consentite utenti generici\\\/base|Origine\\\/path file autorizzata|path file consentite|caricamento file utenti generici|Path autorizzata:|Origine autorizzata:|Sorgente autorizzata:\/i.test(t);\n        return isUpload;\n    }\n    function firstAuthorizedSourcePath642(){\n        var rows = instructionRows642();\n        for (var i=0;i<rows.length;i++) { if (isSysUploadRule642(rows[i])) { var p = extractAuthorizedPath642(rows[i]); if (p && isAbsoluteUploadPath651(p)) return p; } }\n        if (state.serverAuthorizedPath659 && isAbsoluteUploadPath651(state.serverAuthorizedPath659)) return state.serverAuthorizedPath659;\n        try { var sp = sessionStorage.getItem('tiAuthorizedUploadPath659') || ''; if (sp && isAbsoluteUploadPath651(sp)) { state.serverAuthorizedPath659 = sp; return sp; } } catch(e) {}\n        return '';\n    }\n    function displayDittaLabel658(v){\n        v = trim(v || companyLabel642() || 'corrente');\n        v = v.replace(\/\\.json$\/i, '').replace(\/[_\\-]+\/g, ' ').trim();\n        return v || 'corrente';\n    }\n    function missingAuthorizedSourceMessage644(){ return 'Errore caricamento file: Nessuna origine\/path file risulta disponibile per la ditta ' + displayDittaLabel658(companyLabel642()) + '.'; }\nfunction verifiedPathUnavailableMessage651(){\n        var p = firstAuthorizedSourcePath642();\n        if (p) return 'Origine\/path autorizzata configurata per la ditta: ' + p + '. Verr\u00e0 aperta la selezione file di sistema: scegli il file solo dal supporto autorizzato indicato.';\n        return missingAuthorizedSourceMessage644();\n    }\nfunction jsNormPath651(v){\n        v = cleanUploadPath653(trim(v || '')).replace(\/\\\\\/g, '\/').replace(\/\\\/+\/g, '\/');\n        if (\/^[A-Za-z]:$\/.test(v)) v += '\/';\n        if (\/^[A-Za-z]:\\\/$\/.test(v)) return v.toLowerCase();\n        return v.replace(\/\\\/+$\/,'').toLowerCase();\n    }\n    function isAbsoluteUploadPath651(v){\n        v = trim(v || '');\n        return !!(\/^[A-Za-z]:[\\\\\\\\\/]\/.test(v) || \/^[A-Za-z]:$\/.test(v) || \/^\\\\\\\\\/.test(v) || \/^\\\/\\\/\/.test(v) || \/^\\\/\/.test(v));\n    }\n    function strictUploadPathMatch651(allowed, declared){\n        var a = jsNormPath651(allowed), d = jsNormPath651(declared);\n        if (!a || !d) return false;\n        if (a === d) return true;\n        var ap = \/\\\/$\/.test(a) ? a : (a + '\/');\n        return d.indexOf(ap) === 0;\n    }\n        function showMissingAuthorizedSource644(kind){\n        var msg = missingAuthorizedSourceMessage644();\n        setInlineStatus(isManager(kind) ? 'manager' : 'main', msg, true);\n        try { if (window.tiAlert) window.tiAlert(msg); else alert(msg); } catch(e) { try { alert(msg); } catch(ee) {} }\n        return false;\n    }\n    function setSourceMapVisible(show){\n        var box = byId('ti-direct-upload-map-629');\n        if (!box) return;\n        var basic = isBasicUploadUser();\n        if (!basic && window.__tiEnablePrivilegedUploadSourceMapping !== true) show = false;\n        box.style.display = show ? 'block' : 'none';\n        var cb = byId('ti-direct-upload-map-check-629'), inp = byId('ti-direct-upload-source-label-629'), lab = byId('ti-direct-upload-map-label-629'), labTxt = byId('ti-direct-upload-map-label-text-629'), saveBtn651 = byId('ti-direct-upload-save-source-651'), pickBtn655 = byId('ti-direct-upload-pick-path-655');\n        try { if (box) { box.style.setProperty('background','#000','important'); box.style.setProperty('color','#fff','important'); } if (lab) { lab.style.setProperty('background','#000','important'); lab.style.setProperty('color','#fff','important'); } if (labTxt) { labTxt.style.setProperty('background','#000','important'); labTxt.style.setProperty('color','#fff','important'); } if (inp) { inp.style.setProperty('background','#000','important'); inp.style.setProperty('color','#fff','important'); } } catch(e) {}\n        if (basic) {\n            if (saveBtn651) saveBtn651.style.display = 'none';\n            if (pickBtn655) pickBtn655.style.display = 'none';\n            var first = firstAuthorizedSourcePath642();\n            if (cb) { cb.checked = false; cb.style.display = 'none'; }\n            if (lab) lab.style.display = 'block';\n            if (labTxt) labTxt.textContent = first ? ('Origine\/path autorizzata dalla ditta: ' + first) : ('Nessuna origine\/path file risulta disponibile per la ditta ' + displayDittaLabel658(companyLabel642()) + '.');\n            if (inp) { inp.value = first || ''; inp.style.display = 'none'; inp.disabled = true; inp.setAttribute('aria-hidden','true'); }\n        } else {\n            if (saveBtn651) saveBtn651.style.display = show ? 'inline-flex' : 'none';\n            if (pickBtn655) pickBtn655.style.display = show ? 'inline-flex' : 'none';\n            if (cb) cb.style.display = '';\n            if (lab) lab.style.display = 'block';\n            if (labTxt) labTxt.textContent = 'Salva questa origine\/path come istruzione di caricamento consentita';\n            if (inp) { inp.style.display = 'block'; inp.disabled = false; inp.removeAttribute('aria-hidden'); inp.placeholder = 'Esempio path assoluta: F:\\\\ oppure \/Volumes\/ChiaveUSB'; }\n        }\n        if (!show) {\n            if (cb) cb.checked = false;\n            if (inp) { inp.value = ''; inp.removeAttribute('data-authorized-path'); }\n            if (saveBtn651) saveBtn651.style.display = 'none';\n            if (pickBtn655) pickBtn655.style.display = 'none';\n        }\n    }\n    function sourceMapEnabled(){\n        if (!isBasicUploadUser() && window.__tiEnablePrivilegedUploadSourceMapping !== true) return false;\n        var cb = byId('ti-direct-upload-map-check-629');\n        return !!(cb && cb.checked);\n    }\n    function sourceMapLabel(){\n        var inp = byId('ti-direct-upload-source-label-629');\n        var parts = [];\n        if (inp) {\n            parts.push(inp.value || '');\n            parts.push(inp.getAttribute('data-authorized-path') || '');\n        }\n        try { parts.push(state.authorizedPath657 || state.authorizedPath656 || window.__tiLastAuthorizedUploadPath657 || window.__tiLastAuthorizedUploadPath656 || ''); } catch(e) {}\n        try { var saveBtn = byId('ti-direct-upload-save-source-651'); if (saveBtn) parts.push(saveBtn.getAttribute('data-authorized-path') || ''); } catch(e2) {}\n        try { var txtEl = byId('ti-direct-upload-text-621'); if (txtEl) parts.push(txtEl.textContent || txtEl.innerText || ''); } catch(e3) {}\n        for (var i=0; i<parts.length; i++) { var v = cleanUploadPath653(trim(parts[i] || '')); if (v && isAbsoluteUploadPath651(v)) return v; }\n        var raw = cleanUploadPath653(trim(parts.join(' ') || ''));\n        if (raw && isAbsoluteUploadPath651(raw)) return raw;\n        if (isBasicUploadUser()) return firstAuthorizedSourcePath642();\n        return raw || '';\n    }\n    function setSourceMapLabel(v){ var inp = byId('ti-direct-upload-source-label-629'); if (inp) inp.value = cleanUploadPath653(trim(v)); }\n    function proposedAuthorizedPath641(file){\n        var typed = sourceMapLabel();\n        if (typed) return typed;\n        var rel = clientRelativePath(file);\n        if (rel && isAbsoluteUploadPath651(rel)) return rel;\n        return '';\n    }\n    function confirmPrivilegedSourcePath641(file){\n        if (state.target === 'config-bot-file') return false;\n        if (isBasicUploadUser() || !sourceMapEnabled()) return false;\n        var proposed = proposedAuthorizedPath641(file);\n        setSourceMapLabel(proposed);\n        state.file = file;\n        state.confirmingPath = true;\n        setFileLine(file);\n        setModalText('Conferma la path assoluta da autorizzare per gli utenti generici\/base.<br><br><b>Path assoluta autorizzata:<\/b><br>' + esc(proposed || 'Inserisci una path assoluta nel campo sotto, ad esempio F:\\\\') + '<br><br>Indica o conferma la path assoluta, poi premi <b>Conferma path e carica<\/b>. L\\'istruzione salvata nel database conterr\u00e0 esplicitamente questa path autorizzata.', false);\n        showStartButton(true, 'Conferma path e carica');\n        return true;\n    }\n        function sourceLabelForPayload(file){\n        if (isBasicUploadUser()) return firstAuthorizedSourcePath642() || sourceMapLabel();\n        return sourceMapLabel() || 'origine caricamento autorizzata da utente abilitato';\n    }\n    function clientRelativePath(file){\n        try { return file && file.webkitRelativePath ? String(file.webkitRelativePath) : ''; } catch(e) {}\n        return '';\n    }\n    function showStartButton(show, text){\n        var btn = byId('ti-direct-upload-start-621');\n        if (!btn) return;\n        btn.style.display = show ? 'inline-flex' : 'none';\n        btn.disabled = false;\n        btn.textContent = text || 'Avvia caricamento';\n    }\n    function uploadFileName792(file){\n        try { return (file && file.name) ? String(file.name) : 'file selezionato'; } catch(e) {}\n        return 'file selezionato';\n    }\n    function showUploadWaitPopup792(kind, target, file){\n        var name = uploadFileName792(file);\n        var isChat = !isManager(kind) && (!target || target === 'chat');\n        var title = isChat ? 'Carica file AI' : 'Caricamento file';\n        var sub = '';\n        try {\n            if (typeof window.showProgressPopup === 'function') {\n                window.showProgressPopup(title, sub, {startPercent:3, targetPercent:isChat ? 91 : 96, stepMs:420, cancellable:true, currentItem:name});\n            } else if (typeof window.tiAlert === 'function') {\n                window.tiAlert('File scelto: ' + name + '. Attendi l esito del caricamento.');\n            }\n        } catch(e) {}\n        try { if (window.addMsg && isChat) window.addMsg('ai', '\ud83d\udcce File scelto: ' + name + '. Caricamento e analisi AI in corso, attendi l esito.'); } catch(e2) {}\n    }\n    function updateUploadWaitPopup792(percent, title, subtitle, item){\n        try { if (typeof window.updateProgressPopup === 'function') window.updateProgressPopup(percent, title || 'Caricamento file', '', item || ''); } catch(e) {}\n    }\n    function finishUploadWaitPopup792(success, title, message, notify){\n        try {\n            if (typeof window.hideProgressPopup === 'function') {\n                window.hideProgressPopup(success !== false, title || (success === false ? 'Upload non riuscito' : 'Upload completato'), {notifyUser: notify !== false, successMessage: message || title || 'Upload completato.', errorMessage: message || title || 'Upload non riuscito.'});\n            } else if (notify !== false && typeof window.tiAlert === 'function') {\n                window.tiAlert(message || title || (success === false ? 'Upload non riuscito.' : 'Upload completato.'));\n            }\n        } catch(e) {}\n    }\n    function addUploadAiStatus861(kind, target, message){\n        try {\n            if (isManager(kind)) return;\n            target = trim(target || state.target || 'chat');\n            message = trim(message || '');\n            if (!message) return;\n            var key = target + '|' + message;\n            var now = Date.now();\n            if (state.lastAiUploadStatus861 === key && (now - (state.lastAiUploadStatusAt861 || 0)) < 2500) return;\n            state.lastAiUploadStatus861 = key;\n            state.lastAiUploadStatusAt861 = now;\n            if (target === 'config-bot-file') {\n                var r = byId('ti-conf-ai-reply');\n                if (r) { r.style.display = 'block'; r.innerHTML = esc(message).replace(\/\\n\/g, '<br>'); return; }\n            }\n            if (typeof window.addMsg === 'function') { window.addMsg('ai', message); return; }\n            var chat = byId('ti-chat') || byId('ti-chat-box');\n            if (chat) {\n                var b = document.createElement('div');\n                b.className = 'ti-bubble ai ti-upload-ai-status-861';\n                b.textContent = message;\n                chat.appendChild(b);\n            }\n        } catch(e861msg) {}\n    }\n\n    function checkAuthorizedSourceServer659(kind, target){\n        var db = dbName();\n        if (!db || db === 'NEW_DB' || db === 'Global') { showMissingAuthorizedSource644(kind); return false; }\n        setInlineStatus(isManager(kind) ? 'manager' : 'main', 'Verifica origine\/path autorizzata...', false);\n        var fd = new FormData();\n        fd.append('action', 'ti_ai_ss_upload_source_check_664');\n        fd.append('ti_action', 'ti_ai_ss_upload_source_check_664');\n        fd.append('db', db);\n        var urls = ajaxUrlList();\n        if (!urls || !urls.length) { showMissingAuthorizedSource644(kind); return false; }\n        function attempt(i){\n            return fetch(urls[i], {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){ return r.text().then(function(raw){\n                var res = null; try { res = JSON.parse(raw); } catch(e) { throw new Error(raw && raw.trim() ? ('Risposta server non JSON: ' + raw.slice(0,180)) : 'Risposta server vuota\/non JSON durante il controllo origine\/path. Verifica che il plugin attivo sia aggiornato e che admin-ajax.php sia raggiungibile.'); }\n                if (!res || !res.success) throw new Error(res && res.data && res.data.message ? res.data.message : 'Controllo origine\/path non riuscito.');\n                return res.data || {};\n            }); }).catch(function(err){ if (i + 1 < urls.length) return attempt(i+1); throw err; });\n        }\n        attempt(0).then(function(data){\n            var p = cleanUploadPath653(data.default_source || data.matched || data.authorized_path || '');\n            if (data.company_label) state.serverCompanyLabel659 = displayDittaLabel658(String(data.company_label));\n            if (p && isAbsoluteUploadPath651(p)) {\n                state.serverAuthorizedPath659 = p;\n                try { sessionStorage.setItem('tiAuthorizedUploadPath659', p); } catch(e) {}\n                showConfirm(kind, target || (isManager(kind) ? 'manager' : 'chat'));\n            } else {\n                var msg = data.message || missingAuthorizedSourceMessage644();\n                setInlineStatus(isManager(kind) ? 'manager' : 'main', sanitizeNonPrivilegedMessage634(msg), true);\n                try { if (window.tiAlert) window.tiAlert(sanitizeNonPrivilegedMessage634(msg)); else alert(sanitizeNonPrivilegedMessage634(msg)); } catch(e) {}\n            }\n        }).catch(function(err){\n            var msg = sanitizeNonPrivilegedMessage634(err && err.message ? err.message : missingAuthorizedSourceMessage644());\n            setInlineStatus(isManager(kind) ? 'manager' : 'main', msg, true);\n            try { if (window.tiAlert) window.tiAlert(msg); else alert(msg); } catch(e) {}\n        });\n        return false;\n    }\n\n    function xhrAlive810(){\n        try { return !!(state.xhr && state.xhr.readyState && state.xhr.readyState !== 4); } catch(e) {}\n        return false;\n    }\n    function resetUploadState810(reason){\n        try { clearUploadWatchdog812(); } catch(e812w) {}\n        try { if (state.xhr && state.xhr.readyState !== 4) state.xhr.abort();\n                try { if (state.currentUploadAbort821) state.currentUploadAbort821.abort(); } catch(e821a) {}\n                try { uploadLog821('watchdog_timeout', 'Watchdog 90s: processo interrotto e form sbloccata', 'progress=' + (state.progressLabel814 || '')); } catch(e821l) {}\n                state.busy = false;\n                state.xhr = null;\n                state.currentUploadAbort821 = null;\n                state.confirmingUpload = true;\n                showStartButton(true, 'Riprova stesso file');\n                setProgress(0, '0% - Timeout watchdog, pronto per riprova');\n                try { document.body.classList.remove('ti-upload-busy','ti-ai-upload-busy','ti-loader-active'); } catch(e821b) {} } catch(e) {}\n        state.busy = false;\n        state.xhr = null;\n        state.file = null;\n        state.confirmingPath = false;\n        state.confirmingUpload = false;\n        state.autoCloseUploadModalAfterSelect791 = false;\n        state.popupClosedAfterSelect791 = false;\n        state.cancelRequested808 = false;\n        state.timeoutRequested812 = false;\n        state.uploadStartedAt812 = 0;\n        state.uploadLastProgressAt812 = 0;\n        state.exitReason808 = reason || '';\n        try { window.__tiGuidedUploadCancelled808 = 0; } catch(e0) {}\n        try { document.body.classList.remove('ti-upload-busy','ti-ai-upload-busy','ti-loader-active'); } catch(e1) {}\n    }\n    function clearStaleUploadLock810(reason){\n        if (!state.busy) return;\n        if (xhrAlive810()) {\n            if (uploadAge812 && uploadAge812() > 90000) {\n                try { state.timeoutRequested812 = true; state.xhr.abort(); } catch(e812) {}\n            } else {\n                return;\n            }\n        }\n        resetUploadState810(reason || 'stale_lock');\n        try { setInlineStatus(state.kind || 'main', 'Caricamento precedente sbloccato. Puoi riprovare.', false); } catch(e) {}\n    }\n    function showConfirm(kind, target){\n        clearStaleUploadLock810('show_confirm');\n        state.kind = isManager(kind) ? 'manager' : 'main';\n        state.target = target || (state.kind === 'main' ? 'chat' : 'manager');\n        state.file = null;\n        state.confirmingPath = false;\n        state.confirmingUpload = false;\n        state.cancelRequested808 = false;\n        try { window.__tiGuidedUploadCancelled808 = 0; } catch(e810) {}\n        if (state.kind === 'manager') state.ctx = readCtx();\n        ensureModal().style.display = 'flex';\n        try { clearGuidedModalPreview1526(); } catch(e1526clear) {}\n        initUploadLog821('apertura popup caricamento guidato', state.kind, state.target, null);\n        setFileLine(null);\n        setSourceMapVisible(isBasicUploadUser());\n        setProgress(0, '0% - In attesa di avvio');\n        var wrap = byId('ti-direct-progress-wrap-621'); if (wrap) wrap.style.display = 'none';\n        if (isBasicUploadUser()) {\n            var first = firstAuthorizedSourcePath642();\n            setSourceMapLabel(first);\n            if (!first) {\n                setModalText(esc(missingAuthorizedSourceMessage644()), true);\n                showStartButton(false);\n                var ex0 = byId('ti-direct-upload-exit-621'); if (ex0) ex0.textContent = 'Chiudi';\n                return;\n            }\n            setModalText('Confermi l\\'apertura della selezione file di sistema?<br><br>Origine\/path autorizzata registrata: <b>' + esc(first) + '<\/b><br><br>Seleziona il file esclusivamente dal supporto autorizzato indicato, ad esempio <b>' + esc(first) + '<\/b>. Se la finestra di sistema non si apre direttamente su tale supporto, selezionalo manualmente dalla barra laterale o dal percorso del sistema.', false);\n            showStartButton(true, 'Apri selezione file da ' + first);\n            var ex1 = byId('ti-direct-upload-exit-621'); if (ex1) ex1.textContent = 'Chiudi';\n            return;\n        } else {\n            var label = state.kind === 'manager' ? 'Il file verr\u00e0 caricato e associato al campo selezionato.' : 'Il file verr\u00e0 caricato direttamente dal dispositivo o da un supporto esterno selezionabile.';\n            setModalText('Confermi l\\'avvio della scelta file?<br><br>' + removableNoticeText(state.kind) + '<br><br>' + esc(label), false);\n            showStartButton(true, 'Scegli file');\n        }\n        var ex = byId('ti-direct-upload-exit-621'); if (ex) ex.textContent = 'Chiudi';\n    }\n    function closeUploadModal(){\n        var ov = byId('ti-direct-upload-ov-621');\n        if (ov) ov.style.display = 'none';\n    }\n    function forceHideUploadProgress808(reason){\n        try {\n            if (window.tiLoaderState) {\n                window.tiLoaderState.active = false;\n                if (window.tiLoaderState.timer) clearInterval(window.tiLoaderState.timer);\n                window.tiLoaderState.timer = null;\n            }\n        } catch(e) {}\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e2) {}\n        try { if (typeof window.closeModal === 'function') window.closeModal('ti-ai-loader-ov'); } catch(e3) {}\n        try { var ov = byId('ti-ai-loader-ov'); if (ov) { ov.style.display = 'none'; ov.classList.remove('ti-modal-visible','ti-open','show'); } } catch(e4) {}\n        try { if (typeof window.updatePluginScrollLock === 'function') window.updatePluginScrollLock(); } catch(e5) {}\n    }\n    function removePendingNativeInputs808(){\n        try { Array.prototype.forEach.call(document.querySelectorAll('input[data-ti-guided-upload-808]'), function(el){ try { el.value = ''; el.remove(); } catch(e) {} }); } catch(e2) {}\n    }\n    function clearUploadWatchdog812(){\n        try { if (state.watchdogTimer812) clearTimeout(state.watchdogTimer812); } catch(e) {}\n        state.watchdogTimer812 = null;\n    }\n    function uploadAge812(){\n        try { return state.uploadStartedAt812 ? (Date.now() - state.uploadStartedAt812) : 0; } catch(e) {}\n        return 0;\n    }\n    function armUploadWatchdog812(kind, file){\n        clearUploadWatchdog812();\n        state.timeoutRequested812 = false;\n        state.uploadStartedAt812 = Date.now();\n        state.uploadLastProgressAt812 = Date.now();\n        state.watchdogTimer812 = setTimeout(function(){\n            try {\n                if (!state.busy) return;\n                state.timeoutRequested812 = true;\n                setModalText('Caricamento guidato file in timeout o senza conferma dal server. Operazione interrotta per evitare blocco della form.<br><br>Premi <b>Riprova stesso file<\/b> oppure <b>Chiudi<\/b>.', true);\n                setInlineStatus(kind || 'main', 'Timeout caricamento file. Ripeti il caricamento.', true);\n                updateUploadWaitPopup792(0, 'Timeout caricamento file', 'Operazione interrotta per evitare blocco. Ripeti il caricamento.', file && file.name ? file.name : 'file');\n                if (state.xhr && state.xhr.readyState !== 4) state.xhr.abort();\n            } catch(e) {}\n        }, 90000);\n    }\n    function exitUpload(){\n        var completedOk1528 = !!state.completedOk1528 && !state.busy;\n        uploadLog821(completedOk1528 ? 'close' : 'exit', completedOk1528 ? 'Utente ha premuto Chiudi dopo completamento: nessun annullamento\/cleanup' : 'Utente ha premuto Chiudi\/Annulla');\n        var cleanupToken859 = currentUploadCleanupToken859(false);\n        var preserveConfig1526 = !!state.preserveConfigFile1526 && \/^config-bot-file\/i.test(String(state.target||''));\n        if (completedOk1528) {\n            \/\/ 30.9.1596: un upload del File Manager puo essere fisicamente completato ma ancora in bozza.\n            \/\/ Chiudere il popup upload NON salva l associazione e NON deve mostrare un falso avviso di interruzione.\n            var managerPending1596 = !!state.managerAssociationPending1596 && state.kind === 'manager';\n            if (!managerPending1596) {\n                try { if (state.savedUploads859 && state.savedUploads859.length) commitSavedUploads859('chiusura_successo_1528'); } catch(e1528c) {}\n            } else {\n                \/\/ Il token e gia conservato nella sessione del File Manager 1596: scollega solo lo stato del popup.\n                try { state.savedUploads859 = []; window.__tiGuidedUploadSaved859 = []; } catch(e1596own) {}\n                state.uploadCleanupToken859 = '';\n            }\n            clearUploadWatchdog812();\n            state.cancelRequested808 = false; state.exitReason808 = 'completed_close'; state.xhr = null; state.currentUploadAbort821 = null; state.file = null;\n            state.confirmingPath = false; state.confirmingUpload = false; state.autoCloseUploadModalAfterSelect791 = false; state.popupClosedAfterSelect791 = false;\n            try { window.__tiGuidedUploadCancelled808 = 0; window.__tiGuidedUploadBusy810 = false; window.__tiComplexProcessActive845 = false; } catch(e1528g) {}\n            try { setSourceMapVisible(false); } catch(e1528s) {}\n            try { setFileLine(null); } catch(e1528f) {}\n            try { clearGuidedModalPreview1526(); } catch(e1528p) {}\n            try { if (typeof window.tiClearPersistentFilePreview1520 === 'function') window.tiClearPersistentFilePreview1520('chiusura dopo successo'); } catch(e1528pp) {}\n            removePendingNativeInputs808(); closeUploadModal(); forceHideUploadProgress808('upload_completed_close_1528');\n            try { document.body.classList.remove('ti-upload-busy','ti-ai-upload-busy','ti-loader-active'); } catch(e1528b) {}\n            state.preserveConfigFile1526 = false; state.completedOk1528 = false; state.managerAssociationPending1596 = false;\n            return false;\n        }\n        try {\n            if (!preserveConfig1526 && (state.busy || cleanupToken859 || (state.savedUploads859 && state.savedUploads859.length))) scheduleCleanup859('chiudi_annulla_upload_guidato', true, cleanupToken859);\n            if (preserveConfig1526) { state.savedUploads859=[]; window.__tiGuidedUploadSaved859=[]; state.uploadCleanupToken859=''; uploadLog821('storage_preserve_1526','Chiusura dopo successo: file Config\/Docs mantenuto',''); }\n        } catch(e859exit) {}\n        clearUploadWatchdog812();\n        state.cancelRequested808 = true;\n        state.exitReason808 = 'user_exit';\n        try { window.__tiGuidedUploadCancelled808 = Date.now(); } catch(e0) {}\n        if (state.xhr) { try { state.xhr.abort(); } catch(e) {} }\n        try { if (state.currentUploadAbort821) state.currentUploadAbort821.abort(); } catch(e821) {}\n        state.currentUploadAbort821 = null;\n        state.busy = false;\n        state.xhr = null;\n        state.file = null;\n        state.confirmingPath = false;\n        state.confirmingUpload = false;\n        state.autoCloseUploadModalAfterSelect791 = false;\n        state.popupClosedAfterSelect791 = false;\n        try { setSourceMapVisible(false); } catch(e) {}\n        try { setProgress(0, 'Upload annullato'); } catch(e2) {}\n        try { setInlineStatus(state.kind || 'main', 'Caricamento file annullato.', false); } catch(e3) {}\n        try { setFileLine(null); } catch(e942a) {}\n        try { clearGuidedModalPreview1526(); } catch(ePreviewExit1526) {}\n        try { if (typeof window.tiClearPersistentFilePreview1520 === 'function') window.tiClearPersistentFilePreview1520('chiusura caricamento guidato'); } catch(ePersistentExit1526) {}\n        try { showStartButton(true, 'Scegli file'); } catch(e942b) {}\n        try { if (!preserveConfig1526 && typeof window.tiCancelConfigFileUpload931 === 'function') window.tiCancelConfigFileUpload931('exit_upload_generic'); } catch(e942c) {}\n        removePendingNativeInputs808();\n        closeUploadModal();\n        forceHideUploadProgress808('upload_exit');\n        try { document.body.classList.remove('ti-upload-busy','ti-ai-upload-busy','ti-loader-active'); } catch(e4) {}\n        state.preserveConfigFile1526 = false;\n        return false;\n    }\n    window.tiDirectUploadExit621 = exitUpload;\n    window.tiGuidedUploadExit808 = exitUpload;\n    if (!window.__tiGuidedUploadExitCapture808) {\n        window.__tiGuidedUploadExitCapture808 = true;\n        document.addEventListener('click', function(ev){\n            try {\n                var t = ev && ev.target;\n                if (!t || !t.closest) return;\n                var btn = t.closest('button, a, [role=\"button\"]');\n                if (!btn) return;\n                var label = trim(btn.textContent || btn.getAttribute('aria-label') || btn.title || '');\n                var directExit = btn.id === 'ti-direct-upload-exit-621' || !!btn.closest('#ti-direct-upload-ov-621 .ti-direct-exit-621');\n                var loaderExit = btn.id === 'ti-loader-close' && (state.busy || \/caricamento file|carica file|upload|file caricato|analisi file\/i.test(((byId('ti-loader-title')||{}).textContent || '') + ' ' + ((byId('ti-loader-sub')||{}).textContent || '')));\n                if (!directExit && !(loaderExit && \/^\\s*(chiudi|esci|annulla|interrompi)\/i.test(label || 'Chiudi'))) return;\n                ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                \/\/ 30.9.1556: dopo il commit riuscito, Chiudi chiude soltanto la UI.\n                if (state.completedOk1528 && !state.busy) { exitUpload(); return false; }\n                var reallyActive1556 = !!state.busy;\n                try { if (!reallyActive1556 && typeof window.tiIsActiveProcess1546==='function') reallyActive1556 = !!window.tiIsActiveProcess1546(); } catch(e1556a) {}\n                if(reallyActive1556 && typeof window.tiConfirmAndAbortActiveProcess1546==='function' && !window.__tiCancel1546Force) return window.tiConfirmAndAbortActiveProcess1546('Caricamento guidato file');\n                exitUpload();\n                return false;\n            } catch(e) {}\n        }, true);\n        document.addEventListener('keydown', function(ev){\n            try {\n                if (!ev || ev.key !== 'Escape') return;\n                var ov = byId('ti-direct-upload-ov-621');\n                var visible = ov && getComputedStyle(ov).display !== 'none';\n                if (!visible && !state.busy) return;\n                ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                var isActiveNow972 = false;\n                try { isActiveNow972 = !!(window.__tiNativeFileUploadState && window.__tiNativeFileUploadState.busy); } catch(e972chk) {}\n                if (isActiveNow972) {\n                    if(typeof window.tiConfirmAndAbortActiveProcess1546==='function' && !window.__tiCancel1546Force) return window.tiConfirmAndAbortActiveProcess1546('Caricamento guidato file');\n                    exitUpload();\n                    return false;\n                }\n                exitUpload();\n                return false;\n            } catch(e) {}\n        }, true);\n    }\n    function chooseFileNow(){\n        clearStaleUploadLock810('choose_file');\n        if (state.busy) return false;\n        state.cancelRequested808 = false;\n        try { window.__tiGuidedUploadCancelled808 = 0; } catch(e810) {}\n        var kind = state.kind;\n        if (isManager(kind)) {\n            var ctx = readCtx();\n            if (!validCtx(ctx)) { setModalText('Contesto riga\/campo non disponibile. Riapri Gestione File Associati dalla riga corretta.', true); return false; }\n            state.ctx = ctx;\n        }\n        if (isBasicUploadUser()) {\n            var firstBasicPath660 = firstAuthorizedSourcePath642();\n            if (!firstBasicPath660) {\n                setModalText(esc(missingAuthorizedSourceMessage644()), true);\n                showStartButton(false);\n                return false;\n            }\n            setSourceMapLabel(firstBasicPath660);\n        }\n        try { uploadLog821('native_picker_849', 'Apertura selettore file richiesta da click\/pointerdown utente', 'kind=' + (kind || '') + ' target=' + (state.target || '')); } catch(e849l) {}\n        var input = document.createElement('input');\n        input.type = 'file';\n        if (!isManager(kind) && isBasicUploadUser()) {\n            input.setAttribute('accept', 'image\/*,application\/pdf,text\/plain,text\/csv,.txt,.csv,.tsv,.pdf,.doc,.docx,.xls,.xlsx,.json,.xml,.html,.htm,.log,.ini,.conf,.cfg,.sql,.yaml,.yml');\n            input.setAttribute('aria-label', 'Scegli file da origine autorizzata ' + (firstAuthorizedSourcePath642() || ''));\n            input.setAttribute('title', 'Scegli file da origine autorizzata ' + (firstAuthorizedSourcePath642() || ''));\n            input.setAttribute('data-ti-authorized-path', firstAuthorizedSourcePath642() || '');\n        } else {\n            input.setAttribute('aria-label', 'Scegli file');\n        }\n        input.style.position = 'fixed'; input.style.left = '0'; input.style.top = '0'; input.style.width = '1px'; input.style.height = '1px'; input.style.opacity = '0.01'; input.style.pointerEvents = 'auto'; input.style.zIndex = '2147483647';\n        input.setAttribute('aria-hidden','true');\n        input.setAttribute('data-ti-guided-upload-808','1');\n        document.body.appendChild(input);\n        try { input.value = ''; } catch(e810) {}\n        var pickerResolved861 = false;\n        var pickerFallbackTimer861 = null;\n        function clearPickerWatch861(){\n            try { if (pickerFallbackTimer861) clearTimeout(pickerFallbackTimer861); } catch(e) {}\n            pickerFallbackTimer861 = null;\n            try { window.removeEventListener('focus', pickerFocusBack861, true); } catch(e2) {}\n            try { document.removeEventListener('visibilitychange', pickerVisibilityBack861, true); } catch(e3) {}\n        }\n        function restorePickerButton861(reason){\n            try {\n                if (pickerResolved861 || state.busy || state.confirmingUpload || state.file) return;\n                pickerResolved861 = true;\n                clearPickerWatch861();\n                try { if (input && input.parentNode) input.parentNode.removeChild(input); } catch(e0) {}\n                state.suppressStartClickUntil849 = 0;\n                state.nativePickerArmedAt849 = 0;\n                setFileLine(null);\n                setModalText('Nessun file scelto oppure la finestra del dispositivo non si \u00e8 aperta. Premi <b>Scegli file<\/b> per ripetere senza usare F5.', true);\n                showStartButton(true, 'Scegli file');\n                uploadLog821('native_picker_restore_861', 'Ripristino pulsante Scegli file', 'reason=' + (reason || 'unknown'));\n            } catch(e861r) {}\n        }\n        function pickerHasSelectedFile926(){ try { return !!(input && input.files && input.files.length); } catch(e) {} return false; }\n        function pickerFocusBack861(){ setTimeout(function(){ if (!pickerHasSelectedFile926()) restorePickerButton861('focus_back_no_change'); }, 1200); }\n        function pickerVisibilityBack861(){ try { if (!document.hidden) setTimeout(function(){ if (!pickerHasSelectedFile926()) restorePickerButton861('visibility_back_no_change'); }, 1200); } catch(e) {} }\n        window.addEventListener('focus', pickerFocusBack861, true);\n        document.addEventListener('visibilitychange', pickerVisibilityBack861, true);\n        pickerFallbackTimer861 = setTimeout(function(){ try { if (document.hasFocus && document.hasFocus() && !pickerHasSelectedFile926()) restorePickerButton861('picker_not_opened'); } catch(e) {} }, 4500);\n        input.addEventListener('change', function(){\n            pickerResolved861 = true;\n            clearPickerWatch861();\n            var file = input.files && input.files.length ? input.files[0] : null;\n            try { document.body.removeChild(input); } catch(e) {}\n            if (!file) {\n                setFileLine(null);\n                setModalText('Nessun file scelto. Premi <b>Scegli file<\/b> per ripetere il caricamento.', true);\n                showStartButton(true, 'Scegli file');\n                return;\n            }\n            if (confirmPrivilegedSourcePath641(file)) return;\n            state.file = file;\n            uploadLog821('file_selected', 'File scelto dall utente', 'name=' + (file.name || '') + ' size=' + (file.size || 0) + ' type=' + (file.type || '') + ' rel=' + (file.webkitRelativePath || ''));\n            try { window.__tiGuidedUploadSelectedFile810 = file; } catch(e810) {}\n            if (!isManager(kind) && ((state.target || '') === 'config-bot-file' || window.targetUploadContext === 'config-bot-file')) {\n                state.target = 'config-bot-file';\n                state.confirmingUpload = false;\n                state.confirmingPath = false;\n                \/\/ 30.9.1526: la form resta visibile durante upload\/analisi per mantenere sempre disponibile la preview.\n                state.autoCloseUploadModalAfterSelect791 = false;\n                state.popupClosedAfterSelect791 = false;\n                setFileLine(file);\n                try { renderGuidedModalPreview1526(file); } catch(ePreview1526) {}\n                setProgress(1, 'File scelto - avvio caricamento AI');\n                setModalText('File scelto correttamente.<br><br><b>File:<\/b> ' + esc(file.name || 'file selezionato') + '<br><br>\u23f3 <b>Attendi il completamento del caricamento.<\/b> Avvio caricamento e interpretazione AI dal file: nessun dato viene salvato senza anteprima e conferma successiva.<br><br>\u26a0\ufe0f Non cambiare schermata o applicazione durante questa fase: i tempi di elaborazione si allungano quando il browser non e in primo piano.<br><br>Premi <b>Chiudi<\/b> solo se vuoi annullare il caricamento in corso.', false);\n                showStartButton(false);\n                uploadLog821('auto_start_config_file_926', 'Config AI: avvio automatico upload dopo scelta file', 'name=' + (file.name || '') + ' size=' + (file.size || 0));\n                function tryStartUpload926(retriesLeft) {\n                    try {\n                        if (typeof window.tiStartConfigBotFileUpload930 === 'function') {\n                            window.tiStartConfigBotFileUpload930(file, {kind:kind, target:'config-bot-file', source:'auto_start_config_file_930'});\n                            return;\n                        }\n                        if (retriesLeft > 0) {\n                            setTimeout(function(){ tryStartUpload926(retriesLeft - 1); }, 150);\n                            return;\n                        }\n                        uploadLog821('auto_start_config_file_926_fallback_929', 'Canale diretto non disponibile dopo attesa: uso canale a blocchi (meno affidabile)', '');\n                        startUpload(kind, 'config-bot-file', file);\n                    }\n                    catch(e926) {\n                        setProgress(0, '0% - Errore avvio upload AI');\n                        setModalText('Errore avvio automatico upload AI: ' + esc(e926 && e926.message ? e926.message : 'errore sconosciuto') + '<br><br>Premi <b>Conferma e carica file<\/b> per riprovare.', true);\n                        state.file = file;\n                        state.confirmingUpload = true;\n                        showStartButton(true, 'Conferma e carica file');\n                    }\n                }\n                var started926 = false;\n                var origTryStartUpload926 = tryStartUpload926;\n                tryStartUpload926 = function(retriesLeft) {\n                    if (started926) return;\n                    if (typeof window.tiStartConfigBotFileUpload930 === 'function') started926 = true;\n                    origTryStartUpload926(retriesLeft);\n                };\n                function retryOnVisible926() {\n                    if (started926 || document.visibilityState !== 'visible') return;\n                    tryStartUpload926(20);\n                }\n                document.addEventListener('visibilitychange', retryOnVisible926);\n                window.addEventListener('focus', retryOnVisible926);\n                setTimeout(function(){ tryStartUpload926(20); }, 0);\n                return;\n            }\n            state.confirmingUpload = true;\n            state.autoCloseUploadModalAfterSelect791 = false;\n            state.popupClosedAfterSelect791 = false;\n            setFileLine(file);\n            setProgress(0, 'File scelto - in attesa conferma');\n            if (!isManager(kind) && isBasicUploadUser()) {\n                var ap663 = firstAuthorizedSourcePath642() || sourceMapLabel();\n                setModalText('File scelto correttamente.<br><br><b>File:<\/b> ' + esc(file.name || 'file selezionato') + '<br><b>Origine\/path autorizzata dichiarata:<\/b> ' + esc(ap663 || '') + '<br><br>Per caricare il file premi <b>Conferma e carica file<\/b>. Prima della conferma non viene inviato alcun file.', false);\n            } else {\n                setModalText('File scelto correttamente.<br><br><b>File:<\/b> ' + esc(file.name || 'file selezionato') + '<br><br>Per caricare il file premi <b>Conferma e carica file<\/b>. Prima della conferma non viene inviato alcun file.', false);\n            }\n            showStartButton(true, 'Conferma e carica file');\n        }, {once:true});\n        if (!isBasicUploadUser()) { try { setSourceMapVisible(false); } catch(e) {} }\n        if (state.target !== 'config-bot-file') {\n            setModalText((!isManager(kind) && isBasicUploadUser()) ? (\"La selezione file di sistema si sta aprendo. Scegli il file esclusivamente dall'origine\/path autorizzata: <b>\" + esc(firstAuthorizedSourcePath642()) + \"<\/b>. Se necessario seleziona manualmente tale supporto nella finestra del sistema.\") : 'Seleziona il file dalla finestra del dispositivo. Dopo la scelta dovrai confermare il caricamento nel popup Shop & Service.', false);\n        } else {\n            setModalText('\u23f3 Apertura selettore file in corso. Attendi la scelta del file: il caricamento partir\u00e0 automaticamente subito dopo.', false);\n        }\n        showStartButton(false);\n        try {\n            state.nativePickerArmedAt849 = Date.now();\n            if (input.showPicker && typeof input.showPicker === 'function') input.showPicker();\n            else input.click();\n        } catch(e) {\n            try { pickerResolved861 = true; clearPickerWatch861(); } catch(e861cw) {}\n            try { document.body.removeChild(input); } catch(ee) {}\n            state.suppressStartClickUntil849 = 0;\n            state.nativePickerArmedAt849 = 0;\n            setModalText('Il browser ha bloccato l\\'apertura del selettore file. Premi <b>Scegli file<\/b> per ripetere senza usare F5.', true);\n            showStartButton(true, 'Scegli file');\n            uploadLog821('native_picker_blocked_861', 'Browser ha bloccato apertura selettore file', e && e.message ? e.message : '');\n        }\n        return false;\n    }\n    function makeFd(data, file){\n        var fd = new FormData();\n        fd.append('action', 'ti_ai_ss_direct_upload_664');\n        fd.append('ti_action', 'ti_ai_ss_direct_upload_664');\n        Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k] == null ? '' : data[k]); });\n        if (file) fd.append('file', file, file.name || 'upload');\n        try {\n            if (isBasicUploadUser()) {\n                fd.append('source_policy', 'basic_authorized_path');\n                fd.append('source_label', sourceLabelForPayload(file));\n                fd.append('client_path_unavailable', '1');\n                fd.append('client_relative_path', clientRelativePath(file));\n                fd.append('authorized_path', sourceLabelForPayload(file));\n            } else {\n                fd.append('source_policy', 'privileged_upload');\n                fd.append('source_label', sourceLabelForPayload(file));\n                fd.append('client_path_unavailable', clientRelativePath(file) ? '0' : '1');\n                fd.append('client_relative_path', clientRelativePath(file));\n                fd.append('authorized_path', sourceLabelForPayload(file));\n                if (sourceMapEnabled()) {\n                    fd.append('map_upload_source', '1');\n                    fd.append('source_instruction_text', sourceMapLabel() || sourceLabelForPayload(file));\n                    fd.append('authorized_path', sourceMapLabel() || sourceLabelForPayload(file));\n                }\n            }\n        } catch(e) {}\n        try { fd.append('upload_cleanup_token', currentUploadCleanupToken859(true)); fd.append('guided_upload_target', state.target || ''); } catch(e859fd) {}\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        return fd;\n    }\n    function iframeMultipartUpload831(data, file, priorErr){\n        return new Promise(function(resolve, reject){\n            if (!file) { reject(new Error('Fallback iframe: file non disponibile.')); return; }\n            if (state && state.cancelRequested808) { reject(new Error('Caricamento annullato.')); return; }\n            var dt = null;\n            try { dt = new DataTransfer(); dt.items.add(file); } catch(dtErr831) { dt = null; }\n            if (!dt || !dt.files || !dt.files.length) {\n                reject(new Error('Fallback iframe non disponibile: il browser non consente di riagganciare il file selezionato.'));\n                return;\n            }\n            var id = 'ti-upload-iframe-831-' + Date.now() + '-' + Math.floor(Math.random() * 100000);\n            var endpoint = \"https:\/\/www.tisoft.it\/en\/?ti_action=ti_ai_ss_direct_upload_664\";\n            var iframe = document.createElement('iframe');\n            var form = document.createElement('form');\n            var done = false;\n            var timer = null;\n            function cleanup(){\n                try { if (timer) clearTimeout(timer); } catch(e) {}\n                timer = null;\n                try { if (form && form.parentNode) form.parentNode.removeChild(form); } catch(e) {}\n                try { if (iframe && iframe.parentNode) iframe.parentNode.removeChild(iframe); } catch(e) {}\n            }\n            function addField(k, v){\n                var inp = document.createElement('input');\n                inp.type = 'hidden';\n                inp.name = k;\n                inp.value = (v == null ? '' : String(v));\n                form.appendChild(inp);\n            }\n            function addSourceFields(){\n                try {\n                    if (isBasicUploadUser()) {\n                        addField('source_policy', 'basic_authorized_path');\n                        addField('source_label', sourceLabelForPayload(file));\n                        addField('client_path_unavailable', '1');\n                        addField('client_relative_path', clientRelativePath(file));\n                        addField('authorized_path', sourceLabelForPayload(file));\n                    } else {\n                        addField('source_policy', 'privileged_upload');\n                        addField('source_label', sourceLabelForPayload(file));\n                        addField('client_path_unavailable', clientRelativePath(file) ? '0' : '1');\n                        addField('client_relative_path', clientRelativePath(file));\n                        addField('authorized_path', sourceLabelForPayload(file));\n                        if (sourceMapEnabled()) {\n                            addField('map_upload_source', '1');\n                            addField('source_instruction_text', sourceMapLabel() || sourceLabelForPayload(file));\n                            addField('authorized_path', sourceMapLabel() || sourceLabelForPayload(file));\n                        }\n                    }\n                } catch(e) {}\n            }\n            try { uploadLog821('iframe_fallback_831', 'Avvio fallback multipart iframe', 'endpoint=' + endpoint + ' prior=' + (priorErr && priorErr.message ? priorErr.message : priorErr || '')); } catch(e831l) {}\n            try { setUploadActivity814(11, '11% - Fallback upload iframe', 'Caricamento file', 'Il canale XHR non ha risposto. Provo il canale form\/iframe tradizionale.', file); } catch(e831p) {}\n            iframe.name = id;\n            iframe.id = id;\n            iframe.style.position = 'fixed';\n            iframe.style.left = '-10000px';\n            iframe.style.top = '0';\n            iframe.style.width = '1px';\n            iframe.style.height = '1px';\n            iframe.style.opacity = '0';\n            form.method = 'post';\n            form.enctype = 'multipart\/form-data';\n            form.encoding = 'multipart\/form-data';\n            form.action = endpoint;\n            form.target = id;\n            form.style.position = 'fixed';\n            form.style.left = '-10000px';\n            form.style.top = '0';\n            addField('action', 'ti_ai_ss_direct_upload_664');\n            addField('ti_action', 'ti_ai_ss_direct_upload_664');\n            Object.keys(data || {}).forEach(function(k){ addField(k, data[k] == null ? '' : data[k]); });\n            addSourceFields();\n            try { if (window.tiAppendCurrentLanguageToFormData) { var fakeFd = { append:function(k,v){ addField(k,v); } }; window.tiAppendCurrentLanguageToFormData(fakeFd); } } catch(e) {}\n            var fileInput = document.createElement('input');\n            fileInput.type = 'file';\n            fileInput.name = 'file';\n            fileInput.style.position = 'fixed';\n            fileInput.style.left = '-10000px';\n            fileInput.style.top = '0';\n            try { fileInput.files = dt.files; } catch(assignErr831) {\n                cleanup();\n                reject(new Error('Fallback iframe: impossibile agganciare il file selezionato (' + (assignErr831 && assignErr831.message ? assignErr831.message : assignErr831) + ').'));\n                return;\n            }\n            form.appendChild(fileInput);\n            iframe.onload = function(){\n                if (done) return;\n                done = true;\n                try { setUploadActivity814(90, '90% - Risposta iframe ricevuta', 'Caricamento file', 'Risposta server ricevuta dal fallback iframe. Verifica esito.', file); } catch(e831olp) {}\n                try {\n                    var doc = iframe.contentDocument || (iframe.contentWindow && iframe.contentWindow.document);\n                    var raw = doc && doc.body ? (doc.body.innerText || doc.body.textContent || '') : '';\n                    raw = String(raw || '').trim();\n                    try { uploadLog821('iframe_response_831', 'Risposta fallback iframe', 'chars=' + raw.length + ' head=' + raw.slice(0, 180)); } catch(e831rl) {}\n                    var res = JSON.parse(raw);\n                    if (!res || !res.success) {\n                        var emsg = res && res.data && res.data.message ? res.data.message : 'Upload iframe non riuscito.';\n                        cleanup();\n                        reject(new Error(sanitizeNonPrivilegedMessage634(emsg)));\n                        return;\n                    }\n                    cleanup();\n                    resolve(res.data || {});\n                } catch(parseErr831) {\n                    cleanup();\n                    reject(new Error('Fallback iframe: risposta server non JSON o non leggibile: ' + (parseErr831 && parseErr831.message ? parseErr831.message : parseErr831)));\n                }\n            };\n            timer = setTimeout(function(){\n                if (done) return;\n                done = true;\n                try { uploadLog821('iframe_timeout_831', 'Timeout fallback iframe', 'endpoint=' + endpoint); } catch(e831tl) {}\n                cleanup();\n                reject(new Error('Timeout fallback iframe: il server non ha restituito esito upload.'));\n            }, 45000);\n            try {\n                document.body.appendChild(iframe);\n                document.body.appendChild(form);\n                try { setUploadActivity814(16, '16% - Invio fallback iframe', 'Caricamento file', 'Invio file tramite form tradizionale in corso.', file); } catch(e831sp) {}\n                form.submit();\n            } catch(submitErr831) {\n                done = true;\n                cleanup();\n                reject(new Error('Fallback iframe non avviato: ' + (submitErr831 && submitErr831.message ? submitErr831.message : submitErr831)));\n            }\n        });\n    }\n    function locateAuthorizedPathOnly655(){\n        if (isBasicUploadUser()) return false;\n        var inp = byId('ti-direct-upload-source-label-629');\n        function applyPath(path, note, warn){\n            path = cleanUploadPath653(trim(path || ''));\n            if (inp && path) { inp.value = path; inp.setAttribute('data-authorized-path', path); }\n            if (path) { try { state.authorizedPath657 = path; state.authorizedPath656 = path; window.__tiLastAuthorizedUploadPath657 = path; window.__tiLastAuthorizedUploadPath656 = path; var sb = byId('ti-direct-upload-save-source-651'); if (sb) sb.setAttribute('data-authorized-path', path); } catch(e) {} }\n            var msg = note || '';\n            if (path) msg += '<br><br><b>Path\/origine individuata:<\/b> ' + esc(path);\n            if (!path || !isAbsoluteUploadPath651(path)) {\n                msg += '<br><br>Il browser non ha fornito una path assoluta completa. Inserisci o conferma manualmente una path assoluta, ad esempio <b>F:\\\\<\/b> oppure <b>\/Volumes\/ChiaveUSB<\/b>, poi premi <b>Salva origine\/path<\/b>.';\n                setModalText(msg, true);\n            } else {\n                setModalText(msg + '<br><br>Verifica la path proposta e premi <b>Salva origine\/path<\/b>.', !!warn);\n            }\n        }\n        try {\n            if (window.showDirectoryPicker) {\n                setModalText('Apertura scelta cartella\/origine. Seleziona la chiavetta, cartella o supporto da autorizzare.', false);\n                window.showDirectoryPicker({mode:'read'}).then(function(handle){\n                    var name = handle && handle.name ? String(handle.name) : '';\n                    var existing = sourceMapLabel();\n                    var proposed = existing && isAbsoluteUploadPath651(existing) ? existing : name;\n                    applyPath(proposed, 'Origine selezionata tramite scelta cartella del browser.', !isAbsoluteUploadPath651(proposed));\n                }).catch(function(err){\n                    setModalText('Scelta path annullata o non consentita dal browser. Puoi inserire manualmente la path assoluta, ad esempio <b>F:\\\\<\/b> oppure <b>\/Volumes\/ChiaveUSB<\/b>.', true);\n                });\n                return false;\n            }\n        } catch(e) {}\n        var input = document.createElement('input');\n        input.type = 'file';\n        input.setAttribute('webkitdirectory', 'webkitdirectory');\n        input.setAttribute('directory', 'directory');\n        input.setAttribute('aria-label', 'Individua cartella o supporto da autorizzare');\n        input.style.position = 'fixed'; input.style.left = '0'; input.style.top = '0'; input.style.width = '1px'; input.style.height = '1px'; input.style.opacity = '0'; input.style.pointerEvents = 'none';\n        document.body.appendChild(input);\n        input.addEventListener('change', function(){\n            var f = input.files && input.files.length ? input.files[0] : null;\n            var rel = '';\n            try { rel = f && f.webkitRelativePath ? String(f.webkitRelativePath) : ''; } catch(e) {}\n            try { document.body.removeChild(input); } catch(e2) {}\n            if (!f) { setModalText('Nessuna origine selezionata. Puoi inserire manualmente la path assoluta, ad esempio <b>F:\\\\<\/b>.', true); return; }\n            var root = rel ? rel.split('\/')[0] : '';\n            applyPath(root || sourceMapLabel(), 'Origine\/cartella individuata dalla scelta browser. Per sicurezza i browser normalmente comunicano il nome cartella, non la path assoluta reale.', true);\n        }, {once:true});\n        try { input.click(); } catch(e) {\n            try { document.body.removeChild(input); } catch(ee) {}\n            setModalText('Il browser ha bloccato la scelta cartella. Inserisci manualmente la path assoluta, ad esempio <b>F:\\\\<\/b> oppure <b>\/Volumes\/ChiaveUSB<\/b>.', true);\n        }\n        return false;\n    }\n\n    function saveAuthorizedSourceOnly651(){\n        if (isBasicUploadUser()) return false;\n        var path = sourceMapLabel();\n        if (!path || !isAbsoluteUploadPath651(path)) {\n            try {\n                var txtEl = byId('ti-direct-upload-text-621');\n                var txtPath = txtEl ? cleanUploadPath653(txtEl.textContent || txtEl.innerText || '') : '';\n                if (txtPath && isAbsoluteUploadPath651(txtPath)) path = txtPath;\n            } catch(e) {}\n        }\n        if (!path || !isAbsoluteUploadPath651(path)) {\n            setModalText('Indica una path assoluta autorizzata prima di salvare, ad esempio F:\\ oppure \/Volumes\/ChiaveUSB. Puoi usare anche il pulsante <b>Individua path<\/b> quando il browser lo consente.', true);\n            return false;\n        }\n        var db = dbName();\n        if (!db || db === 'NEW_DB' || db === 'Global') {\n            setModalText('Seleziona una ditta prima di salvare la path autorizzata.', true);\n            return false;\n        }\n        setModalText('Salvataggio origine\/path autorizzata in corso...', false);\n        setProgress(15, 'Salvataggio istruzione...');\n        var fd = new FormData();\n        fd.append('action', 'ti_ai_ss_save_upload_source_652');\n        fd.append('ti_action', 'ti_ai_ss_save_upload_source_652');\n        fd.append('db', db);\n        fd.append('authorized_path', path);\n        fd.append('source_label', path);\n        fd.append('detected_path', path);\n        fd.append('path', path);\n        fd.append('absolute_path', path);\n        fd.append('selected_path', path);\n        fd.append('folder_path', path);\n        try { var txtEl2 = byId('ti-direct-upload-text-621'); if (txtEl2) fd.append('path_text', txtEl2.textContent || txtEl2.innerText || ''); } catch(e) {}\n        fd.append('context', 'Mappatura manuale origine\/path autorizzata senza caricamento file');\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        var urls = ajaxUrlList();\n        if (!urls || !urls.length) { showMissingAuthorizedSource644(kind); return false; }\n        function attempt(i){\n            return fetch(urls[i], {method:'POST', body:fd, credentials:'same-origin'}).then(function(r){\n                return r.text().then(function(raw){\n                    var res = null;\n                    try { res = JSON.parse(raw); } catch(e) { throw new Error(raw && raw.trim() ? ('Risposta server non JSON: ' + raw.slice(0,220)) : 'Risposta server vuota\/non JSON. Verifica che admin-ajax.php sia raggiungibile e che il plugin attivo sia aggiornato.'); }\n                    if (!res || !res.success) throw new Error(res && res.data && res.data.message ? res.data.message : 'Salvataggio non riuscito.');\n                    return res.data || {};\n                });\n            }).catch(function(err){\n                if (i + 1 < urls.length) return attempt(i + 1);\n                throw err;\n            });\n        }\n        attempt(0).then(function(data){\n            setProgress(100, '100% - Istruzione salvata');\n            var msg = (data && data.message) ? data.message : 'Path autorizzata salvata.';\n            setModalText('Origine\/path autorizzata salvata.<br><br><b>Path autorizzata:<\/b> ' + esc(path) + '<br><br>' + esc(msg), false);\n            setInlineStatus('main', 'Path autorizzata salvata: ' + path, false);\n            try { state.serverAuthorizedPath659 = path; sessionStorage.setItem('tiAuthorizedUploadPath659', path); } catch(e) {}\n            try {\n                var d = currentDb642(); if (d) { if (!d.Tabelle) d.Tabelle = {}; if (!d.Tabelle.Istruzioni) d.Tabelle.Istruzioni = []; if (Array.isArray(d.Tabelle.Istruzioni)) d.Tabelle.Istruzioni.push({'Descrizione':'Origine\/path autorizzata per caricamento file utenti generici\/base','Path assoluta autorizzata':path,'Path autorizzata':path,'Origine autorizzata':path,'Istruzione':'Origine\/path file autorizzata per utenti generici\/base. Path assoluta autorizzata: '+path+'. Path autorizzata: '+path+'.'}); }\n            } catch(e) {}\n            try { if (window.tiAlert) window.tiAlert('Path autorizzata salvata: ' + path); } catch(e) {}\n        }).catch(function(err){\n            var msg = sanitizeNonPrivilegedMessage634(err && err.message ? err.message : 'errore sconosciuto');\n            setProgress(0, '0% - Errore');\n            setModalText('Errore salvataggio origine\/path: ' + esc(msg), true);\n        });\n        return false;\n    }\n    function ajaxUrlList(){\n        var urls = [];\n        var hardAjax661 = \"https:\/\/www.tisoft.it\/wp-admin\/admin-ajax.php\";\n        var hardDirect817 = \"https:\/\/www.tisoft.it\/en\/?ti_action=ti_ai_ss_direct_upload_664\";\n        function cleanUrl815(u){\n            u = trim(u || '');\n            if (!u) return '';\n            try { u = u.replace(\/#.*$\/, ''); } catch(e) {}\n            return u;\n        }\n        function looksAjax815(u){\n            u = cleanUrl815(u);\n            if (!u) return false;\n            return \/admin-ajax\\.php(?:\\?|$)\/i.test(u) || \/[?&]ti_action=ti_ai_ss_direct_upload_\/i.test(u) || \/[?&]action=ti_ai_ss_direct_upload_\/i.test(u);\n        }\n        function add815(u){\n            u = cleanUrl815(u);\n            if (!u || !looksAjax815(u)) return;\n            if (urls.indexOf(u) === -1) urls.push(u);\n        }\n        add815(hardDirect817);\n        add815(hardAjax661);\n        add815(window.ajaxurl);\n        add815(window.tiAjaxUrl);\n        add815(window.tiUrl);\n        return urls;\n    }\n    function xhrDirect(data, file){\n        var urls = ajaxUrlList();\n        if (!urls || !urls.length) return Promise.reject(new Error('Endpoint AJAX non disponibile per upload file. Aggiorna la pagina e riprova.'));\n        function attempt(i){\n            return new Promise(function(resolve, reject){\n                var xhr = new XMLHttpRequest();\n                state.xhr = xhr;\n                xhr.open('POST', urls[i], true);\n                xhr.withCredentials = true;\n                xhr.timeout = 35000;\n                var attemptDone817 = false;\n                var retryTimer817 = null;\n                var hardStallTimer831 = null;\n                var stallNoticeTimer831 = null;\n                var noByteTimer845 = null;\n                var longNoByteTimer845 = null;\n                var softProgressTimer861 = null;\n                function clearRetryTimer817(){ try { if (retryTimer817) clearTimeout(retryTimer817); } catch(e817ct) {} retryTimer817 = null; try { if (hardStallTimer831) clearTimeout(hardStallTimer831); } catch(e831ct) {} hardStallTimer831 = null; try { if (stallNoticeTimer831) clearTimeout(stallNoticeTimer831); } catch(e831cnt) {} stallNoticeTimer831 = null; try { if (noByteTimer845) clearTimeout(noByteTimer845); } catch(e845ct) {} noByteTimer845 = null; try { if (longNoByteTimer845) clearTimeout(longNoByteTimer845); } catch(e845lt) {} longNoByteTimer845 = null; }\n                function clearSoftProgress861(){ try { if (softProgressTimer861) clearInterval(softProgressTimer861); } catch(e861ct) {} softProgressTimer861 = null; }\n                function endpointLabel817(){ try { return String(urls[i] || '').indexOf('admin-ajax.php') !== -1 ? 'admin-ajax.php' : 'endpoint diretto ti_action'; } catch(e817el) { return 'endpoint upload'; } }\n                function startSoftProgress861(maxPct, softFile){\n                    clearSoftProgress861();\n                    var started861 = Date.now();\n                    softProgressTimer861 = setInterval(function(){\n                        try {\n                            if (attemptDone817 || state.cancelRequested808 || state.timeoutRequested812) { clearSoftProgress861(); return; }\n                            var cur861 = parseInt(state.progressPercent814 || 0, 10) || 0;\n                            var events861 = parseInt(state.uploadProgressEvents814 || 0, 10) || 0;\n                            var stage861 = String(state.uploadStage814 || '');\n                            var elapsed861 = Date.now() - started861;\n                            var ceiling861 = 64;\n                            if (\/upload_sent|response|server|headers|loading\/i.test(stage861)) ceiling861 = 91;\n                            else if (events861 > 0 || \/uploading\/i.test(stage861)) ceiling861 = 78;\n                            else if (elapsed861 > 16000) ceiling861 = 84;\n                            else if (elapsed861 > 7000) ceiling861 = 72;\n                            var max861 = Math.min(maxPct || 91, ceiling861);\n                            if (cur861 >= max861) return;\n                            var inc861 = elapsed861 < 8000 ? 2 : 1;\n                            var next861 = Math.min(max861, Math.max(cur861 + inc861, cur861 < 7 ? 7 : cur861 + inc861));\n                            setUploadActivity814(next861, next861 + '% - Caricamento file in corso', 'Caricamento file', '', softFile || file);\n                        } catch(e861sp) {}\n                    }, 1200);\n                }\n                function armHardStallWatchdog831(){\n                    clearRetryTimer817();\n                    try { uploadLog821('multipart_watchdog_831', 'Watchdog blocco iniziale armato', 'endpoint=' + (urls[i] || '') + ' stage=' + (state.uploadStage814 || '')); } catch(e831wl) {}\n                    stallNoticeTimer831 = setTimeout(function(){\n                        try {\n                            if (!attemptDone817 && (xhr.readyState || 0) <= 1 && (parseInt(state.uploadProgressEvents814 || 0, 10) || 0) < 1) {\n                                setUploadActivity814(8, '8% - Nessuna conferma upload, preparo fallback', 'Caricamento file', '', file);\n                                uploadLog821('multipart_silent_831', 'Nessun evento dopo invio browser', 'readyState=' + (xhr.readyState || 0) + ' pct=' + (state.progressPercent814 || 0));\n                            }\n                        } catch(e831nt) {}\n                    }, 2500);\n                    hardStallTimer831 = setTimeout(function(){\n                        try {\n                            if (!attemptDone817 && (xhr.readyState || 0) <= 1 && (parseInt(state.uploadProgressEvents814 || 0, 10) || 0) < 1) {\n                                uploadLog821('multipart_no_response_831', 'Blocco reale al 7%: nessun progress\/readyState server', 'endpoint=' + (urls[i] || '') + ' readyState=' + (xhr.readyState || 0) + ' stage=' + (state.uploadStage814 || ''));\n                                retryNext817('Blocco al 7%: il server\/browser non ha generato eventi di trasferimento o risposta.');\n                            }\n                        } catch(e831ht) { try { retryNext817('Blocco al 7%: watchdog upload iniziale.'); } catch(e831ri) {} }\n                    }, 10000);\n                    noByteTimer845 = setTimeout(function(){\n                        try {\n                            var pct845 = parseInt(state.progressPercent814 || 0, 10) || 0;\n                            var ev845 = parseInt(state.uploadProgressEvents814 || 0, 10) || 0;\n                            var stage845 = String(state.uploadStage814 || '');\n                            if (!attemptDone817 && ev845 < 1 && !\/uploading|upload_sent|response|server|headers|loading\/i.test(stage845)) {\n                                uploadLog821('multipart_no_byte_845', 'Nessun byte reale trasferito entro 16 secondi: passo a endpoint alternativo\/fallback', 'endpoint=' + (urls[i] || '') + ' readyState=' + (xhr.readyState || 0) + ' pct=' + pct845 + ' stage=' + (state.uploadStage814 || ''));\n                                setUploadActivity814(9, '9% - Upload lento\/bloccato, provo canale alternativo', 'Caricamento file', '', file);\n                                retryNext817('Upload lento\/bloccato: nessun byte reale trasferito entro 16 secondi.');\n                            }\n                        } catch(e845nb) { try { retryNext817('Upload lento\/bloccato: watchdog no-byte.'); } catch(e845ri) {} }\n                    }, 16000);\n                    longNoByteTimer845 = setTimeout(function(){\n                        try {\n                            var pctL845 = parseInt(state.progressPercent814 || 0, 10) || 0;\n                            var evL845 = parseInt(state.uploadProgressEvents814 || 0, 10) || 0;\n                            var stageL845 = String(state.uploadStage814 || '');\n                            if (!attemptDone817 && evL845 < 1 && !\/uploading|upload_sent|response|server|headers|loading\/i.test(stageL845)) {\n                                uploadLog821('multipart_long_stall_845', 'Stallo upload oltre 35 secondi senza progress reale: abort forzato', 'endpoint=' + (urls[i] || '') + ' readyState=' + (xhr.readyState || 0) + ' pct=' + pctL845 + ' stage=' + (state.uploadStage814 || ''));\n                                setUploadActivity814(0, '0% - Upload bloccato: canale interrotto', 'Timeout caricamento file', '', file);\n                                retryNext817('Upload bloccato oltre 35 secondi senza avanzamento reale.');\n                            }\n                        } catch(e845ls) { try { retryNext817('Upload bloccato: watchdog lungo.'); } catch(e845ri2) {} }\n                    }, 35000);\n                }\n                function retryNext817(msg){\n                    if (attemptDone817) return;\n                    attemptDone817 = true;\n                    clearRetryTimer817();\n                    clearSoftProgress861();\n                    try { state.uploadStage814 = 'retry_endpoint'; } catch(e817rs) {}\n                    try { xhr.abort(); } catch(e817ab) {}\n                    if (i + 1 < urls.length) {\n                        setUploadActivity814(10, '10% - Nessuna conferma da ' + endpointLabel817() + ', provo endpoint alternativo', 'Caricamento file', 'Il primo endpoint non ha confermato la ricezione. Provo canale diretto anti-timeout.', file);\n                        attempt(i + 1).then(resolve).catch(reject);\n                    } else {\n                        reject(new Error(msg || 'Timeout iniziale upload: il server non ha confermato ricezione file.'));\n                    }\n                }\n                xhr.timeout = 35000;\n                try { uploadLog821('multipart_attempt_829', 'Upload multipart diretto browser', 'endpoint=' + (urls[i] || '')); } catch(e829ma) {}\n                try { state.progressPercent814 = 0; state.uploadProgressEvents814 = 0; state.uploadStage814 = 'opening'; state.uploadEndpoint817 = urls[i] || ''; } catch(e814s) {}\n                setUploadActivity814(2, '2% - Apertura connessione upload (' + endpointLabel817() + ')', 'Caricamento file', '', file);\n                xhr.onloadstart = function(){\n                    try { state.uploadStage814 = 'request_started'; } catch(e814ls) {}\n                    setUploadActivity814(4, '4% - Richiesta inviata al server', 'Caricamento file', '', file);\n                };\n                if (xhr.upload) {\n                    xhr.upload.onloadstart = function(){\n                        try { state.uploadStage814 = 'upload_started'; } catch(e814uls) {}\n                        setUploadActivity814(6, '6% - Trasferimento file avviato', 'Caricamento file', '', file);\n                    };\n                    xhr.upload.onprogress = function(ev){\n                        clearRetryTimer817();\n                        try { state.uploadLastProgressAt812 = Date.now(); state.uploadProgressEvents814 = (state.uploadProgressEvents814 || 0) + 1; state.uploadStage814 = 'uploading'; } catch(e812p) {}\n                        if (ev && ev.lengthComputable && ev.total > 0) {\n                            var pct = Math.max(8, Math.min(72, Math.round(8 + (ev.loaded \/ ev.total) * 64)));\n                            var loadedKb = Math.round((ev.loaded || 0) \/ 1024);\n                            var totalKb = Math.round((ev.total || 0) \/ 1024);\n                            setUploadActivity814(pct, pct + '% - Invio file al server (' + loadedKb + '\/' + totalKb + ' KB)', 'Caricamento file', '', file);\n                        } else {\n                            var cur = parseInt(state.progressPercent814 || 0, 10) || 8;\n                            var pct2 = Math.min(64, Math.max(12, cur + 6));\n                            setUploadActivity814(pct2, pct2 + '% - Evento trasferimento ricevuto', 'Caricamento file', '', file);\n                        }\n                    };\n                    xhr.upload.onload = function(){\n                        clearRetryTimer817();\n                        try { state.uploadStage814 = 'upload_sent'; } catch(e814ul) {}\n                        setUploadActivity814(74, '74% - File inviato, attendo risposta server', 'Caricamento file', '', file);\n                        startSoftProgress861(91, file);\n                    };\n                    xhr.upload.onerror = function(){\n                        setUploadActivity814(0, '0% - Errore durante invio file', 'Errore caricamento file', 'Errore durante il trasferimento del file.', file);\n                    };\n                }\n                xhr.onreadystatechange = function(){\n                    try { state.uploadLastProgressAt812 = Date.now(); } catch(e814rs) {}\n                    if (xhr.readyState >= 2) clearRetryTimer817();\n                    if (xhr.readyState === 1) {\n                        bumpUploadActivity814(4, 8, '4% - Connessione upload aperta', 'Caricamento file', '', file);\n                    } else if (xhr.readyState === 2) {\n                        setUploadActivity814(Math.max(82, parseInt(state.progressPercent814 || 0, 10) || 0), '82% - Server raggiunto, risposta avviata', 'Caricamento file', '', file);\n                    } else if (xhr.readyState === 3) {\n                        setUploadActivity814(Math.max(88, parseInt(state.progressPercent814 || 0, 10) || 0), '88% - Risposta server in lettura', 'Caricamento file', '', file);\n                    }\n                };\n                xhr.onload = function(){\n                    if (attemptDone817) return;\n                    attemptDone817 = true;\n                    clearRetryTimer817();\n                    clearSoftProgress861();\n                    setUploadActivity814(95, '95% - Risposta server ricevuta, verifica esito', 'Caricamento file', '', file);\n                    var raw = xhr.responseText || '';\n                    if (xhr.status < 200 || xhr.status >= 300) {\n                        if (i + 1 < urls.length) { setUploadActivity814(12, '12% - Riprovo endpoint AJAX alternativo', 'Caricamento file', 'Primo endpoint non valido. Tentativo alternativo in corso.', file); attempt(i + 1).then(resolve).catch(reject); return; }\n                        reject(new Error('HTTP ' + xhr.status + ': ' + raw.slice(0, 260))); return;\n                    }\n                    var res;\n                    try { res = JSON.parse(raw); } catch(e) { reject(new Error(raw && raw.trim() ? ('Risposta server non JSON: ' + raw.slice(0, 260)) : 'Risposta server vuota\/non JSON. Verifica che admin-ajax.php sia raggiungibile e che il plugin attivo sia aggiornato.')); return; }\n                    if (!res || !res.success) { var emsg = res && res.data && res.data.message ? res.data.message : 'Upload non riuscito.'; reject(new Error(sanitizeNonPrivilegedMessage634(emsg))); return; }\n                    setUploadActivity814(98, '98% - Upload registrato, aggiorno interfaccia', 'Caricamento file', '', file);\n                    resolve(res.data || {});\n                };\n                xhr.onerror = function(){ if (attemptDone817) return; attemptDone817 = true; clearRetryTimer817(); clearSoftProgress861(); setUploadActivity814(0, '0% - Errore rete upload su ' + endpointLabel817(), 'Errore caricamento file', '', file); if (i + 1 < urls.length) attempt(i + 1).then(resolve).catch(reject); else reject(new Error('Errore rete durante upload file.')); };\n                xhr.ontimeout = function(){ if (attemptDone817) return; attemptDone817 = true; clearRetryTimer817(); clearSoftProgress861(); setUploadActivity814(0, '0% - Timeout server upload su ' + endpointLabel817(), 'Timeout caricamento file', '', file); if (i + 1 < urls.length) attempt(i + 1).then(resolve).catch(reject); else reject(new Error('Timeout server durante upload file. Stadio: ' + (state.uploadStage814 || 'sconosciuto') + '. Endpoint: ' + endpointLabel817() + '.')); };\n                xhr.onabort = function(){ if (attemptDone817 && !state.timeoutRequested812 && !state.cancelRequested808) return; clearRetryTimer817(); clearSoftProgress861(); reject(new Error(state.timeoutRequested812 ? 'Timeout caricamento guidato file: operazione interrotta per evitare blocco. Ripeti il caricamento.' : 'Caricamento annullato.')); };\n                try {\n                    setUploadActivity814(3, '3% - Creo richiesta multipart', 'Caricamento file', 'Preparazione dati file per invio.', file);\n                    xhr.send(makeFd(data || {}, file));\n                    setUploadActivity814(7, '7% - Invio consegnato al browser (' + endpointLabel817() + ')', 'Caricamento file', '', file);\n                    startSoftProgress861(72, file);\n                    armHardStallWatchdog831();\n                } catch(sendErr810) {\n                    reject(new Error('Invio file non avviato dal browser: ' + (sendErr810 && sendErr810.message ? sendErr810.message : sendErr810)));\n                }\n            });\n        }\n        return attempt(0).catch(function(err818){\n            try {\n                if (data && data.mode === 'plain' && file && !state.cancelRequested808) {\n                    return b64UploadDirect818(data, file, err818);\n                }\n            } catch(e818b) {}\n            throw err818;\n        });\n    }\n    function applyAttachedResult(ctx, data){\n        if (!ctx || !data) return;\n        try {\n            var tbl = data.tbl || ctx.tbl;\n            var idx = (data.idx !== undefined && data.idx !== null) ? data.idx : ctx.idx;\n            var key = data.key || ctx.key;\n            if (!window.currentDbData) window.currentDbData = {Tabelle:{}};\n            if (!window.currentDbData.Tabelle) window.currentDbData.Tabelle = {};\n            if (!window.currentDbData.Tabelle[tbl]) window.currentDbData.Tabelle[tbl] = [];\n            if (!window.currentDbData.Tabelle[tbl][idx]) window.currentDbData.Tabelle[tbl][idx] = {};\n            window.currentDbData.Tabelle[tbl][idx][key] = data.value || data.name || data.filename || '';\n            if (data.db_version) window.currentDbData.__db_version = data.db_version;\n            if (window.configOriginalDbData) {\n                if (!window.configOriginalDbData.Tabelle) window.configOriginalDbData.Tabelle = {};\n                if (!window.configOriginalDbData.Tabelle[tbl]) window.configOriginalDbData.Tabelle[tbl] = [];\n                if (!window.configOriginalDbData.Tabelle[tbl][idx]) window.configOriginalDbData.Tabelle[tbl][idx] = {};\n                window.configOriginalDbData.Tabelle[tbl][idx][key] = window.currentDbData.Tabelle[tbl][idx][key];\n                if (data.db_version) window.configOriginalDbData.__db_version = data.db_version;\n            }\n            try { window.currentDbViewData = null; } catch(e1512v) {}\n            try {\n                var esc1512 = window.CSS && CSS.escape ? CSS.escape : function(v){ return String(v).replace(\/([\\\"'\\[\\]#.:>+~*^$|=!])\/g, '\\\\$1'); };\n                document.querySelectorAll('#ti-conf-ov [data-tbl=\"' + esc1512(tbl) + '\"][data-idx=\"' + esc1512(idx) + '\"][data-key=\"' + esc1512(key) + '\"]').forEach(function(inp){ if(inp){ inp.value = window.currentDbData.Tabelle[tbl][idx][key]; try{inp.dispatchEvent(new Event('input',{bubbles:true}));}catch(e){} } });\n            } catch(e1512d) {}\n            try { if (window.syncConfigTableAfterRowMutation) window.syncConfigTableAfterRowMutation(tbl); } catch(e1512s) {}\n            if (window.modifiedFields && typeof window.modifiedFields.delete === 'function') window.modifiedFields.delete(tbl + '-' + idx + '-' + key);\n            if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState();\n            try { if (window.log1088) window.log1088('linked_file_save_1512 - associazione verificata server=' + (data.verified_saved ? '1' : '0') + ' tbl=' + tbl + ' idx=' + idx + ' key=' + key + ' value=' + String(data.value || data.name || '').slice(0,220)); } catch(e1512l) {}\n        } catch(e) {}\n    }\n    function uploadAttach(file){\n        var ctx = state.ctx || readCtx();\n        if (!validCtx(ctx)) return Promise.reject(new Error('Contesto riga\/campo non disponibile. Riapri Gestione File Associati dalla riga corretta.'));\n        var db = dbName();\n        if (!db || db === 'NEW_DB' || db === 'Global') return Promise.reject(new Error('Seleziona una ditta prima di caricare il file.'));\n        var r = rowFor(ctx) || {};\n        return xhrDirect({mode:'attach', defer_association:'1', db:db, tbl:ctx.tbl, idx:ctx.idx, id:ctx.id || r.ID || '', key:ctx.key, record_label:recordLabel(ctx), upload_cleanup_token:currentUploadCleanupToken859(true), guided_upload_target:'manager'}, file).then(function(data){\n            if (!data || data.association_pending_1596 !== true || data.verified_storage_1528 === false) throw new Error('Il file e stato ricevuto, ma il server non ha confermato lo storage provvisorio. Riprova.');\n            if (typeof window.tiFileManagerStageUploaded1596 !== 'function') throw new Error('Gestione provvisoria associazioni non disponibile. Riapri Gestione File Associati e riprova.');\n            window.tiFileManagerStageUploaded1596(ctx, data);\n            state.managerAssociationPending1596 = true;\n            try { setTimeout(function(){ if (window.openFileManager) window.openFileManager(ctx.tbl, ctx.idx, ctx.key); }, 180); } catch(e) {}\n            return data;\n        });\n    }\n    function uploadPlain(target, file){\n        var db = dbName(), tbl = 'Chat', rec = '';\n        if (target === 'config-bot-file') { tbl = 'Config'; rec = ''; }\n        if (target && target !== 'chat' && target !== 'config-bot-file' && target !== 'purchase-import-file') {\n            var m = txt(target).match(\/cfg-img-([^-]+)-\/);\n            tbl = m ? m[1] : (target === 'p-foto' ? 'Utenti' : 'Config');\n            rec = target === 'p-foto' ? ((byId('p-user') && byId('p-user').value) || (byId('p-utente') && byId('p-utente').value) || 'utente') : tbl;\n        }\n        var data = {mode:'plain', db:db, tbl:tbl};\n        data.upload_cleanup_token = currentUploadCleanupToken859(true);\n        data.guided_upload_target = target || 'chat';\n        if (rec) data.record_label = rec;\n        if (!window.tiClaimUpload952) {\n            window.tiClaimUpload952 = function(fileRef, opts){\n                opts = opts || {};\n                try {\n                    var now = Date.now();\n                    var existing = window.__tiUploadClaim952;\n                    if (existing && existing.active) {\n                        var age = now - existing.ts;\n                        var canOverride = !!opts.overrideAfterMs && age > opts.overrideAfterMs;\n                        if (age < 2700000 && !canOverride) return false;\n                    }\n                    window.__tiUploadClaim952 = {active: true, ts: now, name: fileRef && fileRef.name, size: fileRef && fileRef.size, owner: opts.owner || ''};\n                    return true;\n                } catch(e) { return true; }\n            };\n            window.tiReleaseUpload952 = function(){ try { if (window.__tiUploadClaim952) window.__tiUploadClaim952.active = false; } catch(e) {} };\n        }\n        if (target === 'config-bot-file' && file && (file instanceof File)) {\n            if (!window.tiClaimUpload952(file, {owner: '929'})) {\n                try { uploadLog821('config_file_b64_skipped_952', 'Canale a blocchi non avviato: un altro canale ha gia in carico questo file', 'file=' + (file.name || '')); } catch(e952s) {}\n                return Promise.resolve({skipped: true, reason: 'already_claimed'});\n            }\n            try { uploadLog821('config_file_b64_first_929', 'Config AI: canale chunk\/base64 prioritario anti-fermo 1%', 'file=' + (file.name || '') + ' size=' + (file.size || 0)); } catch(e929l) {}\n            try { setUploadActivity814(5, '5% - Avvio upload AI anti-fermo', 'Caricamento file', 'Uso il canale a blocchi per evitare il fermo iniziale del browser.', file); } catch(e929p) {}\n            try {\n                setTimeout(function(){\n                    try {\n                        var stCheck963 = window.__tiNativeFileUploadState;\n                        var pctCheck963 = parseInt((stCheck963 && stCheck963.progressPercent814) || 0, 10) || 0;\n                        if (pctCheck963 > 0 && pctCheck963 < 25 && typeof window.tiStartConfigBotFileUpload930 === 'function') {\n                            uploadLog821('config_file_b64_recovery_963', 'Canale a blocchi fermo da tempo: tento recupero con canale diretto', 'pct=' + pctCheck963);\n                            window.tiStartConfigBotFileUpload930(file, {kind: (state && state.kind) || 'main', target: 'config-bot-file', source: 'recovery_963'});\n                        }\n                    } catch(e963) {}\n                }, 18000);\n            } catch(e963setup) {}\n            return b64UploadDirect818(data, file, null).then(function(res929ok){ try { window.tiReleaseUpload952(); } catch(e952r1) {} return res929ok; }).catch(function(err929){\n                try { window.tiReleaseUpload952(); } catch(e952r2) {}\n                var msg929 = err929 && err929.message ? String(err929.message) : String(err929 || 'errore sconosciuto');\n                try { uploadLog821('config_file_b64_failed_929', 'Config AI: canale chunk\/base64 non completato, provo multipart', msg929); } catch(e929lf) {}\n                try { setUploadActivity814(10, '10% - Fallback upload browser', 'Caricamento file', 'Il canale a blocchi non ha completato. Provo il canale browser tradizionale.', file); } catch(e929fb) {}\n                return xhrDirect(data, file).catch(function(err829){\n                    var msg829 = err829 && err829.message ? String(err829.message) : String(err829 || 'errore sconosciuto');\n                    try { uploadLog821('multipart_failed_829', 'Upload multipart XHR non riuscito: provo fallback iframe', msg829); } catch(e829lf) {}\n                    try { setUploadActivity814(12, '12% - Fallback form\/iframe', 'Caricamento file', 'Il canale browser non ha completato. Provo upload form tradizionale.', file); } catch(e829fb) {}\n                    return iframeMultipartUpload831(data, file, err829).catch(function(err831){\n                        var msg831 = err831 && err831.message ? String(err831.message) : String(err831 || 'errore sconosciuto');\n                        throw new Error('Il caricamento Configurazione AI non ha completato. Chunk\/base64: ' + msg929 + '. XHR: ' + msg829 + '. Iframe: ' + msg831 + '. Riprova stesso file oppure carica TXT\/CSV\/XLSX.');\n                    });\n                });\n            });\n        }\n        if (file && (file instanceof File)) {\n            try { uploadLog821('multipart_first_829', 'Uso upload multipart diretto prima della lettura locale', 'file=' + (file.name || '') + ' size=' + (file.size || 0)); } catch(e829l) {}\n            try { setUploadActivity814(5, '5% - Avvio upload diretto browser', 'Caricamento file', 'Invio il file con il canale nativo del browser, senza lettura locale base64 preventiva.', file); } catch(e829p) {}\n            return xhrDirect(data, file).catch(function(err829){\n                var msg829 = err829 && err829.message ? String(err829.message) : String(err829 || 'errore sconosciuto');\n                try { uploadLog821('multipart_failed_829', 'Upload multipart XHR non riuscito: provo fallback iframe', msg829); } catch(e829lf) {}\n                try { setUploadActivity814(10, '10% - Fallback form\/iframe', 'Caricamento file', 'Il canale XHR non ha completato. Provo upload form tradizionale prima di leggere il file in base64.', file); } catch(e829fb) {}\n                return iframeMultipartUpload831(data, file, err829).catch(function(err831){\n                    var msg831 = err831 && err831.message ? String(err831.message) : String(err831 || 'errore sconosciuto');\n                    try { uploadLog821('iframe_failed_831', 'Fallback iframe non riuscito: passo a base64\/chunk', msg831); } catch(e831lf) {}\n                    try { setUploadActivity814(13, '13% - Fallback upload a blocchi', 'Caricamento file', 'Anche il canale form\/iframe non ha completato. Provo il canale a blocchi anti-blocco.', file); } catch(e831fb) {}\n                    return b64UploadDirect818(data, file, err829).catch(function(err819){\n                        var msg819 = err819 && err819.message ? String(err819.message) : String(err819 || 'errore sconosciuto');\n                        if (\/Lettura locale|FileReader|arrayBuffer|Timeout lettura chunk|timeout\/i.test(msg819)) {\n                            throw new Error('Il browser\/server non ha completato il caricamento. XHR: ' + msg829 + '. Iframe: ' + msg831 + '. Fallback: ' + msg819 + '. Riprova stesso file oppure carica una versione TXT\/CSV\/XLSX.');\n                        }\n                        throw err819;\n                    });\n                });\n            });\n        }\n        return xhrDirect(data, file);\n    }\n    function processMainTarget(target, file){\n        if (validCtx(target)) { state.ctx = target; return uploadAttach(file); }\n        target = target || 'chat';\n        if (target === 'config-bot-file') {\n            return uploadPlain(target, file).then(function(data){\n                window.configBotFile = data.url || '';\n                var fileBox = byId('ti-conf-ai-file'), promptBox = byId('ti-conf-ai-prompt'), replyBox = byId('ti-conf-ai-reply'), fileName = data.name || file.name || 'file';\n                try { if (window.tiFileAiSetAvailable799) window.tiFileAiSetAvailable799(data.url || '', fileName, 'config'); } catch(e799) {}\n                if (fileBox) { fileBox.style.display = 'block'; fileBox.innerHTML = '\ud83d\udcce <b>File caricato per AI:<\/b> ' + esc(fileName) + '<br><span style=\"font-size:13px;color:#cbd5e1;\">Adesso indica cosa deve fare la AI con il contenuto del file.<\/span>'; }\n                if (replyBox && !(window.tiFileAiSetAvailable799)) { replyBox.style.display = 'block'; replyBox.innerHTML = '\u2705 File caricato correttamente. File disponibile per la AI.'; }\n                if (promptBox && !trim(promptBox.value)) promptBox.value = 'Ho caricato un file per la AI. Analizza il contenuto del file e applica la mia prossima istruzione operativa. Aggiungi servizi e prodotti dal file, preparando prima una anteprima senza salvare.';\n                if (promptBox) { try { promptBox.focus({preventScroll:true}); } catch(e) {} }\n                try {\n                    var url926 = data && data.url ? String(data.url) : '';\n                    if (url926 && window.__tiConfigFileAutoRunUrl926 !== url926) {\n                        window.__tiConfigFileAutoRunUrl926 = url926;\n                        var currentPrompt926 = promptBox ? trim(promptBox.value || '') : '';\n                        var genericPrompt926 = !currentPrompt926 || (\/ho\\s+caricato\\s+un\\s+file\\s+per\\s+la\\s+ai\/i.test(currentPrompt926) && \/applica\\s+la\\s+mia\\s+prossima\\s+istruzione\/i.test(currentPrompt926));\n                        var autoPrompt926 = 'Aggiungi servizi e prodotti dal file caricato, preparando prima una anteprima senza salvare. Usa il file allegato come sorgente principale; non usare la preview prezzi da fonti ditta.';\n                        if (promptBox) promptBox.value = genericPrompt926 ? autoPrompt926 : currentPrompt926;\n                        if (replyBox) { replyBox.style.display = 'block'; replyBox.innerHTML = '\u2705 File caricato correttamente. Avvio interpretazione AI dal file e preparo anteprima senza salvare.'; }\n                        var promptLog926 = (promptBox ? promptBox.value : ''); if (window.tiRedactConfigAiSecrets1587) promptLog926 = window.tiRedactConfigAiSecrets1587(promptLog926);\n                        uploadLog821('auto_run_config_ai_926', 'Config AI: avvio interpretazione dopo upload file', 'url=' + url926 + ' prompt=' + promptLog926);\n                        setTimeout(function(){\n                            try {\n                                if (typeof window.tiStartConfigFileImport929 === 'function') {\n                                    window.tiStartConfigFileImport929({url:url926, name:fileName}, (promptBox ? promptBox.value : autoPrompt926), 'auto_after_upload_929');\n                                } else if (typeof window.runConfigBot === 'function') {\n                                    window.runConfigBot();\n                                } else if (replyBox) {\n                                    replyBox.innerHTML = '\u2705 File caricato. Scrivi 1 oppure premi Invia per avviare l interpretazione AI dal file.';\n                                }\n                            } catch(eRun926) {\n                                if (replyBox) replyBox.innerHTML = '\u26a0\ufe0f File caricato, ma avvio interpretazione non riuscito: ' + esc(eRun926 && eRun926.message ? eRun926.message : 'errore sconosciuto') + '<br>Premi Invia per riprovare.';\n                            }\n                        }, 180);\n                    }\n                } catch(e926run) {}\n                return data;\n            });\n        }\n        if (target === 'purchase-import-file') {\n            return uploadPlain(target, file).then(function(data){ var fileName = data.name || file.name || 'file'; if (window.startPurchaseFileImport) window.startPurchaseFileImport(data.url || '', fileName); return data; });\n        }\n        if (target && target !== 'chat') {\n            return uploadPlain(target, file).then(function(data){\n                var inp = byId(target);\n                if (inp) { inp.value = data.name || data.filename || file.name || ''; try { inp.dispatchEvent(new Event('change', {bubbles:true})); } catch(e) {} }\n                if (txt(target).indexOf('cfg-') === 0 && window.renderConfig) window.renderConfig();\n                return data;\n            });\n        }\n        var runUpload = function(uploadFile){\n            var realFile = (uploadFile instanceof File) ? uploadFile : file;\n            return uploadPlain('chat', realFile).then(function(data){ window.lastUploadedFile = data.url || ''; try { if (window.tiFileAiSetAvailable799) window.tiFileAiSetAvailable799(window.lastUploadedFile, realFile.name || file.name || '', 'chat'); } catch(e799) {} if (window.startUserUploadedFileAI) window.startUserUploadedFileAI(window.lastUploadedFile, realFile.name || file.name || ''); return data; });\n        };\n        if (typeof window.prepareUploadFileForAI === 'function') return window.prepareUploadFileForAI(file).then(runUpload);\n        return runUpload(file);\n    }\n    function startUpload(kind, target, file){\n        clearStaleUploadLock810('start_upload');\n        if (!file) { try { file = window.__tiGuidedUploadSelectedFile810 || state.file || null; } catch(e810) { file = state.file || null; } }\n        if (!file) {\n            setModalText('Nessun file disponibile per il caricamento. Premi <b>Scegli file<\/b> e seleziona nuovamente il file.', true);\n            showStartButton(true, 'Scegli file');\n            return false;\n        }\n        state.cancelRequested808 = false;\n        try { window.__tiGuidedUploadCancelled808 = 0; } catch(e810) {}\n        if (isBasicUploadUser()) {\n            var allowedPath664 = firstAuthorizedSourcePath642() || sourceMapLabel();\n            if (!allowedPath664) {\n                setModalText(esc(missingAuthorizedSourceMessage644()), true);\n                showStartButton(false);\n                return false;\n            }\n            setSourceMapLabel(allowedPath664);\n        }\n        if (!isBasicUploadUser() && sourceMapEnabled() && (!sourceMapLabel() || !isAbsoluteUploadPath651(sourceMapLabel()))) {\n            setModalText(\"Per salvare l'origine come istruzione indica una path assoluta autorizzata, ad esempio F:\\\\ oppure \/Volumes\/ChiaveUSB.\", true);\n            showStartButton(true, 'Scegli file');\n            return;\n        }\n        kind = isManager(kind) ? 'manager' : 'main';\n        state.kind = kind; state.target = target || (kind === 'main' ? 'chat' : 'manager'); state.file = file; state.confirmingUpload = false;\n        state.uploadCleanupToken859 = makeUploadCleanupToken859();\n        state.savedUploads859 = []; state.preserveConfigFile1526 = false; state.completedOk1528 = false; state.managerAssociationPending1596 = false;\n        try { window.__tiGuidedUploadSaved859 = []; } catch(e859new) {}\n        initUploadLog821('avvio upload confermato', kind, state.target, file);\n        try { window.__tiComplexProcessActive845 = true; window.__tiGuidedUploadBusy810 = true; } catch(e845b) {}\n        setFileLine(file);\n        try { renderGuidedModalPreview1526(file); } catch(ePreviewStart1526) {}\n        setModalText('Caricamento in corso. La preview del file resta disponibile fino alla chiusura del processo. Puoi premere Chiudi per annullare l\\'operazione.', false);\n        showStartButton(false);\n        var ex = byId('ti-direct-upload-exit-621'); if (ex) ex.textContent = 'Chiudi \/ annulla';\n        setProgress(1, '1% - File confermato, preparo richiesta upload');\n        setInlineStatus(kind, 'Caricamento file in corso: ' + (file.name || 'upload'), false);\n        addUploadAiStatus861(kind, state.target, '\ud83d\udcce Caricamento file in corso. Attendi: ti avviso quando il file \u00e8 disponibile per la AI.');\n        state.cancelRequested808 = false;\n        state.timeoutRequested812 = false;\n        state.exitReason808 = '';\n        try { window.__tiGuidedUploadCancelled808 = 0; } catch(eCancelReset808) {}\n        state.busy = true;\n        armUploadWatchdog812(kind, file);\n        try { document.body.classList.add('ti-upload-busy'); } catch(eBusy808) {}\n        var autoCloseAfterSelect791 = !!state.autoCloseUploadModalAfterSelect791;\n        state.autoCloseUploadModalAfterSelect791 = false;\n        if (autoCloseAfterSelect791) {\n            state.popupClosedAfterSelect791 = true;\n            try { closeUploadModal(); } catch(eClose791) {}\n            showUploadWaitPopup792(kind, state.target, file);\n        }\n        var p = isManager(kind) ? uploadAttach(file) : processMainTarget(state.target, file);\n        p.then(function(data){\n            try { registerSavedUpload859(data, kind, state.target, file); } catch(e859reg) {}\n            try {\n                if (isManager(kind) && data && data.verified_saved === true) {\n                    commitSavedUploads859('manager_attach_verified_1528');\n                    uploadLog821('storage_commit_1528','File associato verificato: reso definitivo e rimosso dal cleanup temporanei','tbl='+(data.tbl||'')+' key='+(data.key||'')+' path='+(data.storage_path||data.path||''));\n                }\n            } catch(eCommitAttach1528) {}\n            try {\n                if (\/^config-bot-file\/i.test(String(state.target||'')) && data && data.verified_storage_1526 !== false && (!data.stored_table || String(data.stored_table).toLowerCase()==='config')) {\n                    state.preserveConfigFile1526 = true;\n                    commitSavedUploads859('config_file_verificato_1526');\n                    uploadLog821('storage_commit_1526','File Config\/Docs reso definitivo: escluso dalla pulizia temporanei','path='+(data.storage_path||data.path||''));\n                }\n            } catch(eCommit1526) {}\n            if (state.cancelRequested808 || window.__tiGuidedUploadCancelled808) {\n                try { cleanupSavedUploads859('risposta_tardiva_dopo_annullo', true, false); } catch(e859late) {}\n                clearUploadWatchdog812(); state.busy = false; state.xhr = null; state.file = null; state.cancelRequested808 = false; state.timeoutRequested812 = false; state.completedOk1528 = false;\n                try { document.body.classList.remove('ti-upload-busy'); } catch(eDone808) {}\n                try { window.__tiComplexProcessActive845 = false; window.__tiGuidedUploadBusy810 = false; } catch(e845late) {}\n                forceHideUploadProgress808('late_success_ignored');\n                return data;\n            }\n            clearUploadWatchdog812(); state.busy = false; state.xhr = null; state.timeoutRequested812 = false; state.completedOk1528 = true;\n            state.popupClosedAfterSelect791 = false;\n            state.autoCloseUploadModalAfterSelect791 = false;\n            try { document.body.classList.remove('ti-upload-busy'); } catch(eDone808b) {}\n            try { window.__tiComplexProcessActive845 = false; window.__tiGuidedUploadBusy810 = false; } catch(e845done) {}\n            uploadLog821('success', 'Upload completato', 'name=' + ((data && (data.name || data.filename || data.original_name)) || (file && file.name) || 'file'));\n            setProgress(100, '100% - Caricamento completato e registrato');\n            var name = (data && (data.name || data.filename || data.original_name)) || file.name || 'file';\n            var pendingAssoc1596 = !!(isManager(kind) && data && data.association_pending_1596 === true);\n            setModalText(pendingAssoc1596 ? 'File caricato nello storage e aggiunto alla bozza.<br><br><b>L associazione NON e ancora salvata.<\/b><br>Chiudi questo popup, controlla l anteprima nella Gestione File Associati e premi <b>Salva<\/b>.' : (isManager(kind) ? 'File caricato e associato.<br><br><b>Chiudi questo popup di caricamento per proseguire.<\/b>' : 'File caricato correttamente.<br><br><b>Chiudi questo popup di caricamento per proseguire.<\/b>'), false);\n            setFileLine({name:name, size:file.size || 0});\n            var okMsg = pendingAssoc1596 ? ('File caricato in bozza: ' + name + '. L associazione verra registrata solo premendo Salva nella Gestione File Associati.') : (isManager(kind) ? ('File associato: ' + name + '. Chiudi il popup di caricamento per proseguire.') : ('File caricato: ' + name + '. Chiudi il popup di caricamento per proseguire.'));\n            if (data && data.source_instruction_message) okMsg += ' - ' + data.source_instruction_message;\n            setInlineStatus(kind, okMsg, false);\n            var isChatAi792 = !isManager(kind) && (!state.target || state.target === 'chat');\n            addUploadAiStatus861(kind, state.target, '\u2705 File caricato. Avvio la fase AI e ti mostro le opzioni appena disponibili.');\n            if (isChatAi792) {\n                updateUploadWaitPopup792(93, 'File caricato', '', name);\n            } else {\n                updateUploadWaitPopup792(100, 'Caricamento completato', okMsg + ' Premi Chiudi per proseguire.', name);\n                finishUploadWaitPopup792(true, 'Caricamento completato', okMsg, true);\n            }\n            showStartButton(false);\n            try { setSourceMapVisible(false); } catch(e) {}\n            var ex2 = byId('ti-direct-upload-exit-621'); if (ex2) ex2.textContent = 'Chiudi';\n            setTimeout(function(){\n                if (!state.busy) {\n                    try { showStartButton(false); } catch(e810) {}\n                    var ex810 = byId('ti-direct-upload-exit-621'); if (ex810) ex810.textContent = 'Chiudi';\n                }\n            }, 650);\n        }).catch(function(err){\n            var cancelled808 = !!(state.cancelRequested808 || (err && (err.name === 'AbortError' || \/abort|annull\/i.test(String(err.message || '')))));\n            if (cancelled808) {\n                clearUploadWatchdog812(); state.busy = false; state.xhr = null; state.file = null; state.confirmingUpload = false; state.confirmingPath = false; state.timeoutRequested812 = false;\n                state.popupClosedAfterSelect791 = false; state.autoCloseUploadModalAfterSelect791 = false; state.cancelRequested808 = false;\n                try { document.body.classList.remove('ti-upload-busy'); } catch(eCancel808) {}\n                try { window.__tiComplexProcessActive845 = false; window.__tiGuidedUploadBusy810 = false; } catch(e845cancel) {}\n                setInlineStatus(kind, 'Caricamento file annullato.', false);\n                closeUploadModal();\n                forceHideUploadProgress808('upload_cancelled');\n                return;\n            }\n            var reopenUploadPopup791 = !!state.popupClosedAfterSelect791;\n            var retryFile815 = state.file || file || null;\n            try { if (!retryFile815 && window.__tiGuidedUploadSelectedFile810) retryFile815 = window.__tiGuidedUploadSelectedFile810; } catch(e815rf) {}\n            var rawMsg815 = (err && err.message) ? String(err.message) : 'errore sconosciuto';\n            uploadLog821('error', 'Upload fallito', rawMsg815);\n            var isTimeout815 = !!(state.timeoutRequested812 || \/timeout|tempo massimo|timed\\s*out|scadut\/i.test(rawMsg815));\n            clearUploadWatchdog812(); state.busy = false; state.xhr = null; state.timeoutRequested812 = false; state.completedOk1528 = false;\n            state.confirmingPath = false;\n            state.popupClosedAfterSelect791 = false;\n            state.autoCloseUploadModalAfterSelect791 = false;\n            try { document.body.classList.remove('ti-upload-busy'); } catch(eErr808) {}\n            try { window.__tiComplexProcessActive845 = false; window.__tiGuidedUploadBusy810 = false; } catch(e845err) {}\n            if (reopenUploadPopup791) { try { ensureModal().style.display = 'flex'; } catch(eOpen791) {} }\n            var msg = sanitizeNonPrivilegedMessage634(rawMsg815);\n            try { cleanupSavedUploads859(isTimeout815 ? 'timeout_pronto_riprova' : 'upload_non_a_buon_fine', true, !!(isTimeout815 && retryFile815)); } catch(e859errclean) {}\n            if (isTimeout815 && retryFile815) {\n                state.file = retryFile815;\n                state.confirmingUpload = true;\n                try { window.__tiGuidedUploadSelectedFile810 = retryFile815; } catch(e815sf) {}\n                setFileLine(retryFile815);\n                setModalText('Timeout caricamento file: il server non ha risposto entro il limite neppure con il canale alternativo anti-timeout.<br><br>Il file selezionato e ancora disponibile in questa finestra: premi <b>Riprova stesso file<\/b> per ritentare senza riaprire la scelta file, oppure <b>Chiudi<\/b> per annullare. Se il documento era gia stato ricevuto dalla AI, verra mostrata una risposta\/opzione file disponibile invece del silenzio.', true);\n                setInlineStatus(kind, 'Timeout upload. Puoi riprovare lo stesso file senza riselezionarlo.', true);\n                addUploadAiStatus861(kind, state.target, '\u26a0\ufe0f Caricamento file in timeout. Puoi premere Riprova stesso file oppure Chiudi.');\n                setProgress(0, '0% - Timeout, pronto per riprova');\n                finishUploadWaitPopup792(false, 'Timeout caricamento file', 'Il caricamento e stato sbloccato. Puoi riprovare lo stesso file.', true);\n                showStartButton(true, 'Riprova stesso file');\n            } else {\n                state.file = null;\n                state.confirmingUpload = false;\n                setModalText('Errore caricamento file: ' + esc(msg), true);\n                setInlineStatus(kind, 'Errore upload: ' + msg, true);\n                addUploadAiStatus861(kind, state.target, '\u26a0\ufe0f Upload file non completato. Premi Scegli file e seleziona nuovamente il file.');\n                setProgress(0, '0% - Errore');\n                finishUploadWaitPopup792(false, 'Errore caricamento file', 'Errore caricamento file: ' + msg, true);\n                showStartButton(true, 'Scegli file');\n            }\n            try { if (!isBasicUploadUser()) setSourceMapVisible(false); } catch(e) {}\n            var ex3 = byId('ti-direct-upload-exit-621'); if (ex3) ex3.textContent = 'Chiudi';\n        });\n        return false;\n    }\n    function openDirect(kind, target){\n        clearStaleUploadLock810('open_direct');\n        if (state.busy) {\n            try { setInlineStatus(kind === 'manager' ? 'manager' : 'main', 'Caricamento file gia in corso. Premi Chiudi\/annulla se vuoi interrompere.', true); } catch(e810) {}\n            return false;\n        }\n        kind = isManager(kind) ? 'manager' : 'main';\n        if (isBasicUploadUser() && !firstAuthorizedSourcePath642()) {\n            return checkAuthorizedSourceServer659(kind, target);\n        }\n        if (kind === 'manager') {\n            var ctx = readCtx();\n            if (!validCtx(ctx)) { if (window.tiAlert) window.tiAlert('Gestione File Associati: record\/campo non disponibile. Riapri la finestra dalla riga corretta.'); return false; }\n            state.ctx = ctx;\n        }\n        showConfirm(kind, target || (kind === 'main' ? 'chat' : 'manager'));\n        return false;\n    }\n    window.tiNativeUpload617 = function(kind){ return openDirect(kind === 'manager' ? 'manager' : 'main'); };\n    window.tiNativeUpload620 = window.tiNativeUpload617;\n    window.tiNativeUpload621 = window.tiNativeUpload617;\n    window.tiNativeUpload622 = window.tiNativeUpload617;\n    window.tiNativeUpload623 = window.tiNativeUpload617;\n    window.tiNativeUpload624 = window.tiNativeUpload617;\n    window.tiNativeUpload625 = window.tiNativeUpload617;\n    window.tiNativeUpload629 = window.tiNativeUpload617;\n    window.tiNativeUpload633 = window.tiNativeUpload617;\n    window.tiNativeUpload634 = window.tiNativeUpload617;\n    window.tiNativeUpload640 = window.tiNativeUpload617;\n    window.tiNativeUpload641 = window.tiNativeUpload617;\n    window.tiNativeUpload642 = window.tiNativeUpload617;\n    window.tiNativeUpload643 = window.tiNativeUpload617;\n    window.tiNativeUpload644 = window.tiNativeUpload617;\n    window.tiNativeUpload645 = window.tiNativeUpload617;\n    window.tiNativeUpload646 = window.tiNativeUpload617;\n    window.tiNativeUpload651 = window.tiNativeUpload617;\n    window.tiNativeUpload648 = window.tiNativeUpload617;\n    window.tiNativeUpload664 = window.tiNativeUpload617;\n    function applyUploadRoleLabels(){\n        try {\n            var mainBtn = byId('ti-main-native-upload-btn-617');\n            var fmBtn = byId('ti-fm-native-upload-btn-617');\n            if (mainBtn) mainBtn.textContent = isBasicUploadUser() ? '\ud83d\udcc1 Carica da origine autorizzata' : '\ud83d\udcc1 Carica file da dispositivo \/ supporto';\n            if (fmBtn) fmBtn.textContent = '\ud83d\udcc1 Aggiungi file';\n        } catch(e) {}\n    }\n    window.showUploadChoice = function(target){ target = target || 'chat'; if (aiUploadTarget859(target)) { try { hardResetUploadForReopen859('riapertura_carica_file_ai', true); } catch(e859show) {} } applyUploadRoleLabels(); window.__tiNativeMainTarget621 = target; window.targetUploadContext = target; return openDirect('main', target); };\n    window.chooseLocal = function(){ return window.showUploadChoice(window.__tiNativeMainTarget621 || window.targetUploadContext || 'chat'); };\n    window.chooseLocalManager = function(){ return openDirect('manager', 'manager'); };\n    window.tiDirectUploadFromInput616 = function(){ return window.showUploadChoice('chat'); };\n    window.tiOpenDirectUpload616 = function(target){ return window.showUploadChoice(target || 'chat'); };\n    window.pickConfigBotFile = function(){ return window.showUploadChoice('config-bot-file'); };\n    window.pickPurchaseImportFile = function(){ return window.showUploadChoice('purchase-import-file'); };\n\n    if (!window.__tiConfigBotFileReload859Capture) {\n        window.__tiConfigBotFileReload859Capture = true;\n        document.addEventListener('click', function(ev){\n            try {\n                var t = ev && ev.target;\n                if (!t || !t.closest) return;\n                var btn = t.closest('button, a, [role=\"button\"]');\n                if (!btn) return;\n                var label = trim(btn.textContent || btn.getAttribute('aria-label') || btn.title || '');\n                var onclick = trim(btn.getAttribute('onclick') || '');\n                if (!\/pickConfigBotFile\/i.test(onclick) && !\/^\\s*(?:ri)?carica\\s+file\\s+per\\s+ai\\s*$\/i.test(label)) return;\n                ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();\n                window.pickConfigBotFile();\n                return false;\n            } catch(e859cap) {}\n        }, true);\n    }\n\n    var prevOpenFM = window.openFileManager;\n    if (typeof prevOpenFM === 'function' && !prevOpenFM.__tiNative621) {\n        window.openFileManager = function(tbl, idx, key){\n            saveCtx({tbl:tbl, idx:idx, key:key});\n            var ret = prevOpenFM.apply(this, arguments);\n            try {\n                var fm = byId('ti-file-manager-ov');\n                if (fm) {\n                    fm.dataset.tbl = tbl || '';\n                    fm.dataset.idx = String(idx);\n                    fm.dataset.key = key || '';\n                    fm.setAttribute('data-ti-context-table', tbl || '');\n                    fm.setAttribute('data-ti-context-row', String(idx));\n                    fm.setAttribute('data-ti-context-field', key || '');\n                }\n            } catch(e) {}\n            setInlineStatus('manager', '', false);\n            return ret;\n        };\n        window.openFileManager.__tiNative621 = true;\n        window.openFileManager.__tiNative620 = true;\n        window.openFileManager.__tiNative617 = true;\n    }\n    function handleNativeUploadButton849(evt){\n        var t = evt && evt.target;\n        if (!t || !t.closest) return;\n        var btn = t.closest('#ti-fm-native-upload-btn-617,#ti-main-native-upload-btn-617');\n        if (!btn) return;\n        try { if (evt.preventDefault) evt.preventDefault(); if (evt.stopImmediatePropagation) evt.stopImmediatePropagation(); } catch(e) {}\n        return openDirect(btn.id === 'ti-fm-native-upload-btn-617' ? 'manager' : 'main', btn.id === 'ti-fm-native-upload-btn-617' ? 'manager' : (window.__tiNativeMainTarget621 || window.targetUploadContext || 'chat'));\n    }\n    document.addEventListener('click', handleNativeUploadButton849, true);\n    if (document.readyState !== 'loading') { ensureModal(); applyUploadRoleLabels(); installUploadAlertSanitizer634(); }\n    else document.addEventListener('DOMContentLoaded', function(){ ensureModal(); applyUploadRoleLabels(); installUploadAlertSanitizer634(); }, false);\n    setTimeout(installUploadAlertSanitizer634, 300);\n    setTimeout(installUploadAlertSanitizer634, 1200);\n    document.addEventListener('ti:login', applyUploadRoleLabels, true);\n})();\n\n<\/script>\n\n<style id=\"ti-hide-login-logged-612-css\">\n#ti-login-btn[data-ti-logged-hidden=\"1\"],\n#ti-ai-outer.ti-logged-plugin-user #ti-login-btn {\n    display:none !important;\n    visibility:hidden !important;\n    opacity:0 !important;\n    pointer-events:none !important;\n    width:0 !important;\n    min-width:0 !important;\n    max-width:0 !important;\n    padding:0 !important;\n    margin:0 !important;\n    border:0 !important;\n    overflow:hidden !important;\n}\n<\/style>\n<script id=\"ti-login-hide-logged-612\">\n(function(){\n    \"use strict\";\n    if (window.__tiHideLoginLogged612Installed) return;\n    window.__tiHideLoginLogged612Installed = true;\n    var serverLogged = false;\n    var serverUser = \"\";\n    function byId(id){ return document.getElementById(id); }\n    function text(v){ return String(v == null ? '' : v); }\n    function norm(v){ return text(v).trim().toLowerCase(); }\n    function visible(el){\n        try {\n            if (!el) return false;\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0')) return false;\n            return true;\n        } catch(e) { return !!el; }\n    }\n    function hasRealUserName(){\n        var n = norm((byId('ti-user-name') || {}).textContent || '');\n        return !!(n && n !== 'cliente\/utente' && n !== 'cliente' && n !== 'utente' && n !== 'guest' && n !== 'ospite');\n    }\n    function isLogged(){\n        if (serverLogged || norm(serverUser)) return true;\n        \/\/ 30.9.1753: la modalita Registrazione e solo uno stato UI guest, non una sessione autenticata.\n        if (window.__tiProfileRegistrationMode384 === true || window.__tiProfileRegistrationMode385 === true) return false;\n        var u = norm(window.tiUser || window.currentUser || window.tiCurrentUser || '');\n        if (u && u !== 'cliente\/utente' && u !== 'cliente' && u !== 'utente' && u !== 'guest' && u !== 'ospite') return true;\n        if (hasRealUserName()) return true;\n        var role = norm((byId('ti-user-role') || {}).textContent || '');\n        if (role && role !== '-' && role !== 'registrazione' && role !== 'registration') return true;\n        var logout = byId('ti-logout-btn');\n        if (visible(logout)) return true;\n        return false;\n    }\n    function hideLogin(){\n        var outer = byId('ti-ai-outer');\n        var login = byId('ti-login-btn');\n        var logout = byId('ti-logout-btn');\n        if (!isLogged()) return false;\n        if (outer) outer.classList.add('ti-logged-plugin-user');\n        if (login) {\n            login.setAttribute('data-ti-logged-hidden','1');\n            login.setAttribute('aria-hidden','true');\n            login.setAttribute('tabindex','-1');\n            login.disabled = true;\n            login.onclick = function(ev){ try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {} return false; };\n            try { login.style.setProperty('display','none','important'); } catch(e) {}\n            try { login.style.setProperty('visibility','hidden','important'); } catch(e) {}\n            try { login.style.setProperty('pointer-events','none','important'); } catch(e) {}\n        }\n        if (logout) {\n            try { logout.style.setProperty('display','inline-flex','important'); } catch(e) {}\n            logout.removeAttribute('aria-hidden');\n            logout.disabled = false;\n        }\n        var direct = byId('ti-mobile-direct-login');\n        if (direct) {\n            try { direct.style.setProperty('display','none','important'); } catch(e) {}\n            direct.classList.remove('ti-direct-login-visible');\n        }\n        return true;\n    }\n    window.tiHideLoginIfLogged612 = hideLogin;\n    var prevSetAdmin = window.setAdminUI;\n    if (typeof prevSetAdmin === 'function' && !prevSetAdmin.__ti612HideLogin) {\n        window.setAdminUI = function(){ var r = prevSetAdmin.apply(this, arguments); setTimeout(hideLogin,0); return r; };\n        window.setAdminUI.__ti612HideLogin = true;\n    }\n    var prevOpenModal = window.openModal;\n    if (typeof prevOpenModal === 'function' && !prevOpenModal.__ti612HideLogin) {\n        window.openModal = function(){ var r = prevOpenModal.apply(this, arguments); setTimeout(hideLogin,0); return r; };\n        window.openModal.__ti612HideLogin = true;\n    }\n    ['DOMContentLoaded','ti:login','ti:config-opened','click','input','change'].forEach(function(evt){\n        document.addEventListener(evt, function(){ setTimeout(hideLogin,0); }, true);\n    });\n    hideLogin();\n    setTimeout(hideLogin, 50);\n    setTimeout(hideLogin, 300);\n    setTimeout(hideLogin, 1000);\n})();\n<\/script>\n\n\n<script id=\"ti-orphan-cleanup-refresh-614\">\n(function(){\n    \"use strict\";\n    if (window.__tiOrphanCleanupRefresh614Installed) return;\n    window.__tiOrphanCleanupRefresh614Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function selectedDb(){ var s = byId('ti-ditta'); return s ? String(s.value || '').trim() : ''; }\n    function isVisible(el){\n        if (!el) return false;\n        try {\n            var cs = window.getComputedStyle ? window.getComputedStyle(el) : null;\n            if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return false;\n            return el.style.display !== 'none' && el.getAttribute('aria-hidden') !== 'true';\n        } catch(e) { return true; }\n    }\n    function fileManagerCtx(){\n        var ov = byId('ti-file-manager-ov');\n        var ctx = null;\n        try {\n            if (ov && isVisible(ov)) ctx = {tbl:ov.dataset.tbl || ov.getAttribute('data-ti-context-table') || '', idx:ov.dataset.idx || ov.getAttribute('data-ti-context-row') || '', key:ov.dataset.key || ov.getAttribute('data-ti-context-field') || ''};\n            if ((!ctx || !ctx.tbl || !ctx.key) && window.targetUploadContext) ctx = {tbl:window.targetUploadContext.tbl || '', idx:window.targetUploadContext.idx, key:window.targetUploadContext.key || ''};\n            if (ctx && ctx.tbl && ctx.key) return ctx;\n        } catch(e) {}\n        return null;\n    }\n    function reopenFileManager(ctx){\n        if (!ctx || !ctx.tbl || !ctx.key || typeof window.openFileManager !== 'function') return;\n        setTimeout(function(){\n            try { window.openFileManager(ctx.tbl, parseInt(ctx.idx, 10) || 0, ctx.key); } catch(e) {}\n        }, 150);\n    }\n    function fetchDb(dbVal){\n        if (!dbVal || dbVal === 'NEW_DB' || dbVal === 'Global') return Promise.resolve(false);\n        if (typeof window.refreshCurrentConfigDb === 'function') {\n            return Promise.resolve(window.refreshCurrentConfigDb(dbVal)).catch(function(){ return false; });\n        }\n        if (!window.fetchJsonSafe) return Promise.resolve(false);\n        var fd = new FormData();\n        fd.append('ti_action', 'ti_ai_get_db_data');\n        fd.append('db', dbVal);\n        return window.fetchJsonSafe(window.tiUrl, {method:'POST', body:fd, tiNoLongProcessSignal:true}).then(function(res){\n            if (res && res.success && res.data) {\n                window.currentDbData = res.data;\n                try { if (window.renderConfig) window.renderConfig(); } catch(e) {}\n                return true;\n            }\n            return false;\n        }).catch(function(){ return false; });\n    }\n    window.tiRefreshAfterOrphanCleanup614 = function(dbVal, ctx){\n        ctx = ctx || fileManagerCtx();\n        dbVal = dbVal || selectedDb();\n        return fetchDb(dbVal).then(function(ok){\n            if (ok) reopenFileManager(ctx);\n            return ok;\n        });\n    };\n\n    function install(){\n        if (!window.fetchJsonSafe || !window.tiUrl) return false;\n        if (typeof window.forceCleanupMissingMediaRefs610 === 'function' && !window.forceCleanupMissingMediaRefs610.__ti614RefreshWrapped) {\n            var oldForce = window.forceCleanupMissingMediaRefs610;\n            window.forceCleanupMissingMediaRefs610 = function(dbVal){\n                var ctx = fileManagerCtx();\n                return oldForce.apply(this, arguments).then(function(data){\n                    var removed = parseInt((data && data.removed) || 0, 10) || 0;\n                    if (removed > 0) {\n                        return window.tiRefreshAfterOrphanCleanup614(dbVal, ctx).then(function(){ return data; });\n                    }\n                    return data;\n                });\n            };\n            window.forceCleanupMissingMediaRefs610.__ti614RefreshWrapped = true;\n        }\n        if (typeof window.startOrphanFileCleanup === 'function' && !window.startOrphanFileCleanup.__ti614ForceFirst) {\n            var oldStart = window.startOrphanFileCleanup;\n            window.startOrphanFileCleanup = function(dbVal){\n                dbVal = dbVal || selectedDb();\n                var started = false;\n                var beginOriginal = function(){\n                    if (started) return;\n                    started = true;\n                    return oldStart.call(window, dbVal);\n                };\n                try {\n                    if (typeof window.showProgressPopup === 'function') window.showProgressPopup('Pulizia file non associati', 'Verifico prima le associazioni fantasma nei campi database.', {startPercent:2, targetPercent:14, stepMs:300, cancellable:false, currentItem:'Scansione associazioni fantasma'});\n                    if (typeof window.showOrphanCleanupEmergencyButton === 'function') window.showOrphanCleanupEmergencyButton();\n                    if (typeof window.forceCleanupMissingMediaRefs610 === 'function') {\n                        return window.forceCleanupMissingMediaRefs610(dbVal).then(function(data){\n                            var removed = parseInt((data && data.removed) || 0, 10) || 0;\n                            if (removed > 0 && typeof window.updateProgressPopup === 'function') window.updateProgressPopup(15, 'Pulizia file non associati', 'Associazioni fantasma eliminate: ' + removed + '. Avvio scansione file fisici.', 'Associazioni fantasma eliminate: ' + removed);\n                            return beginOriginal();\n                        }).catch(function(err){\n                            if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Errore pulizia associazioni fantasma');\n                            if (typeof window.tiAlert === 'function') window.tiAlert('Errore durante la verifica delle associazioni fantasma: ' + ((err && err.message) ? err.message : 'errore sconosciuto'));\n                        });\n                    }\n                } catch(e) {}\n                return beginOriginal();\n            };\n            window.startOrphanFileCleanup.__ti614ForceFirst = true;\n        }\n        if (typeof window.showOrphanCleanupFinalReport === 'function' && !window.showOrphanCleanupFinalReport.__ti614RefreshWrapped) {\n            var oldReport = window.showOrphanCleanupFinalReport;\n            window.showOrphanCleanupFinalReport = function(deletedPaths, errors, total, deleted, interrupted, processed, scopeInfo){\n                var ret = oldReport.apply(this, arguments);\n                if (!interrupted) {\n                    var dbVal = selectedDb();\n                    var ctx = fileManagerCtx();\n                    var notify = function(removed){\n                        if (removed > 0 && typeof window.tiAlert === 'function') {\n                            setTimeout(function(){ window.tiAlert('Associazioni fantasma residue eliminate: <b>' + removed + '<\/b><br>La schermata Gestione File Associati e stata aggiornata.'); }, 650);\n                        }\n                    };\n                    if (dbVal && typeof window.forceCleanupMissingMediaRefs610 === 'function') {\n                        window.forceCleanupMissingMediaRefs610(dbVal).then(function(data){\n                            var removed = parseInt((data && data.removed) || 0, 10) || 0;\n                            return window.tiRefreshAfterOrphanCleanup614(dbVal, ctx).then(function(){ notify(removed); });\n                        }).catch(function(){\n                            window.tiRefreshAfterOrphanCleanup614(dbVal, ctx);\n                        });\n                    } else {\n                        window.tiRefreshAfterOrphanCleanup614(dbVal, ctx);\n                    }\n                }\n                return ret;\n            };\n            window.showOrphanCleanupFinalReport.__ti614RefreshWrapped = true;\n        }\n        return true;\n    }\n    function retry(n){ if (install()) return; if (n > 0) setTimeout(function(){ retry(n - 1); }, 250); }\n    retry(30);\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ retry(30); });\n    else setTimeout(function(){ retry(30); }, 0);\n})();\n<\/script>\n\n\n<script id=\"ti-config-field-copy-646\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigFieldCopy646Installed) return;\n    window.__tiConfigFieldCopy646Installed = true;\n\n    function txt(v){ return String(v == null ? '' : v); }\n    function trim(v){ return txt(v).trim(); }\n    function byId(id){ return document.getElementById(id); }\n    function isCfgField(el){\n        if (!el || !el.getAttribute) return false;\n        var id = txt(el.id || '');\n        if (\/^cfg-(txt|img|rel)-\/.test(id)) return true;\n        return !!(el.dataset && el.dataset.tbl && el.dataset.key && (el.classList && (el.classList.contains('ti-in') || el.classList.contains('ti-rel-select'))));\n    }\n    function idxVal(v){\n        var n = parseInt(v, 10);\n        return isNaN(n) ? v : n;\n    }\n    function markChanged(tbl, idx, key){\n        try {\n            if (!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(String(tbl) + '-' + String(idx) + '-' + String(key));\n        } catch(e) {}\n        try { window.configWasSaved = false; } catch(e) {}\n        try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n    }\n    function ensureRow(tbl, idx){\n        if (!window.currentDbData) window.currentDbData = {Tabelle:{}};\n        if (!window.currentDbData.Tabelle) window.currentDbData.Tabelle = {};\n        if (!window.currentDbData.Tabelle[tbl]) window.currentDbData.Tabelle[tbl] = [];\n        if (!window.currentDbData.Tabelle[tbl][idx]) window.currentDbData.Tabelle[tbl][idx] = {};\n        return window.currentDbData.Tabelle[tbl][idx];\n    }\n    function setConfigValue(tbl, idx, key, value, el){\n        tbl = trim(tbl); key = trim(key); idx = idxVal(idx);\n        if (!tbl || !key || idx === '' || idx === null || typeof idx === 'undefined') return false;\n        try {\n            var row = ensureRow(tbl, idx);\n            row[key] = txt(value);\n            markChanged(tbl, idx, key);\n            if (el) {\n                try { el.setAttribute('data-ti-value-copied-646', '1'); } catch(e) {}\n                try { el.style.setProperty('border-color', '#fbbf24', 'important'); } catch(e) {}\n                try { if (window.forceWhiteEditStyle) window.forceWhiteEditStyle(el); } catch(e) {}\n            }\n            return true;\n        } catch(e) { return false; }\n    }\n    function selectedValue(sel){\n        if (!sel) return '';\n        if (sel.multiple) {\n            return Array.prototype.slice.call(sel.selectedOptions || []).map(function(opt){\n                return trim(opt && opt.value);\n            }).filter(Boolean).join(', ');\n        }\n        return trim(sel.value);\n    }\n    function applyRelationSelect(sel){\n        if (!sel || !sel.dataset) return false;\n        var tbl = sel.dataset.tbl || sel.getAttribute('data-tbl') || '';\n        var idx = sel.dataset.idx || sel.getAttribute('data-idx') || '';\n        var key = sel.dataset.key || sel.getAttribute('data-key') || '';\n        var joined = selectedValue(sel);\n        var ok = setConfigValue(tbl, idx, key, joined, sel);\n        try {\n            var hint = sel.parentElement ? sel.parentElement.querySelector('.ti-rel-summary') : null;\n            if (hint) hint.textContent = joined || 'Nessun record associato';\n            sel.setAttribute('data-ti-selected-value-646', joined);\n            if (joined) sel.title = 'Valore copiato nel campo: ' + joined;\n        } catch(e) {}\n        return ok;\n    }\n    function applyTextField(el){\n        if (!isCfgField(el) || !el.dataset) return false;\n        if (el.classList && el.classList.contains('ti-rel-select')) return applyRelationSelect(el);\n        if (el.disabled || el.readOnly) return false;\n        var tbl = el.dataset.tbl || el.getAttribute('data-tbl') || '';\n        var idx = el.dataset.idx || el.getAttribute('data-idx') || '';\n        var key = el.dataset.key || el.getAttribute('data-key') || '';\n        return setConfigValue(tbl, idx, key, el.value, el);\n    }\n\n    var prevRel = window.updateMemFieldFromRelationSelect;\n    window.updateMemFieldFromRelationSelect = function(tbl, idx, key, sel){\n        var ret;\n        try { if (typeof prevRel === 'function') ret = prevRel.apply(this, arguments); } catch(e) {}\n        try {\n            if (sel) {\n                if (tbl) sel.dataset.tbl = tbl;\n                if (idx !== undefined && idx !== null) sel.dataset.idx = String(idx);\n                if (key) sel.dataset.key = key;\n                applyRelationSelect(sel);\n            }\n        } catch(e) {}\n        return ret;\n    };\n    window.updateMemFieldFromMultiSelect = window.updateMemFieldFromRelationSelect;\n\n    ['input','change','blur'].forEach(function(evtName){\n        document.addEventListener(evtName, function(ev){\n            var el = ev && ev.target;\n            if (!isCfgField(el)) return;\n            if (el.classList && el.classList.contains('ti-rel-select')) applyRelationSelect(el);\n            else applyTextField(el);\n        }, true);\n    });\n    document.addEventListener('click', function(ev){\n        var el = ev && ev.target;\n        if (!el || !el.closest) return;\n        var sel = el.closest('select.ti-rel-select');\n        if (!sel) return;\n        setTimeout(function(){ applyRelationSelect(sel); }, 0);\n        setTimeout(function(){ applyRelationSelect(sel); }, 80);\n    }, true);\n\n    function readCtxFromManager(){\n        try {\n            var fm = byId('ti-file-manager-ov');\n            if (!fm) return null;\n            var c = {\n                tbl: (fm.dataset && (fm.dataset.tbl || fm.dataset.table)) || fm.getAttribute('data-ti-context-table') || '',\n                idx: (fm.dataset && (fm.dataset.idx || fm.dataset.row)) || fm.getAttribute('data-ti-context-row') || '',\n                key: (fm.dataset && (fm.dataset.key || fm.dataset.field)) || fm.getAttribute('data-ti-context-field') || ''\n            };\n            if (c.tbl && c.key && c.idx !== '') return c;\n        } catch(e) {}\n        return null;\n    }\n    function preserveManagerCtx(){\n        var c = readCtxFromManager();\n        if (!c && window.targetUploadContext && typeof window.targetUploadContext === 'object') c = window.targetUploadContext;\n        if (!c || !c.tbl || !c.key) return null;\n        try {\n            window.targetUploadContext = {tbl:c.tbl, idx:c.idx, key:c.key};\n            window.__tiNativeUploadCtx621 = window.targetUploadContext;\n            window.__tiNativeUploadCtx646 = window.targetUploadContext;\n            sessionStorage.setItem('tiNativeUploadCtx621', JSON.stringify(window.targetUploadContext));\n            sessionStorage.setItem('tiNativeUploadCtx646', JSON.stringify(window.targetUploadContext));\n        } catch(e) {}\n        return window.targetUploadContext;\n    }\n    var prevChooseManager = window.chooseLocalManager;\n    window.chooseLocalManager = function(){\n        preserveManagerCtx();\n        if (typeof window.tiNativeUpload617 === 'function') return window.tiNativeUpload617('manager');\n        if (typeof prevChooseManager === 'function') return prevChooseManager.apply(this, arguments);\n        return false;\n    };\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var btn = t.closest('#ti-fm-native-upload-btn-617');\n        if (!btn) return;\n        preserveManagerCtx();\n    }, true);\n})();\n<\/script>\n\n\n<script id=\"ti-file-manager-meta-666\">\n(function(){\n    \"use strict\";\n    if (window.__tiFileManagerMeta666Installed) return;\n    window.__tiFileManagerMeta666Installed = true;\n    function txt(v){ return String(v == null ? '' : v); }\n    function trim(v){ return txt(v).trim(); }\n    function decodeEntities(v){\n        var s = txt(v).replace(\/&amp;\/g, '&').replace(\/&#038;\/g, '&');\n        try { var ta = document.createElement('textarea'); ta.innerHTML = s; s = ta.value; } catch(e) {}\n        return s;\n    }\n    function basenameFromRef(ref){\n        var s = decodeEntities(ref).replace(\/\\\\\/g, '\/').trim();\n        try {\n            if (\/ti_action=ti_ai_get_image\/i.test(s)) {\n                var base = \/^https?:\\\/\\\/\/i.test(s) ? undefined : window.location.origin;\n                var u = new URL(s, base);\n                var f = u.searchParams.get('file') || '';\n                if (f) return decodeURIComponent(f).split(\/[\\\\\/]\/).pop();\n            }\n        } catch(e) {\n            var m = s.match(\/[?&]file=([^&#\\s\"'<>\\)]+)\/i);\n            if (m && m[1]) { try { return decodeURIComponent(m[1]).split(\/[\\\\\/]\/).pop(); } catch(x) { return m[1].split(\/[\\\\\/]\/).pop(); } }\n        }\n        s = s.split(\/[?#]\/)[0].replace(\/\\\/+$\/, '');\n        return (s.split(\/[\\\\\/]\/).pop() || '').trim();\n    }\n    window.tiTokenizeFileRefs666 = function(raw){\n        var src = decodeEntities(raw);\n        var arr = [], seen = {};\n        function add(x){ x = trim(x).replace(\/^[\"']+|[\"']+$\/g, ''); if (!x) return; var k = x.toLowerCase(); if (seen[k]) return; seen[k] = 1; arr.push(x); }\n        var re = \/(?:https?:)?\\\/\\\/[^\\s\"'<>,;]+ti_action=ti_ai_get_image[^\\s\"'<>,;]*|(?:\\\/[A-Za-z0-9_.\\\/%+-]*)?\\?ti_action=ti_ai_get_image[^\\s\"'<>,;]*|(?:^|[?&])ti_action=ti_ai_get_image[^\\s\"'<>,;]*\/ig;\n        src = src.replace(re, function(m){ add(m); return ' '; });\n        src.split(\/[,;\\r\\n]+\/).forEach(add);\n        return arr;\n    };\n    window.tiFileExt666 = function(name){ var m = txt(name).match(\/\\.([a-z0-9]{1,8})(?:$|[?#])\/i); return m ? ('.' + m[1].toLowerCase()) : ''; };\n    window.tiFormatBytes666 = function(n){\n        n = parseInt(n, 10); if (!isFinite(n) || n < 0) return '';\n        var u = ['B','KB','MB','GB']; var i = 0; var v = n;\n        while (v >= 1024 && i < u.length - 1) { v = v \/ 1024; i++; }\n        return (i === 0 ? String(v) : v.toFixed(v >= 10 ? 1 : 2)).replace('.', ',') + ' ' + u[i];\n    };\n    window.tiFileMetaFromRef666 = function(ref, url){\n        var name = basenameFromRef(ref) || basenameFromRef(url) || trim(ref) || 'file';\n        var ext = window.tiFileExt666(name) || window.tiFileExt666(ref) || window.tiFileExt666(url) || 'n\/d';\n        return { name:name, ext:ext, isImg:\/\\.(jpg|jpeg|png|webp|gif)$\/i.test(name), isPdf:\/\\.pdf$\/i.test(name) };\n    };\n    window.tiRefreshFileManagerMeta666 = function(){\n        document.querySelectorAll('#fm-grid [data-ti-file-size-url]').forEach(function(el){\n            if (el.getAttribute('data-ti-size-loading') === '1') return;\n            var url = el.getAttribute('data-ti-file-size-url') || '';\n            if (!url) { el.textContent = 'n\/d'; return; }\n            el.setAttribute('data-ti-size-loading', '1');\n            fetch(url, {method:'HEAD', credentials:'same-origin', cache:'no-store'}).then(function(r){\n                var len = r.headers ? r.headers.get('Content-Length') : '';\n                var fmt = window.tiFormatBytes666(len || 0);\n                el.textContent = fmt || 'n\/d';\n            }).catch(function(){ el.textContent = 'n\/d'; });\n        });\n    };\n    try {\n        if (!document.getElementById('ti-file-manager-meta-666-style')) {\n            var st = document.createElement('style'); st.id = 'ti-file-manager-meta-666-style';\n            st.textContent = '#ti-ai-outer .ti-file-preview-666{width:100%;height:86px;border-radius:8px;overflow:hidden;background:#0f172a;border:1px solid #334155;display:flex;align-items:center;justify-content:center;margin-bottom:4px}#ti-ai-outer .ti-file-preview-666 img{width:100%;height:100%;object-fit:cover;cursor:pointer}#ti-ai-outer .ti-file-preview-666 iframe{width:100%;height:100%;border:0;background:#fff}#ti-ai-outer .ti-file-meta-666{font-size:10px;line-height:1.25;color:#cbd5e1;margin-top:2px;word-break:break-word}';\n            document.head.appendChild(st);\n        }\n    } catch(e) {}\n})();\n<\/script>\n\n<script id=\"ti-config-autofill-saved-info-666\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigAutofillSavedInfo666Installed) return;\n    window.__tiConfigAutofillSavedInfo666Installed = true;\n    var last = new WeakMap();\n    function isCfg(el){ return !!(el && el.matches && el.matches('#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]')); }\n    function valueOf(el){\n        if (!el) return '';\n        if (el.tagName === 'SELECT' && el.multiple) return Array.from(el.selectedOptions || []).map(function(o){ return String(o.value || '').trim(); }).filter(Boolean).join(', ');\n        if (el.type === 'checkbox') return el.checked ? (el.value || '1') : '';\n        return el.value == null ? '' : el.value;\n    }\n    function apply(el){\n        if (!isCfg(el) || !window.currentDbData || !window.currentDbData.Tabelle) return false;\n        var tbl = el.getAttribute('data-tbl') || '', key = el.getAttribute('data-key') || '', idx = parseInt(el.getAttribute('data-idx') || '', 10);\n        if (!tbl || !key || isNaN(idx)) return false;\n        var realTbl = window.resolveConfigTableName ? window.resolveConfigTableName(tbl) : tbl;\n        if (!window.currentDbData.Tabelle[realTbl]) window.currentDbData.Tabelle[realTbl] = [];\n        if (!window.currentDbData.Tabelle[realTbl][idx]) window.currentDbData.Tabelle[realTbl][idx] = {};\n        var val = valueOf(el);\n        if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val);\n        var oldVal = window.currentDbData.Tabelle[realTbl][idx][key];\n        var changed = String(oldVal == null ? '' : oldVal) !== String(val == null ? '' : val);\n        if (changed) {\n            window.currentDbData.Tabelle[realTbl][idx][key] = val;\n            if (!window.modifiedFields) window.modifiedFields = new Set();\n            window.modifiedFields.add(realTbl + '-' + idx + '-' + key);\n            try { el.style.borderColor = '#60a5fa'; } catch(e) {}\n            try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        }\n        last.set(el, String(val == null ? '' : val));\n        return changed;\n    }\n    function delayedApply(el){ setTimeout(function(){ apply(el); }, 0); setTimeout(function(){ apply(el); }, 80); setTimeout(function(){ apply(el); }, 300); }\n    ['input','change','blur','focusout','keyup','paste','cut','mouseup','pointerup','click'].forEach(function(ev){ document.addEventListener(ev, function(e){ if (isCfg(e.target)) delayedApply(e.target); }, true); });\n    document.addEventListener('focusin', function(e){\n        if (!isCfg(e.target)) return;\n        var el = e.target, n = 0;\n        last.set(el, String(valueOf(el) == null ? '' : valueOf(el)));\n        var timer = setInterval(function(){\n            n++;\n            if (!document.body.contains(el) || (document.activeElement !== el && n > 5) || n > 25) { clearInterval(timer); return; }\n            var v = String(valueOf(el) == null ? '' : valueOf(el));\n            if (last.get(el) !== v) apply(el);\n        }, 160);\n    }, true);\n    \/\/ 30.9.1630: il sync massivo non usa piu apply() del listener 666, perche apply() considerava\n    \/\/ anche click\/focus e poteva trasformare i placeholder visuali vuoti in modifiche reali.\n    window.tiSyncConfigAutofillSavedInfo666 = function(){\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n    };\n    try {\n        if (typeof window.saveConfig === 'function' && !window.saveConfig.__tiAutofill666) {\n            var prevSaveConfig666 = window.saveConfig;\n            window.saveConfig = function(){\n                try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n                try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n                return prevSaveConfig666.apply(this, arguments);\n            };\n            window.saveConfig.__tiAutofill666 = true;\n        }\n    } catch(e) {}\n})();\n<\/script>\n\n\n<script id=\"ti-config-no-saved-info-667\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigNoSavedInfo667Installed) return;\n    window.__tiConfigNoSavedInfo667Installed = true;\n    function safeId(v){ return String(v == null ? '' : v).toLowerCase().replace(\/[^a-z0-9]+\/g, '_').slice(0, 60); }\n    function isConfigEditField(el){\n        return !!(el && el.matches && el.matches('#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],.ti-conf-window .ti-cfg-table input[data-tbl][data-idx][data-key],.ti-conf-window .ti-cfg-table textarea[data-tbl][data-idx][data-key]'));\n    }\n    function hardDisableSavedInfo(el){\n        if (!isConfigEditField(el)) return;\n        try {\n            el.setAttribute('autocomplete', 'off');\n            el.setAttribute('autocorrect', 'off');\n            el.setAttribute('autocapitalize', 'off');\n            el.setAttribute('spellcheck', 'false');\n            el.setAttribute('aria-autocomplete', 'none');\n            el.setAttribute('data-ti-no-saved-info', '1');\n            el.removeAttribute('list');\n            if (el.tagName === 'INPUT') {\n                var typ = String(el.getAttribute('type') || 'text').toLowerCase();\n                if (typ === 'email' || typ === 'search' || typ === 'url' || typ === 'tel') el.setAttribute('type', 'text');\n            }\n            var tbl = el.getAttribute('data-tbl') || 'tbl';\n            var idx = el.getAttribute('data-idx') || '0';\n            var key = el.getAttribute('data-key') || 'field';\n            var wantedName = 'ti_cfg_no_saved_' + safeId(tbl) + '_' + safeId(idx) + '_' + safeId(key);\n            if (el.getAttribute('name') !== wantedName) el.setAttribute('name', wantedName);\n        } catch(e) {}\n    }\n    function apply(root){\n        var scope = root && root.querySelectorAll ? root : document;\n        try {\n            if (isConfigEditField(root)) hardDisableSavedInfo(root);\n            scope.querySelectorAll('#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],.ti-conf-window .ti-cfg-table input[data-tbl][data-idx][data-key],.ti-conf-window .ti-cfg-table textarea[data-tbl][data-idx][data-key]').forEach(hardDisableSavedInfo);\n        } catch(e) {}\n    }\n    window.tiDisableConfigSavedInfo667 = apply;\n    try {\n        if (typeof window.renderConfig === 'function' && !window.renderConfig.__tiNoSavedInfo667) {\n            var prevRender667 = window.renderConfig;\n            window.renderConfig = function(){\n                var ret = prevRender667.apply(this, arguments);\n                setTimeout(function(){ apply(document); }, 0);\n                setTimeout(function(){ apply(document); }, 120);\n                return ret;\n            };\n            window.renderConfig.__tiNoSavedInfo667 = true;\n        }\n    } catch(e) {}\n    ['focusin','mousedown','pointerdown','touchstart','input','change'].forEach(function(evt){\n        document.addEventListener(evt, function(ev){\n            var t = ev && ev.target;\n            if (isConfigEditField(t)) hardDisableSavedInfo(t);\n        }, true);\n    });\n    try {\n        var obs = new MutationObserver(function(muts){\n            for (var i=0; i<muts.length; i++) {\n                var added = muts[i] && muts[i].addedNodes ? muts[i].addedNodes : [];\n                for (var j=0; j<added.length; j++) {\n                    var node = added[j];\n                    if (node && node.nodeType === 1) apply(node);\n                }\n            }\n        });\n        var root667 = document.getElementById('ti-conf-ov') || document.body || document.documentElement;\n        obs.observe(root667, {childList:true, subtree:true});\n    } catch(e) {}\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ apply(document); }, {once:true});\n    setTimeout(function(){ apply(document); }, 0);\n    setTimeout(function(){ apply(document); }, 600);\n})();\n<\/script>\n\n\n\n<style id=\"ti-config-mobile-hscroll-674\">\n@media (hover:none), (pointer:coarse), (max-width:980px) {\n  #ti-conf-ov.ti-ov,\n  #ti-ai-outer #ti-conf-ov.ti-ov {\n    overflow:hidden !important;\n    align-items:stretch !important;\n    justify-content:center !important;\n    padding:0 !important;\n    touch-action:auto !important;\n  }\n  #ti-conf-ov .ti-conf-window,\n  #ti-ai-outer #ti-conf-ov .ti-conf-window {\n    position:fixed !important;\n    top:max(4px, env(safe-area-inset-top)) !important;\n    bottom:max(4px, env(safe-area-inset-bottom)) !important;\n    left:max(2px, env(safe-area-inset-left)) !important;\n    right:max(2px, env(safe-area-inset-right)) !important;\n    width:auto !important;\n    max-width:none !important;\n    height:auto !important;\n    max-height:none !important;\n    margin:0 !important;\n    border-radius:10px !important;\n    overflow:hidden !important;\n  }\n  #ti-conf-ov .ti-conf-header,\n  #ti-ai-outer #ti-conf-ov .ti-conf-header {\n    height:48px !important;\n    min-height:48px !important;\n    padding:0 42px 0 8px !important;\n  }\n  #ti-conf-ov .ti-conf-header h3,\n  #ti-ai-outer #ti-conf-ov .ti-conf-header h3 {\n    font-size:13px !important;\n    line-height:1.1 !important;\n    white-space:nowrap !important;\n    overflow:hidden !important;\n    text-overflow:ellipsis !important;\n  }\n  #ti-conf-ov .ti-conf-body,\n  #ti-ai-outer #ti-conf-ov .ti-conf-body {\n    top:48px !important;\n    bottom:50px !important;\n    left:0 !important;\n    right:0 !important;\n    padding:7px !important;\n    overflow-y:auto !important;\n    overflow-x:hidden !important;\n    -webkit-overflow-scrolling:touch !important;\n    touch-action:pan-y !important;\n    overscroll-behavior:contain !important;\n  }\n  #ti-conf-ov .ti-conf-footer,\n  #ti-ai-outer #ti-conf-ov .ti-conf-footer {\n    height:50px !important;\n    min-height:50px !important;\n    padding:7px 6px !important;\n    gap:4px !important;\n    overflow-x:auto !important;\n    overflow-y:hidden !important;\n    -webkit-overflow-scrolling:touch !important;\n    touch-action:pan-x !important;\n  }\n  #ti-conf-ov .ti-conf-footer .ti-btn,\n  #ti-ai-outer #ti-conf-ov .ti-conf-footer .ti-btn {\n    flex:0 0 auto !important;\n    min-height:32px !important;\n    height:32px !important;\n    padding:4px 7px !important;\n    font-size:10px !important;\n    line-height:1 !important;\n    white-space:nowrap !important;\n  }\n  #ti-conf-ov details.ti-cfg-details,\n  #ti-ai-outer #ti-conf-ov details.ti-cfg-details {\n    width:100% !important;\n    min-width:0 !important;\n    max-width:100% !important;\n    overflow:visible !important;\n    margin-bottom:7px !important;\n  }\n  #ti-conf-ov .ti-cfg-summary,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-summary {\n    padding:8px !important;\n    font-size:12px !important;\n    line-height:1.1 !important;\n  }\n  #ti-conf-ov .ti-cfg-top-scroll,\n  #ti-conf-ov .ti-cfg-bottom-scroll,\n  #ti-conf-ov .ti-sync-hscroll-top,\n  #ti-conf-ov .ti-sync-hscroll-bottom,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-top-scroll,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-bottom-scroll,\n  #ti-ai-outer #ti-conf-ov .ti-sync-hscroll-top,\n  #ti-ai-outer #ti-conf-ov .ti-sync-hscroll-bottom {\n    display:block !important;\n    width:100% !important;\n    max-width:100% !important;\n    height:13px !important;\n    overflow-x:auto !important;\n    overflow-y:hidden !important;\n    -webkit-overflow-scrolling:touch !important;\n    touch-action:pan-x !important;\n    background:#0f172a !important;\n    border-left:1px solid #374151 !important;\n    border-right:1px solid #374151 !important;\n  }\n  #ti-conf-ov .ti-cfg-table-container,\n  #ti-conf-ov .ti-sync-hscroll-wrap,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table-container,\n  #ti-ai-outer #ti-conf-ov .ti-sync-hscroll-wrap {\n    display:block !important;\n    width:100% !important;\n    max-width:100% !important;\n    min-width:0 !important;\n    max-height:calc((var(--ti-vh, 1vh) * 58)) !important;\n    overflow-x:scroll !important;\n    overflow-y:auto !important;\n    -webkit-overflow-scrolling:touch !important;\n    touch-action:pan-x pan-y !important;\n    overscroll-behavior:contain !important;\n    scrollbar-width:auto !important;\n    cursor:grab !important;\n  }\n  #ti-conf-ov .ti-cfg-table-container.ti-hdrag-674,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table-container.ti-hdrag-674 { cursor:grabbing !important; }\n  #ti-conf-ov .ti-cfg-table,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table {\n    width:max-content !important;\n    min-width:max(920px, 100%) !important;\n    table-layout:auto !important;\n    border-collapse:separate !important;\n    border-spacing:0 !important;\n  }\n  #ti-conf-ov .ti-cfg-table th,\n  #ti-conf-ov .ti-cfg-table td,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table th,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table td {\n    white-space:nowrap !important;\n    min-width:126px !important;\n    max-width:none !important;\n    padding:3px !important;\n    font-size:10.5px !important;\n    line-height:1.15 !important;\n    vertical-align:top !important;\n  }\n  #ti-conf-ov .ti-cfg-table th.ti-cfg-rownum,\n  #ti-conf-ov .ti-cfg-table td.ti-cfg-rownum,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table th.ti-cfg-rownum,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table td.ti-cfg-rownum {\n    left:0 !important;\n    width:34px !important;\n    min-width:34px !important;\n    max-width:34px !important;\n    padding:3px 2px !important;\n    z-index:36 !important;\n  }\n  #ti-conf-ov .ti-cfg-table th.ti-sticky-col,\n  #ti-conf-ov .ti-cfg-table td.ti-sticky-col,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table th.ti-sticky-col,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table td.ti-sticky-col {\n    left:34px !important;\n    min-width:136px !important;\n    width:136px !important;\n    max-width:136px !important;\n    z-index:35 !important;\n  }\n  #ti-conf-ov .ti-cfg-table th.ti-cfg-actions-col-1609,\n  #ti-conf-ov .ti-cfg-table td.ti-cfg-actions-col-1609,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table th.ti-cfg-actions-col-1609,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table td.ti-cfg-actions-col-1609 {\n    width:108px !important;\n    min-width:108px !important;\n    max-width:108px !important;\n    padding:2px !important;\n  }\n  #ti-conf-ov .ti-cfg-table .ti-config-action-mini-1609,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table .ti-config-action-mini-1609 {\n    width:22px !important;\n    min-width:22px !important;\n    max-width:22px !important;\n    height:22px !important;\n    min-height:22px !important;\n    padding:0 !important;\n    margin:0 !important;\n    font-size:10px !important;\n    line-height:1 !important;\n  }\n  #ti-conf-ov .ti-cfg-table .ti-in,\n  #ti-conf-ov .ti-cfg-table input:not([type=\"checkbox\"]):not([type=\"radio\"]),\n  #ti-conf-ov .ti-cfg-table textarea,\n  #ti-conf-ov .ti-cfg-table select,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table .ti-in,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table input:not([type=\"checkbox\"]):not([type=\"radio\"]),\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table textarea,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table select {\n    min-width:118px !important;\n    width:100% !important;\n    max-width:none !important;\n    min-height:26px !important;\n    padding:3px 4px !important;\n    font-size:12px !important;\n    line-height:1.15 !important;\n    touch-action:manipulation !important;\n  }\n  #ti-conf-ov .ti-cfg-table textarea,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table textarea {\n    min-width:190px !important;\n    min-height:46px !important;\n    white-space:pre-wrap !important;\n  }\n  #ti-conf-ov .ti-cfg-filter-wrap-526,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-filter-wrap-526 { min-width:118px !important; }\n  #ti-conf-ov .ti-cfg-filter,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-filter { min-width:78px !important; font-size:11px !important; }\n}\n@media (hover:none) and (orientation:landscape), (pointer:coarse) and (orientation:landscape), (max-width:980px) and (orientation:landscape) {\n  #ti-conf-ov .ti-conf-body,\n  #ti-ai-outer #ti-conf-ov .ti-conf-body { padding:5px !important; }\n  #ti-conf-ov .ti-cfg-table-container,\n  #ti-conf-ov .ti-sync-hscroll-wrap,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table-container,\n  #ti-ai-outer #ti-conf-ov .ti-sync-hscroll-wrap { max-height:calc((var(--ti-vh, 1vh) * 48)) !important; }\n  #ti-conf-ov .ti-cfg-table,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table { min-width:max(980px, 100%) !important; }\n  #ti-conf-ov .ti-cfg-table th,\n  #ti-conf-ov .ti-cfg-table td,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table th,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table td { font-size:9.5px !important; padding:2px !important; min-width:112px !important; }\n  #ti-conf-ov .ti-cfg-table .ti-in,\n  #ti-conf-ov .ti-cfg-table input:not([type=\"checkbox\"]):not([type=\"radio\"]),\n  #ti-conf-ov .ti-cfg-table textarea,\n  #ti-conf-ov .ti-cfg-table select,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table .ti-in,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table input:not([type=\"checkbox\"]):not([type=\"radio\"]),\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table textarea,\n  #ti-ai-outer #ti-conf-ov .ti-cfg-table select { font-size:10px !important; min-height:23px !important; padding:2px 3px !important; }\n}\n<\/style>\n\n<script id=\"ti-config-mobile-hscroll-674\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigMobileHScroll674Installed) return;\n    window.__tiConfigMobileHScroll674Installed = true;\n    function safe(fn){ try { return fn(); } catch(e) { return null; } }\n    function qsa(root, sel){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\n    function isTouchLike(){ return safe(function(){ return window.matchMedia && (window.matchMedia('(hover:none)').matches || window.matchMedia('(pointer:coarse)').matches || window.matchMedia('(max-width:980px)').matches); }) !== false; }\n    function syncBars(wrap){\n        if (!wrap) return;\n        var det = wrap.closest && wrap.closest('details.ti-cfg-details');\n        if (!det) return;\n        var left = wrap.scrollLeft || 0;\n        qsa(det, '.ti-sync-hscroll-top,.ti-sync-hscroll-bottom,.ti-cfg-top-scroll,.ti-cfg-bottom-scroll').forEach(function(bar){ if (bar !== wrap) bar.scrollLeft = left; });\n    }\n    function updateWidths(root){\n        var scope = root || document;\n        qsa(scope, '#ti-conf-ov .ti-cfg-table-container, #ti-conf-ov .ti-sync-hscroll-wrap').forEach(function(wrap){\n            var table = wrap.querySelector && wrap.querySelector('table');\n            if (!table) return;\n            var cols = table.querySelectorAll ? Math.max(table.querySelectorAll('thead th').length || 0, table.rows && table.rows[0] ? table.rows[0].cells.length : 0) : 0;\n            var minByCols = Math.max(920, cols * (window.innerHeight < window.innerWidth ? 112 : 126));\n            var wanted = Math.max(minByCols, wrap.clientWidth || 0, table.scrollWidth || 0);\n            table.style.setProperty('min-width', wanted + 'px', 'important');\n            table.style.setProperty('width', 'max-content', 'important');\n            wrap.style.setProperty('overflow-x', 'scroll', 'important');\n            wrap.style.setProperty('overflow-y', 'auto', 'important');\n            wrap.style.setProperty('-webkit-overflow-scrolling', 'touch', 'important');\n            wrap.style.setProperty('touch-action', 'pan-x pan-y', 'important');\n            var det = wrap.closest && wrap.closest('details.ti-cfg-details');\n            if (det) qsa(det, '.ti-sync-hscroll-inner,.ti-cfg-top-scroll-inner,.ti-cfg-bottom-scroll-inner').forEach(function(inner){ inner.style.width = wanted + 'px'; });\n        });\n    }\n    function attachDrag(wrap){\n        if (!wrap || wrap.__tiConfigHDrag674) return;\n        wrap.__tiConfigHDrag674 = true;\n        var sx=0, sy=0, sl=0, st=0, dragging=false, decided=false;\n        wrap.addEventListener('touchstart', function(ev){\n            if (!isTouchLike() || !ev.touches || ev.touches.length !== 1) return;\n            var t = ev.touches[0]; sx = t.clientX; sy = t.clientY; sl = wrap.scrollLeft || 0; st = wrap.scrollTop || 0; dragging = false; decided = false;\n        }, {passive:true});\n        wrap.addEventListener('touchmove', function(ev){\n            if (!isTouchLike() || !ev.touches || ev.touches.length !== 1) return;\n            var t = ev.touches[0], dx = t.clientX - sx, dy = t.clientY - sy;\n            if (!decided && (Math.abs(dx) > 7 || Math.abs(dy) > 7)) { decided = true; dragging = Math.abs(dx) > Math.abs(dy) + 2; }\n            if (!dragging) return;\n            if (ev.cancelable) ev.preventDefault();\n            wrap.scrollLeft = sl - dx;\n            wrap.scrollTop = st;\n            wrap.classList.add('ti-hdrag-674');\n            syncBars(wrap);\n        }, {passive:false});\n        function end(){ dragging=false; decided=false; wrap.classList.remove('ti-hdrag-674'); }\n        wrap.addEventListener('touchend', end, {passive:true});\n        wrap.addEventListener('touchcancel', end, {passive:true});\n        wrap.addEventListener('scroll', function(){ syncBars(wrap); }, {passive:true});\n    }\n    function refresh(root){\n        var ov = document.getElementById('ti-conf-ov');\n        if (!ov) return;\n        updateWidths(root || ov);\n        qsa(root || ov, '#ti-conf-ov .ti-cfg-table-container, #ti-conf-ov .ti-sync-hscroll-wrap').forEach(attachDrag);\n        safe(function(){ if (window.initConfigTopScrollbars) window.initConfigTopScrollbars(ov); });\n    }\n    window.tiFixConfigMobileHScroll674 = refresh;\n    safe(function(){\n        if (typeof window.renderConfig === 'function' && !window.renderConfig.__tiMobileHScroll674) {\n            var prev = window.renderConfig;\n            window.renderConfig = function(){\n                var ret = prev.apply(this, arguments);\n                setTimeout(function(){ refresh(document); }, 0);\n                setTimeout(function(){ refresh(document); }, 120);\n                setTimeout(function(){ refresh(document); }, 500);\n                return ret;\n            };\n            window.renderConfig.__tiMobileHScroll674 = true;\n        }\n    });\n    document.addEventListener('toggle', function(ev){ if (ev.target && ev.target.matches && ev.target.matches('#ti-conf-ov details.ti-cfg-details')) setTimeout(function(){ refresh(ev.target); }, 30); }, true);\n    window.addEventListener('resize', function(){ setTimeout(function(){ refresh(document); }, 80); }, {passive:true});\n    window.addEventListener('orientationchange', function(){ setTimeout(function(){ refresh(document); }, 180); setTimeout(function(){ refresh(document); }, 600); }, {passive:true});\n    if (typeof MutationObserver !== 'undefined') safe(function(){\n        new MutationObserver(function(){ setTimeout(function(){ refresh(document); }, 60); }).observe(document.getElementById('ti-ai-outer') || document.body || document.documentElement, {childList:true, subtree:true});\n    });\n    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function(){ refresh(document); }, {once:true}); else refresh(document);\n    setTimeout(function(){ refresh(document); }, 300);\n    setTimeout(function(){ refresh(document); }, 1200);\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-stable-675\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveStable675Installed) return;\n    window.__tiConfigSaveStable675Installed = true;\n    function el(id){ return document.getElementById(id); }\n    function now(){ return Date.now ? Date.now() : (new Date()).getTime(); }\n    function safe(fn, fb){ try { var v = fn(); return (typeof v === 'undefined') ? fb : v; } catch(e) { return fb; } }\n    function txt(v){ return String(v == null ? '' : v); }\n    function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\n    function encPayload(obj){\n        var json = JSON.stringify(obj || {});\n        if (typeof window.utoa === 'function') return window.utoa(json);\n        return btoa(unescape(encodeURIComponent(json)));\n    }\n    function saveButton(){ return el('lbl-conf-save'); }\n    function setButtonSaving(){\n        var b = saveButton();\n        if (!b) return;\n        b.disabled = true;\n        b.setAttribute('aria-busy', 'true');\n        b.setAttribute('data-ti-saving', '1');\n        b.style.pointerEvents = 'none';\n        b.innerText = 'Salvataggio...';\n        try {\n            b.style.setProperty('background', '#d97706', 'important');\n            b.style.setProperty('background-color', '#d97706', 'important');\n            b.style.setProperty('color', '#fff', 'important');\n            b.style.setProperty('cursor', 'wait', 'important');\n        } catch(e) {}\n    }\n    function resetButton(forceClean){\n        window.__saveConfigInFlight = false;\n        window.__tiSaveConfigStartedAt585 = 0;\n        window.__tiSaveConfigStartedAt = 0;\n        try { if (window.__tiSaveConfigHardTimer585) { clearTimeout(window.__tiSaveConfigHardTimer585); window.__tiSaveConfigHardTimer585 = null; } } catch(e) {}\n        var b = saveButton();\n        if (!b) return;\n        if (forceClean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') {\n            try { window.modifiedFields.clear(); } catch(e) {}\n        }\n        var dirty = !!(!forceClean && window.modifiedFields && window.modifiedFields.size > 0);\n        b.disabled = false;\n        b.removeAttribute('disabled');\n        b.removeAttribute('aria-busy');\n        b.removeAttribute('data-ti-saving');\n        b.style.pointerEvents = '';\n        b.classList.toggle('ti-save-dirty', dirty);\n        b.classList.toggle('ti-save-clean', !dirty);\n        b.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n        try {\n            b.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important');\n            b.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important');\n            b.style.setProperty('color', '#fff', 'important');\n            b.style.setProperty('cursor', 'pointer', 'important');\n        } catch(e) {}\n    }\n    function clearBusyUi(){\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n        try {\n            qsa('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(x){ if (x && x.parentNode) x.parentNode.removeChild(x); });\n        } catch(e) {}\n    }\n    function normalizeTablesToArrays(){\n        var data = window.currentDbData;\n        if (!data || !data.Tabelle) return;\n        Object.keys(data.Tabelle).forEach(function(t){ if (!Array.isArray(data.Tabelle[t])) data.Tabelle[t] = Object.values(data.Tabelle[t] || {}); });\n    }\n    function resolveTable(t){\n        return safe(function(){ return window.resolveConfigTableName ? (window.resolveConfigTableName(t) || t) : t; }, t) || t;\n    }\n    function readFieldValue(input){\n        if (!input) return '';\n        if (input.tagName === 'SELECT' && input.multiple) return Array.prototype.slice.call(input.selectedOptions || []).map(function(o){ return txt(o.value).trim(); }).filter(Boolean).join(', ');\n        if (input.type === 'checkbox') return input.checked ? (input.value || '1') : '';\n        return input.value == null ? '' : input.value;\n    }\n    function syncVisibleFields(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        var data = window.currentDbData;\n        if (!data || !data.Tabelle) return;\n        var sel = '#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        qsa(sel).forEach(function(input){\n            if (!input || input.disabled || input.readOnly) return;\n            var tbl = input.getAttribute('data-tbl') || '';\n            var key = input.getAttribute('data-key') || '';\n            var idx = parseInt(input.getAttribute('data-idx') || '', 10);\n            if (!tbl || !key || isNaN(idx)) return;\n            var rt = resolveTable(tbl);\n            if (!data.Tabelle[rt]) data.Tabelle[rt] = [];\n            if (!data.Tabelle[rt][idx] || typeof data.Tabelle[rt][idx] !== 'object') data.Tabelle[rt][idx] = {};\n            var val = readFieldValue(input);\n            if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val);\n            var old = data.Tabelle[rt][idx][key];\n            if (txt(old) !== txt(val)) {\n                data.Tabelle[rt][idx][key] = val;\n                if (!window.modifiedFields) window.modifiedFields = new Set();\n                window.modifiedFields.add(rt + '-' + idx + '-' + key);\n            }\n        });\n        try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n    }\n    function parseModifiedTables(){\n        var map = {};\n        var tables = Object.keys((window.currentDbData && window.currentDbData.Tabelle) ? window.currentDbData.Tabelle : {}).sort(function(a,b){ return String(b).length - String(a).length; });\n        try {\n            if (window.modifiedFields && typeof window.modifiedFields.forEach === 'function') {\n                window.modifiedFields.forEach(function(k){\n                    k = txt(k);\n                    for (var i=0; i<tables.length; i++) {\n                        var t = tables[i];\n                        if (k.indexOf(t + '-') === 0) { map[t] = true; return; }\n                    }\n                    var p = k.indexOf('-');\n                    if (p > 0) map[k.slice(0, p)] = true;\n                });\n            }\n        } catch(e) {}\n        try { (window.tiConfigDeletedRowsManifest || []).forEach(function(x){ if (x && x.table) map[resolveTable(x.table)] = true; }); } catch(e) {}\n        try { Object.keys(window.tiConfigDeletedTableSnapshots || {}).forEach(function(t){ if (t) map[resolveTable(t)] = true; }); } catch(e) {}\n        return map;\n    }\n    function addDeepChangedTables(map){\n        var cur = (window.currentDbData && window.currentDbData.Tabelle) ? window.currentDbData.Tabelle : {};\n        var old = (window.configOriginalDbData && window.configOriginalDbData.Tabelle) ? window.configOriginalDbData.Tabelle : {};\n        var all = {};\n        Object.keys(cur || {}).forEach(function(t){ all[t] = true; });\n        Object.keys(old || {}).forEach(function(t){ all[t] = true; });\n        Object.keys(all).forEach(function(t){\n            if (map[t]) return;\n            var a = JSON.stringify(cur[t] === undefined ? null : cur[t]);\n            var b = JSON.stringify(old[t] === undefined ? null : old[t]);\n            if (a !== b) map[t] = true;\n        });\n        return map;\n    }\n    function changedTables(){\n        var map = parseModifiedTables();\n        return Object.keys(addDeepChangedTables(map)).filter(function(t){ return !!t; });\n    }\n    function hasPendingDelete(){\n        try { if ((window.tiConfigDeletedRowsManifest || []).length) return true; } catch(e) {}\n        try { if (Object.keys(window.tiConfigDeletedTableSnapshots || {}).length) return true; } catch(e) {}\n        try { if (parseInt(window.tiConfigDeletedRowsCountTotal || 0, 10) > 0) return true; } catch(e) {}\n        return false;\n    }\n    function postForm(fd, timeoutMs){\n        timeoutMs = timeoutMs || 75000;\n        return new Promise(function(resolve, reject){\n            var ctrl = (typeof AbortController !== 'undefined') ? new AbortController() : null;\n            var done = false;\n            var timer = setTimeout(function(){\n                if (done) return;\n                done = true;\n                try { if (ctrl) ctrl.abort(); } catch(e) {}\n                reject(new Error('Timeout salvataggio configurazione. Verifica la connessione e riprova.'));\n            }, timeoutMs);\n            fetch(window.tiUrl, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', signal: ctrl ? ctrl.signal : undefined}).then(function(r){\n                return r.text().then(function(raw){\n                    if (!r.ok) throw new Error('Errore server ' + r.status + (raw ? ': ' + raw.slice(0, 220) : ''));\n                    try { return JSON.parse(raw); }\n                    catch(e) { throw new Error('Risposta salvataggio non JSON: ' + raw.slice(0, 220)); }\n                });\n            }).then(function(data){ if (done) return; done = true; clearTimeout(timer); resolve(data); }).catch(function(err){ if (done) return; done = true; clearTimeout(timer); reject(err); });\n        });\n    }\n    function updateAfterSuccess(res, changed){\n        var data = (res && res.data) ? res.data : {};\n        if (data.db && data.db.Tabelle) {\n            window.currentDbData = data.db;\n            window.currentDbViewData = null;\n        } else if (window.currentDbData && data.db_version) {\n            window.currentDbData.__db_version = data.db_version;\n        }\n        try { if (window.currentDbData) window.configOriginalDbData = JSON.parse(JSON.stringify(window.currentDbData)); } catch(e) {}\n        try { if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); } catch(e) {}\n        window.tiConfigDeletedRowsManifest = [];\n        window.tiConfigDeletedTableSnapshots = {};\n        window.tiConfigDeletedTableSnapshotBeforeCounts = {};\n        window.tiConfigDeletedRowsCountTotal = 0;\n        window.tiLastConfigDeleteCount = 0;\n        resetButton(true);\n        try { if (window.updateConfigSaveButtonState) window.updateConfigSaveButtonState(); } catch(e) {}\n        var warns = Array.isArray(data.value_warnings) ? data.value_warnings : [];\n        setTimeout(function(){\n            if (warns.length && window.showConfigValidationWarning) window.showConfigValidationWarning(warns, true);\n            else if (window.tiAlert) window.tiAlert('Salvataggio completato.');\n        }, 80);\n    }\n    function buildSaveForm(db, tables){\n        var fd = new FormData();\n        var data = window.currentDbData || {};\n        var payload = data;\n        if (tables && tables.length && data && data.Tabelle) {\n            payload = {Database: data.Database || db, __db_version: data.__db_version || '', Tabelle:{}};\n            tables.forEach(function(t){ if (data.Tabelle && data.Tabelle[t]) payload.Tabelle[t] = data.Tabelle[t]; });\n        }\n        fd.append('ti_action', 'ti_ai_save_full_db');\n        fd.append('db', db);\n        fd.append('payload', encPayload(payload));\n        fd.append('light_save', '1');\n        fd.append('response_light', '1');\n        fd.append('save_mode', 'light');\n        fd.append('compact_save', (tables && tables.length) ? '1' : '0');\n        fd.append('db_version', (data && data.__db_version) ? data.__db_version : '');\n        fd.append('changed_tables', encPayload(tables || []));\n        fd.append('deleted_rows', encPayload(window.tiConfigDeletedRowsManifest || []));\n        fd.append('deleted_table_snapshots', encPayload(window.tiConfigDeletedTableSnapshots || {}));\n        fd.append('deleted_rows_client_total', String(parseInt(window.tiConfigDeletedRowsCountTotal || 0, 10) || 0));\n        return fd;\n    }\n    function forceResetOnConfigOpen(){\n        var b = saveButton();\n        if (!b) return;\n        if (!window.__tiConfigSaveActive675 && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving') === '1')) {\n            resetButton(false);\n        }\n    }\n    var prevOpen = window.openModal;\n    if (typeof prevOpen === 'function' && !prevOpen.__tiSaveStable675) {\n        window.openModal = function(id){\n            var ret = prevOpen.apply(this, arguments);\n            if (id === 'ti-conf-ov') setTimeout(forceResetOnConfigOpen, 60);\n            return ret;\n        };\n        window.openModal.__tiSaveStable675 = true;\n    }\n    if (typeof window.renderConfig === 'function' && !window.renderConfig.__tiSaveStable675) {\n        var prevRender = window.renderConfig;\n        window.renderConfig = function(){\n            var ret = prevRender.apply(this, arguments);\n            setTimeout(forceResetOnConfigOpen, 80);\n            return ret;\n        };\n        window.renderConfig.__tiSaveStable675 = true;\n    }\n    window.tiForceUnlockConfigSave585 = window.tiForceUnlockConfigSave587 = window.tiForceUnlockConfigSave588 = function(reason){\n        window.__tiConfigSaveActive675 = false;\n        clearBusyUi();\n        resetButton(false);\n        if (reason && window.tiAlert) window.tiAlert(reason);\n    };\n    window.saveConfig = function(){\n        var start = now();\n        if (window.__tiConfigSaveActive675 || window.__saveConfigInFlight) {\n            var age = start - (parseInt(window.__tiSaveConfigStartedAt675 || window.__tiSaveConfigStartedAt585 || window.__tiSaveConfigStartedAt || 0, 10) || 0);\n            if (age < 8000) return;\n            window.__tiConfigSaveActive675 = false;\n            window.__saveConfigInFlight = false;\n        }\n        if (!window.currentDbData || !window.currentDbData.Tabelle) {\n            resetButton(false);\n            if (window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.');\n            return;\n        }\n        window.__tiConfigSaveActive675 = true;\n        window.__saveConfigInFlight = true;\n        window.__tiSaveConfigStartedAt675 = start;\n        window.__tiSaveConfigStartedAt585 = start;\n        window.__tiSaveConfigStartedAt = start;\n        setButtonSaving();\n        try {\n            syncVisibleFields();\n            normalizeTablesToArrays();\n            if (window.validateConfigUniqueUsernames && !window.validateConfigUniqueUsernames()) throw new Error('Salvataggio bloccato: username duplicato.');\n            var localIssues = window.collectConfigValidationIssues ? window.collectConfigValidationIssues() : [];\n            if (localIssues && localIssues.length && window.showConfigValidationWarning) window.showConfigValidationWarning(localIssues, true);\n            var dbEl = el('ti-ditta');\n            var db = dbEl ? dbEl.value : '';\n            if (!db || db === 'NEW_DB' || db === 'Global') throw new Error('Seleziona ditta.');\n            var tables = changedTables();\n            if (!tables.length && !hasPendingDelete()) {\n                try { if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); } catch(e) {}\n                window.__tiConfigSaveActive675 = false;\n                clearBusyUi();\n                resetButton(true);\n                if (window.tiAlert) window.tiAlert('Nessuna modifica da salvare.');\n                return;\n            }\n            var fd = buildSaveForm(db, tables);\n            postForm(fd, 75000).then(function(res){\n                if (!res || !res.success) throw new Error((res && res.data && res.data.message) ? res.data.message : 'Salvataggio configurazione non riuscito.');\n                updateAfterSuccess(res, tables);\n            }).catch(function(err){\n                var msg = (err && err.message) ? err.message : 'Errore durante il salvataggio configurazione.';\n                resetButton(false);\n                if (window.tiAlert) window.tiAlert(msg); else alert(msg);\n            }).finally(function(){\n                window.__tiConfigSaveActive675 = false;\n                window.__saveConfigInFlight = false;\n                window.__tiSaveConfigStartedAt675 = 0;\n                clearBusyUi();\n                var b = saveButton();\n                if (b && \/salvataggio\/i.test(txt(b.innerText))) resetButton(false);\n            });\n        } catch(e) {\n            window.__tiConfigSaveActive675 = false;\n            clearBusyUi();\n            resetButton(false);\n            if (window.tiAlert) window.tiAlert((e && e.message) ? e.message : 'Errore preparazione salvataggio configurazione.');\n        }\n    };\n    setInterval(function(){\n        try {\n            var b = saveButton();\n            if (!b) return;\n            var age = now() - (parseInt(window.__tiSaveConfigStartedAt675 || window.__tiSaveConfigStartedAt585 || window.__tiSaveConfigStartedAt || 0, 10) || 0);\n            if (!window.__tiConfigSaveActive675 && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving') === '1')) resetButton(false);\n            if (window.__tiConfigSaveActive675 && age > 90000) { window.__tiConfigSaveActive675 = false; clearBusyUi(); resetButton(false); }\n        } catch(e) {}\n    }, 900);\n    setTimeout(forceResetOnConfigOpen, 300);\n})();\n<\/script>\n\n\n<script id=\"ti-file-manager-meta-save-676\">\n(function(){\n    \"use strict\";\n    if (window.__tiFileManagerMetaSave676Installed) return;\n    window.__tiFileManagerMetaSave676Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function trim(v){ return txt(v).trim(); }\n    function decodeEntities(v){\n        var s = txt(v).replace(\/&amp;\/g, '&').replace(\/&#038;\/g, '&');\n        try { var ta = document.createElement('textarea'); ta.innerHTML = s; s = ta.value; } catch(e) {}\n        return s;\n    }\n    function basenameFromRef(ref){\n        var s = decodeEntities(ref).replace(\/\\\\\/g, '\/').trim();\n        try {\n            if (\/ti_action=ti_ai_get_image\/i.test(s)) {\n                var u = new URL(s, \/^https?:\\\/\\\/\/i.test(s) ? undefined : window.location.origin);\n                var f = u.searchParams.get('file') || '';\n                if (f) return decodeURIComponent(f).split(\/[\\\\\/]\/).pop();\n            }\n        } catch(e) {}\n        s = s.split(\/[?#]\/)[0].replace(\/\\\/+$\/, '');\n        return (s.split(\/[\\\\\/]\/).pop() || '').trim();\n    }\n    function normFile(v){ return basenameFromRef(v).toLowerCase(); }\n    function refsFrom(v){\n        if (window.tiTokenizeFileRefs666) return window.tiTokenizeFileRefs666(v);\n        return txt(v).split(\/[,;\\r\\n]+\/).map(function(x){ return x.trim(); }).filter(Boolean);\n    }\n    function removeRefFromValue(raw, file){\n        var targetWhole = trim(decodeEntities(file)).toLowerCase();\n        var targetBase = normFile(file);\n        return refsFrom(raw).filter(function(one){\n            var oneWhole = trim(decodeEntities(one)).toLowerCase();\n            var oneBase = normFile(one);\n            if (targetWhole && oneWhole === targetWhole) return false;\n            if (targetBase && oneBase && oneBase === targetBase) return false;\n            return true;\n        }).join(', ');\n    }\n    window.tiApplyPendingLinkedFileRemovals676 = function(){\n        var list = Array.isArray(window.pendingLinkedFileRemovals) ? window.pendingLinkedFileRemovals : [];\n        if (!list.length || !window.currentDbData || !window.currentDbData.Tabelle) return 0;\n        var changed = 0;\n        list.forEach(function(item){\n            if (!item) return;\n            var tbl = trim(item.tbl), key = trim(item.key), file = trim(item.file), idx = parseInt(item.idx, 10);\n            if (!tbl || !key || !file || isNaN(idx)) return;\n            var realTbl = (window.resolveConfigTableName ? (window.resolveConfigTableName(tbl) || tbl) : tbl);\n            if (!window.currentDbData.Tabelle[realTbl] || !window.currentDbData.Tabelle[realTbl][idx]) return;\n            var row = window.currentDbData.Tabelle[realTbl][idx];\n            var realKey = Object.prototype.hasOwnProperty.call(row, key) ? key : Object.keys(row).find(function(k){ return String(k).toLowerCase() === String(key).toLowerCase(); }) || key;\n            var oldVal = txt(row[realKey]);\n            var newVal = removeRefFromValue(oldVal, file);\n            if (oldVal !== newVal) {\n                row[realKey] = newVal;\n                changed++;\n            } else {\n                row[realKey] = newVal;\n            }\n            try { window.currentDbViewData = null; } catch(e) {}\n            if (!window.modifiedFields) window.modifiedFields = new Set();\n            try { window.modifiedFields.add(realTbl + '-' + idx + '-' + realKey); } catch(e) {}\n            try { if (window.syncConfigTableAfterRowMutation) window.syncConfigTableAfterRowMutation(realTbl); } catch(e) {}\n            try {\n                var cssEsc = window.CSS && CSS.escape ? CSS.escape : function(v){ return String(v).replace(\/([\\\\\"'\\[\\]#.:>+~*^$|=!])\/g, '\\\\$1'); };\n                document.querySelectorAll('#ti-conf-ov [data-tbl=\"' + cssEsc(realTbl) + '\"][data-idx=\"' + cssEsc(idx) + '\"][data-key=\"' + cssEsc(realKey) + '\"]').forEach(function(inp){ if (inp) inp.value = newVal; });\n            } catch(e) {}\n        });\n        if (changed && window.updateConfigSaveButtonState) { try { window.updateConfigSaveButtonState(); } catch(e) {} }\n        return changed;\n    };\n    if (typeof window.saveConfig === 'function' && !window.saveConfig.__tiPendingLinkedFileRemovals676) {\n        var prevSave676 = window.saveConfig;\n        window.saveConfig = function(){\n            try { window.tiApplyPendingLinkedFileRemovals676(); } catch(e) {}\n            return prevSave676.apply(this, arguments);\n        };\n        window.saveConfig.__tiPendingLinkedFileRemovals676 = true;\n    }\n    window.tiRefreshFileManagerMeta666 = function(){\n        var nodes = Array.prototype.slice.call(document.querySelectorAll('#fm-grid [data-ti-file-size-url]'));\n        nodes.forEach(function(el){\n            if (!el || el.getAttribute('data-ti-size-loading') === '1') return;\n            var url = el.getAttribute('data-ti-file-size-url') || '';\n            var ref = el.getAttribute('data-ti-file-ref') || url || '';\n            var db = el.getAttribute('data-ti-file-db') || ((byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : '');\n            var tbl = el.getAttribute('data-ti-file-tbl') || ((window.targetUploadContext && window.targetUploadContext.tbl) ? window.targetUploadContext.tbl : '');\n            var record = el.getAttribute('data-ti-file-record') || '';\n            if (!url && !ref) { el.textContent = 'n\/d'; return; }\n            el.setAttribute('data-ti-size-loading', '1');\n            el.textContent = 'calcolo...';\n            var fd = new FormData();\n            fd.append('ti_action', 'ti_ai_file_meta_676');\n            fd.append('action', 'ti_ai_file_meta_676');\n            fd.append('db', db || '');\n            fd.append('tbl', tbl || '');\n            fd.append('record', record || '');\n            fd.append('ref', ref || '');\n            fd.append('url', url || '');\n            var ajaxUrl = window.tiUrl || window.tiAjaxUrl || window.location.href;\n            fetch(ajaxUrl, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store'}).then(function(r){ return r.text(); }).then(function(raw){\n                var d = null;\n                try { d = JSON.parse(raw); } catch(e) { throw new Error('meta non JSON'); }\n                if (!d || !d.success) throw new Error((d && d.data && d.data.message) || 'meta non disponibile');\n                var meta = d.data || {};\n                el.textContent = meta.size_label || (meta.size ? (window.tiFormatBytes666 ? window.tiFormatBytes666(meta.size) : String(meta.size) + ' B') : 'n\/d');\n                var item = el.closest ? el.closest('.ti-file-item') : null;\n                if (item && meta.ext) {\n                    var extBox = item.querySelector('.ti-file-meta-666 b');\n                    var all = item.querySelectorAll('.ti-file-meta-666');\n                    if (all && all[0]) all[0].innerHTML = '<b>Tipo:<\/b> ' + String(meta.ext || 'n\/d');\n                }\n            }).catch(function(){\n                if (!url) { el.textContent = 'n\/d'; return; }\n                fetch(url, {method:'GET', credentials:'same-origin', cache:'no-store'}).then(function(r){\n                    var len = r.headers ? r.headers.get('Content-Length') : '';\n                    var fmt = window.tiFormatBytes666 ? window.tiFormatBytes666(len || 0) : '';\n                    el.textContent = fmt || 'n\/d';\n                }).catch(function(){ el.textContent = 'n\/d'; });\n            }).finally(function(){ el.removeAttribute('data-ti-size-loading'); });\n        });\n    };\n    var prevOpenFileManager676 = window.openFileManager;\n    if (typeof prevOpenFileManager676 === 'function' && !prevOpenFileManager676.__tiMetaRefresh676) {\n        window.openFileManager = function(){\n            var ret = prevOpenFileManager676.apply(this, arguments);\n            setTimeout(function(){ try { window.tiRefreshFileManagerMeta666(); } catch(e) {} }, 40);\n            setTimeout(function(){ try { window.tiRefreshFileManagerMeta666(); } catch(e) {} }, 500);\n            return ret;\n        };\n        window.openFileManager.__tiMetaRefresh676 = true;\n    }\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-verified-677\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveVerified677Installed) return;\n    window.__tiConfigSaveVerified677Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function now(){ return Date.now ? Date.now() : (new Date()).getTime(); }\n    function enc(obj){\n        var json = JSON.stringify(obj || {});\n        if (typeof window.utoa === 'function') return window.utoa(json);\n        return btoa(unescape(encodeURIComponent(json)));\n    }\n    function saveButton(){ return byId('lbl-conf-save'); }\n    function setBtnSaving(){\n        var b = saveButton();\n        if (!b) return;\n        b.disabled = true;\n        b.setAttribute('aria-busy', 'true');\n        b.setAttribute('data-ti-saving', '1');\n        b.style.pointerEvents = 'none';\n        b.innerText = 'Salvataggio...';\n        try {\n            b.style.setProperty('background', '#d97706', 'important');\n            b.style.setProperty('background-color', '#d97706', 'important');\n            b.style.setProperty('color', '#fff', 'important');\n            b.style.setProperty('cursor', 'wait', 'important');\n        } catch(e) {}\n    }\n    function resetBtn(clean){\n        window.__tiConfigSaveActive675 = false;\n        window.__tiConfigSaveActive677 = false;\n        window.__saveConfigInFlight = false;\n        window.__tiSaveConfigStartedAt675 = 0;\n        window.__tiSaveConfigStartedAt585 = 0;\n        window.__tiSaveConfigStartedAt = 0;\n        try { if (window.__tiSaveConfigHardTimer585) { clearTimeout(window.__tiSaveConfigHardTimer585); window.__tiSaveConfigHardTimer585 = null; } } catch(e) {}\n        var b = saveButton();\n        if (!b) return;\n        if (clean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') {\n            try { window.modifiedFields.clear(); } catch(e) {}\n        }\n        b.disabled = false;\n        try { b.removeAttribute('disabled'); b.removeAttribute('aria-busy'); b.removeAttribute('data-ti-saving'); } catch(e) {}\n        b.style.pointerEvents = '';\n        b.classList.remove('ti-save-dirty');\n        b.classList.add('ti-save-clean');\n        b.innerText = 'Salva Modifiche';\n        try {\n            b.style.setProperty('background', '#374151', 'important');\n            b.style.setProperty('background-color', '#374151', 'important');\n            b.style.setProperty('color', '#fff', 'important');\n            b.style.setProperty('cursor', 'pointer', 'important');\n        } catch(e) {}\n    }\n    function clearBusy(){\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n        try {\n            document.querySelectorAll('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(x){ if (x && x.parentNode) x.parentNode.removeChild(x); });\n        } catch(e) {}\n    }\n    function normalizeTables(){\n        var d = window.currentDbData;\n        if (!d || !d.Tabelle) return;\n        Object.keys(d.Tabelle).forEach(function(t){\n            if (!Array.isArray(d.Tabelle[t])) d.Tabelle[t] = Object.values(d.Tabelle[t] || {});\n        });\n    }\n    function readInputValue(input){\n        if (!input) return '';\n        if (input.tagName === 'SELECT' && input.multiple) return Array.prototype.slice.call(input.selectedOptions || []).map(function(o){ return txt(o.value).trim(); }).filter(Boolean).join(', ');\n        if (input.type === 'checkbox') return input.checked ? (input.value || '1') : '';\n        return input.value == null ? '' : input.value;\n    }\n    function resolveTable(t){\n        try { return window.resolveConfigTableName ? (window.resolveConfigTableName(t) || t) : t; } catch(e) { return t; }\n    }\n    function syncVisibleFields(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        var data = window.currentDbData;\n        if (!data || !data.Tabelle) return;\n        var sel = '#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        Array.prototype.slice.call(document.querySelectorAll(sel)).forEach(function(input){\n            if (!input || input.disabled || input.readOnly) return;\n            var tbl = input.getAttribute('data-tbl') || '';\n            var key = input.getAttribute('data-key') || '';\n            var idx = parseInt(input.getAttribute('data-idx') || '', 10);\n            if (!tbl || !key || isNaN(idx)) return;\n            var rt = resolveTable(tbl);\n            if (!data.Tabelle[rt]) data.Tabelle[rt] = [];\n            if (!data.Tabelle[rt][idx] || typeof data.Tabelle[rt][idx] !== 'object') data.Tabelle[rt][idx] = {};\n            var val = readInputValue(input);\n            try { if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val); } catch(e) {}\n            var old = data.Tabelle[rt][idx][key];\n            if (txt(old) !== txt(val)) {\n                data.Tabelle[rt][idx][key] = val;\n                if (!window.modifiedFields) window.modifiedFields = new Set();\n                try { window.modifiedFields.add(rt + '-' + idx + '-' + key); } catch(e) {}\n            }\n        });\n        try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n    }\n    function changedTables(){\n        var map = {};\n        var cur = (window.currentDbData && window.currentDbData.Tabelle) ? window.currentDbData.Tabelle : {};\n        var old = (window.configOriginalDbData && window.configOriginalDbData.Tabelle) ? window.configOriginalDbData.Tabelle : {};\n        var tables = Object.keys(cur || {}).sort(function(a,b){ return String(b).length - String(a).length; });\n        try {\n            if (window.modifiedFields && typeof window.modifiedFields.forEach === 'function') {\n                window.modifiedFields.forEach(function(k){\n                    k = txt(k);\n                    for (var i=0;i<tables.length;i++) {\n                        var t=tables[i];\n                        if (k.indexOf(t + '-') === 0) { map[t]=true; return; }\n                    }\n                    var p=k.indexOf('-');\n                    if (p > 0) map[k.slice(0,p)] = true;\n                });\n            }\n        } catch(e) {}\n        try { (window.tiConfigDeletedRowsManifest || []).forEach(function(x){ if (x && x.table) map[resolveTable(x.table)] = true; }); } catch(e) {}\n        try { Object.keys(window.tiConfigDeletedTableSnapshots || {}).forEach(function(t){ if (t) map[resolveTable(t)] = true; }); } catch(e) {}\n        var all = {};\n        Object.keys(cur || {}).forEach(function(t){ all[t]=true; });\n        Object.keys(old || {}).forEach(function(t){ all[t]=true; });\n        Object.keys(all).forEach(function(t){\n            try { if (JSON.stringify(cur[t] === undefined ? null : cur[t]) !== JSON.stringify(old[t] === undefined ? null : old[t])) map[t]=true; } catch(e) { map[t]=true; }\n        });\n        return Object.keys(map).filter(Boolean);\n    }\n    function postJson(fd, timeoutMs){\n        timeoutMs = timeoutMs || 180000;\n        if (typeof window.ensureAjaxActionField === 'function') fd = window.ensureAjaxActionField(fd);\n        else { if (!fd.has('action') && fd.has('ti_action')) fd.append('action', fd.get('ti_action')); }\n        if (typeof window.tiAppendCurrentLanguageToFormData === 'function') window.tiAppendCurrentLanguageToFormData(fd);\n        var url = window.tiUrl || window.tiAjaxUrl || window.location.href;\n        if (typeof window.postFormDataJsonSafe === 'function') {\n            return Promise.race([\n                window.postFormDataJsonSafe(url, fd, {tiNoLongProcessSignal:true, cache:'no-store'}),\n                new Promise(function(_, reject){ setTimeout(function(){ reject(new Error('Timeout salvataggio configurazione. Riprova dopo aver verificato la connessione.')); }, timeoutMs); })\n            ]);\n        }\n        return new Promise(function(resolve, reject){\n            var ctrl = (typeof AbortController !== 'undefined') ? new AbortController() : null;\n            var done = false;\n            var timer = setTimeout(function(){ if (done) return; done = true; try { if (ctrl) ctrl.abort(); } catch(e) {} reject(new Error('Timeout salvataggio configurazione.')); }, timeoutMs);\n            fetch(url, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', signal: ctrl ? ctrl.signal : undefined}).then(function(r){\n                return r.text().then(function(raw){\n                    if (!r.ok) throw new Error('Errore server ' + r.status + (raw ? ': ' + raw.slice(0,220) : ''));\n                    try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta salvataggio non JSON: ' + raw.slice(0,220)); }\n                });\n            }).then(function(data){ if (done) return; done=true; clearTimeout(timer); resolve(data); }).catch(function(err){ if (done) return; done=true; clearTimeout(timer); reject(err); });\n        });\n    }\n    function buildFullSaveForm(db, tables){\n        var fd = new FormData();\n        var data = window.currentDbData || {};\n        fd.append('action', 'ti_ai_save_full_db');\n        fd.append('ti_action', 'ti_ai_save_full_db');\n        fd.append('db', db);\n        fd.append('payload', enc(data));\n        fd.append('db_version', (data && data.__db_version) ? data.__db_version : '');\n        fd.append('changed_tables', enc(tables || []));\n        fd.append('deleted_rows', enc(window.tiConfigDeletedRowsManifest || []));\n        fd.append('deleted_table_snapshots', enc(window.tiConfigDeletedTableSnapshots || {}));\n        fd.append('deleted_rows_client_total', String(parseInt(window.tiConfigDeletedRowsCountTotal || 0, 10) || 0));\n        fd.append('force_full_save', '1');\n        fd.append('verified_save_677', '1');\n        return fd;\n    }\n    function afterSuccess(res){\n        var data = (res && res.data) ? res.data : {};\n        if (data.db && data.db.Tabelle) {\n            window.currentDbData = data.db;\n            window.currentDbViewData = null;\n        } else if (window.currentDbData && data.db_version) {\n            window.currentDbData.__db_version = data.db_version;\n        }\n        try { if (window.currentDbData) window.configOriginalDbData = JSON.parse(JSON.stringify(window.currentDbData)); } catch(e) {}\n        try { if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); } catch(e) {}\n        window.pendingLinkedFileRemovals = [];\n        window.tiConfigDeletedRowsManifest = [];\n        window.tiConfigDeletedTableSnapshots = {};\n        window.tiConfigDeletedTableSnapshotBeforeCounts = {};\n        window.tiConfigDeletedRowsCountTotal = 0;\n        window.tiLastConfigDeleteCount = 0;\n        resetBtn(true);\n        setTimeout(function(){ resetBtn(true); }, 120);\n        var warns = Array.isArray(data.value_warnings) ? data.value_warnings : [];\n        setTimeout(function(){\n            if (warns.length && window.showConfigValidationWarning) window.showConfigValidationWarning(warns, true);\n            else if (window.tiAlert) window.tiAlert('\u2705 Salvataggio configurazione completato.');\n        }, 160);\n    }\n    window.tiForceUnlockConfigSave585 = window.tiForceUnlockConfigSave587 = window.tiForceUnlockConfigSave588 = window.tiForceUnlockConfigSave677 = function(reason){\n        clearBusy();\n        resetBtn(false);\n        if (reason && window.tiAlert) window.tiAlert(reason);\n    };\n    window.saveConfig = function(){\n        var start = now();\n        if (window.__tiConfigSaveActive677 || window.__saveConfigInFlight) {\n            var age = start - (parseInt(window.__tiSaveConfigStartedAt675 || window.__tiSaveConfigStartedAt585 || window.__tiSaveConfigStartedAt || 0, 10) || 0);\n            if (age < 10000) return;\n            clearBusy();\n            resetBtn(false);\n        }\n        if (!window.currentDbData || !window.currentDbData.Tabelle) {\n            resetBtn(false);\n            if (window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.');\n            return;\n        }\n        window.__tiConfigSaveActive677 = true;\n        window.__tiConfigSaveActive675 = false;\n        window.__saveConfigInFlight = true;\n        window.__tiSaveConfigStartedAt675 = start;\n        window.__tiSaveConfigStartedAt585 = start;\n        window.__tiSaveConfigStartedAt = start;\n        setBtnSaving();\n        try {\n            syncVisibleFields();\n            \/* Importante: le rimozioni file vengono riapplicate DOPO il sync dei campi visibili,\n               cos\u00ec un input ancora renderizzato non pu\u00f2 reinserire il vecchio riferimento. *\/\n            try { if (window.tiApplyPendingLinkedFileRemovals676) window.tiApplyPendingLinkedFileRemovals676(); } catch(e) {}\n            normalizeTables();\n            try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n            if (window.validateConfigUniqueUsernames && !window.validateConfigUniqueUsernames()) throw new Error('Salvataggio bloccato: username duplicato.');\n            var issues = window.collectConfigValidationIssues ? window.collectConfigValidationIssues() : [];\n            if (issues && issues.length && window.showConfigValidationWarning) window.showConfigValidationWarning(issues, true);\n            var dbEl = byId('ti-ditta');\n            var db = dbEl ? dbEl.value : '';\n            if (!db || db === 'NEW_DB' || db === 'Global') throw new Error('Seleziona ditta.');\n            var tables = changedTables();\n            var fd = buildFullSaveForm(db, tables);\n            postJson(fd, 180000).then(function(res){\n                if (!res || !res.success) throw new Error((res && res.data && res.data.message) ? res.data.message : 'Salvataggio configurazione non riuscito.');\n                afterSuccess(res);\n            }).catch(function(err){\n                var msg = (err && err.message) ? err.message : 'Errore durante il salvataggio configurazione.';\n                if (\/Accesso negato\/i.test(msg)) msg += ' Verifica di essere ancora autenticato nel login del plugin con ruolo autorizzato.';\n                if (\/Risposta salvataggio non JSON|Risposta server non valida|non JSON\/i.test(msg)) msg += ' Possibile pagina di cache\/manutenzione o sessione scaduta.';\n                resetBtn(false);\n                if (window.tiAlert) window.tiAlert(msg); else alert(msg);\n            }).finally(function(){\n                window.__tiConfigSaveActive677 = false;\n                window.__tiConfigSaveActive675 = false;\n                window.__saveConfigInFlight = false;\n                window.__tiSaveConfigStartedAt675 = 0;\n                window.__tiSaveConfigStartedAt585 = 0;\n                window.__tiSaveConfigStartedAt = 0;\n                clearBusy();\n                var b = saveButton();\n                if (b && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving') === '1')) resetBtn(false);\n            });\n        } catch(e) {\n            window.__tiConfigSaveActive677 = false;\n            window.__tiConfigSaveActive675 = false;\n            window.__saveConfigInFlight = false;\n            clearBusy();\n            resetBtn(false);\n            if (window.tiAlert) window.tiAlert((e && e.message) ? e.message : 'Errore preparazione salvataggio configurazione.');\n        }\n    };\n    setInterval(function(){\n        try {\n            var b = saveButton();\n            if (!b) return;\n            var age = now() - (parseInt(window.__tiSaveConfigStartedAt675 || window.__tiSaveConfigStartedAt585 || window.__tiSaveConfigStartedAt || 0, 10) || 0);\n            if (!window.__tiConfigSaveActive677 && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving') === '1')) resetBtn(false);\n            if (window.__tiConfigSaveActive677 && age > 190000) { clearBusy(); resetBtn(false); }\n        } catch(e) {}\n    }, 1000);\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-real-678\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveReal678Installed) return;\n    window.__tiConfigSaveReal678Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function clone(o){ try { return JSON.parse(JSON.stringify(o || {})); } catch(e) { return {}; } }\n    function enc(obj){ var json = JSON.stringify(obj || {}); if (typeof window.utoa === 'function') return window.utoa(json); return btoa(unescape(encodeURIComponent(json))); }\n    function saveButton(){ return byId('lbl-conf-save'); }\n    function clearBusy(){\n        try { window.__tiConfigSaveActive675 = false; window.__tiConfigSaveActive677 = false; window.__tiConfigSaveActive678 = false; window.__saveConfigInFlight = false; } catch(e) {}\n        try { window.__tiSaveConfigStartedAt675 = 0; window.__tiSaveConfigStartedAt585 = 0; window.__tiSaveConfigStartedAt = 0; } catch(e) {}\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n    }\n    function setButtonSaving(){\n        var b = saveButton(); if (!b) return;\n        b.disabled = true; b.setAttribute('aria-busy','true'); b.setAttribute('data-ti-saving','1'); b.style.pointerEvents='none'; b.innerText='Salvataggio...';\n        try { b.style.setProperty('background','#d97706','important'); b.style.setProperty('background-color','#d97706','important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','wait','important'); } catch(e) {}\n    }\n    function resetButton(clean){\n        clearBusy();\n        if (clean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') { try { window.modifiedFields.clear(); } catch(e) {} }\n        var b = saveButton(); if (!b) return;\n        var dirty = !!(!clean && window.modifiedFields && window.modifiedFields.size > 0);\n        b.disabled = false; try { b.removeAttribute('disabled'); b.removeAttribute('aria-busy'); b.removeAttribute('data-ti-saving'); } catch(e) {}\n        b.style.pointerEvents=''; b.classList.toggle('ti-save-dirty', dirty); b.classList.toggle('ti-save-clean', !dirty); b.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n        try { b.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','pointer','important'); } catch(e) {}\n    }\n    function readVal(el){\n        if (!el) return '';\n        if (el.tagName === 'SELECT' && el.multiple) return Array.prototype.slice.call(el.selectedOptions || []).map(function(o){ return txt(o.value).trim(); }).filter(Boolean).join(', ');\n        if (el.type === 'checkbox') return el.checked ? (el.value || '1') : '';\n        return el.value == null ? '' : el.value;\n    }\n    function resolveTable(t){ try { return window.resolveConfigTableName ? (window.resolveConfigTableName(t) || t) : t; } catch(e) { return t; } }\n    function ensureArrays(){\n        var d = window.currentDbData; if (!d || !d.Tabelle) return;\n        Object.keys(d.Tabelle).forEach(function(t){ if (!Array.isArray(d.Tabelle[t])) d.Tabelle[t] = Object.values(d.Tabelle[t] || {}); });\n    }\n    function syncVisible(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        ensureArrays();\n        var d = window.currentDbData; if (!d || !d.Tabelle) return;\n        var sel = '#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        Array.prototype.slice.call(document.querySelectorAll(sel)).forEach(function(input){\n            if (!input || input.disabled || input.readOnly) return;\n            var tbl = input.getAttribute('data-tbl') || '', key = input.getAttribute('data-key') || '', idx = parseInt(input.getAttribute('data-idx') || '', 10);\n            if (!tbl || !key || isNaN(idx)) return;\n            var rt = resolveTable(tbl); if (!d.Tabelle[rt]) d.Tabelle[rt] = []; if (!d.Tabelle[rt][idx] || typeof d.Tabelle[rt][idx] !== 'object') d.Tabelle[rt][idx] = {};\n            var val = readVal(input); try { if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val); } catch(e) {}\n            if (txt(d.Tabelle[rt][idx][key]) !== txt(val)) { d.Tabelle[rt][idx][key] = val; if (!window.modifiedFields) window.modifiedFields = new Set(); try { window.modifiedFields.add(rt + '-' + idx + '-' + key); } catch(e) {} }\n        });\n        try { if (window.tiApplyPendingLinkedFileRemovals676) window.tiApplyPendingLinkedFileRemovals676(); } catch(e) {}\n        try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n    }\n    function changedTablesFromFields(changes){\n        var m={};\n        (changes||[]).forEach(function(c){ if(c && c.table) m[c.table]=true; });\n        \/\/ 30.9.1907: aggiunta\/eliminazione riga puo' avere changes=[] perche' la riga non esiste nello\n        \/\/ snapshot originale. Rileva quindi anche le differenze strutturali fra current e original e usa\n        \/\/ la tabella interessata nel compact full-save, senza ricadere sull'intero database.\n        try {\n            var cur=(window.currentDbData&&window.currentDbData.Tabelle)?window.currentDbData.Tabelle:{};\n            var old=(window.configOriginalDbData&&window.configOriginalDbData.Tabelle)?window.configOriginalDbData.Tabelle:{};\n            var all={}; Object.keys(cur||{}).forEach(function(t){all[t]=1;}); Object.keys(old||{}).forEach(function(t){all[t]=1;});\n            Object.keys(all).forEach(function(t){\n                var a=Array.isArray(cur[t])?cur[t]:Object.values(cur[t]||{});\n                var b=Array.isArray(old[t])?old[t]:Object.values(old[t]||{});\n                if(a.length!==b.length) m[t]=true;\n            });\n        } catch(e) {}\n        try {\n            var st=window.tiConfigStructuralChangedTables1907;\n            if(st && typeof st.forEach==='function') st.forEach(function(t){ if(t) m[String(t)]=true; });\n        } catch(e) {}\n        return Object.keys(m);\n    }\n    function parseModifiedField(raw, tables){\n        raw = txt(raw); if (!raw) return null;\n        for (var i=0;i<tables.length;i++) { var t=tables[i], pfx=String(t)+'-'; if (raw.indexOf(pfx) === 0) { var rest=raw.slice(pfx.length), p=rest.indexOf('-'); if (p<=0) return null; var idx=parseInt(rest.slice(0,p),10); if (isNaN(idx)) return null; return {table:t,row:idx,key:rest.slice(p+1)}; } }\n        return null;\n    }\n    function buildFieldChanges(){\n        ensureArrays();\n        var cur = (window.currentDbData && window.currentDbData.Tabelle) ? window.currentDbData.Tabelle : {};\n        var old = (window.configOriginalDbData && window.configOriginalDbData.Tabelle) ? window.configOriginalDbData.Tabelle : {};\n        var tables = Object.keys(cur || {}).sort(function(a,b){ return String(b).length - String(a).length; });\n        var changes=[], seen={}, fullNeeded=false;\n        function add(table,row,key,value){\n            if (!table || row < 0 || !key || String(key).indexOf('__') === 0) { fullNeeded=true; return; }\n            var sig = table + '\\u0001' + row + '\\u0001' + key;\n            if (seen[sig]) return; seen[sig]=true;\n            if (value && typeof value === 'object') { fullNeeded=true; return; }\n            changes.push({table:table,row:row,key:key,value:(value == null ? '' : value)});\n        }\n        try {\n            if (window.modifiedFields && typeof window.modifiedFields.forEach === 'function') {\n                window.modifiedFields.forEach(function(raw){ var p=parseModifiedField(raw,tables); if (!p) { fullNeeded=true; return; } var r=(cur[p.table]||[])[p.row]; if (!r || typeof r !== 'object') { fullNeeded=true; return; } add(p.table,p.row,p.key,r[p.key]); });\n            }\n        } catch(e) { fullNeeded=true; }\n        try {\n            var all={}; Object.keys(cur||{}).forEach(function(t){all[t]=true;}); Object.keys(old||{}).forEach(function(t){all[t]=true;});\n            Object.keys(all).forEach(function(t){\n                var cr=Array.isArray(cur[t])?cur[t]:Object.values(cur[t]||{}), or=Array.isArray(old[t])?old[t]:Object.values(old[t]||{});\n                if (cr.length !== or.length) { fullNeeded=true; return; }\n                for (var i=0;i<cr.length;i++) {\n                    var a=cr[i]||{}, b=or[i]||{}; if (!a || typeof a !== 'object' || !b || typeof b !== 'object') { fullNeeded=true; return; }\n                    var keys={}; Object.keys(a).forEach(function(k){keys[k]=true;}); Object.keys(b).forEach(function(k){keys[k]=true;});\n                    Object.keys(keys).forEach(function(k){ if (JSON.stringify(a[k] == null ? '' : a[k]) !== JSON.stringify(b[k] == null ? '' : b[k])) add(t,i,k,a[k]); });\n                }\n            });\n        } catch(e) { fullNeeded=true; }\n        try { if ((window.tiConfigDeletedRowsManifest||[]).length || Object.keys(window.tiConfigDeletedTableSnapshots||{}).length || parseInt(window.tiConfigDeletedRowsCountTotal||0,10)>0) fullNeeded=true; } catch(e) {}\n        if (changes.length > 1000) fullNeeded=true;\n        return {changes:changes, fullNeeded:fullNeeded};\n    }\n    function postJson(fd, timeoutMs){\n        timeoutMs = timeoutMs || 120000;\n        try { if (!fd.has('action') && fd.has('ti_action')) fd.append('action', fd.get('ti_action')); } catch(e) {}\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        var url = window.tiUrl || window.location.href;\n        return new Promise(function(resolve,reject){\n            var ctrl = (typeof AbortController !== 'undefined') ? new AbortController() : null, done=false;\n            var startedAt1432 = Date.now ? Date.now() : (new Date()).getTime();\n            \/\/ 30.9.1432: CORREZIONE CRITICA - confermato con un caso reale di perdita dati che questo timeout,\n            \/\/ basato su un singolo setTimeout, puo' non scattare mai in certi ambienti\/condizioni (assieme, in\n            \/\/ quel caso, anche alla rete di sicurezza separata checkSaveSafetyNet1366, anch'essa basata su\n            \/\/ timer) - lasciando la richiesta di salvataggio bloccata indefinitamente, senza mai segnalare ne'\n            \/\/ successo ne' fallimento, con l'utente ignaro che le proprie modifiche non sono state salvate. Ora\n            \/\/ quattro meccanismi indipendenti (setTimeout, controllo periodico via setInterval, controllo\n            \/\/ guidato da requestAnimationFrame, e cambio scheda\/focus) verificano il tempo trascorso e possono\n            \/\/ ciascuno attivare il timeout - basta che uno solo funzioni nell'ambiente dell'utente.\n            function doTimeout1432(source){\n                if (done) return;\n                done = true;\n                try { if (ctrl) ctrl.abort(); } catch(e) {}\n                reject(new Error('Timeout salvataggio configurazione (' + source + ').'));\n            }\n            var timer = setTimeout(function(){ doTimeout1432('setTimeout'); }, timeoutMs);\n            var intervalCheck1432 = setInterval(function(){\n                if (done) { clearInterval(intervalCheck1432); return; }\n                if ((Date.now ? Date.now() : (new Date()).getTime()) - startedAt1432 >= timeoutMs) doTimeout1432('controllo-periodico');\n            }, 2000);\n            function rafCheck1432(){\n                if (done) return;\n                if ((Date.now ? Date.now() : (new Date()).getTime()) - startedAt1432 >= timeoutMs) { doTimeout1432('requestAnimationFrame'); return; }\n                try { if (typeof requestAnimationFrame === 'function') requestAnimationFrame(rafCheck1432); else setTimeout(rafCheck1432, 200); } catch(e) { setTimeout(rafCheck1432, 200); }\n            }\n            try { rafCheck1432(); } catch(e) {}\n            var visCheck1432 = function(){ if (!done && !document.hidden && (Date.now ? Date.now() : (new Date()).getTime()) - startedAt1432 >= timeoutMs) doTimeout1432('visibilitychange-o-focus'); };\n            try { document.addEventListener('visibilitychange', visCheck1432); window.addEventListener('focus', visCheck1432); } catch(e) {}\n            fetch(url,{method:'POST',body:fd,credentials:'same-origin',cache:'no-store',signal:ctrl?ctrl.signal:undefined}).then(function(r){ return r.text().then(function(raw){ if(!r.ok) throw new Error('Errore server '+r.status+': '+(raw||'').slice(0,220)); try{return JSON.parse(raw);}catch(e){throw new Error('Risposta salvataggio non JSON: '+(raw||'').slice(0,220));} }); }).then(function(d){ if(done) return; done=true; clearTimeout(timer); clearInterval(intervalCheck1432); resolve(d); }).catch(function(e){ if(done) return; done=true; clearTimeout(timer); clearInterval(intervalCheck1432); reject(e); });\n        });\n    }\n    function postFieldSave(db, changes){ var fd=new FormData(); fd.append('ti_action','ti_ai_save_config_fields_678'); fd.append('action','ti_ai_save_config_fields_678'); fd.append('db',db); fd.append('changes',enc(changes)); fd.append('db_version',(window.currentDbData&&window.currentDbData.__db_version)||''); return postJson(fd,120000); }\n    function buildCompactPayload(tables){\n        var d=window.currentDbData||{}, payload={Database:d.Database||'', __db_version:d.__db_version||'', Tabelle:{}};\n        (tables&&tables.length?tables:Object.keys((d&&d.Tabelle)||{})).forEach(function(t){ if(d.Tabelle && d.Tabelle[t]) payload.Tabelle[t]=d.Tabelle[t]; });\n        return payload;\n    }\n    function postFullSave(db, changes){\n        var tables=changedTablesFromFields(changes);\n        var usedFallbackAllTables1443 = false;\n        \/\/ 30.9.1909: nuova\/eliminata riga Istruzioni viene salvata con un endpoint tabella-specifico.\n        \/\/ Evita che un singolo cambio strutturale dipenda dal full-save generale o da snapshot di altre tabelle.\n        if(tables.length===1 && String(tables[0]||'').toLowerCase().replace(\/[^a-z0-9]\/g,'')==='istruzioni') {\n            var realInstr=tables[0], d1909=window.currentDbData||{}, rows1909=(d1909.Tabelle&&Array.isArray(d1909.Tabelle[realInstr]))?d1909.Tabelle[realInstr]:[];\n            var fd1909=new FormData();\n            fd1909.append('ti_action','ti_ai_save_instructions_table_1909'); fd1909.append('action','ti_ai_save_instructions_table_1909'); fd1909.append('db',db); fd1909.append('table',realInstr); fd1909.append('rows',enc(rows1909)); fd1909.append('db_version',(d1909&&d1909.__db_version)||'');\n            try { window.__tiConfigSaveDiagLog687=window.__tiConfigSaveDiagLog687||[]; window.__tiConfigSaveDiagLog687.push({time:(Date.now?Date.now():(new Date()).getTime()),event:'INSTRUCTIONS_1909_salve_tabella_dedicata',detail:{table:realInstr,rows:rows1909.length},level:'info'}); } catch(e1909) {}\n            return postJson(fd1909,120000);\n        }\n        if(!tables.length) { tables=Object.keys((window.currentDbData&&window.currentDbData.Tabelle)||{}); usedFallbackAllTables1443 = true; }\n        var fd=new FormData();\n        fd.append('ti_action','ti_ai_save_full_db'); fd.append('action','ti_ai_save_full_db'); fd.append('db',db); fd.append('payload',enc(buildCompactPayload(tables))); fd.append('compact_save','1'); fd.append('light_save','1'); fd.append('response_light','1'); fd.append('save_mode','light'); fd.append('changed_tables',enc(tables)); fd.append('deleted_rows',enc(window.tiConfigDeletedRowsManifest||[])); fd.append('deleted_table_snapshots',enc(window.tiConfigDeletedTableSnapshots||{})); fd.append('deleted_rows_client_total',String(parseInt(window.tiConfigDeletedRowsCountTotal||0,10)||0)); fd.append('db_version',''); fd.append('stable_save_678','1');\n        \/\/ 30.9.1443: diagnostica diretta per postFullSave - confermato che nemmeno il primo checkpoint lato\n        \/\/ server viene mai raggiunto per questa richiesta, quindi bisogna verificare se il problema sia qui,\n        \/\/ PRIMA che la richiesta di rete venga anche solo tentata (dimensione payload eccessiva, tabelle\n        \/\/ incluse per errore, ecc.) - scrive nell'array diagnostico globale gia' esistente (687), accessibile\n        \/\/ da qualsiasi punto della pagina, dato che log692 non e' raggiungibile da questo blocco di script.\n        try {\n            var payloadVal1443 = fd.get('payload');\n            var payloadSizeKb1443 = payloadVal1443 ? Math.round((String(payloadVal1443).length \/ 1024) * 10) \/ 10 : 0;\n            window.__tiConfigSaveDiagLog687 = window.__tiConfigSaveDiagLog687 || [];\n            window.__tiConfigSaveDiagLog687.push({time: (Date.now?Date.now():(new Date()).getTime()), event: 'FULLSAVE_1443_payload_pronto', detail: {tables_incluse: tables, fallback_tutte_tabelle: usedFallbackAllTables1443, payload_kb: payloadSizeKb1443}, level:'info'});\n        } catch(eDiag1443) {}\n        return postJson(fd,180000);\n    }\n    \/\/ 30.9.1444: CORREZIONE DELLA CAUSA RADICE, confermata da un errore JavaScript reale mostrato all'utente\n    \/\/ (\"Uncaught ReferenceError: postFullSave is not defined\") - questa funzione vive in un blocco <script>\n    \/\/ separato e isolato rispetto a directSave692 (che la richiama), quindi non era mai raggiungibile da li'.\n    \/\/ Ogni tentativo di chiamarla falliva immediatamente con un errore sincrono, PRIMA che qualsiasi richiesta\n    \/\/ di rete venisse anche solo tentata - questo spiega perche' nessun log lato server, nemmeno il primissimo\n    \/\/ checkpoint, sia mai comparso per queste richieste. Esposta qui globalmente cosi' resta richiamabile da\n    \/\/ qualsiasi altro blocco di script sulla pagina.\n    window.tiPostFullSave1444 = postFullSave;\n    function success(res){\n        var data=(res&&res.data)?res.data:{};\n        if (window.currentDbData && data.db_version) window.currentDbData.__db_version=data.db_version;\n        try { if (window.currentDbData) window.configOriginalDbData=clone(window.currentDbData); } catch(e) {}\n        try { if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); } catch(e) {}\n        window.pendingLinkedFileRemovals=[]; window.tiConfigDeletedRowsManifest=[]; window.tiConfigDeletedTableSnapshots={}; window.tiConfigDeletedRowsCountTotal=0; try { if(window.tiConfigStructuralChangedTables1907 && typeof window.tiConfigStructuralChangedTables1907.clear==='function') window.tiConfigStructuralChangedTables1907.clear(); } catch(e1907) {}\n        resetButton(true);\n        var warns=Array.isArray(data.value_warnings)?data.value_warnings:[];\n        setTimeout(function(){ if (warns.length && window.showConfigValidationWarning) window.showConfigValidationWarning(warns,true); else if (window.tiAlert) window.tiAlert('\u2705 Salvataggio configurazione completato.'); }, 100);\n    }\n    window.saveConfig = function(){\n        var started=Date.now?Date.now():(new Date()).getTime();\n        if (window.__tiConfigSaveActive678 || window.__saveConfigInFlight) { clearBusy(); }\n        if (!window.currentDbData || !window.currentDbData.Tabelle) { resetButton(false); if (window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.'); return; }\n        var dbEl=byId('ti-ditta'), db=dbEl?dbEl.value:''; if(!db || db==='NEW_DB' || db==='Global'){ resetButton(false); if(window.tiAlert) window.tiAlert('Seleziona ditta.'); return; }\n        window.__tiConfigSaveActive678=true; window.__saveConfigInFlight=true; window.__tiSaveConfigStartedAt=started; window.__tiSaveConfigStartedAt675=started; window.__tiSaveConfigStartedAt585=started; setButtonSaving();\n        try { syncVisible(); } catch(e) { resetButton(false); if(window.tiAlert) window.tiAlert('Errore preparazione salvataggio: '+(e.message||e)); return; }\n        var built=buildFieldChanges();\n        if (!built.changes.length && !built.fullNeeded) { resetButton(true); if(window.tiAlert) window.tiAlert('Nessuna modifica da salvare.'); return; }\n        var p = postFullSave(db,built.changes);\n        p.then(function(res){ if(!res || !res.success) throw new Error((res&&res.data&&res.data.message)?res.data.message:'Salvataggio configurazione non riuscito.'); success(res); })\n         .catch(function(err){ var msg=(err&&err.message)?err.message:'Errore durante il salvataggio configurazione.'; resetButton(false); if(window.tiAlert) window.tiAlert(msg); else alert(msg); })\n         .finally(function(){ window.__tiConfigSaveActive678=false; window.__saveConfigInFlight=false; window.__tiSaveConfigStartedAt=0; window.__tiSaveConfigStartedAt675=0; window.__tiSaveConfigStartedAt585=0; clearBusy(); var b=saveButton(); if(b && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving')==='1')) resetButton(false); });\n    };\n    window.tiForceUnlockConfigSave678 = function(reason){ resetButton(false); if(reason && window.tiAlert) window.tiAlert(reason); };\n    \/\/ 30.9.1427: rimosso il controllo periodico \"orfano\" che verificava solo la bandiera __tiConfigSaveActive678\n    \/\/ - questa versione della logica di salvataggio (678) e' stata superata da versioni successive (l'attuale\n    \/\/ e' la 692, che ha gia' un proprio controllo equivalente), ma questo controllo continuava a girare ogni\n    \/\/ secondo per sempre, verificando una bandiera che la logica attuale non imposta mai a vero - durante un\n    \/\/ salvataggio realmente in corso (che imposta solo __tiConfigSaveActive692), questo controllo poteva\n    \/\/ resettare prematuramente il pulsante \"Salva\" mentre il salvataggio era ancora effettivamente attivo sul\n    \/\/ server, dando la falsa impressione di un salvataggio concluso o fallito.\n})();\n<\/script>\n\n\n<style id=\"ti-config-single-bottom-hscroll-681\">\n#ti-conf-ov .ti-cfg-bottom-scroll,\n#ti-conf-ov .ti-sync-hscroll-bottom,\n#ti-ai-outer #ti-conf-ov .ti-cfg-bottom-scroll,\n#ti-ai-outer #ti-conf-ov .ti-sync-hscroll-bottom {\n  display:none !important;\n  height:0 !important;\n  min-height:0 !important;\n  max-height:0 !important;\n  padding:0 !important;\n  margin:0 !important;\n  border:0 !important;\n  overflow:hidden !important;\n}\n#ti-conf-ov .ti-cfg-table-container,\n#ti-conf-ov .ti-sync-hscroll-wrap,\n#ti-ai-outer #ti-conf-ov .ti-cfg-table-container,\n#ti-ai-outer #ti-conf-ov .ti-sync-hscroll-wrap {\n  margin-bottom:0 !important;\n}\n<\/style>\n\n\n\n<script id=\"ti-config-save-real-682\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveReal682Installed) return;\n    window.__tiConfigSaveReal682Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function clone(o){ try { return JSON.parse(JSON.stringify(o || {})); } catch(e) { return {}; } }\n    function enc(obj){ var json = JSON.stringify(obj || {}); if (typeof window.utoa === 'function') return window.utoa(json); return btoa(unescape(encodeURIComponent(json))); }\n    function saveButton(){ return byId('lbl-conf-save'); }\n    function clearBusy(){\n        try { window.__tiConfigSaveActive675=false; window.__tiConfigSaveActive677=false; window.__tiConfigSaveActive678=false; window.__tiConfigSaveActive682=false; window.__saveConfigInFlight=false; } catch(e) {}\n        try { window.__tiSaveConfigStartedAt=0; window.__tiSaveConfigStartedAt585=0; window.__tiSaveConfigStartedAt675=0; } catch(e) {}\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n    }\n    function setSaving(){\n        var b=saveButton(); if(!b) return;\n        b.disabled=true; b.setAttribute('aria-busy','true'); b.setAttribute('data-ti-saving','1'); b.style.pointerEvents='none'; b.innerText='Salvataggio...';\n        try { b.style.setProperty('background','#d97706','important'); b.style.setProperty('background-color','#d97706','important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','wait','important'); } catch(e) {}\n    }\n    function resetButton(clean){\n        if (clean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') { try { window.modifiedFields.clear(); } catch(e) {} }\n        clearBusy();\n        var b=saveButton(); if(!b) return;\n        var dirty = !!(!clean && window.modifiedFields && window.modifiedFields.size>0);\n        b.disabled=false; try { b.removeAttribute('disabled'); b.removeAttribute('aria-busy'); b.removeAttribute('data-ti-saving'); } catch(e) {}\n        b.style.pointerEvents=''; b.classList.toggle('ti-save-dirty',dirty); b.classList.toggle('ti-save-clean',!dirty); b.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n        try { b.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','pointer','important'); } catch(e) {}\n    }\n    function readVal(el){\n        if(!el) return '';\n        if(el.tagName==='SELECT' && el.multiple) return Array.prototype.slice.call(el.selectedOptions||[]).map(function(o){return txt(o.value).trim();}).filter(Boolean).join(', ');\n        if(el.type==='checkbox') return el.checked ? (el.value || '1') : '';\n        return el.value == null ? '' : el.value;\n    }\n    function resolveTable(t){ try { return window.resolveConfigTableName ? (window.resolveConfigTableName(t)||t) : t; } catch(e) { return t; } }\n    function ensureArrays(){\n        var d=window.currentDbData; if(!d || !d.Tabelle) return;\n        Object.keys(d.Tabelle).forEach(function(t){ if(!Array.isArray(d.Tabelle[t])) d.Tabelle[t]=Object.values(d.Tabelle[t]||{}); });\n    }\n    function syncVisible(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        ensureArrays();\n        var d=window.currentDbData; if(!d || !d.Tabelle) return;\n        var sel='#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        Array.prototype.slice.call(document.querySelectorAll(sel)).forEach(function(input){\n            if(!input || input.disabled || input.readOnly) return;\n            var tbl=input.getAttribute('data-tbl')||'', key=input.getAttribute('data-key')||'', idx=parseInt(input.getAttribute('data-idx')||'',10);\n            if(!tbl || !key || isNaN(idx)) return;\n            var rt=resolveTable(tbl); if(!d.Tabelle[rt]) d.Tabelle[rt]=[]; if(!d.Tabelle[rt][idx] || typeof d.Tabelle[rt][idx] !== 'object') d.Tabelle[rt][idx]={};\n            var val=readVal(input); try { if(window.normalizeInputValueForKey) val=window.normalizeInputValueForKey(key,val); } catch(e) {}\n            if(txt(d.Tabelle[rt][idx][key]) !== txt(val)) { d.Tabelle[rt][idx][key]=val; if(!window.modifiedFields) window.modifiedFields=new Set(); try { window.modifiedFields.add(rt+'-'+idx+'-'+key); } catch(e) {} }\n        });\n        try { if (window.tiApplyPendingLinkedFileRemovals676) window.tiApplyPendingLinkedFileRemovals676(); } catch(e) {}\n        try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n    }\n    function modifiedTables(){\n        var d=(window.currentDbData&&window.currentDbData.Tabelle)?window.currentDbData.Tabelle:{};\n        var o=(window.configOriginalDbData&&window.configOriginalDbData.Tabelle)?window.configOriginalDbData.Tabelle:{};\n        var tables={}, names={};\n        Object.keys(d||{}).forEach(function(t){names[t]=true;}); Object.keys(o||{}).forEach(function(t){names[t]=true;});\n        Object.keys(names).forEach(function(t){ try { if (JSON.stringify(d[t]||[]) !== JSON.stringify(o[t]||[])) tables[t]=true; } catch(e) { tables[t]=true; } });\n        try {\n            if (window.modifiedFields && typeof window.modifiedFields.forEach === 'function') {\n                var all=Object.keys(d||{}).sort(function(a,b){return String(b).length-String(a).length;});\n                window.modifiedFields.forEach(function(raw){ raw=txt(raw); all.forEach(function(t){ if(raw.indexOf(t+'-')===0) tables[t]=true; }); });\n            }\n        } catch(e) {}\n        try { (window.tiConfigDeletedRowsManifest||[]).forEach(function(x){ if(x && x.table) tables[resolveTable(x.table)]=true; }); } catch(e) {}\n        try { Object.keys(window.tiConfigDeletedTableSnapshots||{}).forEach(function(t){ tables[resolveTable(t)]=true; }); } catch(e) {}\n        return Object.keys(tables);\n    }\n    function buildPayload(tables){\n        var d=window.currentDbData||{}, all=(d&&d.Tabelle)?d.Tabelle:{};\n        var list=(tables&&tables.length)?tables:Object.keys(all||{});\n        var payload={Database:d.Database||'', __db_version:d.__db_version||'', Tabelle:{}};\n        list.forEach(function(t){ if(all && Object.prototype.hasOwnProperty.call(all,t)) payload.Tabelle[t]=all[t]; });\n        return payload;\n    }\n    function postFull(db,tables){\n        var fd=new FormData();\n        fd.append('ti_action','ti_ai_save_full_db'); fd.append('action','ti_ai_save_full_db'); fd.append('db',db);\n        fd.append('payload',enc(buildPayload(tables))); fd.append('compact_save','1'); fd.append('light_save','1'); fd.append('response_light','1'); fd.append('save_mode','light');\n        fd.append('changed_tables',enc(tables||[])); fd.append('deleted_rows',enc(window.tiConfigDeletedRowsManifest||[])); fd.append('deleted_table_snapshots',enc(window.tiConfigDeletedTableSnapshots||{}));\n        fd.append('deleted_rows_client_total',String(parseInt(window.tiConfigDeletedRowsCountTotal||0,10)||0)); fd.append('db_version',''); fd.append('stable_save_682','1'); fd.append('verify_after_save_682','1');\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        var url=window.tiUrl || window.location.href.split('?')[0];\n        return new Promise(function(resolve,reject){\n            var done=false, ctrl=(typeof AbortController!=='undefined')?new AbortController():null;\n            var timer=setTimeout(function(){ if(done) return; done=true; try{ if(ctrl) ctrl.abort(); }catch(e){} reject(new Error('Timeout salvataggio configurazione. Riprova o ricarica la pagina.')); }, 180000);\n            fetch(url,{method:'POST',body:fd,credentials:'same-origin',cache:'no-store',signal:ctrl?ctrl.signal:undefined}).then(function(r){ return r.text().then(function(raw){ if(!r.ok) throw new Error('Errore server '+r.status+': '+(raw||'').slice(0,260)); var d=null; try{ d=JSON.parse(raw); }catch(e){ throw new Error('Risposta salvataggio non JSON: '+(raw||'').slice(0,260)); } return d; }); }).then(function(d){ if(done) return; done=true; clearTimeout(timer); resolve(d); }).catch(function(e){ if(done) return; done=true; clearTimeout(timer); reject(e); });\n        });\n    }\n    window.saveConfig = function(){\n        if (!window.currentDbData || !window.currentDbData.Tabelle) { resetButton(false); if(window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.'); return; }\n        var dbEl=byId('ti-ditta'), db=dbEl ? (dbEl.value||'') : ''; if(!db || db==='NEW_DB' || db==='Global') { resetButton(false); if(window.tiAlert) window.tiAlert('Seleziona ditta.'); return; }\n        try { window.__tiConfigSaveActive682=true; window.__saveConfigInFlight=true; window.__tiSaveConfigStartedAt=Date.now?Date.now():(new Date()).getTime(); setSaving(); syncVisible(); } catch(e) { resetButton(false); if(window.tiAlert) window.tiAlert('Errore preparazione salvataggio: '+(e.message||e)); return; }\n        var tables=modifiedTables();\n        var hasDeleted=false; try { hasDeleted = ((window.tiConfigDeletedRowsManifest||[]).length>0 || Object.keys(window.tiConfigDeletedTableSnapshots||{}).length>0 || parseInt(window.tiConfigDeletedRowsCountTotal||0,10)>0); } catch(e) {}\n        if (!tables.length && !hasDeleted) { resetButton(true); if(window.tiAlert) window.tiAlert('Nessuna modifica da salvare.'); return; }\n        postFull(db,tables).then(function(res){\n            if(!res || !res.success) throw new Error((res&&res.data&&res.data.message)?res.data.message:'Salvataggio configurazione non riuscito.');\n            var data=res.data||{}; if(window.currentDbData && data.db_version) window.currentDbData.__db_version=data.db_version;\n            try { window.configOriginalDbData=clone(window.currentDbData); } catch(e) {}\n            window.pendingLinkedFileRemovals=[]; window.tiConfigDeletedRowsManifest=[]; window.tiConfigDeletedTableSnapshots={}; window.tiConfigDeletedRowsCountTotal=0; try { if(window.tiConfigStructuralChangedTables1907 && typeof window.tiConfigStructuralChangedTables1907.clear==='function') window.tiConfigStructuralChangedTables1907.clear(); } catch(e1907) {}\n            resetButton(true);\n            var warns=Array.isArray(data.value_warnings)?data.value_warnings:[];\n            setTimeout(function(){ if(warns.length && window.showConfigValidationWarning) window.showConfigValidationWarning(warns,true); else if(window.tiAlert) window.tiAlert('\u2705 Salvataggio configurazione completato.'); },100);\n        }).catch(function(err){\n            resetButton(false);\n            if(window.tiAlert) window.tiAlert((err&&err.message)?err.message:'Errore durante il salvataggio configurazione.');\n        }).finally(function(){ clearBusy(); var b=saveButton(); if(b && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving')==='1')) resetButton(false); });\n    };\n    window.tiForceUnlockConfigSave682=function(reason){ resetButton(false); if(reason&&window.tiAlert) window.tiAlert(reason); };\n    \/\/ 30.9.1427: rimosso lo stesso controllo periodico orfano, versione 682 - stesse motivazioni della 678.\n})();\n<\/script>\n\n<script id=\"ti-file-manager-meta-682\">\n(function(){\n    \"use strict\";\n    if (window.__tiFileManagerMeta682Installed) return;\n    window.__tiFileManagerMeta682Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function fmt(bytes){\n        bytes = parseInt(bytes || 0, 10) || 0;\n        if (bytes < 0) bytes = 0;\n        if (window.tiFormatBytes666) { try { var f = window.tiFormatBytes666(bytes); if (f) return f; } catch(e) {} }\n        if (bytes < 1024) return bytes + ' B';\n        var units=['KB','MB','GB','TB'], v=bytes\/1024, i=0;\n        while(v>=1024 && i<units.length-1){ v\/=1024; i++; }\n        var dec = v>=10 ? 1 : 2;\n        return String(v.toFixed(dec)).replace('.', ',') + ' ' + units[i];\n    }\n    function postMeta(fd, timeoutMs){\n        timeoutMs = timeoutMs || 20000;\n        try { if (!fd.has('action')) fd.append('action','ti_ai_file_meta_676'); } catch(e) {}\n        var url = window.tiUrl || window.location.href.split('?')[0];\n        return new Promise(function(resolve,reject){\n            var done=false, ctrl=(typeof AbortController!=='undefined')?new AbortController():null;\n            var timer=setTimeout(function(){ if(done) return; done=true; try{ if(ctrl) ctrl.abort(); }catch(e){} reject(new Error('timeout meta')); }, timeoutMs);\n            fetch(url,{method:'POST',body:fd,credentials:'same-origin',cache:'no-store',signal:ctrl?ctrl.signal:undefined}).then(function(r){\n                return r.text().then(function(raw){\n                    var d=null; try { d=JSON.parse(raw); } catch(e) { throw new Error('meta non JSON'); }\n                    if(!d || !d.success) throw new Error((d&&d.data&&d.data.message)||'meta non disponibile');\n                    return d.data || {};\n                });\n            }).then(function(data){ if(done) return; done=true; clearTimeout(timer); resolve(data); }).catch(function(err){ if(done) return; done=true; clearTimeout(timer); reject(err); });\n        });\n    }\n    function fetchSizeFromUrl(url, timeoutMs){\n        timeoutMs = timeoutMs || 20000;\n        if (!url) return Promise.reject(new Error('url mancante'));\n        function one(method){\n            return new Promise(function(resolve,reject){\n                var done=false, ctrl=(typeof AbortController!=='undefined')?new AbortController():null;\n                var timer=setTimeout(function(){ if(done) return; done=true; try{ if(ctrl) ctrl.abort(); }catch(e){} reject(new Error('timeout url')); }, timeoutMs);\n                fetch(url,{method:method,credentials:'same-origin',cache:'no-store',signal:ctrl?ctrl.signal:undefined}).then(function(r){\n                    if(!r.ok) throw new Error('http '+r.status);\n                    var len = r.headers && r.headers.get ? (r.headers.get('Content-Length') || r.headers.get('content-length') || '') : '';\n                    if (len && parseInt(len,10)>0) return parseInt(len,10);\n                    if (method === 'HEAD') throw new Error('no length');\n                    return r.blob().then(function(b){ return b && b.size ? b.size : 0; });\n                }).then(function(size){ if(done) return; done=true; clearTimeout(timer); resolve(size); }).catch(function(err){ if(done) return; done=true; clearTimeout(timer); reject(err); });\n            });\n        }\n        return one('HEAD').catch(function(){ return one('GET'); });\n    }\n    window.tiRefreshFileManagerMeta666 = function(){\n        var nodes = Array.prototype.slice.call(document.querySelectorAll('#fm-grid [data-ti-file-size-url],#fm-grid [data-ti-file-ref]'));\n        nodes.forEach(function(el){\n            if (!el) return;\n            var started = parseInt(el.getAttribute('data-ti-size-started') || '0', 10) || 0;\n            var now = Date.now ? Date.now() : (new Date()).getTime();\n            if (el.getAttribute('data-ti-size-loading') === '1' && started && (now - started) < 22000) return;\n            var url = el.getAttribute('data-ti-file-size-url') || '';\n            var ref = el.getAttribute('data-ti-file-ref') || url || '';\n            var db = el.getAttribute('data-ti-file-db') || ((byId('ti-ditta') && byId('ti-ditta').value) ? byId('ti-ditta').value : '');\n            var tbl = el.getAttribute('data-ti-file-tbl') || ((window.targetUploadContext && window.targetUploadContext.tbl) ? window.targetUploadContext.tbl : '');\n            var record = el.getAttribute('data-ti-file-record') || '';\n            if (!url && !ref) { el.textContent = 'n\/d'; return; }\n            el.setAttribute('data-ti-size-loading','1');\n            el.setAttribute('data-ti-size-started', String(now));\n            el.textContent = 'calcolo...';\n            var fd = new FormData();\n            fd.append('ti_action','ti_ai_file_meta_676');\n            fd.append('action','ti_ai_file_meta_676');\n            fd.append('db', db || '');\n            fd.append('tbl', tbl || '');\n            fd.append('record', record || '');\n            fd.append('ref', ref || '');\n            fd.append('url', url || '');\n            postMeta(fd, 18000).then(function(meta){\n                var size = parseInt(meta.size || 0, 10) || 0;\n                var label = meta.size_label || (size > 0 ? fmt(size) : '');\n                if (!label || label === 'n\/d' || label === '0 B') {\n                    if (url) return fetchSizeFromUrl(url, 20000).then(function(sz){ return {meta:meta, label: sz>0 ? fmt(sz) : (label || 'n\/d')}; });\n                }\n                return {meta:meta, label:label || 'n\/d'};\n            }).catch(function(){\n                if (!url) return {meta:null, label:'n\/d'};\n                return fetchSizeFromUrl(url, 20000).then(function(sz){ return {meta:null, label: sz>0 ? fmt(sz) : 'n\/d'}; }).catch(function(){ return {meta:null, label:'n\/d'}; });\n            }).then(function(res){\n                el.textContent = (res && res.label) ? res.label : 'n\/d';\n                var meta = res && res.meta ? res.meta : null;\n                var item = el.closest ? el.closest('.ti-file-item') : null;\n                if (item && meta && meta.ext) {\n                    var all = item.querySelectorAll('.ti-file-meta-666');\n                    if (all && all[0]) all[0].innerHTML = '<b>Tipo:<\/b> ' + String(meta.ext || 'n\/d');\n                }\n            }).finally(function(){\n                el.removeAttribute('data-ti-size-loading');\n                el.removeAttribute('data-ti-size-started');\n                if (\/calcolo\/i.test(txt(el.textContent))) el.textContent = 'n\/d';\n            });\n        });\n    };\n    if (typeof window.openFileManager === 'function' && !window.openFileManager.__tiMeta682) {\n        var prev = window.openFileManager;\n        window.openFileManager = function(){\n            var ret = prev.apply(this, arguments);\n            [50,600,1600].forEach(function(ms){ setTimeout(function(){ try { window.tiRefreshFileManagerMeta666(); } catch(e) {} }, ms); });\n            return ret;\n        };\n        window.openFileManager.__tiMeta682 = true;\n    }\n    setTimeout(function(){\n        try { document.querySelectorAll('#fm-grid [data-ti-file-size-url]').forEach(function(el){ if (\/calcolo|in corso\/i.test(txt(el.textContent))) el.textContent='dimensione non disponibile'; }); } catch(e) {}\n    }, 9000);\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-and-meta-683\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveAndMeta683Installed) return;\n    window.__tiConfigSaveAndMeta683Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\n    function enc(obj){\n        var json = JSON.stringify(obj || {});\n        if (typeof window.utoa === 'function') return window.utoa(json);\n        return btoa(unescape(encodeURIComponent(json)));\n    }\n    function clone(o){ return JSON.parse(JSON.stringify(o || {})); }\n    function saveButton(){ return byId('lbl-conf-save'); }\n    function setSaving(){\n        var b = saveButton(); if (!b) return;\n        b.disabled = true;\n        b.setAttribute('aria-busy','true');\n        b.setAttribute('data-ti-saving','1');\n        b.style.pointerEvents = 'none';\n        b.innerText = 'Salvataggio...';\n        try { b.style.setProperty('background','#d97706','important'); b.style.setProperty('background-color','#d97706','important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','wait','important'); } catch(e) {}\n    }\n    function resetSaveButton(clean){\n        window.__tiConfigSaveActive682 = false;\n        window.__tiConfigSaveActive683 = false;\n        window.__saveConfigInFlight = false;\n        window.__tiSaveConfigStartedAt = 0;\n        window.__tiSaveConfigStartedAt585 = 0;\n        window.__tiSaveConfigStartedAt675 = 0;\n        var b = saveButton(); if (!b) return;\n        if (clean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') { try { window.modifiedFields.clear(); } catch(e) {} }\n        var dirty = !!(!clean && window.modifiedFields && window.modifiedFields.size > 0);\n        b.disabled = false;\n        try { b.removeAttribute('disabled'); b.removeAttribute('aria-busy'); b.removeAttribute('data-ti-saving'); } catch(e) {}\n        b.style.pointerEvents = '';\n        b.classList.toggle('ti-save-dirty', dirty);\n        b.classList.toggle('ti-save-clean', !dirty);\n        b.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n        try { b.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','pointer','important'); } catch(e) {}\n    }\n    function clearBusy(){\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n        try { qsa('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(x){ if (x && x.parentNode) x.parentNode.removeChild(x); }); } catch(e) {}\n    }\n    function readVal(el){\n        if (!el) return '';\n        if (el.tagName === 'SELECT' && el.multiple) return Array.prototype.slice.call(el.selectedOptions || []).map(function(o){ return txt(o.value).trim(); }).filter(Boolean).join(', ');\n        if (el.type === 'checkbox') return el.checked ? (el.value || '1') : '';\n        return el.value == null ? '' : el.value;\n    }\n    function resolveTable(t){ try { return window.resolveConfigTableName ? (window.resolveConfigTableName(t) || t) : t; } catch(e) { return t; } }\n    function syncVisibleToData(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        var d = window.currentDbData;\n        if (!d || !d.Tabelle) return [];\n        Object.keys(d.Tabelle).forEach(function(t){ if (!Array.isArray(d.Tabelle[t])) d.Tabelle[t] = Object.values(d.Tabelle[t] || {}); });\n        var changed = {};\n        var sel = '#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        qsa(sel).forEach(function(input){\n            if (!input || input.disabled || input.readOnly) return;\n            var tbl = input.getAttribute('data-tbl') || '', key = input.getAttribute('data-key') || '', idx = parseInt(input.getAttribute('data-idx') || '', 10);\n            if (!tbl || !key || isNaN(idx)) return;\n            var rt = resolveTable(tbl);\n            if (!d.Tabelle[rt]) d.Tabelle[rt] = [];\n            if (!d.Tabelle[rt][idx] || typeof d.Tabelle[rt][idx] !== 'object') d.Tabelle[rt][idx] = {};\n            var val = readVal(input);\n            try { if (window.normalizeInputValueForKey) val = window.normalizeInputValueForKey(key, val); } catch(e) {}\n            if (txt(d.Tabelle[rt][idx][key]) !== txt(val)) {\n                d.Tabelle[rt][idx][key] = val;\n                changed[rt] = true;\n                if (!window.modifiedFields) window.modifiedFields = new Set();\n                try { window.modifiedFields.add(rt + '-' + idx + '-' + key); } catch(e) {}\n            }\n        });\n        try { if (window.tiApplyPendingLinkedFileRemovals676) { var n = window.tiApplyPendingLinkedFileRemovals676(); if (n && window.targetUploadContext && window.targetUploadContext.tbl) changed[resolveTable(window.targetUploadContext.tbl)] = true; } } catch(e) {}\n        try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n        return Object.keys(changed);\n    }\n    function changedTables(localChanged){\n        var out = {}, cur = (window.currentDbData && window.currentDbData.Tabelle) ? window.currentDbData.Tabelle : {}, old = (window.configOriginalDbData && window.configOriginalDbData.Tabelle) ? window.configOriginalDbData.Tabelle : {};\n        (localChanged || []).forEach(function(t){ if (t) out[t] = true; });\n        try { if (window.modifiedFields && typeof window.modifiedFields.forEach === 'function') {\n            var names = Object.keys(cur || {}).sort(function(a,b){ return String(b).length - String(a).length; });\n            window.modifiedFields.forEach(function(raw){ raw = txt(raw); names.forEach(function(t){ if (raw.indexOf(t + '-') === 0) out[t] = true; }); });\n        }} catch(e) {}\n        var all = {}; Object.keys(cur || {}).forEach(function(t){ all[t] = true; }); Object.keys(old || {}).forEach(function(t){ all[t] = true; });\n        Object.keys(all).forEach(function(t){ try { if (JSON.stringify(cur[t] || []) !== JSON.stringify(old[t] || [])) out[t] = true; } catch(e) { out[t] = true; } });\n        try { (window.tiConfigDeletedRowsManifest || []).forEach(function(x){ if (x && x.table) out[resolveTable(x.table)] = true; }); } catch(e) {}\n        try { Object.keys(window.tiConfigDeletedTableSnapshots || {}).forEach(function(t){ if (t) out[resolveTable(t)] = true; }); } catch(e) {}\n        return Object.keys(out);\n    }\n    function postSnapshot(fd, timeoutMs){\n        timeoutMs = timeoutMs || 180000;\n        var url = window.tiUrl || window.tiAjaxUrl || window.location.href.split('?')[0];\n        return new Promise(function(resolve, reject){\n            var done = false, ctrl = (typeof AbortController !== 'undefined') ? new AbortController() : null;\n            var timer = setTimeout(function(){ if (done) return; done = true; try { if (ctrl) ctrl.abort(); } catch(e) {} reject(new Error('Timeout salvataggio configurazione. Il server non ha concluso la scrittura.')); }, timeoutMs);\n            fetch(url, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', signal:ctrl ? ctrl.signal : undefined}).then(function(r){\n                return r.text().then(function(raw){\n                    if (!r.ok) throw new Error('Errore server ' + r.status + ': ' + (raw || '').slice(0, 260));\n                    try { return JSON.parse(raw); } catch(e) { throw new Error('Risposta salvataggio non JSON: ' + (raw || '').slice(0, 260)); }\n                });\n            }).then(function(d){ if (done) return; done = true; clearTimeout(timer); resolve(d); }).catch(function(e){ if (done) return; done = true; clearTimeout(timer); reject(e); });\n        });\n    }\n    window.saveConfig = function(){\n        if (!window.currentDbData || !window.currentDbData.Tabelle) { resetSaveButton(false); if (window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.'); return; }\n        var dbEl = byId('ti-ditta'), db = dbEl ? (dbEl.value || '') : '';\n        if (!db || db === 'NEW_DB' || db === 'Global') { resetSaveButton(false); if (window.tiAlert) window.tiAlert('Seleziona ditta.'); return; }\n        setSaving();\n        window.__tiConfigSaveActive683 = true;\n        window.__saveConfigInFlight = true;\n        window.__tiSaveConfigStartedAt = Date.now ? Date.now() : (new Date()).getTime();\n        var localChanged = [];\n        try { localChanged = syncVisibleToData(); } catch(e) { resetSaveButton(false); if (window.tiAlert) window.tiAlert('Errore preparazione salvataggio: ' + (e.message || e)); return; }\n        var tables = changedTables(localChanged);\n        if (!tables.length) tables = Object.keys((window.currentDbData && window.currentDbData.Tabelle) || {});\n        var fd = new FormData();\n        fd.append('ti_action', 'ti_ai_save_config_snapshot_683');\n        fd.append('action', 'ti_ai_save_config_snapshot_683');\n        fd.append('db', db);\n        fd.append('payload', enc(window.currentDbData));\n        fd.append('changed_tables', enc(tables));\n        fd.append('deleted_rows', enc(window.tiConfigDeletedRowsManifest || []));\n        fd.append('deleted_table_snapshots', enc(window.tiConfigDeletedTableSnapshots || {}));\n        fd.append('deleted_rows_client_total', String(parseInt(window.tiConfigDeletedRowsCountTotal || 0, 10) || 0));\n        fd.append('snapshot_save_683', '1');\n        try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        postSnapshot(fd, 180000).then(function(res){\n            if (!res || !res.success) throw new Error((res && res.data && res.data.message) ? res.data.message : 'Salvataggio configurazione non riuscito.');\n            var data = res.data || {};\n            if (window.currentDbData && data.db_version) window.currentDbData.__db_version = data.db_version;\n            try { window.configOriginalDbData = clone(window.currentDbData); } catch(e) {}\n            try { if (window.modifiedFields && typeof window.modifiedFields.clear === 'function') window.modifiedFields.clear(); } catch(e) {}\n            window.pendingLinkedFileRemovals = [];\n            window.tiConfigDeletedRowsManifest = [];\n            window.tiConfigDeletedTableSnapshots = {};\n            window.tiConfigDeletedRowsCountTotal = 0;\n            resetSaveButton(true);\n            var warns = Array.isArray(data.value_warnings) ? data.value_warnings : [];\n            setTimeout(function(){\n                if (warns.length && window.showConfigValidationWarning) window.showConfigValidationWarning(warns, true);\n                else if (window.tiAlert) window.tiAlert('\u2705 Salvataggio configurazione completato.');\n            }, 80);\n        }).catch(function(err){\n            resetSaveButton(false);\n            if (window.tiAlert) window.tiAlert((err && err.message) ? err.message : 'Errore durante il salvataggio configurazione.');\n        }).finally(function(){\n            clearBusy();\n            window.__tiConfigSaveActive683 = false;\n            window.__saveConfigInFlight = false;\n            var b = saveButton();\n            if (b && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving') === '1')) resetSaveButton(false);\n        });\n    };\n    function fmt(bytes){\n        bytes = parseInt(bytes || 0, 10) || 0;\n        if (bytes <= 0) return 'dimensione non disponibile';\n        if (window.tiFormatBytes666) { try { var f = window.tiFormatBytes666(bytes); if (f) return f; } catch(e) {} }\n        if (bytes < 1024) return bytes + ' B';\n        var units = ['KB','MB','GB','TB'], v = bytes \/ 1024, i = 0;\n        while (v >= 1024 && i < units.length - 1) { v \/= 1024; i++; }\n        return String(v.toFixed(v >= 10 ? 1 : 2)).replace('.', ',') + ' ' + units[i];\n    }\n    function metaPost(el){\n        var fd = new FormData();\n        fd.append('ti_action','ti_ai_file_meta_683'); fd.append('action','ti_ai_file_meta_683');\n        fd.append('db', el.getAttribute('data-ti-file-db') || (byId('ti-ditta') ? (byId('ti-ditta').value || '') : ''));\n        fd.append('tbl', el.getAttribute('data-ti-file-tbl') || ((window.targetUploadContext && window.targetUploadContext.tbl) ? window.targetUploadContext.tbl : ''));\n        fd.append('record', el.getAttribute('data-ti-file-record') || '');\n        fd.append('ref', el.getAttribute('data-ti-file-ref') || '');\n        fd.append('url', el.getAttribute('data-ti-file-size-url') || '');\n        var url = window.tiUrl || window.location.href.split('?')[0];\n        return new Promise(function(resolve, reject){\n            var done = false, ctrl = (typeof AbortController !== 'undefined') ? new AbortController() : null;\n            var timer = setTimeout(function(){ if (done) return; done = true; try { if (ctrl) ctrl.abort(); } catch(e) {} reject(new Error('timeout meta')); }, 22000);\n            fetch(url, {method:'POST', body:fd, credentials:'same-origin', cache:'no-store', signal:ctrl ? ctrl.signal : undefined}).then(function(r){ return r.text().then(function(raw){ var d; try { d = JSON.parse(raw); } catch(e) { throw new Error('meta non JSON'); } if (!d || !d.success) throw new Error((d && d.data && d.data.message) || 'meta non disponibile'); return d.data || {}; }); }).then(function(d){ if (done) return; done = true; clearTimeout(timer); resolve(d); }).catch(function(e){ if (done) return; done = true; clearTimeout(timer); reject(e); });\n        });\n    }\n    function browserSize(url){\n        if (!url) return Promise.reject(new Error('url mancante'));\n        function head(){ return fetch(url, {method:'HEAD', credentials:'same-origin', cache:'no-store'}).then(function(r){ if (!r.ok) throw new Error('http ' + r.status); var len = r.headers && r.headers.get ? (r.headers.get('Content-Length') || r.headers.get('content-length') || '') : ''; var n = parseInt(len || '0', 10) || 0; if (n > 0) return n; throw new Error('length assente'); }); }\n        function get(){ return fetch(url, {method:'GET', credentials:'same-origin', cache:'no-store'}).then(function(r){ if (!r.ok) throw new Error('http ' + r.status); var len = r.headers && r.headers.get ? (r.headers.get('Content-Length') || r.headers.get('content-length') || '') : ''; var n = parseInt(len || '0', 10) || 0; if (n > 0) return n; return r.blob().then(function(b){ return b && b.size ? b.size : 0; }); }); }\n        return head().catch(get);\n    }\n    window.tiRefreshFileManagerMeta666 = function(){\n        qsa('#fm-grid [data-ti-file-size-url],#fm-grid [data-ti-file-ref]').forEach(function(el){\n            if (!el) return;\n            var now = Date.now ? Date.now() : (new Date()).getTime();\n            var loadingAt = parseInt(el.getAttribute('data-ti-size-loading-at') || '0', 10) || 0;\n            if (el.getAttribute('data-ti-size-loading') === '1' && loadingAt && (now - loadingAt) < 25000) return;\n            var url = el.getAttribute('data-ti-file-size-url') || '';\n            el.setAttribute('data-ti-size-loading','1');\n            el.setAttribute('data-ti-size-loading-at', String(now));\n            el.textContent = 'calcolo...';\n            metaPost(el).then(function(meta){\n                var size = parseInt(meta.size || 0, 10) || 0;\n                var label = meta.size_label || (size > 0 ? fmt(size) : '');\n                if ((!size || \/non disponibile|n\\\/d\/i.test(label)) && url) return browserSize(url).then(function(n){ return {meta:meta, label:n > 0 ? fmt(n) : (label || 'dimensione non disponibile')}; }).catch(function(){ return {meta:meta, label:label || 'dimensione non disponibile'}; });\n                return {meta:meta, label:label || 'dimensione non disponibile'};\n            }).catch(function(){\n                if (!url) return {meta:null, label:'dimensione non disponibile'};\n                return browserSize(url).then(function(n){ return {meta:null, label:n > 0 ? fmt(n) : 'dimensione non disponibile'}; }).catch(function(){ return {meta:null, label:'dimensione non disponibile'}; });\n            }).then(function(res){\n                el.textContent = (res && res.label) ? res.label : 'dimensione non disponibile';\n                var meta = res && res.meta ? res.meta : null;\n                var item = el.closest ? el.closest('.ti-file-item') : null;\n                if (item && meta && meta.ext) {\n                    var all = item.querySelectorAll('.ti-file-meta-666');\n                    if (all && all[0]) all[0].innerHTML = '<b>Tipo:<\/b> ' + txt(meta.ext || 'n\/d');\n                }\n            }).finally(function(){\n                el.removeAttribute('data-ti-size-loading');\n                el.removeAttribute('data-ti-size-loading-at');\n                if (\/calcolo\/i.test(txt(el.textContent))) el.textContent = 'dimensione non disponibile';\n            });\n        });\n    };\n    if (typeof window.openFileManager === 'function' && !window.openFileManager.__tiMeta683) {\n        var oldOpen = window.openFileManager;\n        window.openFileManager = function(){\n            var ret = oldOpen.apply(this, arguments);\n            [80, 700, 1800, 4500].forEach(function(ms){ setTimeout(function(){ try { window.tiRefreshFileManagerMeta666(); } catch(e) {} }, ms); });\n            return ret;\n        };\n        window.openFileManager.__tiMeta683 = true;\n    }\n    setTimeout(function(){\n        try { qsa('#fm-grid [data-ti-file-size-url],#fm-grid [data-ti-file-ref]').forEach(function(el){ if (\/calcolo|in corso\/i.test(txt(el.textContent))) el.textContent='dimensione non disponibile'; }); } catch(e) {}\n    }, 9000);\n    setInterval(function(){\n        try { var b = saveButton(); if (b && !window.__tiConfigSaveActive683 && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving') === '1')) resetSaveButton(false); } catch(e) {}\n    }, 1000);\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-and-meta-684\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveAndMeta684Installed) return;\n    window.__tiConfigSaveAndMeta684Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\n    function clone(o){ try { return JSON.parse(JSON.stringify(o || {})); } catch(e) { return {}; } }\n    function enc(obj){ var json = JSON.stringify(obj || {}); if (typeof window.utoa === 'function') return window.utoa(json); return btoa(unescape(encodeURIComponent(json))); }\n    function saveButton(){ return byId('lbl-conf-save'); }\n    function clearBusy(){\n        try { window.__tiConfigSaveActive675=false; window.__tiConfigSaveActive677=false; window.__tiConfigSaveActive678=false; window.__tiConfigSaveActive682=false; window.__tiConfigSaveActive683=false; window.__tiConfigSaveActive684=false; window.__saveConfigInFlight=false; } catch(e) {}\n        try { window.__tiSaveConfigStartedAt=0; window.__tiSaveConfigStartedAt585=0; window.__tiSaveConfigStartedAt675=0; } catch(e) {}\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n        try { qsa('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(x){ if (x && x.parentNode) x.parentNode.removeChild(x); }); } catch(e) {}\n    }\n    function setSaving(){\n        var b=saveButton(); if(!b) return;\n        b.disabled=true; b.setAttribute('aria-busy','true'); b.setAttribute('data-ti-saving','1'); b.style.pointerEvents='none'; b.innerText='Salvataggio...';\n        try { b.style.setProperty('background','#d97706','important'); b.style.setProperty('background-color','#d97706','important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','wait','important'); } catch(e) {}\n    }\n    function resetButton(clean){\n        if (clean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') { try { window.modifiedFields.clear(); } catch(e) {} }\n        clearBusy();\n        var b=saveButton(); if(!b) return;\n        var dirty = !!(!clean && window.modifiedFields && window.modifiedFields.size>0);\n        b.disabled=false; try { b.removeAttribute('disabled'); b.removeAttribute('aria-busy'); b.removeAttribute('data-ti-saving'); } catch(e) {}\n        b.style.pointerEvents=''; b.classList.toggle('ti-save-dirty',dirty); b.classList.toggle('ti-save-clean',!dirty); b.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n        try { b.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','pointer','important'); } catch(e) {}\n    }\n    function readVal(el){\n        if(!el) return '';\n        if(el.tagName==='SELECT' && el.multiple) return Array.prototype.slice.call(el.selectedOptions||[]).map(function(o){return txt(o.value).trim();}).filter(Boolean).join(', ');\n        if(el.type==='checkbox') return el.checked ? (el.value || '1') : '';\n        return el.value == null ? '' : el.value;\n    }\n    function resolveTable(t){ try { return window.resolveConfigTableName ? (window.resolveConfigTableName(t)||t) : t; } catch(e) { return t; } }\n    function ensureArrays(){ var d=window.currentDbData; if(!d || !d.Tabelle) return; Object.keys(d.Tabelle).forEach(function(t){ if(!Array.isArray(d.Tabelle[t])) d.Tabelle[t]=Object.values(d.Tabelle[t]||{}); }); }\n    function syncVisible(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        ensureArrays();\n        var d=window.currentDbData; if(!d || !d.Tabelle) return;\n        var sel='#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        qsa(sel).forEach(function(input){\n            if(!input || input.disabled || input.readOnly) return;\n            var tbl=input.getAttribute('data-tbl')||'', key=input.getAttribute('data-key')||'', idx=parseInt(input.getAttribute('data-idx')||'',10);\n            if(!tbl || !key || isNaN(idx)) return;\n            var rt=resolveTable(tbl); if(!d.Tabelle[rt]) d.Tabelle[rt]=[]; if(!d.Tabelle[rt][idx] || typeof d.Tabelle[rt][idx] !== 'object') d.Tabelle[rt][idx]={};\n            var val=readVal(input); try { if (window.normalizeInputValueForKey) val=window.normalizeInputValueForKey(key,val); } catch(e) {}\n            if(txt(d.Tabelle[rt][idx][key]) !== txt(val)) { d.Tabelle[rt][idx][key]=val; if(!window.modifiedFields) window.modifiedFields=new Set(); try { window.modifiedFields.add(rt+'-'+idx+'-'+key); } catch(e) {} }\n        });\n        try { if (window.tiApplyPendingLinkedFileRemovals676) window.tiApplyPendingLinkedFileRemovals676(); } catch(e) {}\n        try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n    }\n    function parseModifiedField(raw, tables){ raw=txt(raw); if(!raw) return null; for(var i=0;i<tables.length;i++){ var t=tables[i], pfx=String(t)+'-'; if(raw.indexOf(pfx)===0){ var rest=raw.slice(pfx.length), p=rest.indexOf('-'); if(p<=0) return null; var idx=parseInt(rest.slice(0,p),10); if(isNaN(idx)) return null; return {table:t,row:idx,key:rest.slice(p+1)}; } } return null; }\n    function buildFieldChanges(){\n        ensureArrays();\n        var cur=(window.currentDbData&&window.currentDbData.Tabelle)?window.currentDbData.Tabelle:{};\n        var old=(window.configOriginalDbData&&window.configOriginalDbData.Tabelle)?window.configOriginalDbData.Tabelle:{};\n        var tables=Object.keys(cur||{}).sort(function(a,b){return String(b).length-String(a).length;});\n        var changes=[], seen={}, fullNeeded=false;\n        function add(table,row,key,value){\n            if(!table || row<0 || !key || String(key).indexOf('__')===0){ fullNeeded=true; return; }\n            var sig=table+'\\u0001'+row+'\\u0001'+key; if(seen[sig]) return; seen[sig]=true;\n            if(value && typeof value==='object'){ fullNeeded=true; return; }\n            changes.push({table:table,row:row,key:key,value:(value==null?'':value)});\n        }\n        try { if(window.modifiedFields && typeof window.modifiedFields.forEach==='function') window.modifiedFields.forEach(function(raw){ var p=parseModifiedField(raw,tables); if(!p){ fullNeeded=true; return; } var r=(cur[p.table]||[])[p.row]; if(!r || typeof r!=='object'){ fullNeeded=true; return; } add(p.table,p.row,p.key,r[p.key]); }); } catch(e){ fullNeeded=true; }\n        try {\n            var all={}; Object.keys(cur||{}).forEach(function(t){all[t]=true;}); Object.keys(old||{}).forEach(function(t){all[t]=true;});\n            Object.keys(all).forEach(function(t){\n                var cr=Array.isArray(cur[t])?cur[t]:Object.values(cur[t]||{}), or=Array.isArray(old[t])?old[t]:Object.values(old[t]||{});\n                if(cr.length!==or.length){ fullNeeded=true; return; }\n                for(var i=0;i<cr.length;i++){\n                    var a=cr[i]||{}, b=or[i]||{}; if(!a || typeof a!=='object' || !b || typeof b!=='object'){ fullNeeded=true; return; }\n                    var keys={}; Object.keys(a).forEach(function(k){keys[k]=true;}); Object.keys(b).forEach(function(k){keys[k]=true;});\n                    Object.keys(keys).forEach(function(k){ if(JSON.stringify(a[k]==null?'':a[k]) !== JSON.stringify(b[k]==null?'':b[k])) add(t,i,k,a[k]); });\n                }\n            });\n        } catch(e){ fullNeeded=true; }\n        try { if((window.tiConfigDeletedRowsManifest||[]).length || Object.keys(window.tiConfigDeletedTableSnapshots||{}).length || parseInt(window.tiConfigDeletedRowsCountTotal||0,10)>0) fullNeeded=true; } catch(e) {}\n        if(changes.length>1000) fullNeeded=true;\n        return {changes:changes, fullNeeded:fullNeeded};\n    }\n    function postJson(fd, timeoutMs){\n        timeoutMs=timeoutMs||90000; try { if(!fd.has('action') && fd.has('ti_action')) fd.append('action', fd.get('ti_action')); } catch(e) {}\n        try { if(window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n        var url=window.tiUrl || window.tiAjaxUrl || window.location.href.split('?')[0];\n        return new Promise(function(resolve,reject){\n            var ctrl=(typeof AbortController!=='undefined')?new AbortController():null, done=false;\n            var timer=setTimeout(function(){ if(done) return; done=true; try{ if(ctrl) ctrl.abort(); }catch(e){} reject(new Error('Timeout salvataggio configurazione. Salvataggio non confermato dal server.')); }, timeoutMs);\n            fetch(url,{method:'POST',body:fd,credentials:'same-origin',cache:'no-store',signal:ctrl?ctrl.signal:undefined}).then(function(r){ return r.text().then(function(raw){ if(!r.ok) throw new Error('Errore server '+r.status+': '+(raw||'').slice(0,260)); try{return JSON.parse(raw);}catch(e){throw new Error('Risposta salvataggio non JSON: '+(raw||'').slice(0,260));} }); }).then(function(d){ if(done) return; done=true; clearTimeout(timer); resolve(d); }).catch(function(e){ if(done) return; done=true; clearTimeout(timer); reject(e); });\n        });\n    }\n    function postFieldSave(db, changes){ var fd=new FormData(); fd.append('ti_action','ti_ai_save_config_fields_690'); fd.append('action','ti_ai_save_config_fields_690'); fd.append('db',db); fd.append('changes',enc(changes)); fd.append('field_save_690','1'); return postJson(fd,30000); }\n    function changedTablesFromChanges(changes){ var m={}; (changes||[]).forEach(function(c){ if(c&&c.table)m[c.table]=true; }); return Object.keys(m); }\n    function buildCompactPayload(tables){ var d=window.currentDbData||{}, payload={Database:d.Database||'', __db_version:d.__db_version||'', Tabelle:{}}; (tables&&tables.length?tables:Object.keys((d&&d.Tabelle)||{})).forEach(function(t){ if(d.Tabelle && d.Tabelle[t]) payload.Tabelle[t]=d.Tabelle[t]; }); return payload; }\n    function postCompactFullSave(db, changes){\n        var tables=changedTablesFromChanges(changes); if(!tables.length) tables=Object.keys((window.currentDbData&&window.currentDbData.Tabelle)||{});\n        var fd=new FormData(); fd.append('ti_action','ti_ai_save_full_db'); fd.append('action','ti_ai_save_full_db'); fd.append('db',db); fd.append('payload',enc(buildCompactPayload(tables))); fd.append('compact_save','1'); fd.append('light_save','1'); fd.append('response_light','1'); fd.append('save_mode','light'); fd.append('changed_tables',enc(tables)); fd.append('deleted_rows',enc(window.tiConfigDeletedRowsManifest||[])); fd.append('deleted_table_snapshots',enc(window.tiConfigDeletedTableSnapshots||{})); fd.append('deleted_rows_client_total',String(parseInt(window.tiConfigDeletedRowsCountTotal||0,10)||0)); fd.append('db_version',''); fd.append('compact_save_684','1'); return postJson(fd,150000);\n    }\n    function onSuccess(res){\n        var data=(res&&res.data)?res.data:{}; if(window.currentDbData && data.db_version) window.currentDbData.__db_version=data.db_version;\n        try { if(window.currentDbData) window.configOriginalDbData=clone(window.currentDbData); } catch(e) {}\n        try { if(window.modifiedFields && typeof window.modifiedFields.clear==='function') window.modifiedFields.clear(); } catch(e) {}\n        window.pendingLinkedFileRemovals=[]; window.tiConfigDeletedRowsManifest=[]; window.tiConfigDeletedTableSnapshots={}; window.tiConfigDeletedRowsCountTotal=0; try { if(window.tiConfigStructuralChangedTables1907 && typeof window.tiConfigStructuralChangedTables1907.clear==='function') window.tiConfigStructuralChangedTables1907.clear(); } catch(e1907) {}\n        resetButton(true);\n        var warns=Array.isArray(data.value_warnings)?data.value_warnings:[];\n        setTimeout(function(){ if(warns.length && window.showConfigValidationWarning) window.showConfigValidationWarning(warns,true); else if(window.tiAlert) window.tiAlert('\u2705 Salvataggio configurazione completato.'); },80);\n    }\n    window.saveConfig = function(){\n        if(!window.currentDbData || !window.currentDbData.Tabelle){ resetButton(false); if(window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.'); return; }\n        var dbEl=byId('ti-ditta'), db=dbEl?(dbEl.value||''):''; if(!db || db==='NEW_DB' || db==='Global'){ resetButton(false); if(window.tiAlert) window.tiAlert('Seleziona ditta.'); return; }\n        clearBusy(); setSaving(); window.__tiConfigSaveActive684=true; window.__saveConfigInFlight=true; window.__tiSaveConfigStartedAt=Date.now?Date.now():(new Date()).getTime();\n        var built;\n        try { syncVisible(); built=buildFieldChanges(); } catch(e){ resetButton(false); if(window.tiAlert) window.tiAlert('Errore preparazione salvataggio: '+(e.message||e)); return; }\n        if(!built.changes.length && !built.fullNeeded){ window.__tiConfigSaveActive692=false; window.__saveConfigInFlight=false; clearBusy(); resetButton(true); log692('no_changes_after_build_699', {modifiedFields: window.modifiedFields && window.modifiedFields.size ? window.modifiedFields.size : 0, removals:Array.isArray(window.pendingLinkedFileRemovals)?window.pendingLinkedFileRemovals.length:0}, 'info'); if(window.tiAlert) window.tiAlert('Nessuna modifica da salvare.'); return; }\n        var promise = (!built.fullNeeded && built.changes.length <= 1000) ? postFieldSave(db,built.changes) : postCompactFullSave(db,built.changes);\n        promise.then(function(res){ if(!res || !res.success) throw new Error((res&&res.data&&res.data.message)?res.data.message:'Salvataggio configurazione non riuscito.'); onSuccess(res); })\n        .catch(function(err){ resetButton(false); var msg=(err&&err.message)?err.message:'Errore durante il salvataggio configurazione.'; if(window.tiAlert) window.tiAlert(msg); else alert(msg); })\n        .finally(function(){ window.__tiConfigSaveActive684=false; window.__saveConfigInFlight=false; clearBusy(); var b=saveButton(); if(b && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving')==='1')) resetButton(false); });\n    };\n    window.tiForceUnlockConfigSave684=function(reason){ resetButton(false); if(reason && window.tiAlert) window.tiAlert(reason); };\n    function fmt(bytes){ bytes=parseInt(bytes||0,10)||0; if(bytes<=0) return 'dimensione non disponibile'; if(window.tiFormatBytes666){ try{ var f=window.tiFormatBytes666(bytes); if(f) return f; }catch(e){} } if(bytes<1024) return bytes+' B'; var units=['KB','MB','GB','TB'], v=bytes\/1024, i=0; while(v>=1024 && i<units.length-1){v\/=1024;i++;} return String(v.toFixed(v>=10?1:2)).replace('.',',')+' '+units[i]; }\n    function timeoutPromise(ms,label){ return new Promise(function(_,reject){ setTimeout(function(){ reject(new Error(label||'timeout')); }, ms); }); }\n    function fetchHeadSize(url){ if(!url) return Promise.reject(new Error('url mancante')); var ctrl=(typeof AbortController!=='undefined')?new AbortController():null; var t=setTimeout(function(){ try{ if(ctrl) ctrl.abort(); }catch(e){} },7000); return fetch(url,{method:'HEAD',credentials:'same-origin',cache:'no-store',signal:ctrl?ctrl.signal:undefined}).then(function(r){ clearTimeout(t); if(!r.ok) throw new Error('http '+r.status); var len=r.headers&&r.headers.get?(r.headers.get('Content-Length')||r.headers.get('content-length')||''):''; var n=parseInt(len||'0',10)||0; if(n>0) return n; throw new Error('content length assente'); }); }\n    function postMeta(el){\n        var fd=new FormData(); fd.append('ti_action','ti_ai_file_meta_684'); fd.append('action','ti_ai_file_meta_684'); fd.append('db',el.getAttribute('data-ti-file-db')||(byId('ti-ditta')?(byId('ti-ditta').value||''):'')); fd.append('tbl',el.getAttribute('data-ti-file-tbl')||((window.targetUploadContext&&window.targetUploadContext.tbl)?window.targetUploadContext.tbl:'')); fd.append('record',el.getAttribute('data-ti-file-record')||''); fd.append('ref',el.getAttribute('data-ti-file-ref')||''); fd.append('url',el.getAttribute('data-ti-file-size-url')||'');\n        return postJson(fd,6000).then(function(d){ if(!d||!d.success) throw new Error((d&&d.data&&d.data.message)||'meta non disponibile'); return d.data||{}; });\n    }\n    window.tiRefreshFileManagerMeta666 = function(){\n        qsa('#fm-grid [data-ti-file-size-url],#fm-grid [data-ti-file-ref]').forEach(function(el){\n            if(!el) return; var current=txt(el.textContent); var now=Date.now?Date.now():(new Date()).getTime(); var started=parseInt(el.getAttribute('data-ti-size-loading-at')||'0',10)||0;\n            if(el.getAttribute('data-ti-size-loading')==='1' && started && (now-started)<18000) return;\n            var url=el.getAttribute('data-ti-file-size-url')||'';\n            el.setAttribute('data-ti-size-loading','1'); el.setAttribute('data-ti-size-loading-at',String(now));\n            if(!current || \/calcolo|n\\\/d|non disponibile\/i.test(current)) el.textContent='dimensione in corso...';\n            Promise.race([\n                postMeta(el).then(function(meta){ var n=parseInt(meta.size||0,10)||0; if(n>0) return {label:fmt(n), meta:meta}; if(meta.size_label && !\/non disponibile|n\\\/d\/i.test(meta.size_label)) return {label:meta.size_label, meta:meta}; throw new Error('meta senza dimensione'); }),\n                timeoutPromise(6500,'timeout meta')\n            ]).catch(function(){ return url ? fetchHeadSize(url).then(function(n){ return {label:n>0?fmt(n):'dimensione non disponibile', meta:null}; }) : {label:'dimensione non disponibile', meta:null}; })\n            .catch(function(){ return {label:'dimensione non disponibile', meta:null}; })\n            .then(function(res){ el.textContent=(res&&res.label)?res.label:'dimensione non disponibile'; var meta=res&&res.meta?res.meta:null, item=el.closest?el.closest('.ti-file-item'):null; if(item&&meta&&meta.ext){ var all=item.querySelectorAll('.ti-file-meta-666'); if(all&&all[0]) all[0].innerHTML='<b>Tipo:<\/b> '+txt(meta.ext||'n\/d'); } })\n            .finally(function(){ el.removeAttribute('data-ti-size-loading'); el.removeAttribute('data-ti-size-loading-at'); if(\/calcolo|in corso\/i.test(txt(el.textContent))) el.textContent='dimensione non disponibile'; });\n        });\n    };\n    if(typeof window.openFileManager==='function' && !window.openFileManager.__tiMeta684){ var prev=window.openFileManager; window.openFileManager=function(){ var ret=prev.apply(this,arguments); [120,1500].forEach(function(ms){ setTimeout(function(){ try{ window.tiRefreshFileManagerMeta666(); }catch(e){} },ms); }); return ret; }; window.openFileManager.__tiMeta684=true; }\n    setTimeout(function(){ try{ qsa('#fm-grid [data-ti-file-size-url],#fm-grid [data-ti-file-ref]').forEach(function(el){ if(\/calcolo|in corso\/i.test(txt(el.textContent))) el.textContent='dimensione non disponibile'; }); }catch(e){} },9000);\n    \/\/ 30.9.1427: rimosso lo stesso controllo periodico orfano, versione 684 - stesse motivazioni della 678.\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-diagnostic-687\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveDiagnostic687Installed) return;\n    window.__tiConfigSaveDiagnostic687Installed = true;\n    if (!window.tiConfigSaveLogAllowed) {\n        window.tiShowConfigSaveDiag687 = function(){ return false; };\n        window.tiCopyConfigSaveDiag687 = function(){ return false; };\n        return;\n    }\n    var nativeFetch = window.fetch ? window.fetch.bind(window) : null;\n    var activeTrace = null;\n    var activeStarted = 0;\n    var seq = 0;\n    var maxRows = 260;\n    var lastHeartbeat = 0;\n    var wrapTimer = null;\n    window.__tiConfigSaveDiagLog687 = window.__tiConfigSaveDiagLog687 || [];\n    function nowMs(){ return Date.now ? Date.now() : (new Date()).getTime(); }\n    function iso(){ try { return new Date().toISOString(); } catch(e) { return String(new Date()); } }\n    function txt(v){ return String(v == null ? '' : v); }\n    function byId(id){ return document.getElementById(id); }\n    function short(v,n){ v=txt(v); n=n||300; return v.length>n ? v.slice(0,n)+'...' : v; }\n    function safeJson(v,n){ try { return short(JSON.stringify(v), n || 600); } catch(e) { return short(v, n || 600); } }\n    function dbName(){ var el=byId('ti-ditta'); return el ? (el.value || '') : ''; }\n    function htmlEsc(v){ return txt(v).replace(\/[&<>\"']\/g,function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function ensurePanel(){\n        var el=byId('ti-config-save-diag-687');\n        if (el) return el;\n        el=document.createElement('div');\n        el.id='ti-config-save-diag-687';\n        el.setAttribute('role','dialog');\n        el.setAttribute('aria-live','polite');\n        el.style.cssText='position:fixed;left:50%;top:12px;transform:translateX(-50%);width:min(980px,calc(100vw - 18px));max-width:calc(100vw - 18px);max-height:82vh;max-height:82dvh;z-index:2147483647;background:#020617;color:#e5e7eb;border:2px solid #38bdf8;border-radius:14px;box-shadow:0 22px 70px rgba(0,0,0,.72);font:11px\/1.38 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;display:none;overflow:hidden;pointer-events:auto;box-sizing:border-box;';\n        el.innerHTML='<div style=\"display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:8px 9px;background:#0f172a;border-bottom:1px solid #334155;\">'\n            + '<b style=\"color:#7dd3fc;font-size:13px;white-space:nowrap;\">Log salvataggio configurazione<\/b>'\n            + '<span class=\"ti-diag687-subtitle\" style=\"color:#fde68a;font-size:10px;\">visibile, client-only, anti 503<\/span>'\n            + '<span id=\"ti-config-save-diag-status-687\" style=\"margin-left:auto;color:#bbf7d0;font-size:10px;white-space:nowrap;\"><\/span>'\n            + '<button type=\"button\" id=\"ti-config-save-diag-copy-687\" style=\"font-size:10px;padding:4px 7px;border-radius:7px;border:1px solid #475569;background:#1d4ed8;color:#fff;cursor:pointer;white-space:nowrap;\">Copia<\/button>'\n            + '<button type=\"button\" id=\"ti-config-save-diag-clear-687\" style=\"font-size:10px;padding:4px 7px;border-radius:7px;border:1px solid #475569;background:#334155;color:#fff;cursor:pointer;white-space:nowrap;\">Pulisci<\/button>'\n            + '<button type=\"button\" id=\"ti-config-save-diag-close-687\" style=\"font-size:10px;padding:4px 7px;border-radius:7px;border:1px solid #475569;background:#7f1d1d;color:#fff;cursor:pointer;white-space:nowrap;\">Chiudi<\/button>'\n            + '<\/div>'\n            + '<div id=\"ti-config-save-diag-summary-687\" style=\"padding:7px 9px;border-bottom:1px solid #1e293b;background:#07111f;color:#cbd5e1;font-size:11px;\"><\/div>'\n            + '<pre id=\"ti-config-save-diag-body-687\" style=\"white-space:pre-wrap;word-break:break-word;margin:0;padding:9px;overflow:auto;max-height:calc(82vh - 86px);max-height:calc(82dvh - 86px);background:#020617;color:#e5e7eb;box-sizing:border-box;\"><\/pre>'\n            + '<style>@media (max-width:480px){ .ti-diag687-subtitle{display:none;} }<\/style>';\n        document.body.appendChild(el);\n        byId('ti-config-save-diag-copy-687').onclick=function(){ copyLog(); };\n        byId('ti-config-save-diag-clear-687').onclick=function(){ window.__tiConfigSaveDiagLog687=[]; renderPanel(); };\n        byId('ti-config-save-diag-close-687').onclick=function(){ el.style.display='none'; };\n        return el;\n    }\n    function startTrace(reason){\n        activeTrace='diag-'+(new Date()).toISOString().replace(\/[^0-9]\/g,'').slice(0,14)+'-'+Math.random().toString(36).slice(2,7);\n        activeStarted=nowMs(); seq=0; lastHeartbeat=0; window.__tiConfigSaveDiagLog687=[];\n        showPanel();\n        log('00_apertura_log_visibile', {reason:reason||'start', db:dbName()}, 'info');\n    }\n    function showPanel(forceVisible){\n        var el=ensurePanel();\n        \/\/ 30.9.1437: il pannello ora si aggiorna sempre in background (dati sempre registrati), ma diventa\n        \/\/ visibile solo se esplicitamente richiesto (es. tramite il pulsante \"Log salvataggio\") - non piu'\n        \/\/ automaticamente ad ogni tentativo di salvataggio, su richiesta esplicita dell'utente.\n        if (forceVisible) { try { el.style.display='block'; el.style.visibility='visible'; el.style.opacity='1'; } catch(e) {} }\n        renderPanel();\n    }\n    function renderPanel(){\n        var el=ensurePanel(), body=byId('ti-config-save-diag-body-687'), st=byId('ti-config-save-diag-status-687'), sm=byId('ti-config-save-diag-summary-687');\n        if (st) st.textContent = activeTrace ? ('trace '+activeTrace) : 'in attesa';\n        if (sm) {\n            var btn=byId('lbl-conf-save');\n            sm.innerHTML = 'Database: <b>'+htmlEsc(dbName()||'(non selezionato)')+'<\/b> | Pulsante: <b>'+htmlEsc(btn ? btn.innerText : '(non trovato)')+'<\/b> | In corso: <b>'+htmlEsc(window.__saveConfigInFlight?'SI':'NO')+'<\/b> | Righe log: <b>'+htmlEsc(String((window.__tiConfigSaveDiagLog687||[]).length))+'<\/b> | <span style=\"color:'+(window.tiConfigSaveLogAllowed?'#4ade80':'#f87171')+';\">Log692 attivo: <b>'+(window.tiConfigSaveLogAllowed?'SI':'NO')+'<\/b><\/span> | Utente: <b>'+htmlEsc(window.tiUser||'(vuoto)')+'<\/b>';\n        }\n        if (body) {\n            body.textContent = (window.__tiConfigSaveDiagLog687 || []).map(function(r){\n                var d=''; try { d=JSON.stringify(r.detail || {}, null, 0); } catch(e) { d=txt(r.detail); }\n                return '[' + String(r.seq).padStart(3,'0') + '] +' + String(r.ms).padStart(6,' ') + 'ms ' + r.level.toUpperCase().padEnd(5,' ') + ' ' + r.event + (d && d !== '{}' ? ' ' + d : '');\n            }).join('\\n');\n            body.scrollTop = body.scrollHeight;\n        }\n    }\n    function log(event, detail, level){\n        level=level || 'info';\n        if (!activeTrace) { activeTrace='diag-'+(new Date()).toISOString().replace(\/[^0-9]\/g,'').slice(0,14)+'-'+Math.random().toString(36).slice(2,7); activeStarted=nowMs(); seq=0; }\n        var row={seq:++seq, ts:iso(), ms:Math.max(0, nowMs()-activeStarted), trace_id:activeTrace, event:event, level:level, detail:detail||{}};\n        window.__tiConfigSaveDiagLog687.push(row);\n        if (window.__tiConfigSaveDiagLog687.length > maxRows) window.__tiConfigSaveDiagLog687.splice(0, window.__tiConfigSaveDiagLog687.length - maxRows);\n        try { (level==='error' ? console.error : (level==='warn' ? console.warn : console.log))('[Shop-Service config save diag visible]', row); } catch(e) {}\n        showPanel();\n    }\n    function copyLog(){\n        ensurePanel();\n        var text='';\n        try { text=(byId('ti-config-save-diag-body-687')||{}).textContent || ''; } catch(e) {}\n        if (!text) text=safeJson(window.__tiConfigSaveDiagLog687 || [], 20000);\n        function done(ok){\n            var b=byId('ti-config-save-diag-copy-687'); if(b){ var old=b.textContent; b.textContent=ok?'Copiato':'Copia manuale'; setTimeout(function(){ b.textContent=old||'Copia testo'; }, 1200); }\n        }\n        if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(text).then(function(){ done(true); }).catch(function(){ fallback(); }); else fallback();\n        function fallback(){ var ta=document.createElement('textarea'); ta.value=text; document.body.appendChild(ta); ta.select(); var ok=false; try{ ok=document.execCommand('copy'); }catch(e){} document.body.removeChild(ta); done(ok); }\n    }\n    function sampleModifiedFields(){\n        var count=0, sample=[];\n        try { if (window.modifiedFields && typeof window.modifiedFields.forEach==='function') window.modifiedFields.forEach(function(x){ count++; if(sample.length<80) sample.push(String(x)); }); } catch(e) { sample.push('errore modifiedFields: '+(e.message||e)); }\n        return {count:count, sample:sample};\n    }\n    function sampleRemovals(){\n        var rem=[];\n        try { rem=(Array.isArray(window.pendingLinkedFileRemovals)?window.pendingLinkedFileRemovals:[]); } catch(e) { rem=[]; }\n        return {count:rem.length, sample:rem.slice(0,60)};\n    }\n    function changedTables(){\n        try { return (window.getConfigChangedTables ? window.getConfigChangedTables() : []); } catch(e) { return ['errore: '+(e.message||e)]; }\n    }\n    function summarizeClient(){\n        var btn=byId('lbl-conf-save') || byId('ti-conf-save');\n        var mf=sampleModifiedFields(), rm=sampleRemovals();\n        return {\n            db: dbName(),\n            plugin_version: window.tiVersion || window.tiPluginVersion || '',\n            currentDbLoaded: !!(window.currentDbData && window.currentDbData.Tabelle),\n            originalDbLoaded: !!(window.configOriginalDbData && window.configOriginalDbData.Tabelle),\n            changedTables: changedTables(),\n            modifiedFields_count: mf.count,\n            modifiedFields_sample: mf.sample,\n            pendingLinkedFileRemovals_count: rm.count,\n            pendingLinkedFileRemovals_sample: rm.sample,\n            save_button_text: btn ? btn.innerText : '',\n            save_button_disabled: btn ? !!btn.disabled : null,\n            save_button_style: btn ? short(btn.getAttribute('style') || '', 300) : '',\n            in_flight: !!window.__saveConfigInFlight\n        };\n    }\n    function actionFromBody(body){ try { if (body && typeof body.get === 'function') return body.get('ti_action') || body.get('action') || ''; } catch(e) {} return ''; }\n    function fdSummary(body){\n        var out={keys:[], approx_chars:0, payload_keys:0};\n        try {\n            if (!body || typeof body.forEach !== 'function') return out;\n            body.forEach(function(v,k){\n                var sv=(typeof v==='string') ? v : (v && v.name ? '[file '+v.name+']' : '[object]');\n                out.payload_keys++;\n                out.keys.push(k + '=' + short(sv, 100));\n                out.approx_chars += String(sv).length;\n            });\n        } catch(e) { out.error=e.message||String(e); }\n        return out;\n    }\n    function isRelevantAction(act){ return \/ti_ai_save_config|ti_ai_save_full_db|ti_ai_config_delete_rows|ti_ai_file_meta_\/i.test(act || ''); }\n    if (nativeFetch && !window.fetch.__tiConfigDiag687Wrapped) {\n        var wrappedFetch=function(input, init){\n            var body=init && init.body ? init.body : null;\n            var act=actionFromBody(body);\n            var relevant=isRelevantAction(act);\n            var started=nowMs();\n            if (relevant) { if (!activeTrace) startTrace('ajax_'+act); log('20_ajax_start', {action:act, form:fdSummary(body)}, 'info'); }\n            return nativeFetch(input, init).then(function(resp){\n                if (relevant) {\n                    log('21_ajax_headers', {action:act, ok:!!resp.ok, status:resp.status, elapsed_ms:nowMs()-started, content_type:(resp.headers&&resp.headers.get?resp.headers.get('content-type'):'')}, resp.ok?'info':'warn');\n                    try {\n                        var clone=resp.clone();\n                        clone.text().then(function(t){ log('22_ajax_body_preview', {action:act, bytes:String(t||'').length, preview:short(t,360)}, resp.ok?'info':'warn'); }).catch(function(e){ log('22_ajax_body_preview_error', {action:act, message:e&&e.message}, 'warn'); });\n                    } catch(e) { log('22_ajax_clone_error', {action:act, message:e&&e.message}, 'warn'); }\n                }\n                return resp;\n            }).catch(function(err){\n                if (relevant || activeTrace) log('23_ajax_fetch_error', {action:act, elapsed_ms:nowMs()-started, name:err&&err.name, message:err&&err.message}, 'error');\n                throw err;\n            });\n        };\n        wrappedFetch.__tiConfigDiag687Wrapped=true;\n        window.fetch=wrappedFetch;\n    }\n    function wrapSaveConfig(){\n        if (typeof window.saveConfig !== 'function') return false;\n        if (window.saveConfig.__tiDiag687) return true;\n        var prev=window.saveConfig;\n        var saveWrap=function(){\n            if (!activeTrace) startTrace('saveConfig_wrapper'); else showPanel();\n            log('10_saveConfig_inizio', summarizeClient(), 'info');\n            var ret;\n            try {\n                ret=prev.apply(this, arguments);\n                log('11_saveConfig_return', {return_type:typeof ret, is_promise:!!(ret && typeof ret.then==='function')}, 'info');\n                if (ret && typeof ret.then==='function') ret.then(function(v){ log('12_saveConfig_resolved', {value:safeJson(v,400)}, 'info'); }).catch(function(e){ log('13_saveConfig_rejected', {message:e&&e.message, stack:short(e&&e.stack||'',1000)}, 'error'); });\n            } catch(e) {\n                log('14_saveConfig_exception', {message:e.message||String(e), stack:short(e.stack||'',1000)}, 'error');\n                throw e;\n            }\n            return ret;\n        };\n        saveWrap.__tiDiag687=true;\n        window.saveConfig=saveWrap;\n        return true;\n    }\n    function installSaveWrapperLoop(){\n        var tries=0;\n        wrapTimer=setInterval(function(){ tries++; if (wrapSaveConfig() || tries>80) { clearInterval(wrapTimer); wrapTimer=null; } }, 250);\n        wrapSaveConfig();\n    }\n    function looksLikeSaveButton(t){\n        if (!t) return false;\n        try { if (t.id === 'lbl-conf-save') return true; } catch(e) {}\n        try { return \/salva modifiche|salvataggio\/i.test(String(t.innerText || t.textContent || '')) && (t.tagName === 'BUTTON' || t.closest && t.closest('button')); } catch(e) { return false; }\n    }\n    document.addEventListener('click', function(ev){\n        var t=ev.target;\n        var btn=t && t.closest ? t.closest('button') : t;\n        if (looksLikeSaveButton(btn)) {\n            startTrace('click_capture_pulsante');\n            log('01_click_pulsante_salva', summarizeClient(), 'info');\n        }\n    }, true);\n    var lastBtnText='';\n    function monitorSaveButton(){\n        var btn=byId('lbl-conf-save');\n        var text=btn ? String(btn.innerText || '') : '';\n        if (text && text !== lastBtnText) {\n            lastBtnText=text;\n            if (\/salvataggio\/i.test(text)) { if (!activeTrace) startTrace('monitor_testo_salvataggio'); log('02_pulsante_in_salvataggio', summarizeClient(), 'info'); }\n            else if (activeTrace) log('30_pulsante_cambiato', summarizeClient(), 'info');\n        }\n        var saving=!!(btn && \/salvataggio\/i.test(String(btn.innerText || '')));\n        if ((saving || window.__saveConfigInFlight) && activeTrace) {\n            var n=nowMs();\n            if (!lastHeartbeat || n-lastHeartbeat>5000) { lastHeartbeat=n; log('40_heartbeat_salvataggio', summarizeClient(), saving?'warn':'info'); }\n        }\n    }\n    setInterval(function(){ if (activeTrace) monitorSaveButton(); }, 900);\n    \/\/ 30.9.1484: rimosso observer diagnostico globale; il controllo periodico opera solo durante una traccia attiva.\n    window.addEventListener('unhandledrejection', function(ev){ if (activeTrace) { var r=ev.reason||{}; log('98_unhandledrejection', {message:r.message||String(r), stack:short(r.stack||'',1000)}, 'error'); } });\n    window.addEventListener('error', function(ev){ if (activeTrace) log('99_window_error', {message:ev.message, file:ev.filename, line:ev.lineno, col:ev.colno}, 'error'); });\n    window.tiShowConfigSaveDiag687=function(){ if (!activeTrace) startTrace('manual_open'); else showPanel(); };\n    window.tiCopyConfigSaveDiag687=function(){ showPanel(); copyLog(); };\n    window.tiShowConfigSaveDiag686=window.tiShowConfigSaveDiag687;\n    window.tiCopyConfigSaveDiag686=window.tiCopyConfigSaveDiag687;\n    window.tiShowConfigSaveDiag685=window.tiShowConfigSaveDiag687;\n    window.tiCopyConfigSaveDiag685=window.tiCopyConfigSaveDiag687;\n    installSaveWrapperLoop();\n})();\n<\/script>\n\n\n\n<script id=\"ti-config-save-diagnostic-688\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveDiagnostic688Installed) return;\n    window.__tiConfigSaveDiagnostic688Installed = true;\n    if (!window.tiConfigSaveLogAllowed) {\n        window.tiShowConfigSaveDiag688 = function(){ return false; };\n        window.tiCopyConfigSaveDiag688 = function(){ return false; };\n        window.tiShowConfigSaveDiag687 = window.tiShowConfigSaveDiag688;\n        window.tiCopyConfigSaveDiag687 = window.tiCopyConfigSaveDiag688;\n        return;\n    }\n    var rows = [];\n    var seq = 0;\n    var started = 0;\n    var traceId = '';\n    var wrapping = false;\n    function now(){ return Date.now ? Date.now() : (new Date()).getTime(); }\n    function text(v){ return String(v == null ? '' : v); }\n    function short(v,n){ v=text(v); n=n||500; return v.length>n ? v.slice(0,n)+'...' : v; }\n    function id(x){ return document.getElementById(x); }\n    function esc(v){ return text(v).replace(\/[&<>\"']\/g,function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; }); }\n    function codeVersionLabel(){ var v=text(window.tiVersion || '30.9.925'); var d=text(window.tiVersionDateTime || '2026-07-06 18:35 CEST'); return (v+(d?' - '+d:'')); }\n    function db(){ var e=id('ti-ditta'); return e ? (e.value || '') : ''; }\n    function btn(){ return id('lbl-conf-save') || id('ti-conf-save') || null; }\n    function body(){ return document.body || document.documentElement; }\n    function ensureTrace(reason){\n        if (!traceId) {\n            traceId = 'diag688-' + (new Date()).toISOString().replace(\/[^0-9]\/g,'').slice(0,14) + '-' + Math.random().toString(36).slice(2,7);\n            started = now();\n            seq = 0;\n            rows = [];\n        }\n        showPanel();\n        if (reason) add('00_log_visibile', {reason:reason, db:db(), href:short(location.href,260)}, 'info', true);\n    }\n    function ensurePanel(){\n        var el=id('ti-config-save-diag-688');\n        if (el) return el;\n        el=document.createElement('div');\n        el.id='ti-config-save-diag-688';\n        el.setAttribute('role','dialog');\n        el.setAttribute('aria-live','polite');\n        el.setAttribute('style','position:fixed !important;left:50% !important;top:8px !important;transform:translateX(-50%) !important;width:min(1040px,calc(100vw - 12px)) !important;max-width:calc(100vw - 12px) !important;max-height:84vh !important;max-height:84dvh !important;z-index:2147483647 !important;background:#020617 !important;color:#e5e7eb !important;border:3px solid #facc15 !important;border-radius:14px !important;box-shadow:0 24px 80px rgba(0,0,0,.82) !important;font:11px\/1.38 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace !important;display:none;overflow:hidden !important;pointer-events:auto !important;box-sizing:border-box !important;');\n        el.innerHTML = '<div style=\"display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:8px 9px;background:#111827;border-bottom:1px solid #475569;\">'\n            + '<b style=\"color:#fde68a;font-size:13px;white-space:nowrap;\">Log salvataggio configurazione<\/b>'\n            + '<span id=\"ti-config-save-diag-version-688\" class=\"ti-diag688-extra\" style=\"color:#93c5fd;font-size:10px;white-space:nowrap;\">Versione codice: '+esc(codeVersionLabel())+'<\/span>'\n            + '<span class=\"ti-diag688-extra\" style=\"color:#93c5fd;font-size:10px;\">apertura immediata inline\/click\/touch<\/span>'\n            + '<span id=\"ti-config-save-diag-status-688\" style=\"margin-left:auto;color:#bbf7d0;font-size:10px;white-space:nowrap;\"><\/span>'\n            + '<button type=\"button\" id=\"ti-config-save-diag-copy-688\" style=\"font-size:10px;padding:4px 7px;border-radius:7px;border:1px solid #475569;background:#1d4ed8;color:#fff;cursor:pointer;white-space:nowrap;\">Copia<\/button>'\n            + '<button type=\"button\" id=\"ti-config-save-diag-clear-688\" style=\"font-size:10px;padding:4px 7px;border-radius:7px;border:1px solid #475569;background:#334155;color:#fff;cursor:pointer;white-space:nowrap;\">Pulisci<\/button>'\n            + '<button type=\"button\" id=\"ti-config-save-diag-close-688\" style=\"font-size:10px;padding:4px 7px;border-radius:7px;border:1px solid #475569;background:#7f1d1d;color:#fff;cursor:pointer;white-space:nowrap;\">Chiudi<\/button>'\n            + '<\/div>'\n            + '<div id=\"ti-config-save-diag-summary-688\" style=\"padding:7px 9px;border-bottom:1px solid #1e293b;background:#07111f;color:#cbd5e1;font-size:11px;\"><\/div>'\n            + '<pre id=\"ti-config-save-diag-body-688\" style=\"white-space:pre-wrap;word-break:break-word;margin:0;padding:9px;overflow:auto;max-height:calc(84vh - 88px);max-height:calc(84dvh - 88px);background:#020617;color:#e5e7eb;box-sizing:border-box;\"><\/pre>'\n            + '<style>@media (max-width:520px){ .ti-diag688-extra{display:none;} }<\/style>';\n        body().appendChild(el);\n        var c=id('ti-config-save-diag-copy-688'); if(c) c.onclick=copy;\n        var cl=id('ti-config-save-diag-clear-688'); if(cl) cl.onclick=function(){ rows=[]; seq=0; render(); };\n        var x=id('ti-config-save-diag-close-688'); if(x) x.onclick=function(){ el.style.setProperty('display','none','important'); };\n        return el;\n    }\n    function showPanel(forceVisible){\n        var el=ensurePanel();\n        \/\/ 30.9.1363: il pannello non si apre piu' automaticamente ad ogni salvataggio (era troppo invasivo) -\n        \/\/ i dati vengono comunque registrati in background (render() aggiorna sempre il contenuto), ma la\n        \/\/ visualizzazione va richiesta esplicitamente tramite il nuovo pulsante dedicato \"Log salvataggio\".\n        if (forceVisible || window.__tiSaveDiagForceVisible1363) {\n            try { el.style.setProperty('display','block','important'); el.style.setProperty('visibility','visible','important'); el.style.setProperty('opacity','1','important'); } catch(e) {}\n        }\n        render();\n    }\n    function summary(){\n        var b=btn();\n        var rem=[]; try{ rem=Array.isArray(window.pendingLinkedFileRemovals) ? window.pendingLinkedFileRemovals : []; }catch(e){}\n        var mfCount=0; try{ if(window.modifiedFields && typeof window.modifiedFields.forEach==='function') window.modifiedFields.forEach(function(){mfCount++;}); }catch(e){}\n        return {db:db(), buttonText:b?b.innerText:'(non trovato)', disabled:b?!!b.disabled:null, savingAttr:b?b.getAttribute('data-ti-saving'):'', inFlight:!!window.__saveConfigInFlight, modifiedFields:mfCount, removals:rem.length};\n    }\n    function render(){\n        var st=id('ti-config-save-diag-status-688'), sm=id('ti-config-save-diag-summary-688'), pr=id('ti-config-save-diag-body-688');\n        if(st) st.textContent=traceId || 'in attesa';\n        var ver=id('ti-config-save-diag-version-688'); if(ver) ver.textContent='Versione codice: '+codeVersionLabel();\n        var s=summary();\n        if(sm) sm.innerHTML='Versione codice: <b>'+esc(codeVersionLabel())+'<\/b> | DB: <b>'+esc(s.db||'(non selezionato)')+'<\/b> | Pulsante: <b>'+esc(s.buttonText)+'<\/b> | disabled: <b>'+esc(String(s.disabled))+'<\/b> | inFlight: <b>'+esc(String(s.inFlight))+'<\/b> | modifiedFields: <b>'+esc(String(s.modifiedFields))+'<\/b> | rimozioni file: <b>'+esc(String(s.removals))+'<\/b>';\n        if(pr){\n            var detail = rows.map(function(r){ var d=''; try{ d=JSON.stringify(r.detail||{}); }catch(e){ d=text(r.detail); } return '['+String(r.seq).padStart(3,'0')+'] +'+String(r.ms).padStart(6,' ')+'ms '+r.level.toUpperCase().padEnd(5,' ')+' '+r.event+(d && d!=='{}' ? ' '+d : ''); }).join('\\n');\n            pr.textContent = 'Versione codice: '+codeVersionLabel()+'\\nTrace: '+(traceId || 'in attesa')+'\\n--- Dettaglio log ---\\n'+detail;\n            pr.scrollTop=pr.scrollHeight;\n        }\n    }\n    function add(event, detail, level, noRender){\n        level=level||'info';\n        if(!traceId){ traceId='diag688-'+(new Date()).toISOString().replace(\/[^0-9]\/g,'').slice(0,14)+'-'+Math.random().toString(36).slice(2,7); started=now(); }\n        rows.push({seq:++seq, ms:Math.max(0,now()-started), event:event, level:level, detail:detail||{}});\n        if(rows.length>360) rows.splice(0, rows.length-360);\n        try{ (level==='error'?console.error:(level==='warn'?console.warn:console.log))('[Shop-Service save diag 688]', rows[rows.length-1]); }catch(e){}\n        if(!noRender) showPanel();\n    }\n    function copy(){\n        showPanel();\n        var pr=id('ti-config-save-diag-body-688');\n        var t=pr ? pr.textContent : JSON.stringify(rows,null,2); if(t.indexOf('Versione codice:')!==0) t='Versione codice: '+codeVersionLabel()+'\\nTrace: '+(traceId || 'in attesa')+'\\n--- Dettaglio log ---\\n'+t;\n        function done(ok){ var b=id('ti-config-save-diag-copy-688'); if(b){ var old=b.textContent; b.textContent=ok?'Copiato':'Copia manuale'; setTimeout(function(){ b.textContent=old||'Copia testo'; },1300); } }\n        if(navigator.clipboard && navigator.clipboard.writeText){ navigator.clipboard.writeText(t).then(function(){done(true);}).catch(fallback); } else fallback();\n        function fallback(){ var ta=document.createElement('textarea'); ta.value=t; body().appendChild(ta); ta.select(); var ok=false; try{ ok=document.execCommand('copy'); }catch(e){} ta.parentNode.removeChild(ta); done(ok); }\n    }\n    function looksSave(el){\n        if(!el) return false;\n        var b=el.closest ? el.closest('button') : el;\n        if(!b) return false;\n        if(b.id==='lbl-conf-save') return true;\n        var t=text(b.innerText || b.textContent || '').toLowerCase();\n        return (b.tagName==='BUTTON') && (t.indexOf('salva modifiche')>=0 || t.indexOf('salvataggio')>=0);\n    }\n    function preEvent(kind, ev){\n        var target=ev && ev.target ? ev.target : null;\n        if(looksSave(target)){\n            ensureTrace(kind);\n            add('01_evento_pulsante_'+kind, summary(), 'info');\n        }\n    }\n    ['pointerdown','mousedown','touchstart','click'].forEach(function(k){\n        try{ document.addEventListener(k, function(ev){ preEvent(k,ev); }, true); }catch(e){}\n    });\n    window.tiShowConfigSaveDiag688=function(reason){ ensureTrace(reason || 'manuale'); add('02_apertura_manuale_o_inline', summary(), 'info'); };\n    window.tiCopyConfigSaveDiag688=function(){ ensureTrace('copy_manual'); copy(); };\n    window.tiShowConfigSaveDiag687=window.tiShowConfigSaveDiag688;\n    window.tiCopyConfigSaveDiag687=window.tiCopyConfigSaveDiag688;\n    function wrapSave(){\n        if(wrapping) return;\n        try{\n            var fn=window.saveConfig;\n            if(typeof fn==='function' && !fn.__tiDiag688){\n                var w=function(){\n                    ensureTrace('saveConfig_wrapper');\n                    add('10_saveConfig_chiamata', summary(), 'info');\n                    var ret;\n                    try{ ret=fn.apply(this, arguments); add('11_saveConfig_return', {returnType:typeof ret, promise:!!(ret&&typeof ret.then==='function')}, 'info'); }\n                    catch(e){ add('12_saveConfig_exception', {message:e&&e.message, stack:short(e&&e.stack,1200)}, 'error'); throw e; }\n                    if(ret && typeof ret.then==='function') ret.then(function(v){ add('13_saveConfig_resolved', {value:short(JSON.stringify(v||{}),600)}, 'info'); }).catch(function(e){ add('14_saveConfig_rejected', {message:e&&e.message, stack:short(e&&e.stack,1200)}, 'error'); });\n                    return ret;\n                };\n                w.__tiDiag688=true;\n                wrapping=true; window.saveConfig=w; wrapping=false;\n                add('05_saveConfig_wrapped', {ok:true}, 'info');\n            }\n        } catch(e){ wrapping=false; try{ add('05_saveConfig_wrap_error', {message:e&&e.message}, 'warn'); }catch(_){} }\n    }\n    setInterval(wrapSave, 300);\n    wrapSave();\n    if(window.fetch && !window.fetch.__tiDiag688){\n        var nativeFetch=window.fetch.bind(window);\n        var wf=function(input, init){\n            var act='';\n            try{ var body=init&&init.body; if(body&&typeof body.get==='function') act=body.get('ti_action')||body.get('action')||''; }catch(e){}\n            var rel=\/ti_ai_save_config|ti_ai_save_full_db|ti_ai_config_delete_rows|ti_ai_file_meta\/i.test(act);\n            var st=now();\n            if(rel){ ensureTrace('ajax_'+act); add('20_ajax_start', {action:act}, 'info'); }\n            return nativeFetch(input, init).then(function(r){ if(rel) add('21_ajax_headers', {action:act, status:r.status, ok:r.ok, elapsed:now()-st, contentType:(r.headers&&r.headers.get?r.headers.get('content-type'):'')}, r.ok?'info':'warn'); return r; }).catch(function(e){ if(rel||traceId) add('22_ajax_error', {action:act, elapsed:now()-st, message:e&&e.message, name:e&&e.name}, 'error'); throw e; });\n        };\n        wf.__tiDiag688=true; window.fetch=wf;\n    }\n    setInterval(function(){\n        var b=btn();\n        if(!b) return;\n        var t=text(b.innerText||'');\n        if(\/salvataggio\/i.test(t) || b.disabled || b.getAttribute('data-ti-saving')==='1' || window.__saveConfigInFlight){\n            ensureTrace('monitor_salvataggio');\n            add('30_monitor_salvataggio_visibile', summary(), \/salvataggio\/i.test(t)?'warn':'info');\n        } else if(traceId) {\n            render();\n        }\n    }, 1200);\n    \/\/ 30.9.1363: apertura manuale del pannello su richiesta, richiamabile dal nuovo pulsante dedicato.\n    window.tiOpenSaveDiagPanel1363 = function(){ showPanel(true); };\n})();\n<\/script>\n\n<script id=\"ti-config-save-diag-copy-689\">\n(function(){\n    if (window.__tiConfigSaveDiagCopy689) return;\n    window.__tiConfigSaveDiagCopy689 = true;\n    if (!window.tiConfigSaveLogAllowed) return;\n    function id(x){ return document.getElementById(x); }\n    function txt(v){ return (v==null?'':String(v)); }\n    function trim(v){ return txt(v).replace(\/^\\s+|\\s+$\/g,''); }\n    function panel(){ return id('ti-config-save-diag-panel-688') || id('ti-config-save-diag-panel-687') || null; }\n    function bodyPre(){ return id('ti-config-save-diag-body-688') || id('ti-config-save-diag-body-687') || null; }\n    function summaryEl(){ return id('ti-config-save-diag-summary-688') || id('ti-config-save-diag-summary-687') || null; }\n    function statusEl(){ return id('ti-config-save-diag-status-688') || id('ti-config-save-diag-status-687') || null; }\n    function versionLabel(){\n        var v = txt(window.tiVersion || '30.9.925');\n        var d = txt(window.tiVersionDateTime || '2026-07-06 18:35 CEST');\n        return trim(v + (d ? ' - ' + d : ''));\n    }\n    function getLogText(){\n        var pre = bodyPre();\n        var log = pre ? trim(pre.textContent || pre.innerText || '') : '';\n        var sm = summaryEl();\n        var st = statusEl();\n        var header = [];\n        header.push('Log salvataggio configurazione - Shop & Service');\n        header.push('Versione codice: ' + versionLabel());\n        header.push('Data copia: ' + (new Date()).toISOString());\n        if (st && trim(st.textContent || st.innerText || '')) header.push('Trace: ' + trim(st.textContent || st.innerText || ''));\n        if (sm && trim(sm.textContent || sm.innerText || '')) header.push('Riepilogo: ' + trim(sm.textContent || sm.innerText || '').replace(\/\\s+\/g,' '));\n        header.push('');\n        header.push('--- Dettaglio log ---');\n        if (!log) {\n            log = '[nessuna riga log visibile nel popup al momento della copia]';\n            try {\n                var b = id('lbl-conf-save');\n                log += '\\nPulsante Salva: ' + (b ? trim(b.innerText || b.textContent || '') : '(non trovato)');\n                log += '\\nPulsante disabled: ' + (b ? String(!!b.disabled) : 'n\/d');\n                log += '\\nwindow.__saveConfigInFlight: ' + String(!!window.__saveConfigInFlight);\n                var mf = 0;\n                if (window.modifiedFields && typeof window.modifiedFields.forEach === 'function') window.modifiedFields.forEach(function(){ mf++; });\n                log += '\\nmodifiedFields count: ' + mf;\n                log += '\\npendingLinkedFileRemovals count: ' + (Array.isArray(window.pendingLinkedFileRemovals) ? window.pendingLinkedFileRemovals.length : 'n\/d');\n            } catch(e) { log += '\\nErrore raccolta stato: ' + (e && e.message ? e.message : e); }\n        }\n        return header.join('\\n') + '\\n' + log + '\\n';\n    }\n    function ensureBuffer(text){\n        var host = panel() || document.body;\n        var ta = id('ti-config-save-diag-copy-buffer-689');\n        if (!ta) {\n            ta = document.createElement('textarea');\n            ta.id = 'ti-config-save-diag-copy-buffer-689';\n            ta.setAttribute('aria-label', 'Testo log salvataggio configurazione da copiare');\n            ta.style.cssText = 'display:block !important;width:calc(100% - 18px) !important;min-height:92px !important;max-height:180px !important;margin:8px 9px !important;padding:8px !important;border:1px solid #38bdf8 !important;border-radius:8px !important;background:#0f172a !important;color:#e5e7eb !important;font:11px\/1.35 monospace !important;white-space:pre !important;z-index:2147483647 !important;';\n            var sm = summaryEl();\n            if (sm && sm.parentNode) sm.parentNode.insertBefore(ta, sm.nextSibling);\n            else host.appendChild(ta);\n        }\n        ta.value = text || '';\n        try { ta.removeAttribute('readonly'); ta.focus({preventScroll:true}); ta.select(); ta.setSelectionRange(0, ta.value.length); } catch(e) {}\n        return ta;\n    }\n    function setButtonState(btn, ok, manual, n){\n        if (!btn || !btn.getAttribute) return;\n        var old = btn.getAttribute('data-ti-old-copy-label-689') || btn.textContent || 'Copia testo';\n        btn.setAttribute('data-ti-old-copy-label-689', old);\n        btn.textContent = ok ? ('Log copiato (' + String(n || 0) + ' car.)') : (manual ? 'Copia manuale: testo selezionato' : 'Copia non riuscita');\n        setTimeout(function(){ try { btn.textContent = old || 'Copia testo'; } catch(e){} }, ok ? 1800 : 2600);\n    }\n    function doCopy(btn){\n        var text = getLogText();\n        var ta = ensureBuffer(text);\n        var n = text.length;\n        var execOk = false;\n        try { execOk = document.execCommand && document.execCommand('copy'); } catch(e) { execOk = false; }\n        if (execOk) { setButtonState(btn, true, false, n); return; }\n        if (navigator.clipboard && navigator.clipboard.writeText) {\n            navigator.clipboard.writeText(text).then(function(){\n                setButtonState(btn, true, false, n);\n            }).catch(function(){\n                try { ta.focus({preventScroll:true}); ta.select(); ta.setSelectionRange(0, ta.value.length); } catch(e) {}\n                setButtonState(btn, false, true, n);\n            });\n        } else {\n            setButtonState(btn, false, true, n);\n        }\n    }\n    function isDiagCopyButton(el){\n        if (!el) return null;\n        var b = el.closest ? el.closest('button') : el;\n        if (!b || !b.id) return null;\n        return (b.id === 'ti-config-save-diag-copy-688' || b.id === 'ti-config-save-diag-copy-687') ? b : null;\n    }\n    document.addEventListener('click', function(ev){\n        var b = isDiagCopyButton(ev && ev.target);\n        if (!b) return;\n        try { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        doCopy(b);\n    }, true);\n    window.tiCopyConfigSaveDiag689 = function(){ doCopy(id('ti-config-save-diag-copy-688') || id('ti-config-save-diag-copy-687')); };\n    window.tiCopyConfigSaveDiag688 = window.tiCopyConfigSaveDiag689;\n    window.tiCopyConfigSaveDiag687 = window.tiCopyConfigSaveDiag689;\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-direct-691\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveDirect691Installed) return;\n    window.__tiConfigSaveDirect691Installed = true;\n    function id(x){ return document.getElementById(x); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\n    function clone(o){ try { return JSON.parse(JSON.stringify(o || {})); } catch(e) { return {}; } }\n    function enc(obj){ var json = JSON.stringify(obj || []); if (typeof window.utoa === 'function') return window.utoa(json); return btoa(unescape(encodeURIComponent(json))); }\n    function btn(){ return id('lbl-conf-save'); }\n    function log691(event, detail, level){\n        if(!window.tiConfigSaveLogAllowed) return;\n        try {\n            level = level || 'info';\n            var pre = id('ti-config-save-diag-body-688') || id('ti-config-save-diag-body-687');\n            var arr = window.__tiConfigSaveDiagLog688 || window.__tiConfigSaveDiagLog687;\n            var seq = 1, ms = 0;\n            if (Array.isArray(arr)) {\n                seq = arr.length + 1;\n                try { var first = arr[0]; ms = first && first.ts ? Math.max(0, Date.now() - Date.parse(first.ts)) : 0; } catch(e) {}\n                arr.push({seq:seq, ts:(new Date()).toISOString(), ms:ms, trace_id:'diag691', event:event, level:level, detail:detail||{}});\n            } else if (pre) {\n                var lines = txt(pre.textContent || '').split('\\n').filter(Boolean).length;\n                seq = lines + 1;\n            }\n            var d=''; try { d=JSON.stringify(detail||{}); } catch(e) { d=txt(detail); }\n            var line='['+String(seq).padStart(3,'0')+'] +'+String(ms).padStart(6,' ')+'ms '+level.toUpperCase().padEnd(5,' ')+' '+event+(d && d!=='{}' ? ' '+d : '');\n            if (pre) { pre.textContent = (txt(pre.textContent||'') ? txt(pre.textContent||'')+'\\n' : '') + line; pre.scrollTop = pre.scrollHeight; }\n            var sm = id('ti-config-save-diag-summary-688') || id('ti-config-save-diag-summary-687');\n            if (sm) { var b=btn(); sm.innerHTML = 'DB: <b>'+txt(id('ti-ditta')?id('ti-ditta').value:'')+'<\/b> | Pulsante: <b>'+txt(b?b.innerText:'')+'<\/b> | direct 691 | evento: <b>'+txt(event)+'<\/b>'; }\n            try { (level==='error'?console.error:(level==='warn'?console.warn:console.log))('[Shop-Service save direct 691]', line, detail||{}); } catch(e) {}\n        } catch(e) {}\n    }\n    function clearBusy(){\n        try { window.__tiConfigSaveActive675=false; window.__tiConfigSaveActive677=false; window.__tiConfigSaveActive678=false; window.__tiConfigSaveActive682=false; window.__tiConfigSaveActive683=false; window.__tiConfigSaveActive684=false; window.__tiConfigSaveActive691=false; window.__saveConfigInFlight=false; } catch(e) {}\n        try { window.__tiSaveConfigStartedAt=0; window.__tiSaveConfigStartedAt585=0; window.__tiSaveConfigStartedAt675=0; } catch(e) {}\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n        try { qsa('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(x){ if (x && x.parentNode) x.parentNode.removeChild(x); }); } catch(e) {}\n    }\n    function setSaving(){ var b=btn(); if(!b) return; b.disabled=true; b.setAttribute('data-ti-saving','1'); b.setAttribute('aria-busy','true'); b.style.pointerEvents='none'; b.innerText='Salvataggio...'; try{ b.style.setProperty('background','#d97706','important'); b.style.setProperty('background-color','#d97706','important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','wait','important'); }catch(e){} }\n    function resetButton(clean){\n        if (clean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') { try { window.modifiedFields.clear(); } catch(e){} }\n        clearBusy();\n        var b=btn(); if(!b) return;\n        var dirty = !!(!clean && window.modifiedFields && window.modifiedFields.size>0);\n        b.disabled=false; try{ b.removeAttribute('disabled'); b.removeAttribute('data-ti-saving'); b.removeAttribute('aria-busy'); }catch(e){}\n        b.style.pointerEvents=''; b.innerText = dirty ? 'Salva Modifiche *' : 'Salva Modifiche';\n        try{ b.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','pointer','important'); }catch(e){}\n    }\n    function readVal(el){ if(!el) return ''; if(el.tagName==='SELECT' && el.multiple) return Array.prototype.slice.call(el.selectedOptions||[]).map(function(o){return txt(o.value).trim();}).filter(Boolean).join(', '); if(el.type==='checkbox') return el.checked ? (el.value || '1') : ''; return el.value == null ? '' : el.value; }\n    function resolveTable(t){ try { return window.resolveConfigTableName ? (window.resolveConfigTableName(t)||t) : t; } catch(e) { return t; } }\n    function ensureArrays(){ var d=window.currentDbData; if(!d || !d.Tabelle) return; Object.keys(d.Tabelle).forEach(function(t){ if(!Array.isArray(d.Tabelle[t])) d.Tabelle[t]=Object.values(d.Tabelle[t]||{}); }); }\n    function syncVisible(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        ensureArrays();\n        var d=window.currentDbData; if(!d || !d.Tabelle) return;\n        var sel='#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        qsa(sel).forEach(function(input){\n            if(!input || input.disabled || input.readOnly) return;\n            var tbl=input.getAttribute('data-tbl')||'', key=input.getAttribute('data-key')||'', idx=parseInt(input.getAttribute('data-idx')||'',10);\n            if(!tbl || !key || isNaN(idx)) return;\n            var rt=resolveTable(tbl); if(!d.Tabelle[rt]) d.Tabelle[rt]=[]; if(!d.Tabelle[rt][idx] || typeof d.Tabelle[rt][idx] !== 'object') d.Tabelle[rt][idx]={};\n            var val=readVal(input); try { if (window.normalizeInputValueForKey) val=window.normalizeInputValueForKey(key,val); } catch(e) {}\n            if(txt(d.Tabelle[rt][idx][key]) !== txt(val)) { d.Tabelle[rt][idx][key]=val; if(!window.modifiedFields) window.modifiedFields=new Set(); try { window.modifiedFields.add(rt+'-'+idx+'-'+key); } catch(e) {} }\n        });\n        try { if (window.tiApplyPendingLinkedFileRemovals676) window.tiApplyPendingLinkedFileRemovals676(); } catch(e) {}\n        try { if (window.normalizeAllConfigStateValues) window.normalizeAllConfigStateValues(); } catch(e) {}\n    }\n    function addChange(out, seen, table, row, key, value){ if(!table || row<0 || !key || String(key).indexOf('__')===0) return false; if(value && typeof value==='object') return false; var sig=table+'\\u0001'+row+'\\u0001'+key; if(seen[sig]) return true; seen[sig]=true; out.push({table:table,row:row,key:key,value:(value==null?'':String(value))}); return true; }\n    function buildChanges(){\n        ensureArrays();\n        var cur=(window.currentDbData&&window.currentDbData.Tabelle)?window.currentDbData.Tabelle:{};\n        var old=(window.configOriginalDbData&&window.configOriginalDbData.Tabelle)?window.configOriginalDbData.Tabelle:{};\n        var changes=[], seen={}, fullNeeded=false;\n        var all={}; Object.keys(cur||{}).forEach(function(t){all[t]=true;}); Object.keys(old||{}).forEach(function(t){all[t]=true;});\n        Object.keys(all).forEach(function(t){\n            var cr=Array.isArray(cur[t])?cur[t]:Object.values(cur[t]||{}), or=Array.isArray(old[t])?old[t]:Object.values(old[t]||{});\n            if(cr.length!==or.length){ fullNeeded=true; return; }\n            for(var i=0;i<cr.length;i++){\n                var a=cr[i]||{}, b=or[i]||{}; if(!a || typeof a!=='object' || !b || typeof b!=='object'){ fullNeeded=true; return; }\n                var keys={}; Object.keys(a).forEach(function(k){keys[k]=true;}); Object.keys(b).forEach(function(k){keys[k]=true;});\n                Object.keys(keys).forEach(function(k){ var av=(a[k]==null?'':a[k]), bv=(b[k]==null?'':b[k]); var same=false; try{ same=JSON.stringify(av)===JSON.stringify(bv); if(!same){ var avn=parseFloat(av), bvn=parseFloat(bv); if(!isNaN(avn) && !isNaN(bvn) && String(avn)===String(av).trim() && String(bvn)===String(bv).trim()){ same=(avn===bvn); } else { same=(String(av)===String(bv)); } } }catch(e){ same=txt(av)===txt(bv); } if(!same){ if(!addChange(changes,seen,t,i,k,av)) fullNeeded=true; } });\n            }\n        });\n        try { if((window.tiConfigDeletedRowsManifest||[]).length || Object.keys(window.tiConfigDeletedTableSnapshots||{}).length || parseInt(window.tiConfigDeletedRowsCountTotal||0,10)>0) fullNeeded=true; } catch(e) {}\n        if(changes.length>250) fullNeeded=true;\n        return {changes:changes, fullNeeded:fullNeeded};\n    }\n    function postFields691(db, changes){\n        return new Promise(function(resolve,reject){\n            var fd=new FormData(); fd.append('ti_action','ti_ai_save_config_fields_691'); fd.append('action','ti_ai_save_config_fields_691'); fd.append('db',db); fd.append('changes',enc(changes)); fd.append('field_save_691','1');\n            try { if(window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n            \/\/ 30.9.1701: start\/status\/cancel\/preflight del batch immagini usano sempre il router diretto della pagina,\n            \/\/ evitando admin-ajax.php che su questo hosting ha gia mostrato timeout\/500 durante processi lunghi.\n            var url=\/^ti_ai_batch706_(?:preflight_1701|start_job|get_status|cancel_job)$\/.test(String(action||'')) ? window.location.href.split('?')[0] : (window.tiUrl || window.tiAjaxUrl || window.location.href.split('?')[0]);\n            var xhr=new XMLHttpRequest();\n            var done=false;\n            var finish=function(ok, payload){ if(done) return; done=true; ok ? resolve(payload) : reject(payload); };\n            xhr.open('POST', url, true);\n            xhr.timeout=25000;\n            xhr.withCredentials=true;\n            xhr.onreadystatechange=function(){\n                if(xhr.readyState!==4) return;\n                var raw=xhr.responseText || '';\n                log691('691_xhr_complete', {status:xhr.status, raw_prefix:raw.slice(0,180)}, xhr.status>=200 && xhr.status<300 ? 'info' : 'error');\n                if(xhr.status<200 || xhr.status>=300) return finish(false, new Error('Errore server '+xhr.status+': '+raw.slice(0,220)));\n                var data=null; try { data=JSON.parse(raw); } catch(e) { return finish(false, new Error('Risposta salvataggio non JSON: '+raw.slice(0,220))); }\n                finish(true, data);\n            };\n            xhr.ontimeout=function(){ log691('691_xhr_timeout', {timeout_ms:xhr.timeout}, 'error'); finish(false, new Error('Timeout salvataggio configurazione 691. Salvataggio non confermato dal server.')); };\n            xhr.onerror=function(){ log691('691_xhr_error', {}, 'error'); finish(false, new Error('Errore rete durante salvataggio configurazione 691.')); };\n            log691('691_xhr_start', {action:'ti_ai_save_config_fields_691', changes:changes.length}, 'info');\n            xhr.send(fd);\n        });\n    }\n    var previousSave = window.saveConfig;\n    window.saveConfig = function(){\n        if(!window.currentDbData || !window.currentDbData.Tabelle){ resetButton(false); if(window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.'); return; }\n        var dbEl=id('ti-ditta'), db=dbEl?(dbEl.value||''):''; if(!db || db==='NEW_DB' || db==='Global'){ resetButton(false); if(window.tiAlert) window.tiAlert('Seleziona ditta.'); return; }\n        clearBusy(); setSaving(); window.__tiConfigSaveActive691=true; window.__saveConfigInFlight=true; window.__tiSaveConfigStartedAt=Date.now?Date.now():(new Date()).getTime();\n        var built;\n        try { syncVisible(); built=buildChanges(); } catch(e){ resetButton(false); if(window.tiAlert) window.tiAlert('Errore preparazione salvataggio: '+(e.message||e)); return; }\n        log691('691_build_changes', {changes:built.changes.length, fullNeeded:built.fullNeeded}, 'info');\n        if(!built.changes.length && !built.fullNeeded){ resetButton(true); if(window.tiAlert) window.tiAlert('Nessuna modifica da salvare.'); return; }\n        if(built.fullNeeded){\n            resetButton(false);\n            if (typeof previousSave === 'function') {\n                log691('691_fallback_full_save_previous', {}, 'warn');\n                return previousSave.apply(this, arguments);\n            }\n            if(window.tiAlert) window.tiAlert('Modifica strutturale rilevata: usa il salvataggio completo dopo aver ricaricato la configurazione.');\n            return;\n        }\n        postFields691(db,built.changes).then(function(res){\n            if(!res || !res.success) throw new Error((res&&res.data&&res.data.message)?res.data.message:'Salvataggio configurazione non riuscito.');\n            var data=res.data||{};\n            if(window.currentDbData && data.db_version) window.currentDbData.__db_version=data.db_version;\n            try { if(window.currentDbData) window.configOriginalDbData=clone(window.currentDbData); } catch(e) {}\n            try { if(window.modifiedFields && typeof window.modifiedFields.clear==='function') window.modifiedFields.clear(); } catch(e) {}\n            window.pendingLinkedFileRemovals=[]; window.tiConfigDeletedRowsManifest=[]; window.tiConfigDeletedTableSnapshots={}; window.tiConfigDeletedRowsCountTotal=0; try { if(window.tiConfigStructuralChangedTables1907 && typeof window.tiConfigStructuralChangedTables1907.clear==='function') window.tiConfigStructuralChangedTables1907.clear(); } catch(e1907) {}\n            resetButton(true);\n            log691('691_save_success', {changes_applied:data.changes_applied, elapsed_ms:data.elapsed_ms, mode:data.mode}, 'info');\n            if(window.tiAlert) window.tiAlert('\u2705 Salvataggio configurazione completato.');\n        }).catch(function(err){\n            resetButton(false);\n            var msg=(err&&err.message)?err.message:'Errore durante il salvataggio configurazione.';\n            log691('691_save_error', {message:msg}, 'error');\n            if(window.tiAlert) window.tiAlert(msg); else alert(msg);\n        }).finally(function(){\n            window.__tiConfigSaveActive691=false; window.__saveConfigInFlight=false; clearBusy();\n            var b=btn(); if(b && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving')==='1')) resetButton(false);\n        });\n    };\n    window.tiForceUnlockConfigSave691=function(reason){ resetButton(false); if(reason && window.tiAlert) window.tiAlert(reason); };\n    \/\/ 30.9.1427: rimosso lo stesso controllo periodico orfano, versione 691 - stesse motivazioni della 678.\n})();\n<\/script>\n\n\n<script id=\"ti-config-save-direct-692\">\n(function(){\n    \"use strict\";\n    if (window.__tiConfigSaveDirect692Installed) return;\n    window.__tiConfigSaveDirect692Installed = true;\n\n    function id(x){ return document.getElementById(x); }\n    function txt(v){ return String(v == null ? '' : v); }\n    function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\n    function clone(o){ try { return JSON.parse(JSON.stringify(o || {})); } catch(e) { return {}; } }\n    function enc(obj){ var json = JSON.stringify(obj || []); if (typeof window.utoa === 'function') return window.utoa(json); return btoa(unescape(encodeURIComponent(json))); }\n    function saveButton(){ return id('lbl-conf-save'); }\n    function dbName(){ var e = id('ti-ditta'); return e ? (e.value || '') : ''; }\n    function dirtySignal699(){\n        var mf=0, rem=0, del=0, star=false, pendingRows1911=0;\n        try { mf = window.modifiedFields && typeof window.modifiedFields.size === 'number' ? window.modifiedFields.size : 0; } catch(e) { mf = 0; }\n        try { var p1911=window.tiConfigPendingNewRows1910||{};Object.keys(p1911).forEach(function(t){if(Array.isArray(p1911[t]))pendingRows1911+=p1911[t].length;}); } catch(e) { pendingRows1911=0; }\n        try { rem = Array.isArray(window.pendingLinkedFileRemovals) ? window.pendingLinkedFileRemovals.length : 0; } catch(e) { rem = 0; }\n        try { del += (window.tiConfigDeletedRowsManifest||[]).length || 0; } catch(e) {}\n        try { del += Object.keys(window.tiConfigDeletedTableSnapshots||{}).length || 0; } catch(e) {}\n        try { del += parseInt(window.tiConfigDeletedRowsCountTotal||0,10) || 0; } catch(e) {}\n        try { var b=saveButton(); star = !!(b && \/\\*\/.test(txt(b.innerText||b.textContent||''))); } catch(e) { star=false; }\n        var snapshotDiff1516=false, shadowDel1516=0;\n        try {\n            var cur1516=(window.currentDbData&&window.currentDbData.Tabelle)?window.currentDbData.Tabelle:{};\n            var old1516=(window.configOriginalDbData&&window.configOriginalDbData.Tabelle)?window.configOriginalDbData.Tabelle:{};\n            var all1516={}; Object.keys(cur1516||{}).forEach(function(t){all1516[t]=1;}); Object.keys(old1516||{}).forEach(function(t){all1516[t]=1;});\n            Object.keys(all1516).some(function(t){\n                var a1516=Array.isArray(cur1516[t])?cur1516[t]:Object.values(cur1516[t]||{}), b1516=Array.isArray(old1516[t])?old1516[t]:Object.values(old1516[t]||{});\n                if(a1516.length!==b1516.length){snapshotDiff1516=true; return true;}\n                return false;\n            });\n        } catch(e1516diff) {}\n        try { shadowDel1516 = window.__tiDeletedRowsShadow1516 && Array.isArray(window.__tiDeletedRowsShadow1516.manifest) ? window.__tiDeletedRowsShadow1516.manifest.length : 0; } catch(e1516sd) {}\n        return {dirty: !!(mf || rem || del || star || snapshotDiff1516 || shadowDel1516 || pendingRows1911), modifiedFields:mf, removals:rem, deleted:del, star:star, snapshotDiff1516:snapshotDiff1516, shadowDeleted1516:shadowDel1516, pendingRows1911:pendingRows1911};\n    }\n    function isSaveButton(el){ var b = el && el.closest ? el.closest('button') : el; return !!(b && b.id === 'lbl-conf-save'); }\n    function hasDiag(){ return !!(id('ti-config-save-diag-body-688') || id('ti-config-save-diag-body-687')); }\n    function showDiag(reason){ if(!window.tiConfigSaveLogAllowed) return; try { if (window.tiShowConfigSaveDiag688) window.tiShowConfigSaveDiag688(reason || 'direct_692'); else if (window.tiShowConfigSaveDiag687) window.tiShowConfigSaveDiag687(reason || 'direct_692'); } catch(e) {} }\n    function log692(event, detail, level){\n        if(!window.tiConfigSaveLogAllowed) return;\n        level = level || 'info';\n        try { showDiag('direct_692_' + event); } catch(e) {}\n        try {\n            var pre = id('ti-config-save-diag-body-688') || id('ti-config-save-diag-body-687');\n            var lines = pre ? txt(pre.textContent || '').split('\\n').filter(Boolean).length : 0;\n            var line = '[' + String(lines + 1).padStart(3,'0') + '] +' + String(Date.now ? Date.now() : (new Date()).getTime()).slice(-6).padStart(6,' ') + 'ms ' + level.toUpperCase().padEnd(5,' ') + ' 692_' + event;\n            try { line += detail ? ' ' + JSON.stringify(detail) : ''; } catch(e) { line += ' ' + txt(detail); }\n            if (pre) { pre.textContent = (txt(pre.textContent || '') ? txt(pre.textContent || '') + '\\n' : '') + line; pre.scrollTop = pre.scrollHeight; }\n            var sm = id('ti-config-save-diag-summary-688') || id('ti-config-save-diag-summary-687');\n            if (sm) { var b = saveButton(); sm.innerHTML = 'DB: <b>' + txt(dbName()) + '<\/b> | Pulsante: <b>' + txt(b ? b.innerText : '') + '<\/b> | direct 692 | evento: <b>' + txt(event) + '<\/b>'; }\n        } catch(e) {}\n        try { (level === 'error' ? console.error : (level === 'warn' ? console.warn : console.log))('[Shop-Service save direct 692]', event, detail || {}); } catch(e) {}\n    }\n    function clearBusy(){\n        try { window.__tiConfigSaveActive675=false; window.__tiConfigSaveActive677=false; window.__tiConfigSaveActive678=false; window.__tiConfigSaveActive682=false; window.__tiConfigSaveActive683=false; window.__tiConfigSaveActive684=false; window.__tiConfigSaveActive691=false; window.__tiConfigSaveActive692=false; window.__saveConfigInFlight=false; } catch(e) {}\n        try { window.__tiSaveConfigStartedAt=0; window.__tiSaveConfigStartedAt585=0; window.__tiSaveConfigStartedAt675=0; } catch(e) {}\n        try { if (typeof window.clearLongAIProcess === 'function') window.clearLongAIProcess(); } catch(e) {}\n        try { if (typeof window.hideProgressPopup === 'function') window.hideProgressPopup(false, 'Fine salvataggio configurazione', {notifyUser:false}); } catch(e) {}\n        try { document.body.classList.remove('ti-busy','ti-loading','ti-modal-blocked'); } catch(e) {}\n        try { qsa('.ti-progress-overlay,.ti-progress-popup,#ti-progress-ov,#ti-progress-popup').forEach(function(x){ if (x && x.parentNode) x.parentNode.removeChild(x); }); } catch(e) {}\n    }\n    function formatSaveStar(){\n        var b = saveButton(); if (!b) return;\n        var t = txt(b.textContent || b.innerText || '');\n        if (\/Salva Modifiche\\s*\\*\/i.test(t) && !b.querySelector('.ti-save-star-692')) {\n            b.innerHTML = 'Salva Modifiche <span class=\"ti-save-star-692\" aria-label=\"modifiche da salvare\">*<\/span>';\n        }\n    }\n    function resetButton(clean){\n        if (clean && window.modifiedFields && typeof window.modifiedFields.clear === 'function') { try { window.modifiedFields.clear(); } catch(e) {} }\n        clearBusy();\n        var b = saveButton(); if (!b) return;\n        var dirty = !!(!clean && window.modifiedFields && window.modifiedFields.size > 0);\n        b.disabled = false;\n        try { b.removeAttribute('disabled'); b.removeAttribute('aria-busy'); b.removeAttribute('data-ti-saving'); } catch(e) {}\n        b.style.pointerEvents = '';\n        b.classList.toggle('ti-save-dirty', dirty);\n        b.classList.toggle('ti-save-clean', !dirty);\n        b.innerHTML = dirty ? 'Salva Modifiche <span class=\"ti-save-star-692\" aria-label=\"modifiche da salvare\">*<\/span>' : 'Salva Modifiche';\n        try { b.style.setProperty('background', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('background-color', dirty ? '#10b981' : '#374151', 'important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','pointer','important'); } catch(e) {}\n    }\n    function setSaving(){ var b=saveButton(); if(!b) return; b.disabled=true; b.setAttribute('data-ti-saving','1'); b.setAttribute('aria-busy','true'); b.style.pointerEvents='none'; b.innerText='Salvataggio...'; try{ b.style.setProperty('background','#d97706','important'); b.style.setProperty('background-color','#d97706','important'); b.style.setProperty('color','#fff','important'); b.style.setProperty('cursor','wait','important'); }catch(e){} }\n    function readVal(el){ if(!el) return ''; if(el.tagName==='SELECT' && el.multiple) return Array.prototype.slice.call(el.selectedOptions||[]).map(function(o){return txt(o.value).trim();}).filter(Boolean).join(', '); if(el.type==='checkbox') return el.checked ? (el.value || '1') : ''; return el.value == null ? '' : el.value; }\n    function resolveTable(t){ try { return window.resolveConfigTableName ? (window.resolveConfigTableName(t)||t) : t; } catch(e) { return t; } }\n    function ensureArrays(){ var d=window.currentDbData; if(!d || !d.Tabelle) return; Object.keys(d.Tabelle).forEach(function(t){ if(!Array.isArray(d.Tabelle[t])) d.Tabelle[t]=Object.values(d.Tabelle[t]||{}); }); }\n    function syncVisible(){\n        try { if (window.tiSyncConfigAutofillSavedInfo666) window.tiSyncConfigAutofillSavedInfo666(); } catch(e) {}\n        try { if (window.syncVisibleConfigInputsToMemory) window.syncVisibleConfigInputsToMemory(); } catch(e) {}\n        ensureArrays();\n        var d=window.currentDbData; if(!d || !d.Tabelle) return;\n        var sel='#ti-conf-ov .ti-cfg-table input[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table textarea[data-tbl][data-idx][data-key],#ti-conf-ov .ti-cfg-table select[data-tbl][data-idx][data-key]';\n        qsa(sel).forEach(function(input){\n            if(!input || input.disabled || input.readOnly) return;\n            var tbl=input.getAttribute('data-tbl')||'', key=input.getAttribute('data-key')||'', idx=parseInt(input.getAttribute('data-idx')||'',10);\n            if(!tbl || !key || isNaN(idx)) return;\n            var rt=resolveTable(tbl); if(!d.Tabelle[rt]) d.Tabelle[rt]=[]; if(!d.Tabelle[rt][idx] || typeof d.Tabelle[rt][idx] !== 'object') d.Tabelle[rt][idx]={};\n            var val=readVal(input); try { if (window.normalizeInputValueForKey) val=window.normalizeInputValueForKey(key,val); } catch(e) {}\n            var sig1630 = rt+'-'+idx+'-'+key;\n            var oldRows1630 = window.configOriginalDbData && window.configOriginalDbData.Tabelle ? window.configOriginalDbData.Tabelle[rt] : null;\n            var orig1630 = Array.isArray(oldRows1630) && oldRows1630[idx] && typeof oldRows1630[idx] === 'object' ? oldRows1630[idx][key] : undefined;\n            var edited1630 = false; try { edited1630 = window.tiConfigWasUserEdited1630 ? window.tiConfigWasUserEdited1630(rt,idx,key) : false; } catch(e) {}\n            if(!edited1630 && orig1630 !== undefined && window.tiConfigPlaceholderEquivalent1630 && window.tiConfigPlaceholderEquivalent1630(orig1630,val)) {\n                d.Tabelle[rt][idx][key]=orig1630;\n                try { if(window.modifiedFields) window.modifiedFields.delete(sig1630); } catch(e) {}\n                return;\n            }\n            if(txt(d.Tabelle[rt][idx][key]) !== txt(val)) { d.Tabelle[rt][idx][key]=val; if(!window.modifiedFields) window.modifiedFields=new Set(); try { window.modifiedFields.add(sig1630); } catch(e) {} }\n        });\n        try { if (window.tiApplyPendingLinkedFileRemovals676) window.tiApplyPendingLinkedFileRemovals676(); } catch(e) {}\n        \/\/ Non normalizzare in massa i dati durante il save: eventuali normalizzazioni visuali non devono\n        \/\/ diventare delta di campi mai toccati. La validazione opera comunque sui valori correnti.\n    }\n    function addChange(out, seen, table, row, key, value){\n        if(!table || row<0 || !key || String(key).indexOf('__')===0) return false;\n        if(value && typeof value === 'object') return false;\n        var sig=table+'\\u0001'+row+'\\u0001'+key; if(seen[sig]) return true; seen[sig]=true;\n        out.push({table:table,row:row,key:key,value:(value==null?'':String(value))}); return true;\n    }\n    function buildChanges(){\n        ensureArrays();\n        var cur=(window.currentDbData&&window.currentDbData.Tabelle)?window.currentDbData.Tabelle:{};\n        var old=(window.configOriginalDbData&&window.configOriginalDbData.Tabelle)?window.configOriginalDbData.Tabelle:{};\n        var changes=[], seen={}, fullNeeded=false, stale1630=[];\n        var all={}; Object.keys(cur||{}).forEach(function(t){all[t]=true;}); Object.keys(old||{}).forEach(function(t){all[t]=true;});\n\n        \/\/ Le sole differenze strutturali richiedono il salvataggio completo.\n        Object.keys(all).forEach(function(t){\n            var cr=Array.isArray(cur[t])?cur[t]:Object.values(cur[t]||{}), or=Array.isArray(old[t])?old[t]:Object.values(old[t]||{});\n            if(cr.length!==or.length) fullNeeded=true;\n        });\n        try { if((window.tiConfigDeletedRowsManifest||[]).length || Object.keys(window.tiConfigDeletedTableSnapshots||{}).length || parseInt(window.tiConfigDeletedRowsCountTotal||0,10)>0) fullNeeded=true; } catch(e) {}\n\n        \/\/ 30.9.1630: payload puntuale = modifiedFields, non diff globale dell intero DB.\n        \/\/ Cosi rendering, canonicalizzazioni e placeholder non toccati non possono essere salvati per errore.\n        var tables1630=Object.keys(cur||{}).sort(function(a,b){ return String(b).length-String(a).length; });\n        if(window.modifiedFields && typeof window.modifiedFields.forEach==='function') {\n            window.modifiedFields.forEach(function(raw){\n                raw=String(raw||''); if(!raw) return;\n                var parsed=null;\n                for(var z=0;z<tables1630.length;z++){\n                    var t=tables1630[z], pref=String(t)+'-'; if(raw.indexOf(pref)!==0) continue;\n                    var rest=raw.slice(pref.length), p=rest.indexOf('-');\n                    if(p<=0){ fullNeeded=true; return; }\n                    var ix=rest.slice(0,p), key=rest.slice(p+1);\n                    if(key.indexOf('__')===0 || !\/^\\d+$\/.test(ix) || !key){ fullNeeded=true; return; }\n                    parsed={table:t,row:parseInt(ix,10),key:key}; break;\n                }\n                if(!parsed){ fullNeeded=true; return; }\n                var cr=Array.isArray(cur[parsed.table])?cur[parsed.table]:[], or=Array.isArray(old[parsed.table])?old[parsed.table]:[];\n                if(!cr[parsed.row] || typeof cr[parsed.row]!=='object' || !or[parsed.row] || typeof or[parsed.row]!=='object'){ fullNeeded=true; return; }\n                var av=(cr[parsed.row][parsed.key]==null?'':cr[parsed.row][parsed.key]);\n                var bv=(or[parsed.row][parsed.key]==null?'':or[parsed.row][parsed.key]);\n                var edited=false; try { edited=window.tiConfigWasUserEdited1630 ? window.tiConfigWasUserEdited1630(parsed.table,parsed.row,parsed.key) : false; } catch(e) {}\n                if(!edited && window.tiConfigPlaceholderEquivalent1630 && window.tiConfigPlaceholderEquivalent1630(bv,av)) {\n                    cr[parsed.row][parsed.key]=or[parsed.row][parsed.key]; stale1630.push(raw); return;\n                }\n                var same=false;\n                try {\n                    same=JSON.stringify(av)===JSON.stringify(bv);\n                    if(!same){\n                        var avn=parseFloat(av), bvn=parseFloat(bv);\n                        if(!isNaN(avn) && !isNaN(bvn) && String(avn)===String(av).trim() && String(bvn)===String(bv).trim()) same=(avn===bvn);\n                        else same=(String(av)===String(bv));\n                    }\n                } catch(e) { same=txt(av)===txt(bv); }\n                if(same){ stale1630.push(raw); return; }\n                if(!addChange(changes,seen,parsed.table,parsed.row,parsed.key,av)) fullNeeded=true;\n            });\n        }\n        if(stale1630.length && window.modifiedFields) stale1630.forEach(function(k){ try { window.modifiedFields.delete(k); } catch(e) {} });\n        if(changes.length>250) fullNeeded=true;\n        try { log692('build_changes_1630', {changes:changes.length, fullNeeded:fullNeeded, stale_removed:stale1630.length, modified_after:window.modifiedFields&&window.modifiedFields.size?window.modifiedFields.size:0}, 'info'); } catch(e) {}\n        return {changes:changes, fullNeeded:fullNeeded};\n    }\n    function postFields692(db, changes){\n        return new Promise(function(resolve,reject){\n            var fd=new FormData();\n            fd.append('ti_action','ti_ai_save_config_fields_704'); fd.append('action','ti_ai_save_config_fields_704'); fd.append('db',db); fd.append('changes',enc(changes)); fd.append('field_save_704','1');\n            try { if(window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n            var url=window.tiUrl || window.tiAjaxUrl || window.location.href.split('?')[0];\n            var xhr=new XMLHttpRequest(), done=false;\n            window.__tiCurrentSaveXhr704 = xhr;\n            var timeoutMs1432 = 65000;\n            var startedAt1432b = Date.now ? Date.now() : (new Date()).getTime();\n            function finish(ok, payload){ if(done) return; done=true; try { clearTimeout(watchdog); } catch(e) {} try { clearInterval(intervalWatch1432); } catch(e) {} ok ? resolve(payload) : reject(payload); }\n            \/\/ 30.9.1432: CORREZIONE CRITICA - confermato con un caso reale di perdita dati (salvataggio bloccato\n            \/\/ oltre 9 minuti, ben oltre i 65 secondi qui previsti, senza mai una risposta di successo o errore)\n            \/\/ che l'unico meccanismo di timeout precedente (un singolo setTimeout, assieme al timeout nativo\n            \/\/ xhr.timeout) puo' non attivarsi in certe condizioni - probabilmente perche' anche l'esecuzione\n            \/\/ del suo stesso callback puo' essere ritardata indefinitamente nello stesso ambiente. Ora un\n            \/\/ controllo periodico indipendente (ogni 2 secondi) verifica autonomamente il tempo trascorso e puo'\n            \/\/ forzare l'abort anche se il meccanismo originale non dovesse scattare.\n            function doAbort1432(source){\n                if (done) return;\n                try { xhr.abort(); } catch(e) {}\n                log692('xhr_watchdog_abort_704', {timeout_ms:timeoutMs1432, source:source}, 'error');\n                finish(false, new Error('Timeout salvataggio configurazione. Il server non ha risposto entro 65 secondi. Salvataggio non confermato. (' + source + ')'));\n            }\n            var watchdog=setTimeout(function(){ doAbort1432('setTimeout'); }, timeoutMs1432);\n            var intervalWatch1432 = setInterval(function(){\n                if (done) { clearInterval(intervalWatch1432); return; }\n                if ((Date.now ? Date.now() : (new Date()).getTime()) - startedAt1432b >= timeoutMs1432) doAbort1432('controllo-periodico');\n            }, 2000);\n            try {\n                var visWatch1432 = function(){ if (!done && !document.hidden && (Date.now ? Date.now() : (new Date()).getTime()) - startedAt1432b >= timeoutMs1432) doAbort1432('visibilitychange-o-focus'); };\n                document.addEventListener('visibilitychange', visWatch1432);\n                window.addEventListener('focus', visWatch1432);\n            } catch(e) {}\n            function rafWatch1432(){\n                if (done) return;\n                if ((Date.now ? Date.now() : (new Date()).getTime()) - startedAt1432b >= timeoutMs1432) { doAbort1432('requestAnimationFrame'); return; }\n                try { if (typeof requestAnimationFrame === 'function') requestAnimationFrame(rafWatch1432); else setTimeout(rafWatch1432, 200); } catch(e) { setTimeout(rafWatch1432, 200); }\n            }\n            try { rafWatch1432(); } catch(e) {}\n            xhr.open('POST', url, true); xhr.timeout=timeoutMs1432; xhr.withCredentials=true;\n            xhr.onreadystatechange=function(){\n                if(xhr.readyState!==4) return;\n                var raw=xhr.responseText || '';\n                log692('xhr_complete', {status:xhr.status, raw_prefix:raw.slice(0,220)}, xhr.status>=200 && xhr.status<300 ? 'info' : 'error');\n                if(xhr.status<200 || xhr.status>=300) return finish(false, new Error('Errore server '+xhr.status+': '+raw.slice(0,220)));\n                var data=null; try { data=JSON.parse(raw); } catch(e) { return finish(false, new Error('Risposta salvataggio non JSON: '+raw.slice(0,220))); }\n                finish(true, data);\n            };\n            xhr.ontimeout=function(){ log692('xhr_timeout_704', {timeout_ms:xhr.timeout}, 'error'); finish(false, new Error('Timeout salvataggio configurazione 704. Salvataggio non confermato dal server.')); };\n            xhr.onerror=function(){ log692('xhr_error_704', {}, 'error'); finish(false, new Error('Errore rete durante salvataggio configurazione 704.')); };\n            log692('xhr_start_704', {action:'ti_ai_save_config_fields_704', changes:changes.length}, 'info');\n            xhr.send(fd);\n        });\n    }\n    \/\/ 30.9.1343\/1366: rete di sicurezza indipendente dal timeout XHR\/watchdog gia' presenti in postFields692 - se\n    \/\/ il salvataggio risulta ancora \"in corso\" oltre 80 secondi (i meccanismi di timeout esistenti dovrebbero\n    \/\/ gia' aver agito entro 65s), forza comunque lo sblocco dell'interfaccia e avvisa l'utente, cosi' non resta\n    \/\/ mai bloccata a tempo indeterminato. Confermato con un test reale che i timer (setInterval\/setTimeout)\n    \/\/ possono essere ritardati anche di decine di secondi quando la scheda va in background (comportamento\n    \/\/ standard dei browser per risparmiare risorse) - per questo il controllo ora scatta ANCHE non appena la\n    \/\/ pagina torna visibile (non solo ogni 3s), recuperando immediatamente eventuali controlli \"persi\" durante\n    \/\/ il periodo in background, invece di aspettare che il timer normale (ritardato) se ne accorga.\n    function checkSaveSafetyNet1366(){\n        try {\n            var started = parseInt(window.__tiSaveConfigStartedAt || 0, 10) || 0;\n            if (!started) return;\n            var age = (Date.now ? Date.now() : (new Date()).getTime()) - started;\n            if (age < 80000) return;\n            if (!window.__saveConfigInFlight) return;\n            log692('sicurezza_1343_sblocco_forzato', {age_ms: age, source: document.hidden === false ? 'tab_tornata_visibile' : 'controllo_periodico'}, 'error');\n            window.__tiConfigSaveActive692 = false; window.__saveConfigInFlight = false;\n            window.__tiConfigSaveActive691 = false; window.__tiConfigSaveActive684 = false;\n            window.__tiConfigSaveActive683 = false; window.__tiConfigSaveActive682 = false;\n            window.__tiSaveConfigStartedAt = 0;\n            try { clearBusy(); } catch(e){}\n            try { resetButton(false); } catch(e){}\n            if (window.tiHideSaveWaitOverlay1356) window.tiHideSaveWaitOverlay1356();\n            if (window.tiAlert) window.tiAlert('Il salvataggio non ha ricevuto conferma dal server entro 80 secondi. Verifica se le modifiche sono state effettivamente salvate (ricarica Configurazione) prima di riprovare.');\n        } catch(e) {}\n    }\n    setInterval(checkSaveSafetyNet1366, 3000);\n    try { document.addEventListener('visibilitychange', function(){ if (!document.hidden) checkSaveSafetyNet1366(); }); } catch(e) {}\n    \/\/ 30.9.1432: terzo meccanismo indipendente per questa stessa rete di sicurezza, basato su\n    \/\/ requestAnimationFrame in modo puramente ricorsivo (nessuna dipendenza da setTimeout\/setInterval nella\n    \/\/ ricorsione stessa, cosi' da essere genuinamente indipendente) - confermato con un caso reale di perdita\n    \/\/ dati che ne' il controllo periodico (setInterval) ne' il cambio scheda erano scattati per oltre 190 cicli\n    \/\/ consecutivi durante un salvataggio bloccato. Il controllo effettivo avviene al massimo ogni 2 secondi\n    \/\/ (throttle basato su timestamp locale, non su timer), non ad ogni singolo fotogramma.\n    if (typeof requestAnimationFrame === 'function') {\n        (function loopRaf1432(){\n            var nowTs1432 = Date.now ? Date.now() : (new Date()).getTime();\n            if (!loopRaf1432._last || (nowTs1432 - loopRaf1432._last) >= 2000) {\n                loopRaf1432._last = nowTs1432;\n                try { checkSaveSafetyNet1366(); } catch(e) {}\n            }\n            try { requestAnimationFrame(loopRaf1432); } catch(e) {}\n        })();\n    }\n\n    function activeSaveLooksLive702(){\n        var b=saveButton();\n        var now=(Date.now?Date.now():(new Date()).getTime());\n        var started=parseInt(window.__tiSaveConfigStartedAt||0,10)||0;\n        var age=started ? (now-started) : 0;\n        var buttonSaving=!!(b && (\/salvataggio\/i.test(txt(b.innerText||b.textContent||'')) || b.disabled || b.getAttribute('data-ti-saving')==='1'));\n        var inFlight=!!window.__saveConfigInFlight;\n        \/\/ 30.9.1352: soglia estesa da 30s a 75s (appena oltre il timeout XHR di 65s gia' presente in\n        \/\/ postFields692) - i 30s originali erano molto piu' brevi dei tempi di risposta reali osservati sul\n        \/\/ server (spesso oltre il minuto), causando l'avvio di un secondo salvataggio mentre il primo era\n        \/\/ ancora effettivamente in corso in background (mai annullato, dato che qui si resettano solo i flag\n        \/\/ dell'interfaccia, non la richiesta di rete stessa) - le due richieste sovrapposte causavano poi errori\n        \/\/ lato server (\"Troppe modifiche puntuali\"). Con 75s, il timeout XHR nativo dovrebbe quasi sempre\n        \/\/ intervenire per primo, resettando correttamente lo stato senza lasciare richieste \"fantasma\".\n        return !!(inFlight && buttonSaving && (!started || age < 75000));\n    }\n    function clearStaleSaveLock702(reason){\n        try { window.__tiConfigSaveActive692=false; window.__saveConfigInFlight=false; } catch(e) {}\n        try { window.__tiConfigSaveActive691=false; window.__tiConfigSaveActive684=false; window.__tiConfigSaveActive683=false; window.__tiConfigSaveActive682=false; } catch(e) {}\n        try { window.__tiSaveConfigStartedAt=0; } catch(e) {}\n        \/\/ 30.9.1352: annulla anche l'eventuale richiesta XHR ancora in corso in background, non solo i flag\n        \/\/ dell'interfaccia - senza questo, la richiesta \"fantasma\" continuava a girare sul server anche dopo\n        \/\/ che l'interfaccia sembrava di nuovo pronta per un nuovo tentativo, causando due salvataggi sovrapposti.\n        try { if (window.__tiCurrentSaveXhr704 && window.__tiCurrentSaveXhr704.abort) { window.__tiCurrentSaveXhr704.abort(); window.__tiCurrentSaveXhr704 = null; } } catch(e) {}\n        try { clearBusy(); } catch(e) {}\n        log692('stale_lock_clear_702', {reason:reason||'', buttonText:txt(saveButton()?saveButton().innerText:''), modifiedFields:(window.modifiedFields&&window.modifiedFields.size)||0, removals:Array.isArray(window.pendingLinkedFileRemovals)?window.pendingLinkedFileRemovals.length:0}, 'warn');\n    }\n    \/\/ 30.9.1357: funzione globale che il pulsante \"Esci\" del popup di attesa richiama per annullare\n    \/\/ effettivamente il salvataggio in corso (non solo nascondere il popup) - riusa la stessa logica di\n    \/\/ pulizia\/annullamento gia' presente in clearStaleSaveLock702, cosi' resta sempre coerente con essa.\n    window.tiCancelSaveConfig1357 = function(){\n        clearStaleSaveLock702('annullato manualmente da Esci nel popup di attesa');\n        try { resetButton(false); } catch(e) {}\n        if (window.tiHideSaveWaitOverlay1356) window.tiHideSaveWaitOverlay1356();\n    };\n    function directSave692(){\n        showDiag('direct_692_start');\n        try { if (window.tiRestoreDeletionShadow1516) window.tiRestoreDeletionShadow1516(); } catch(e1516restore) {}\n        if(!window.currentDbData || !window.currentDbData.Tabelle){ resetButton(false); if(window.tiAlert) window.tiAlert('Configurazione non caricata. Riapri Configurazione e riprova.'); return; }\n        var db=dbName(); if(!db || db==='NEW_DB' || db==='Global'){ resetButton(false); if(window.tiAlert) window.tiAlert('Seleziona ditta.'); return; }\n        if(window.__tiConfigSaveActive692){\n            if(activeSaveLooksLive702()){\n                log692('gia_in_corso', {live:true}, 'warn');\n                return;\n            }\n            clearStaleSaveLock702('flag direct_692 attivo senza richiesta salvataggio viva');\n        }\n        \/\/ 30.9.1911: una nuova riga non passa dal salvataggio legacy. Viene acquisita dal DOM e\n        \/\/ confermata sul server prima di qualsiasi diff\/full-save, cosi il primo click non puo farla sparire.\n        if (typeof window.tiHasPendingConfigRows1911 === 'function' && window.tiHasPendingConfigRows1911()) {\n            clearBusy(); setSaving(); window.__tiConfigSaveActive692=true; window.__saveConfigInFlight=true; window.__tiSaveConfigStartedAt=Date.now?Date.now():(new Date()).getTime();\n            window.__tiLastSaveOutcome1364=null;\n            if (window.tiShowSaveWaitOverlay1356) window.tiShowSaveWaitOverlay1356();\n            log692('1911_pending_rows_direct_start', {db:db}, 'info');\n            return Promise.resolve().then(function(){return window.tiSavePendingConfigRows1911(db);}).then(function(r1911){\n                window.__tiConfigSaveActive692=false; window.__saveConfigInFlight=false; clearBusy(); if(window.tiHideSaveWaitOverlay1356)window.tiHideSaveWaitOverlay1356();\n                if(!r1911 || r1911.success===false)throw new Error((r1911&&r1911.message)||'Salvataggio nuova riga non riuscito.');\n                log692('1911_pending_rows_direct_success', r1911, 'info');\n                if(r1911.remainingDirty){ resetButton(false); return directSave692(); }\n                window.__tiLastSaveOutcome1364='success'; resetButton(true); if(window.tiAlert)window.tiAlert(r1911.reply||'\u2705 Salvataggio configurazione completato.'); return r1911;\n            }).catch(function(err1911){\n                window.__tiConfigSaveActive692=false; window.__saveConfigInFlight=false; clearBusy(); if(window.tiHideSaveWaitOverlay1356)window.tiHideSaveWaitOverlay1356(); resetButton(false); window.__tiLastSaveOutcome1364='error';\n                var msg1911=(err1911&&err1911.message)?err1911.message:'Errore durante il salvataggio della nuova riga.';log692('1911_pending_rows_direct_error',{message:msg1911},'error');if(window.tiAlert)window.tiAlert(msg1911);else alert(msg1911);return {success:false,message:msg1911};\n            });\n        }\n        var sig699 = dirtySignal699();\n        if(!sig699.dirty){\n            clearBusy(); resetButton(true);\n            log692('no_changes_skip_699', sig699, 'info');\n            if(window.tiAlert) window.tiAlert('Nessuna modifica da salvare.');\n            return;\n        }\n        clearBusy(); setSaving(); window.__tiConfigSaveActive692=true; window.__saveConfigInFlight=true; window.__tiSaveConfigStartedAt=Date.now?Date.now():(new Date()).getTime();\n        \/\/ 30.9.1433: diagnostica diretta e immediata per confermare con certezza se setSaving() viene\n        \/\/ effettivamente eseguita e quale testo\/stato risultante ha davvero il pulsante subito dopo.\n        try {\n            var btnCheck1433 = saveButton();\n            log692('33_dopo_setSaving_1433', {button_text: btnCheck1433 ? btnCheck1433.innerText : 'BOTTONE_NON_TROVATO', button_disabled: btnCheck1433 ? btnCheck1433.disabled : null, data_saving_attr: btnCheck1433 ? btnCheck1433.getAttribute('data-ti-saving') : null}, 'info');\n        } catch(eDiag1433) {}\n        window.__tiLastSaveOutcome1364 = null;\n        if (window.tiShowSaveWaitOverlay1356) window.tiShowSaveWaitOverlay1356();\n        var built;\n        try { syncVisible(); built=buildChanges(); } catch(e){ resetButton(false); if (window.tiHideSaveWaitOverlay1356) window.tiHideSaveWaitOverlay1356(); log692('build_exception', {message:e.message||String(e)}, 'error'); if(window.tiAlert) window.tiAlert('Errore preparazione salvataggio: '+(e.message||e)); return; }\n        log692('build_changes', {changes:built.changes.length, fullNeeded:built.fullNeeded, modifiedFields: window.modifiedFields && window.modifiedFields.size ? window.modifiedFields.size : 0, removals:Array.isArray(window.pendingLinkedFileRemovals)?window.pendingLinkedFileRemovals.length:0}, 'info');\n        \/\/ 30.9.1353: se le modifiche calcolate superano ampiamente quelle che l'utente crede di aver fatto\n        \/\/ (window.modifiedFields), lo snapshot di riferimento (configOriginalDbData) e' probabilmente\n        \/\/ disallineato dai dati correnti - invece di inviare un pacchetto enorme e probabilmente scorretto (che\n        \/\/ il server rifiuta comunque con \"Troppe modifiche puntuali\"), si blocca qui e si chiede di ricaricare\n        \/\/ Configurazione per ottenere uno snapshot fresco e correttamente sincronizzato.\n        var believedCount1353 = (window.modifiedFields && window.modifiedFields.size) ? window.modifiedFields.size : 0;\n        if (built.changes.length > 15 && built.changes.length > (believedCount1353 * 5)) {\n            window.__tiConfigSaveActive692 = false; window.__saveConfigInFlight = false;\n            resetButton(false);\n            if (window.tiHideSaveWaitOverlay1356) window.tiHideSaveWaitOverlay1356();\n            \/\/ 30.9.1354: aggiunto un campione dettagliato (tabella\/riga\/campo) delle prime modifiche rilevate,\n            \/\/ per capire con dati concreti QUALI campi il sistema considera erroneamente \"cambiati\" - il solo\n            \/\/ conteggio non bastava a individuare la causa del disallineamento.\n            var sampleChanges1354 = built.changes.slice(0, 20).map(function(c){ return c.table + '[' + c.row + '].' + c.key; });\n            var tableCounts1354 = {};\n            built.changes.forEach(function(c){ tableCounts1354[c.table] = (tableCounts1354[c.table]||0) + 1; });\n            log692('mismatch_1353_stop', {changes:built.changes.length, believed:believedCount1353, sample:sampleChanges1354, perTable:tableCounts1354}, 'error');\n            if(window.tiAlert) window.tiAlert('Rilevata una discrepanza: il sistema ha calcolato ' + built.changes.length + ' modifiche, molte piu\\' di quelle che risultano effettivamente digitate (' + believedCount1353 + '). Per sicurezza, il salvataggio e\\' stato annullato. Chiudi e riapri Configurazione, poi ripeti la modifica.');\n            return;\n        }\n        if(!built.changes.length && !built.fullNeeded){\n            var forceSig1516 = dirtySignal699();\n            if (forceSig1516 && forceSig1516.dirty) {\n                built.fullNeeded = true;\n                log692('1516_force_full_save_dirty_without_delta', forceSig1516, 'warn');\n            } else {\n                resetButton(true); if (window.tiHideSaveWaitOverlay1356) window.tiHideSaveWaitOverlay1356(); if(window.tiAlert) window.tiAlert('Nessuna modifica da salvare.'); return;\n            }\n        }\n        var savePromise;\n        if(built.fullNeeded){\n            \/\/ 30.9.1439: prima si fermava qui con un avviso che suggeriva di \"ricaricare Configurazione e\n            \/\/ riprovare\" - ma un'eliminazione di riga imposta SEMPRE fullNeeded, quindi quel consiglio non\n            \/\/ avrebbe mai funzionato per questo caso specifico (causa confermata alla base della perdita di dati\n            \/\/ originale, aggravata da un popup di attesa che restava bloccato in vista anche dopo questo stop).\n            \/\/ Ora si usa invece la funzione di salvataggio completo (postFullSave\/ti_ai_save_full_db), gia'\n            \/\/ presente e attiva lato server, pensata proprio per le modifiche strutturali come le eliminazioni\n            \/\/ di riga.\n            try { log692('34b_prima_di_postFullSave_1439', {changes_count: built.changes.length}, 'info'); } catch(eDiag1439) {}\n            \/\/ 30.9.1443: CORREZIONE CRITICA - avvolto in Promise.resolve().then(...) cosi' un'eventuale\n            \/\/ eccezione sincrona dentro postFullSave (es. durante la codifica del payload), che altrimenti\n            \/\/ sfuggirebbe del tutto alla gestione .catch() qui sotto, viene invece correttamente catturata e\n            \/\/ trasformata in un rifiuto della promise - senza questo, un simile errore lascerebbe il pulsante\n            \/\/ bloccato su \"Salvataggio...\" indefinitamente, con solo la rete di sicurezza indipendente (basata\n            \/\/ sul tempo trascorso) capace di sbloccarlo dopo 80 secondi, senza mai rivelare la causa reale.\n            savePromise = Promise.resolve().then(function(){\n                if (typeof window.tiPostFullSave1444 !== 'function') throw new Error('Funzione di salvataggio completo non disponibile (blocco script non ancora caricato). Ricarica la pagina e riprova.');\n                return window.tiPostFullSave1444(db, built.changes);\n            }).then(function(res){\n                if(!res || !res.success) throw new Error((res&&res.data&&res.data.message)?res.data.message:'Salvataggio completo non riuscito.');\n                var data=res.data||{};\n                if(window.currentDbData && data.db_version) window.currentDbData.__db_version=data.db_version;\n                try { if(window.currentDbData) window.configOriginalDbData=clone(window.currentDbData); } catch(e) {}\n                try { if(window.modifiedFields && typeof window.modifiedFields.clear==='function') window.modifiedFields.clear(); } catch(e) {}\n                try { if(window.tiConfigUserEditedFields1630 && typeof window.tiConfigUserEditedFields1630.clear==='function') window.tiConfigUserEditedFields1630.clear(); } catch(e) {}\n                window.pendingLinkedFileRemovals=[]; window.tiConfigDeletedRowsManifest=[]; window.tiConfigDeletedTableSnapshots={}; window.tiConfigDeletedRowsCountTotal=0; try { if(window.tiConfigStructuralChangedTables1907 && typeof window.tiConfigStructuralChangedTables1907.clear==='function') window.tiConfigStructuralChangedTables1907.clear(); } catch(e1907) {} try { window.__tiDeletedRowsShadow1516=null; } catch(e1516clear) {}\n                try { if (db) { localStorage.removeItem('ti_config_cache_507_' + db); localStorage.removeItem('ti_config_cache_509_' + db); } } catch(e) {}\n                resetButton(true);\n                try { if (!data.skip_refresh_1516 && window.tiRefreshConfigAfterSave1516) setTimeout(function(){ window.tiRefreshConfigAfterSave1516(db); }, 60); } catch(e1516refresh) {}\n                window.__tiLastSaveOutcome1364 = 'success';\n                log692('save_full_success_1439', {reply:data.reply, deleted_rows_total:data.deleted_rows_total}, 'info');\n                if(window.tiAlert) window.tiAlert(data.reply || 'Salvataggio configurazione completato.');\n                if (data.needs_reload) { setTimeout(function(){ location.reload(); }, 900); }\n            });\n        } else {\n            try { log692('34_prima_di_postFields692_1433', {changes_count: built.changes.length}, 'info'); } catch(eDiag1433b) {}\n            savePromise = Promise.resolve().then(function(){ return postFields692(db,built.changes); }).then(function(res){\n                if(!res || !res.success) throw new Error((res&&res.data&&res.data.message)?res.data.message:'Salvataggio configurazione non riuscito.');\n                var data=res.data||{};\n                if(window.currentDbData && data.db_version) window.currentDbData.__db_version=data.db_version;\n                try { if(window.currentDbData) window.configOriginalDbData=clone(window.currentDbData); } catch(e) {}\n                try { if(window.modifiedFields && typeof window.modifiedFields.clear==='function') window.modifiedFields.clear(); } catch(e) {}\n                try { if(window.tiConfigUserEditedFields1630 && typeof window.tiConfigUserEditedFields1630.clear==='function') window.tiConfigUserEditedFields1630.clear(); } catch(e) {}\n                window.pendingLinkedFileRemovals=[]; window.tiConfigDeletedRowsManifest=[]; window.tiConfigDeletedTableSnapshots={}; window.tiConfigDeletedRowsCountTotal=0; try { if(window.tiConfigStructuralChangedTables1907 && typeof window.tiConfigStructuralChangedTables1907.clear==='function') window.tiConfigStructuralChangedTables1907.clear(); } catch(e1907) {} try { window.__tiDeletedRowsShadow1516=null; } catch(e1516clear) {}\n                \/\/ 30.9.1364: svuota anche la cache locale (localStorage) di Configurazione per questa ditta dopo un\n                \/\/ salvataggio riuscito - prima veniva svuotata solo dopo un cambio ditta, non dopo un salvataggio,\n                \/\/ rischiando di mostrare dati non aggiornati (precedenti al salvataggio) riaprendo Configurazione.\n                try { if (db) { localStorage.removeItem('ti_config_cache_507_' + db); localStorage.removeItem('ti_config_cache_509_' + db); } } catch(e) {}\n                resetButton(true);\n                try { if (window.tiRefreshConfigAfterSave1516) setTimeout(function(){ window.tiRefreshConfigAfterSave1516(db); }, 60); } catch(e1516refresh) {}\n                window.__tiLastSaveOutcome1364 = 'success';\n                log692('save_success', {changes_applied:data.changes_applied, elapsed_ms:data.elapsed_ms, mode:data.mode || data.fields_saved_704 || data.fields_saved_703 || data.fields_saved_691}, 'info');\n                if(window.tiAlert) window.tiAlert('Salvataggio configurazione completato.');\n            });\n        }\n        savePromise.catch(function(err){\n            resetButton(false);\n            window.__tiLastSaveOutcome1364 = 'error';\n            var msg=(err&&err.message)?err.message:'Errore durante il salvataggio configurazione.';\n            log692('save_error', {message:msg}, 'error');\n            if(window.tiAlert) window.tiAlert(msg); else alert(msg);\n        }).finally(function(){\n            window.__tiConfigSaveActive692=false; window.__saveConfigInFlight=false; clearBusy();\n            if (window.tiHideSaveWaitOverlay1356) window.tiHideSaveWaitOverlay1356();\n            \/\/ 30.9.1364: questo controllo di sicurezza (pensato per i rari casi in cui ne' then() ne' catch()\n            \/\/ avessero resettato correttamente il pulsante) poteva sovrascrivere erroneamente uno stato di\n            \/\/ SUCCESSO appena impostato da resetButton(true), forzando lo stato \"sporco\" (verde con *) anche\n            \/\/ dopo un salvataggio riuscito - probabilmente per interferenza di un tentativo precedente annullato\n            \/\/ che completava il proprio ciclo in ritardo. Ora si applica solo se QUESTO specifico tentativo non\n            \/\/ ha gia' concluso con successo.\n            if (window.__tiLastSaveOutcome1364 !== 'success') {\n                var b=saveButton(); if(b && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving')==='1')) resetButton(false);\n            }\n            formatSaveStar();\n        });\n    }\n    directSave692.__tiDiag688 = true;\n    directSave692.__tiDirect692 = true;\n    function install(){\n        var b = saveButton();\n        window.saveConfig = directSave692;\n        window.saveConfig.__tiDiag688 = true;\n        window.saveConfig.__tiDirect692 = true;\n        if (b && !b.__tiDirect692Click) {\n            b.__tiDirect692Click = true;\n            try { b.onclick = function(ev){ if(ev){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } directSave692(); return false; }; } catch(e) {}\n        }\n        formatSaveStar();\n    }\n    document.addEventListener('click', function(ev){\n        if(!isSaveButton(ev && ev.target)) return;\n        try { ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); } catch(e) {}\n        log692('capture_click_salva', {buttonText: txt(saveButton() ? saveButton().innerText : ''), db:dbName()}, 'info');\n        directSave692();\n    }, true);\n    try {\n        var css=document.createElement('style');\n        css.id='ti-save-star-692-css';\n        css.textContent='#lbl-conf-save .ti-save-star-692{font-size:22px!important;line-height:10px!important;font-weight:900!important;vertical-align:-2px!important;margin-left:4px!important;color:#fff7ed!important;text-shadow:0 0 5px rgba(255,255,255,.65)!important;}';\n        document.head.appendChild(css);\n    } catch(e) {}\n    function observeSaveButton692(){\n        var root = document.getElementById('ti-conf-ov');\n        if (!root || root.__tiSaveButtonObserver692 || typeof MutationObserver === 'undefined') return;\n        root.__tiSaveButtonObserver692 = true;\n        var scheduled = 0;\n        new MutationObserver(function(muts){\n            var found = false;\n            for (var i=0; i<muts.length && !found; i++) {\n                var added = muts[i].addedNodes || [];\n                for (var j=0; j<added.length; j++) {\n                    var node = added[j];\n                    if (!node || node.nodeType !== 1) continue;\n                    if (node.id === 'lbl-conf-save' || (node.querySelector && node.querySelector('#lbl-conf-save'))) { found = true; break; }\n                }\n            }\n            if (!found || scheduled) return;\n            scheduled = (window.requestAnimationFrame || function(fn){ return setTimeout(fn,16); })(function(){ scheduled = 0; install(); });\n        }).observe(root,{childList:true,subtree:true});\n    }\n    install();\n    observeSaveButton692();\n    setTimeout(install, 0); setTimeout(install, 350); setTimeout(install, 1200);\n    setInterval(function(){ try { var b=saveButton(); if(b && !window.__tiConfigSaveActive692 && (\/salvataggio\/i.test(txt(b.innerText)) || b.disabled || b.getAttribute('data-ti-saving')==='1')) resetButton(false); } catch(e) {} }, 1000);\n})();\n<\/script>\n\n<script id=\"ti-batch-ai-products-services-693\">\n(function(){\n    \"use strict\";\n    if (window.__tiBatchAiProductsServices693Installed) return;\n    window.__tiBatchAiProductsServices693Installed = true;\n\n    function byId(id){ return document.getElementById(id); }\n    function esc(v){\n        if (window.escapeHtml) return window.escapeHtml(String(v == null ? '' : v));\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; });\n    }\n    function norm(v){ return String(v == null ? '' : v).trim(); }\n    function tableScopeFromText(v){\n        var p = norm(v).toLowerCase();\n        var wantsProd = \/prodott|articol|catalogo\/.test(p);\n        var wantsServ = \/serviz|prestaz|trattament\/.test(p);\n        if (wantsProd && wantsServ) return 'SEPARATI';\n        if (wantsServ) return 'Servizi';\n        return 'Prodotti';\n    }\n    function isPhotoPrompt(v){\n        var p = norm(v).toLowerCase();\n        if (!p) return false;\n        var photo = \/(genera|crea|aggiung|inserisc|prepara|produci).*(foto|immagin|image)|foto\\s+ai|immagin[ei]\\s+ai\/.test(p);\n        var scope = \/(prodott|articol|serviz|catalogo|tutti|tutte)\/.test(p);\n        return photo && scope;\n    }\n    function resolveDb(){\n        var candidates = [];\n        var d = byId('ti-ditta');\n        if (d && d.value) candidates.push(d.value);\n        if (window.tiCurrentSelectedDb) candidates.push(window.tiCurrentSelectedDb);\n        if (window.tiSessionDb) candidates.push(window.tiSessionDb);\n        try { var ls = localStorage.getItem('ti_saved_db'); if (ls) candidates.push(ls); } catch(e) {}\n        for (var i=0;i<candidates.length;i++) {\n            var v = norm(candidates[i]);\n            if (v && v !== 'NEW_DB' && v !== 'Global') return v;\n        }\n        return '';\n    }\n    function ajax693(action, data, ms){\n        return new Promise(function(resolve, reject){\n            var fd = new FormData();\n            fd.append('ti_action', action); fd.append('action', action);\n            Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k]); });\n            try { if (window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); } catch(e) {}\n            var url = window.tiUrl || window.tiAjaxUrl || window.location.href.split('?')[0];\n            var xhr = new XMLHttpRequest(), done = false;\n            function finish(ok, payload){ if (done) return; done = true; ok ? resolve(payload) : reject(payload); }\n            xhr.open('POST', url, true);\n            xhr.withCredentials = true;\n            xhr.timeout = ms || 60000;\n            xhr.onreadystatechange = function(){\n                if (xhr.readyState !== 4) return;\n                var raw = xhr.responseText || '';\n                if (xhr.status < 200 || xhr.status >= 300) return finish(false, new Error('HTTP ' + xhr.status + ': ' + raw.slice(0,240)));\n                var json = null;\n                try { json = JSON.parse(raw); } catch(e) { return finish(false, new Error('Risposta non JSON: ' + raw.slice(0,240))); }\n                finish(true, json);\n            };\n            xhr.ontimeout = function(){ finish(false, new Error('Timeout richiesta ' + action)); };\n            xhr.onerror = function(){ finish(false, new Error('Errore rete richiesta ' + action)); };\n            xhr.send(fd);\n        });\n    }\n    function ensureReply(){\n        var rb = byId('ti-conf-ai-reply');\n        if (rb) { rb.style.display = 'block'; return rb; }\n        var area = byId('ti-conf-ai-box') || byId('ti-conf-ov') || document.body;\n        rb = document.createElement('div');\n        rb.id = 'ti-conf-ai-reply';\n        rb.style.cssText = 'display:block;margin:10px 0;padding:10px;border:1px solid #334155;border-radius:10px;background:#0f172a;color:#e5e7eb;font-size:13px;line-height:1.45;max-height:260px;overflow:auto;';\n        area.appendChild(rb);\n        return rb;\n    }\n    function logBox(rb, html){ if (rb) rb.innerHTML = html; }\n    function buildBatchButton(){\n        try {\n            var allBtns = Array.prototype.slice.call(document.querySelectorAll('button'));\n            allBtns.forEach(function(b){\n                var label = String(b.textContent || '').replace(\/\\s+\/g,' ').trim();\n                if (b.id === 'ti-batch-ai-all-693' || \/^Genera (?:foto|immagini) AI Prodotti e Servizi$\/i.test(label)) {\n                    if (b.parentNode) b.parentNode.removeChild(b);\n                }\n            });\n        } catch(e) {}\n    }\n    function setButtonBusy(on){\n        try {\n            document.querySelectorAll('button').forEach(function(b){\n                var t = String(b.textContent || '');\n                if (\/^\\s*Genera (?:foto|immagini) AI (Prodotti|Servizi)\\s*$\/i.test(t)) {\n                    b.disabled = !!on;\n                    b.style.cursor = on ? 'wait' : '';\n                }\n            });\n        } catch(e) {}\n    }\n    window.tiRunBatchAIGen693 = function(tableName){\n        var db = resolveDb();\n        var rb = ensureReply();\n        var scope = norm(tableName || 'Prodotti');\n        if (\/prodotti\\s*e\\s*servizi\/i.test(scope) || \/,\/.test(scope) || scope === 'SEPARATI') {\n            setButtonBusy(false);\n            logBox(rb, '<span style=\"color:#fbbf24;\">Prodotti e Servizi devono essere generati con funzioni separate.<\/span><br>Usa prima <b>Genera immagini AI Prodotti<\/b> e poi <b>Genera immagini AI Servizi<\/b>, oppure viceversa.');\n            if (window.tiAlert) window.tiAlert('Prodotti e Servizi devono essere generati con pulsanti separati.');\n            return false;\n        }\n        if (!\/^Prodotti$|^Servizi$\/i.test(scope)) scope = 'Prodotti';\n        scope = \/^servizi$\/i.test(scope) ? 'Servizi' : 'Prodotti';\n        if (!db) { logBox(rb, '<span style=\"color:#fca5a5;\">Seleziona prima una ditta valida.<\/span>'); if (window.tiAlert) window.tiAlert('Seleziona prima una ditta valida.'); return false; }\n        var detailEl = byId('ti-conf-ai-photo-detail');\n        var photoDetail = detailEl ? norm(detailEl.value) : '';\n        setButtonBusy(true);\n        logBox(rb, 'Avvio generazione foto AI.<br>DB: <b>' + esc(db) + '<\/b><br>Tabelle: <b>' + esc(scope) + '<\/b><br>Preparazione elenco record...');\n        try { if (window.showProgressPopup) window.showProgressPopup('Generazione foto AI', 'Preparazione elenco record per ' + scope + '.', {startPercent:3,targetPercent:15,stepMs:350,cancellable:true}); } catch(e) {}\n        ajax693('ti_ai_config_action', {db:db, mode:'batch_ai_images', tables:scope, detail_prompt:photoDetail, source:'batch693'}, 45000).then(function(res){\n            if (!res || !res.success) throw new Error(res && res.data && res.data.message ? res.data.message : 'Errore preparazione batch immagini.');\n            var data = res.data || {};\n            var targets = Array.isArray(data.targets) ? data.targets : [];\n            if (!targets.length) {\n                setButtonBusy(false);\n                try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'Nessun record da elaborare', {notifyUser:false, remindSave:false}); } catch(e) {}\n                logBox(rb, 'Nessun record trovato per <b>' + esc(scope) + '<\/b> nel database <b>' + esc(db) + '<\/b>.<br>Verifica che la ditta selezionata abbia tabelle Prodotti\/Servizi con righe dati.');\n                return;\n            }\n            var total = targets.length, index = 0, ok = 0, fail = 0, skip = 0, logs = [];\n            window.tiBatchAIGenState = {active:true, db:db, tableName:scope, total:total, generated:[], startedAt:Date.now(), source:'693'};\n            logBox(rb, 'Generazione immagini AI pronta.<br>DB: <b>' + esc(db) + '<\/b><br>Tabelle: <b>' + esc(scope) + '<\/b><br>Record totali: <b>' + total + '<\/b><br>Priorita senza associazioni: <b>' + esc(data.without_associations || 0) + '<\/b><br>Avvio generazione...');\n            function cancelled(){ try { return !!(window.__tiProcessAbortConfirmed1546 || (window.isLongAIProcessCancelled && window.isLongAIProcessCancelled())); } catch(e) { return !!window.__tiProcessAbortConfirmed1546; } }\n            function refreshDb(){\n                if (window.refreshCurrentConfigDb) return Promise.resolve(window.refreshCurrentConfigDb(db)).catch(function(){});\n                return ajax693('ti_ai_get_db_data', {db:db}, 30000).then(function(r){ if (r && r.success && r.data) { window.currentDbData = r.data; if (window.renderConfig) window.renderConfig(); } }).catch(function(){});\n            }\n            function finish(){\n                setButtonBusy(false);\n                if (window.tiBatchAIGenState) window.tiBatchAIGenState.active = false;\n                try { if (window.updateProgressPopup) window.updateProgressPopup(100, 'Generazione foto AI', 'Completamento generazione.'); } catch(e) {}\n                Promise.resolve(refreshDb()).finally(function(){\n                    try { if (window.hideProgressPopup) window.hideProgressPopup(true, 'Generazione foto AI completata', {remindSave:false, successMessage:'Immagini generate\/verificate: ' + ok + ' su ' + total + '. Errori: ' + fail + '.'}); } catch(e) {}\n                    logBox(rb, '\u2705 Generazione foto AI completata.<br>DB: <b>' + esc(db) + '<\/b><br>Tabelle: <b>' + esc(scope) + '<\/b><br>Immagini associate\/verificate: <b>' + ok + '<\/b> \/ ' + total + '<br>Gia presenti\/saltate: <b>' + skip + '<\/b><br>Errori: <b>' + fail + '<\/b><br><br>' + logs.slice(0,120).join('<br>'));\n                });\n            }\n            function next(){\n                if (cancelled()) { setButtonBusy(false); if (window.tiBatchAIGenState) window.tiBatchAIGenState.active=false; logBox(rb, 'Generazione foto AI interrotta dall utente.<br>Completate: ' + ok + '. Errori: ' + fail + '.'); return; }\n                if (index >= total) return finish();\n                var item = targets[index] || {};\n                var name = item.name || 'Elemento';\n                var pct = Math.max(5, Math.min(98, Math.round(((index + 0.1) \/ total) * 100)));\n                try { if (window.updateProgressPopup) window.updateProgressPopup(pct, 'Generazione foto AI', 'Elaborazione ' + (index+1) + ' \/ ' + total + ': ' + name, name); } catch(e) {}\n                logBox(rb, 'Generazione foto AI in corso...<br>DB: <b>' + esc(db) + '<\/b><br>Tabelle: <b>' + esc(scope) + '<\/b><br>Elaborazione <b>' + (index+1) + '<\/b> \/ ' + total + ': <b>' + esc(name) + '<\/b><br><br>' + logs.slice(-20).join('<br>'));\n                ajax693('ti_ai_config_action', {db:db, mode:'batch_ai_image_one', table:item.table || scope.split(',')[0], row_index:item.row_index, detail_prompt:photoDetail, source:'batch693'}, 180000).then(function(one){\n                    var d = one && one.data ? one.data : {};\n                    if (one && one.success && d.generated) {\n                        ok++;\n                        if (window.tiBatchAIGenState && Array.isArray(window.tiBatchAIGenState.generated) && (d.added_value || d.filename || d.url)) {\n                            window.tiBatchAIGenState.generated.push({table:d.table || item.table || '', row_index:(typeof d.row_index !== 'undefined') ? d.row_index : item.row_index, field:d.image_field || 'Immagine', value:d.added_value || d.filename || d.url, name:d.name || name});\n                        }\n                        logs.push('\u2705 ' + esc(d.name || name) + ': ' + (d.fallback_logo ? 'usato logo ditta' : 'immagine generata e associazione salvata'));\n                    } else if (one && one.success && d.skipped) {\n                        skip++; logs.push('\u23ed\ufe0f ' + esc(d.name || name) + ': gia presente');\n                    } else {\n                        fail++; logs.push('\u274c ' + esc(d.name || name) + ': ' + esc(d.message || 'errore generazione'));\n                    }\n                }).catch(function(err){ fail++; logs.push('\u274c ' + esc(name) + ': ' + esc(err && err.message ? err.message : 'errore rete\/timeout')); }).finally(function(){ index++; setTimeout(next, 250); });\n            }\n            next();\n        }).catch(function(err){\n            setButtonBusy(false);\n            try { if (window.hideProgressPopup) window.hideProgressPopup(false, 'Errore generazione foto AI'); } catch(e) {}\n            logBox(rb, '<span style=\"color:#fca5a5;\">Errore avvio generazione foto AI:<\/span><br>' + esc(err && err.message ? err.message : 'errore sconosciuto') + '<br><br>DB: <b>' + esc(db) + '<\/b><br>Tabelle: <b>' + esc(scope) + '<\/b>');\n            if (window.tiAlert) window.tiAlert('Errore avvio generazione foto AI: ' + (err && err.message ? err.message : 'errore sconosciuto'));\n        });\n        return false;\n    };\n\n    window.runBatchAIGen = function(tableName){ return window.tiRunBatchAIGen693(tableName || 'Prodotti'); };\n    window.runBatchAIGen.__tiBatch693 = true;\n\n    var prevRunConfigBot = window.runConfigBot;\n    if (typeof prevRunConfigBot === 'function' && !prevRunConfigBot.__tiPhotoPrompt693) {\n        window.runConfigBot = function(){\n            var box = byId('ti-conf-ai-prompt');\n            var prompt = box ? norm(box.value || '') : '';\n            if (isPhotoPrompt(prompt)) {\n                var scope = tableScopeFromText(prompt);\n                var rb = ensureReply();\n                rb.style.display = 'block';\n                if (scope === 'SEPARATI') {\n                    rb.innerHTML = 'Richiesta riconosciuta: generazione foto AI per <b>Prodotti<\/b> e <b>Servizi<\/b>.<br>Per scelta operativa i flussi restano separati: premi <b>Genera immagini AI Prodotti<\/b> e poi <b>Genera immagini AI Servizi<\/b>.';\n                    return false;\n                }\n                rb.innerHTML = 'Richiesta riconosciuta: generazione foto AI per <b>' + esc(scope) + '<\/b>.<br>Avvio batch dedicato...';\n                return window.tiRunBatchAIGen693(scope);\n            }\n            return prevRunConfigBot.apply(this, arguments);\n        };\n        window.runConfigBot.__tiPhotoPrompt693 = true;\n        var send = byId('ti-conf-ai-send');\n        if (send) send.onclick = function(ev){ if (ev) ev.preventDefault(); return window.runConfigBot(); };\n    }\n\n    document.addEventListener('click', function(ev){\n        var t = ev && ev.target;\n        if (!t || !t.closest) return;\n        var b = t.closest('button');\n        if (!b) return;\n        var label = String(b.textContent || '').trim();\n        if (\/^Genera (?:foto|immagini) AI Prodotti e Servizi$\/i.test(label)) { ev.preventDefault(); ev.stopPropagation(); buildBatchButton(); return false; }\n        if (\/^Genera immagini AI Prodotti$\/i.test(label)) { ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); window.tiRunBatchAIGen693('Prodotti'); }\n        else if (\/^Genera immagini AI Servizi$\/i.test(label)) { ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); window.tiRunBatchAIGen693('Servizi'); }\n    }, true);\n\n    buildBatchButton();\n    \/\/ 30.9.1484: rimosso observer globale; il pulsante viene creato all'avvio e dopo i render iniziali.\n    setTimeout(buildBatchButton, 300); setTimeout(buildBatchButton, 1200);\n})();\n<\/script>\n\n\n\n<script id=\"ti-batch-ai-products-services-698\">\n(function(){\n    \"use strict\";\n    if (window.__tiBatchAiProductsServices698Installed) return;\n    window.__tiBatchAiProductsServices698Installed = true;\n    function byId(id){ return document.getElementById(id); }\n    function norm(v){ return String(v == null ? '' : v).trim(); }\n    function esc(v){\n        if (window.escapeHtml) return window.escapeHtml(String(v == null ? '' : v));\n        return String(v == null ? '' : v).replace(\/[&<>\"']\/g, function(c){ return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c]; });\n    }\n    function resolveDb(){\n        var candidates=[];\n        var d=byId('ti-ditta'); if(d && d.value) candidates.push(d.value);\n        if(window.tiCurrentSelectedDb) candidates.push(window.tiCurrentSelectedDb);\n        if(window.tiSessionDb) candidates.push(window.tiSessionDb);\n        try{ var ls=localStorage.getItem('ti_saved_db'); if(ls) candidates.push(ls); }catch(e){}\n        for(var i=0;i<candidates.length;i++){ var v=norm(candidates[i]); if(v && v!=='NEW_DB' && v!=='Global') return v; }\n        return '';\n    }\n    function ajax698(action, data, ms){\n        return new Promise(function(resolve,reject){\n            var fd=new FormData();\n            fd.append('ti_action', action); fd.append('action', action);\n            Object.keys(data || {}).forEach(function(k){ fd.append(k, data[k]); });\n            try{ if(window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); }catch(e){}\n            var url=window.tiUrl || window.tiAjaxUrl || window.location.href.split('?')[0];\n            var xhr=new XMLHttpRequest(), done=false;\n            function finish(ok,payload){ if(done) return; done=true; ok ? resolve(payload) : reject(payload); }\n            xhr.open('POST', url, true);\n            xhr.withCredentials=true;\n            xhr.timeout=ms || 30000;\n            xhr.onreadystatechange=function(){\n                if(xhr.readyState!==4) return;\n                var raw=xhr.responseText || '';\n                if(xhr.status<200 || xhr.status>=300) return finish(false, new Error('HTTP '+xhr.status+' ['+action+']: '+raw.slice(0,240)));\n                var json=null;\n                try{ json=JSON.parse(raw); }catch(e){ return finish(false, new Error('Risposta non JSON: '+raw.slice(0,240))); }\n                finish(true,json);\n            };\n            xhr.ontimeout=function(){ finish(false, new Error('Timeout richiesta '+action)); };\n            xhr.onerror=function(){ finish(false, new Error('Errore rete richiesta '+action)); };\n            xhr.send(fd);\n        });\n    }\n    function ensureReply(){\n        var rb=byId('ti-conf-ai-reply');\n        if(rb){ rb.style.display='block'; return rb; }\n        var area=byId('ti-conf-ai-area') || byId('ti-config-form') || document.body;\n        rb=document.createElement('div');\n        rb.id='ti-conf-ai-reply';\n        rb.style.cssText='margin:10px 0;padding:10px;border:1px solid rgba(148,163,184,.35);border-radius:10px;background:rgba(15,23,42,.92);color:#e5e7eb;font-size:13px;line-height:1.45;';\n        area.appendChild(rb);\n        return rb;\n    }\n    function setButtonBusy(on){\n        try{\n            document.querySelectorAll('button').forEach(function(b){\n                var t=String(b.textContent || '');\n                if(\/^\\s*Genera (?:foto|immagini) AI (Prodotti|Servizi)\\s*$\/i.test(t)){\n                    b.disabled=!!on;\n                    b.style.cursor=on?'wait':'';\n                }\n            });\n        }catch(e){}\n    }\n    function isPhotoPrompt(v){\n        var p=norm(v).toLowerCase();\n        if(!p) return false;\n        var photo=\/(genera|crea|aggiung|inserisc|prepara|produci).*(foto|immagin|image)|foto\\s+ai|immagin[ei]\\s+ai\/.test(p);\n        var scope=\/(prodott|articol|serviz|catalogo|tutti|tutte)\/.test(p);\n        return photo && scope;\n    }\n    function tableScopeFromText(v){\n        var p=norm(v).toLowerCase();\n        var wantsProd=\/prodott|articol|catalogo\/.test(p);\n        var wantsServ=\/serviz|prestaz|trattament\/.test(p);\n        if(wantsProd && wantsServ) return 'SEPARATI';\n        if(wantsServ) return 'Servizi';\n        return 'Prodotti';\n    }\n    window.tiRunBatchAIGen698=function(tableName){\n        var rb=ensureReply();\n        var db=resolveDb();\n        var scope=norm(tableName || 'Prodotti');\n        if(\/prodotti\\s*e\\s*servizi\/i.test(scope) || \/,\/.test(scope) || scope==='SEPARATI'){\n            setButtonBusy(false);\n            rb.innerHTML='<span style=\"color:#fbbf24;\">Prodotti e Servizi devono essere generati con funzioni separate.<\/span><br>Usa il pulsante <b>Genera immagini AI Prodotti<\/b> oppure <b>Genera immagini AI Servizi<\/b>.';\n            if(window.tiAlert) window.tiAlert('Prodotti e Servizi devono essere generati con pulsanti separati.');\n            return false;\n        }\n        if(!\/^Prodotti$|^Servizi$\/i.test(scope)) scope='Prodotti';\n        scope=\/^servizi$\/i.test(scope) ? 'Servizi' : 'Prodotti';\n        if(!db){ rb.innerHTML='<span style=\"color:#fca5a5;\">Seleziona prima una ditta valida.<\/span>'; if(window.tiAlert) window.tiAlert('Seleziona prima una ditta valida.'); return false; }\n        if(window.tiBatchAIGenState && window.tiBatchAIGenState.active){\n            rb.innerHTML='Generazione foto AI gia in corso.<br>DB: <b>'+esc(window.tiBatchAIGenState.db || db)+'<\/b><br>Tabella: <b>'+esc(window.tiBatchAIGenState.tableName || scope)+'<\/b>.';\n            return false;\n        }\n        var detailEl=byId('ti-conf-ai-photo-detail');\n        var photoDetail=detailEl ? norm(detailEl.value) : '';\n        window.tiBatchAIGenState={active:true,preparing:true,db:db,tableName:scope,total:0,generated:[],startedAt:Date.now(),source:'698'};\n        setButtonBusy(true);\n        rb.innerHTML='Avvio generazione foto AI.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Preparazione elenco record tramite endpoint leggero 698...';\n        try{ if(window.showProgressPopup) window.showProgressPopup('Generazione foto AI','Preparazione elenco record per '+scope+'.',{startPercent:3,targetPercent:15,stepMs:350,cancellable:true}); }catch(e){}\n        ajax698('ti_ai_batch_ai_images_prepare_698', {db:db, tables:scope, detail_prompt:photoDetail, source:'batch698'}, 20000).then(function(res){\n            if(!res || !res.success) throw new Error(res && res.data && res.data.message ? res.data.message : 'Errore preparazione elenco record.');\n            var data=res.data || {};\n            var targets=Array.isArray(data.targets) ? data.targets : [];\n            if(!targets.length){\n                setButtonBusy(false);\n                if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n                try{ if(window.hideProgressPopup) window.hideProgressPopup(true,'Nessun record da elaborare',{notifyUser:false,remindSave:false}); }catch(e){}\n                rb.innerHTML='Nessun record trovato per <b>'+esc(scope)+'<\/b> nel database <b>'+esc(db)+'<\/b>.<br>Verifica che la tabella esista e contenga righe dati.';\n                return;\n            }\n            var total=targets.length,index=0,ok=0,fail=0,skip=0,logs=[];\n            window.tiBatchAIGenState={active:true,preparing:false,db:db,tableName:scope,total:total,generated:[],startedAt:Date.now(),source:'698'};\n            rb.innerHTML='Elenco record pronto.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Record totali: <b>'+total+'<\/b><br>Senza associazioni: <b>'+esc(data.without_associations || 0)+'<\/b><br>Gia con associazioni: <b>'+esc(data.with_associations || 0)+'<\/b><br>Avvio generazione separata '+esc(scope)+'...';\n            function cancelled(){ try{ return !!(window.__tiProcessAbortConfirmed1546 || (window.tiBatchAIGenState&&window.tiBatchAIGenState.cancelled) || (window.isLongAIProcessCancelled && window.isLongAIProcessCancelled())); }catch(e){ return !!window.__tiProcessAbortConfirmed1546; } }\n            function refreshDb(){\n                if(window.refreshCurrentConfigDb) return Promise.resolve(window.refreshCurrentConfigDb(db)).catch(function(){});\n                return ajax698('ti_ai_get_db_data', {db:db}, 30000).then(function(r){ if(r && r.success && r.data){ window.currentDbData=r.data; if(window.renderConfig) window.renderConfig(); } }).catch(function(){});\n            }\n            function finish(){\n                setButtonBusy(false);\n                if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n                try{ if(window.updateProgressPopup) window.updateProgressPopup(100,'Generazione foto AI','Completamento generazione.'); }catch(e){}\n                Promise.resolve(refreshDb()).finally(function(){\n                    try{ if(window.hideProgressPopup) window.hideProgressPopup(true,'Generazione foto AI completata',{remindSave:false,successMessage:'Immagini generate\/verificate: '+ok+' su '+total+'. Errori: '+fail+'.'}); }catch(e){}\n                    rb.innerHTML='\u2705 Generazione foto AI completata.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Immagini associate\/verificate: <b>'+ok+'<\/b> \/ '+total+'<br>Gia presenti\/saltate: <b>'+skip+'<\/b><br>Errori: <b>'+fail+'<\/b><br><br><b>Salvataggio progressivo attivo:<\/b> ogni immagine completata e gia associata al relativo record. Puoi riprendere in seguito scegliendo <b>Solo mancanti<\/b>.<br><br>'+logs.slice(0,120).join('<br>');\n                });\n            }\n            function next(){\n                if(cancelled()){ setButtonBusy(false); if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false; rb.innerHTML='Generazione foto AI interrotta dall utente.<br>Completate: '+ok+'. Errori: '+fail+'.'; return; }\n                if(index>=total) return finish();\n                var item=targets[index] || {};\n                var name=item.name || 'Elemento';\n                var pct=Math.max(5,Math.min(98,Math.round(((index+0.1)\/total)*100)));\n                try{ if(window.updateProgressPopup) window.updateProgressPopup(pct,'Generazione foto AI','Elaborazione '+(index+1)+' \/ '+total+': '+name,name); }catch(e){}\n                rb.innerHTML='Generazione foto AI in corso...<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Elaborazione <b>'+(index+1)+'<\/b> \/ '+total+': <b>'+esc(name)+'<\/b><br><br>'+logs.slice(-20).join('<br>');\n                ajax698('ti_ai_batch_ai_image_one_698', {db:db, table:item.table || scope, row_index:item.row_index, detail_prompt:photoDetail, source:'batch698'}, 240000).then(function(one){\n                    var d=one && one.data ? one.data : {};\n                    if(one && one.success && d.generated){\n                        ok++;\n                        if(window.tiBatchAIGenState && Array.isArray(window.tiBatchAIGenState.generated) && (d.added_value || d.filename || d.url)){\n                            window.tiBatchAIGenState.generated.push({table:d.table || item.table || '', row_index:(typeof d.row_index!=='undefined') ? d.row_index : item.row_index, field:d.image_field || 'Immagine', value:d.added_value || d.filename || d.url, name:d.name || name});\n                        }\n                        logs.push('\u2705 '+esc(d.name || name)+': '+(d.fallback_logo ? 'usato logo ditta' : 'immagine generata e associazione salvata'));\n                    } else if(one && one.success && d.skipped){\n                        skip++; logs.push('\u23ed\ufe0f '+esc(d.name || name)+': gia presente');\n                    } else {\n                        fail++; logs.push('\u274c '+esc(d.name || name)+': '+esc(d.message || 'errore generazione'));\n                    }\n                }).catch(function(err){ fail++; logs.push('\u274c '+esc(name)+': '+esc(err && err.message ? err.message : 'errore rete\/timeout')); }).finally(function(){ index++; setTimeout(next,250); });\n            }\n            next();\n        }).catch(function(err){\n            setButtonBusy(false);\n            if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n            try{ if(window.hideProgressPopup) window.hideProgressPopup(false,'Errore generazione foto AI'); }catch(e){}\n            rb.innerHTML='<span style=\"color:#fca5a5;\">Errore preparazione generazione foto AI:<\/span><br>'+esc(err && err.message ? err.message : 'errore sconosciuto')+'<br><br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b>';\n            if(window.tiAlert) window.tiAlert('Errore preparazione generazione foto AI: '+(err && err.message ? err.message : 'errore sconosciuto'));\n        });\n        return false;\n    };\n    window.tiRunBatchAIGen693=window.tiRunBatchAIGen698;\n    window.runBatchAIGen=function(tableName){ return window.tiRunBatchAIGen698(tableName || 'Prodotti'); };\n    window.runBatchAIGen.__tiBatch698=true;\n    var prevRunConfigBot=window.runConfigBot;\n    if(typeof prevRunConfigBot==='function' && !prevRunConfigBot.__tiPhotoPrompt698){\n        window.runConfigBot=function(){\n            var box=byId('ti-conf-ai-prompt');\n            var prompt=box ? norm(box.value || '') : '';\n            if(isPhotoPrompt(prompt)){\n                var scope=tableScopeFromText(prompt);\n                var rb=ensureReply(); rb.style.display='block';\n                if(scope==='SEPARATI'){\n                    rb.innerHTML='Richiesta riconosciuta: generazione foto AI per <b>Prodotti<\/b> e <b>Servizi<\/b>.<br>I flussi restano separati: usa <b>Genera immagini AI Prodotti<\/b> e poi <b>Genera immagini AI Servizi<\/b>.';\n                    return false;\n                }\n                rb.innerHTML='Richiesta riconosciuta: generazione foto AI per <b>'+esc(scope)+'<\/b>.<br>Avvio batch dedicato 698...';\n                return window.tiRunBatchAIGen698(scope);\n            }\n            return prevRunConfigBot.apply(this, arguments);\n        };\n        window.runConfigBot.__tiPhotoPrompt698=true;\n        var send=byId('ti-conf-ai-send'); if(send) send.onclick=function(ev){ if(ev) ev.preventDefault(); return window.runConfigBot(); };\n    }\n    document.addEventListener('click', function(ev){\n        var t=ev && ev.target;\n        if(!t || !t.closest) return;\n        var b=t.closest('button'); if(!b) return;\n        var label=String(b.textContent || '').trim();\n        if(\/^Genera (?:foto|immagini) AI Prodotti e Servizi$\/i.test(label)){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); if(window.tiAlert) window.tiAlert('Prodotti e Servizi devono essere generati con pulsanti separati.'); return false; }\n        if(\/^Genera immagini AI Prodotti$\/i.test(label)){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); return window.tiRunBatchAIGen698('Prodotti'); }\n        if(\/^Genera immagini AI Servizi$\/i.test(label)){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); return window.tiRunBatchAIGen698('Servizi'); }\n    }, true);\n})();\n<\/script>\n\n\n\n<script id=\"ti-batch-ai-products-services-706\">\n(function(){\n    if(window.__tiBatchAI706Applied) return; window.__tiBatchAI706Applied=true;\n    function byId(id){ return document.getElementById(id); }\n    function norm(v){ return (v==null?'':String(v)).trim(); }\n    function esc(s){ return String(s==null?'':s).replace(\/[&<>\"']\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c];}); }\n    function normalizeKey(k){ return String(k||'').toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').replace(\/[^a-z0-9]\/g,''); }\n    function resolveDb(){\n        var candidates=[];\n        var d=byId('ti-ditta'); if(d && d.value) candidates.push(d.value);\n        if(window.tiCurrentSelectedDb) candidates.push(window.tiCurrentSelectedDb);\n        if(window.tiSessionDb) candidates.push(window.tiSessionDb);\n        try{ var ls=localStorage.getItem('ti_saved_db'); if(ls) candidates.push(ls); }catch(e){}\n        for(var i=0;i<candidates.length;i++){ var v=norm(candidates[i]); if(v && v!=='NEW_DB' && v!=='Global') return v; }\n        return '';\n    }\n    function ensureReply(){\n        var rb=byId('ti-conf-ai-reply');\n        if(rb){\n            rb.style.display='block';\n            \/\/ 30.9.1453: porta l'elemento di stato in vista automaticamente - confermato che il testo si\n            \/\/ aggiornava correttamente (\"Elaborazione X\/Y...\"), ma l'utente non lo notava perche' l'elemento\n            \/\/ poteva trovarsi fuori dalla porzione di schermo visibile, dando l'impressione che il processo non\n            \/\/ stesse facendo nulla o che mancasse del tutto un riscontro visivo.\n            try { rb.scrollIntoView({behavior:'smooth', block:'nearest'}); } catch(e) { try { rb.scrollIntoView(); } catch(e2) {} }\n            return rb;\n        }\n        var area=byId('ti-conf-ai-area') || byId('ti-config-form') || document.body;\n        rb=document.createElement('div'); rb.id='ti-conf-ai-reply';\n        rb.style.cssText='margin:10px 0;padding:10px;border:1px solid rgba(148,163,184,.35);border-radius:10px;background:rgba(15,23,42,.92);color:#e5e7eb;font-size:13px;line-height:1.45;';\n        area.appendChild(rb);\n        try { rb.scrollIntoView({behavior:'smooth', block:'nearest'}); } catch(e) { try { rb.scrollIntoView(); } catch(e2) {} }\n        return rb;\n    }\n    function setButtonBusy(on){\n        try{ document.querySelectorAll('button').forEach(function(b){\n            var t=String(b.textContent || '').replace(\/\\s+\/g,' ').trim();\n            if(\/^Genera immagini AI (Prodotti|Servizi)$\/i.test(t)){ b.disabled=!!on; b.style.cursor=on?'wait':''; }\n        }); }catch(e){}\n    }\n    function ajax706(action, data, ms){\n        return new Promise(function(resolve,reject){\n            var fd=new FormData(); fd.append('ti_action',action); fd.append('action',action);\n            Object.keys(data||{}).forEach(function(k){ fd.append(k,data[k]); });\n            try{ if(window.tiAppendCurrentLanguageToFormData) window.tiAppendCurrentLanguageToFormData(fd); }catch(e){}\n            var url=window.tiUrl || window.tiAjaxUrl || window.location.href.split('?')[0];\n            var xhr=new XMLHttpRequest(), done=false;\n            var timeoutMs1445 = ms||30000;\n            var startedAt1445 = Date.now ? Date.now() : (new Date()).getTime();\n            var abortKind1445 = '';\n            function finish(ok,payload){ if(done) return; done=true; try{clearTimeout(watchdog1445);}catch(e){} try{clearInterval(intervalWatch1445);}catch(e){} try{document.removeEventListener('visibilitychange',visWatch1445);window.removeEventListener('focus',visWatch1445);}catch(e){} try{if(window.__tiProcessXhrs1546)window.__tiProcessXhrs1546.delete(xhr);if(window.tiBatchAIGenState&&window.tiBatchAIGenState.activeXhr===xhr)window.tiBatchAIGenState.activeXhr=null;}catch(e){} ok?resolve(payload):reject(payload); }\n            \/\/ 30.9.1445: CORREZIONE - confermato con un caso reale (log diagnostico che si ferma esattamente\n            \/\/ dopo \"avvio ajax706\", senza mai un esito successivo) che questa funzione, affidandosi al solo\n            \/\/ timeout nativo XHR senza alcuna ridondanza, poteva restare bloccata indefinitamente nello stesso\n            \/\/ modo gia' riscontrato e risolto altrove in questa sessione per il salvataggio configurazione.\n            \/\/ Stessi quattro meccanismi indipendenti (timeout nativo, controllo periodico, requestAnimationFrame,\n            \/\/ cambio scheda\/focus) usati con successo li' vengono applicati anche qui.\n            function doTimeout1445(source){ if(done) return; abortKind1445='timeout'; try{ xhr.abort(); }catch(e){} finish(false, new Error('Timeout richiesta '+action+' ('+source+').')); }\n            var watchdog1445 = setTimeout(function(){ doTimeout1445('setTimeout'); }, timeoutMs1445);\n            var intervalWatch1445 = setInterval(function(){\n                if (done) { clearInterval(intervalWatch1445); return; }\n                if ((Date.now?Date.now():(new Date()).getTime()) - startedAt1445 >= timeoutMs1445) doTimeout1445('controllo-periodico');\n            }, 2000);\n            function rafWatch1445(){\n                if (done) return;\n                if ((Date.now?Date.now():(new Date()).getTime()) - startedAt1445 >= timeoutMs1445) { doTimeout1445('requestAnimationFrame'); return; }\n                try { if (typeof requestAnimationFrame === 'function') requestAnimationFrame(rafWatch1445); else setTimeout(rafWatch1445, 200); } catch(e) { setTimeout(rafWatch1445, 200); }\n            }\n            try { rafWatch1445(); } catch(e) {}\n            try {\n                var visWatch1445 = function(){ if (!done && !document.hidden && (Date.now?Date.now():(new Date()).getTime()) - startedAt1445 >= timeoutMs1445) doTimeout1445('visibilitychange-o-focus'); };\n                document.addEventListener('visibilitychange', visWatch1445);\n                window.addEventListener('focus', visWatch1445);\n            } catch(e) {}\n            xhr.open('POST',url,true); xhr.withCredentials=true; xhr.timeout=timeoutMs1445;\n            xhr.onreadystatechange=function(){\n                if(xhr.readyState!==4) return;\n                var raw=xhr.responseText || '';\n                if(xhr.status<200 || xhr.status>=300) return finish(false,new Error('HTTP '+xhr.status+' ['+action+']: '+raw.slice(0,240)));\n                var json=null; try{ json=JSON.parse(raw); }catch(e){ return finish(false,new Error('Risposta non JSON: '+raw.slice(0,240))); }\n                finish(true,json);\n            };\n            xhr.ontimeout=function(){ finish(false,new Error('Timeout richiesta '+action)); };\n            xhr.onerror=function(){ finish(false,new Error('Errore rete richiesta '+action)); };\n            xhr.onabort=function(){ if(abortKind1445==='timeout')return finish(false,new Error('Timeout richiesta '+action)); var er=new Error('Operazione interrotta dall utente.'); er.userCancelled=true; finish(false,er); };\n            try{ if(!window.__tiProcessXhrs1546)window.__tiProcessXhrs1546=new Set(); window.__tiProcessXhrs1546.add(xhr); if(window.tiBatchAIGenState)window.tiBatchAIGenState.activeXhr=xhr; }catch(e){}\n            xhr.send(fd);\n        });\n    }\n    function getTables(){\n        var db = (window.currentDbData && window.currentDbData.Tabelle) ? window.currentDbData : null;\n        if(!db && window.currentDbViewData && window.currentDbViewData.Tabelle) db=window.currentDbViewData;\n        return db && db.Tabelle ? db.Tabelle : null;\n    }\n    function realTableName(tables, wanted){\n        if(!tables) return wanted;\n        var nw=normalizeKey(wanted);\n        if(Object.prototype.hasOwnProperty.call(tables,wanted)) return wanted;\n        var keys=Object.keys(tables);\n        for(var i=0;i<keys.length;i++){ if(normalizeKey(keys[i])===nw) return keys[i]; }\n        if(\/^prodotti$\/i.test(wanted)){\n            for(var p=0;p<keys.length;p++){ if(\/prodott|articol\/i.test(keys[p])) return keys[p]; }\n        }\n        if(\/^servizi$\/i.test(wanted)){\n            for(var s=0;s<keys.length;s++){ if(\/serviz|prestaz|trattament\/i.test(keys[s])) return keys[s]; }\n        }\n        return wanted;\n    }\n    function pick(row, keys){\n        if(!row) return '';\n        var rowKeys=Object.keys(row), map={}; rowKeys.forEach(function(k){ map[normalizeKey(k)]=k; });\n        for(var i=0;i<keys.length;i++){ var rk=map[normalizeKey(keys[i])]; if(rk && norm(row[rk])!=='') return norm(row[rk]); }\n        return '';\n    }\n    function splitValues(v){\n        var s=norm(v); if(!s) return [];\n        return s.split(\/[\\n|;]+\/).map(function(x){ return norm(x); }).filter(Boolean);\n    }\n    function looksMedia(v){ return \/\\.(png|jpe?g|webp|gif|pdf|docx?|xlsx?|csv|txt)$\/i.test(v) || \/ti_ai_get_image|\\\/wp-content\\\/uploads\\\/AI-data\/i.test(v); }\n    function mediaName1644(v){\n        var s=norm(v); if(!s) return '';\n        try{s=decodeURIComponent(s);}catch(e){}\n        try{\n            var u=new URL(s,window.location.href), qn=u.searchParams.get('file')||u.searchParams.get('filename')||u.searchParams.get('name')||u.searchParams.get('image')||u.searchParams.get('img');\n            if(qn){try{qn=decodeURIComponent(qn);}catch(e){} return String(qn).split('\/').pop();}\n            return String(u.pathname||s).split('\/').pop();\n        }catch(e){return s.replace(\/[?#].*$\/,'').split('\/').pop();}\n    }\n    function splitImageValues1644(v){var s=norm(v);if(!s)return [];return s.split(\/[\\n|;,]+\/).map(function(x){return norm(x);}).filter(Boolean);}\n    function companyLogoNames1644(){\n        var tables=getTables(),out=[]; if(!tables)return out;\n        var cfg=realTableName(tables,'Config'),rows=tables[cfg]; if(rows&&!Array.isArray(rows))rows=Object.values(rows||{});\n        var r=(Array.isArray(rows)&&rows.length)?rows[0]:null; if(!r)return out;\n        splitImageValues1644(pick(r,['Logo'])).forEach(function(v){var n=mediaName1644(v);if(n)out.push(String(n).toLowerCase());});\n        return out;\n    }\n    function countMedia(row){\n        var stats={valid:0,logo:0,totalImages:0}; if(!row||typeof row!=='object')return stats;\n        var logos=companyLogoNames1644();\n        Object.keys(row).forEach(function(k){\n            var nk=normalizeKey(k); if(!\/(immagine|immagini|image|images|foto|photo|picture|img)\/i.test(nk)||\/logo\/i.test(nk))return;\n            splitImageValues1644(row[k]).forEach(function(v){var n=mediaName1644(v);if(!n||!\/\\.(png|jpe?g|webp|gif|avif|bmp|svg)$\/i.test(n))return;stats.totalImages++;if(logos.indexOf(String(n).toLowerCase())!==-1)stats.logo++;else stats.valid++;});\n        });\n        return stats;\n    }\n    function prepareTargetsLocal(scope){\n        var tables=getTables();\n        if(!tables) return {ok:false,message:'Dati configurazione non disponibili in memoria. Riapri Configurazione e riprova.'};\n        var real=realTableName(tables,scope);\n        var rows=tables[real];\n        if(rows && !Array.isArray(rows)) rows=Object.values(rows||{});\n        if(!Array.isArray(rows)) return {ok:false,message:'Tabella '+scope+' non trovata nella configurazione corrente.'};\n        var no=[], yes=[];\n        rows.forEach(function(row,idx){\n            if(!row || typeof row!=='object') return;\n            var ms1644=countMedia(row),ac=ms1644.valid||0;\n            var name=pick(row,['Prodotto','Servizio','Nome','Titolo','Articolo','Descrizione','Dettaglio','Note']);\n            if(!name) name='Elemento riga '+(idx+1);\n            var target={table:real,row_index:idx,row_ref:idx+1,name:name,has_associations:ac>0,association_count:ac,logo_placeholder_count:(ms1644.logo||0),priority_label:(ac>0?'gia con immagine valida':((ms1644.logo||0)>0?'solo logo ditta - immagine da generare':'senza immagine valida'))};\n            if(ac>0) yes.push(target); else no.push(target);\n        });\n        var all1644=no.concat(yes),logoRows1644=all1644.filter(function(t){return (t.logo_placeholder_count||0)>0&&!t.has_associations;}).length;\n        return {ok:true,targets:all1644,without_associations:no.length,with_associations:yes.length,logo_placeholders:logoRows1644,requested_tables:[real]};\n    }\n    function cancelled(){ try{ return !!(window.__tiProcessAbortConfirmed1546 || (window.tiBatchAIGenState&&window.tiBatchAIGenState.cancelled) || (window.isLongAIProcessCancelled && window.isLongAIProcessCancelled())); }catch(e){ return !!window.__tiProcessAbortConfirmed1546; } }\n    \/\/ 30.9.1712: motore autorevole nello stesso script della Configurazione.\n    \/\/ Non dipende da wp_footer e non puo quindi ricadere sul prepareTargetsLocal delle sole 100 righe cache.\n    function tiBatchFullDbModal1712(title,html,buttons){\n        try{var old=document.getElementById('ti-img-full-db-inline-1712');if(old)old.remove();}catch(e){}\n        var ov=document.createElement('div');ov.id='ti-img-full-db-inline-1712';ov.style.cssText='position:fixed;inset:0;z-index:2147483647;background:rgba(0,0,0,.64);display:flex;align-items:center;justify-content:center;padding:18px;';\n        var box=document.createElement('div');box.style.cssText='width:min(640px,94vw);max-height:88vh;overflow:auto;background:#111827;color:#e5e7eb;border:1px solid #475569;border-radius:12px;padding:18px;box-shadow:0 20px 55px rgba(0,0,0,.48);font-family:inherit;';\n        box.innerHTML='<div style=\"font-weight:800;font-size:17px;margin-bottom:10px;\">'+esc(title)+'<\/div><div style=\"font-size:13px;line-height:1.55;\">'+html+'<\/div>';\n        var row=document.createElement('div');row.style.cssText='display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;margin-top:16px;';\n        (buttons||[]).forEach(function(spec){var b=document.createElement('button');b.type='button';b.textContent=spec.label;b.style.cssText='border:none;border-radius:7px;padding:8px 12px;font-size:12px;font-weight:800;cursor:pointer;background:'+(spec.primary?'#059669':'#374151')+';color:#fff;';b.onclick=function(){try{ov.remove();}catch(e){} if(spec.fn)spec.fn();};row.appendChild(b);});\n        box.appendChild(row);ov.appendChild(box);document.body.appendChild(ov);return ov;\n    }\n    function runFullDbInline1712(tableName){\n        var rb=ensureReply(),db=resolveDb(),scope=\/^servizi$\/i.test(norm(tableName||'Prodotti'))?'Servizi':'Prodotti';\n        if(!db){rb.innerHTML='<span style=\"color:#fca5a5;\">Seleziona prima una ditta valida.<\/span>';return false;}\n        if(window.tiBatchAIGenState&&window.tiBatchAIGenState.active){var age=Date.now()-(window.tiBatchAIGenState.startedAt||0);if(age<30000){rb.innerHTML='Generazione immagini gia in corso.';return false;}window.tiBatchAIGenState.active=false;}\n        var countEl=byId('ti-conf-ai-image-count-1672'),rawCount=countEl?norm(countEl.value):'',requested=parseInt(rawCount||'0',10);if(!isFinite(requested)||requested<1)requested=0;\n        var detailEl=byId('ti-conf-ai-photo-detail'),detailPrompt=detailEl?norm(detailEl.value):'';\n        var rnd='';try{rnd=(window.crypto&&window.crypto.randomUUID)?window.crypto.randomUUID():Math.random().toString(36).slice(2)+Math.random().toString(36).slice(2);}catch(e){rnd=Math.random().toString(36).slice(2);}var jobId='batch706-'+Date.now()+'-'+rnd;\n        window.__tiProcessAbortConfirmed1546=false;window.__tiActiveBatch706Token1546=jobId;\n        window.tiBatchAIGenState={active:true,preparing:true,db:db,tableName:scope,total:0,generated:[],startedAt:Date.now(),source:'1712-inline-full-db',jobId:jobId};\n        setButtonBusy(true);rb.innerHTML='Conteggio di <b>'+esc(scope)+'<\/b> sull <b>intero database<\/b>...<br><small>La cache Configurazione da 100 righe non viene usata.<\/small>';\n        try{if(window.showProgressPopup)window.showProgressPopup('Generazione foto AI','Conteggio completo '+scope+' nel database.',{startPercent:3,targetPercent:10,stepMs:350,cancellable:true});}catch(e){}\n        function stopFail(err){setButtonBusy(false);if(window.tiBatchAIGenState)window.tiBatchAIGenState.active=false;try{if(window.hideProgressPopup)window.hideProgressPopup(false,'Generazione immagini non avviata',{notifyUser:false});}catch(e){}var m=err&&err.message?err.message:String(err||'Errore generazione immagini.');rb.innerHTML='<span style=\"color:#fca5a5;\">'+esc(m)+'<\/span>';}\n        function cancelled1712(){try{return !!(window.__tiProcessAbortConfirmed1546||(window.tiBatchAIGenState&&window.tiBatchAIGenState.cancelled));}catch(e){return false;}}\n        function invalidate1712(){try{if(window.__tiCatalogCache1686)window.__tiCatalogCache1686={};}catch(e){}try{if(window.__tiConfigVirtualPageCache1698)delete window.__tiConfigVirtualPageCache1698[scope];}catch(e){}}\n        ajax706('ti_ai_batch_images_prepare_full_1710',{db:db,tables:scope,detail_prompt:detailPrompt,counts_only:1,source:'batch1712-inline-full-db'},180000).then(function(res){\n            if(cancelled1712())throw new Error('Operazione interrotta dall utente.');\n            if(!res||!res.success)throw new Error(res&&res.data&&res.data.message?res.data.message:'Conteggio completo non riuscito.');\n            var p=res.data||{},total=parseInt(p.total||0,10)||0,dbRows=parseInt(p.table_rows_total||0,10)||0,withImg=parseInt(p.with_associations||0,10)||0,missing=parseInt(p.without_associations||0,10)||0,logos=parseInt(p.logo_placeholders||0,10)||0,token=norm(p.selection_token||'');\n            if(!p.authoritative_full_database_1710)throw new Error('Conteggio full-DB non autorevole. Processo fermato: non verranno usate le 100 righe cache.');\n            if(!dbRows)dbRows=total;\n            if(dbRows>100&&total<=100)throw new Error('Il database contiene '+dbRows+' righe ma il batch ne ha rilevate solo '+total+'. Processo fermato per evitare la cache da 100.');\n            if(total<1||!token)throw new Error('Nessun record disponibile o snapshot completo non creato.');\n            window.tiBatchAIGenState.total=total;window.tiBatchAIGenState.preparing=false;\n            try{console.info('[Shop-Service] batch immagini 1712 conteggio FULL DB',{db:db,table:scope,tableRows:dbRows,total:total,withImages:withImg,missing:missing,requested:requested});}catch(e){}\n            try{if(window.hideProgressPopup)window.hideProgressPopup(true,'Conteggio completo pronto',{notifyUser:false,remindSave:false});}catch(e){}\n            function planned(avail){return requested>0?Math.min(requested,avail):avail;}\n            function poll1712(){\n                if(cancelled1712()){ajax706('ti_ai_batch706_cancel_job',{db:db,table:scope,job_id:(window.tiBatchAIGenState&&window.tiBatchAIGenState.jobId)||jobId},15000).catch(function(){});setButtonBusy(false);window.tiBatchAIGenState.active=false;return;}\n                ajax706('ti_ai_batch706_get_status',{db:db,table:scope,job_id:(window.tiBatchAIGenState&&window.tiBatchAIGenState.jobId)||jobId},25000).then(function(rs){\n                    if(!rs||!rs.success){setTimeout(poll1712,4000);return;}\n                    var d=rs.data||{};try{if(window.tiApplyImageServerState1785)window.tiApplyImageServerState1785(d);}catch(e){}var tot=parseInt(d.total||window.tiBatchAIGenState.total||1,10)||1,ok=parseInt(d.ok||0,10)||0,fail=parseInt(d.fail||0,10)||0,skip=parseInt(d.skip||0,10)||0,done=ok+fail+skip,pct=Math.max(5,Math.min(99,Math.round(done\/Math.max(1,tot)*100)));\n                    try{if(window.updateProgressPopup)window.updateProgressPopup(pct,'Generazione foto AI',done+' \/ '+tot+(d.current_item?': '+d.current_item:''),d.current_item||'');}catch(e){}\n                    rb.innerHTML='Generazione immagini AI in corso.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Completati: <b>'+done+'<\/b> \/ '+tot+'<br>Riuscite: <b>'+ok+'<\/b> \u00b7 Errori: <b>'+fail+'<\/b> \u00b7 Saltate: <b>'+skip+'<\/b><br><small>Conteggio iniziale full DB: '+dbRows+' righe. Massimo 1 tentativo AI per voce.<\/small>';\n                    if(d.status==='done'||d.status==='cancelled'||d.status==='error'){setButtonBusy(false);window.tiBatchAIGenState.active=false;invalidate1712();var title=d.status==='done'?'Generazione completata':(d.status==='cancelled'?'Generazione interrotta':'Generazione terminata con errore');try{if(window.hideProgressPopup)window.hideProgressPopup(d.status==='done',title,{notifyUser:false,remindSave:false});}catch(e){}rb.innerHTML='<b>'+esc(title)+'<\/b><br>Totale job: '+tot+' \u00b7 Riuscite: '+ok+' \u00b7 Errori: '+fail+' \u00b7 Saltate: '+skip+'<br><br>Le immagini completate sono gia salvate. Per proseguire usa <b>Solo mancanti<\/b>.';return;}\n                    setTimeout(poll1712,4000);\n                }).catch(function(){if(!cancelled1712())setTimeout(poll1712,5000);});\n            }\n            function startJob1712(mode,count){\n                setButtonBusy(true);rb.innerHTML='Avvio job su <b>'+count+'<\/b> '+esc(scope)+'.<br>Selezione ricavata dall intero database ('+dbRows+' righe).';\n                try{if(window.showProgressPopup)window.showProgressPopup('Generazione foto AI','Avvio job: '+count+' '+scope+'.',{startPercent:3,targetPercent:8,stepMs:350,cancellable:true});}catch(e){}\n                ajax706('ti_ai_batch706_start_job',{db:db,table:scope,selection_token:token,selection_mode:mode,requested_count:requested,detail_prompt:detailPrompt,job_id:jobId,source:'batch1712-inline-full-db'},60000).then(function(sr){\n                    if(!sr||!sr.success)throw new Error(sr&&sr.data&&sr.data.message?sr.data.message:'Avvio job non riuscito.');\n                    var d=sr.data||{};if(d.fallback_direct)throw new Error('Worker server non disponibile. Processo non duplicato: nessun fallback automatico.');if(d.cancelled){setButtonBusy(false);window.tiBatchAIGenState.active=false;return;}\n                    window.tiBatchAIGenState.total=parseInt(d.total||count,10)||count;window.tiBatchAIGenState.jobId=d.job_id||jobId;poll1712();\n                }).catch(stopFail);\n            }\n            function confirmLong1712(mode,count,label){\n                var go=function(){startJob1712(mode,count);};\n                if(count<200){go();return;}\n                var h='<div style=\"padding:10px;border:1px solid #f59e0b;border-radius:8px;background:#422006;color:#fde68a;\"><b>\u26a0\ufe0f Processo molto lungo<\/b><br>Stai per richiedere <b>'+count+'<\/b> immagini su '+dbRows+' voci '+esc(scope)+'. Con centinaia o migliaia di immagini i tempi possono essere molto lunghi.<br><br>Le immagini completate vengono salvate progressivamente.<\/div><div style=\"margin-top:10px;\">Modalita: <b>'+esc(label)+'<\/b>. Confermi?<\/div>';\n                tiBatchFullDbModal1712('Conferma generazione immagini',h,[{label:'Esci',fn:function(){setButtonBusy(false);window.tiBatchAIGenState.active=false;}},{label:'Conferma ('+count+')',primary:true,fn:go}]);\n            }\n            function startMode1712(mode){var avail=mode==='missing'?missing:total,count=planned(avail);if(count<1){setButtonBusy(false);window.tiBatchAIGenState.active=false;rb.innerHTML='Nessun elemento disponibile per la modalita selezionata.';return;}confirmLong1712(mode,count,mode==='missing'?'Solo mancanti':'Rigenera tutti');}\n            var req=requested>0?('<br><br>N. immagini richiesto: <b>'+requested+'<\/b>.'):('<br><br>N. immagini: <b>Tutte<\/b>.');\n            var html='Trovati <b>'+withImg+'<\/b> elementi su <b>'+total+'<\/b> che hanno gia una vera immagine associata. Il logo della ditta non viene considerato immagine valida.'+(logos>0?'<br><br><b>'+logos+'<\/b> elementi contengono solo il logo ditta e sono considerati mancanti.':'')+'<br><br><b>Righe fisiche della tabella nel database: '+dbRows+'<\/b>. La cache da 100 serve solo alla visualizzazione e non viene usata per questo processo.'+req+'<br><br>Le immagini gia completate sono salvate progressivamente: per continuare usa <b>Solo mancanti<\/b>.';\n            if(withImg>0){tiBatchFullDbModal1712('Alcune immagini valide sono gia presenti',html,[{label:'Chiudi',fn:function(){setButtonBusy(false);window.tiBatchAIGenState.active=false;}},{label:'Rigenera tutti ('+total+')',fn:function(){startMode1712('all');}},{label:'Solo mancanti ('+missing+')',primary:true,fn:function(){startMode1712('missing');}}]);}\n            else{rb.innerHTML='<b>Conteggio database completo:<\/b> '+total+' '+esc(scope)+' ('+dbRows+' righe fisiche). Nessuna immagine valida presente.';startMode1712('all');}\n        }).catch(stopFail);\n        return false;\n    }\n    window.tiRunBatchAIGen706=function(tableName){\n        \/\/ 30.9.1712: percorso unico e obbligatorio full DB nello script principale.\n        \/\/ Nessun fallback a prepareTargetsLocal\/currentDbData: la cache da 100 non puo diventare il totale.\n        return runFullDbInline1712(tableName||'Prodotti');\n        window.__tiProcessAbortConfirmed1546 = false;\n        window.__tiProcessCancelEpoch1546 = (parseInt(window.__tiProcessCancelEpoch1546||0,10)||0) + 1;\n        var tiRnd1546='';try{tiRnd1546=(window.crypto&&window.crypto.randomUUID)?window.crypto.randomUUID():Math.random().toString(36).slice(2)+Math.random().toString(36).slice(2);}catch(e){tiRnd1546=Math.random().toString(36).slice(2);}\n        window.__tiActiveBatch706Token1546 = 'batch706-' + Date.now() + '-' + tiRnd1546;\n        window.__tiBatch706AutoRetryCount = 0;\n        try { var tipEl1458 = document.getElementById('ti-loader-tip-keep-active-1458'); if (tipEl1458) tipEl1458.style.display = 'block'; } catch(e) {}\n        \/\/ 30.9.1459: worker dedicato su thread separato del browser - richiesto esplicitamente dall'utente dopo\n        \/\/ aver confermato che un cambio scheda causava un rallentamento di oltre 150 secondi tra un elemento e\n        \/\/ il successivo (dato che i timer del thread principale vengono fortemente rallentati dal browser\n        \/\/ quando la scheda passa in secondo piano). I timer di un web worker sono molto meno soggetti a questo\n        \/\/ rallentamento, essendo su un thread separato. Non risolve il caso di sospensione totale del\n        \/\/ dispositivo\/chiusura del browser (limite del sistema operativo, non aggirabile da codice), ma aiuta\n        \/\/ significativamente nel caso piu' comune di cambio scheda\/app con il browser ancora attivo.\n        try {\n            if (window.__tiBatch706TimerWorker) { try { window.__tiBatch706TimerWorker.terminate(); } catch(eOld) {} }\n            var workerCode1459 = 'setInterval(function(){ postMessage(1); }, 200);';\n            var blob1459 = new Blob([workerCode1459], {type: 'application\/javascript'});\n            var workerUrl1459 = URL.createObjectURL(blob1459);\n            window.__tiBatch706TimerWorker = new Worker(workerUrl1459);\n            window.__tiBatch706PendingFire = null;\n            window.__tiBatch706TimerWorker.onmessage = function(){\n                try {\n                    var pending = window.__tiBatch706PendingFire;\n                    if (pending && (Date.now?Date.now():(new Date()).getTime()) >= pending.fireAt) {\n                        window.__tiBatch706PendingFire = null;\n                        pending.callback('web-worker');\n                    }\n                } catch(e) {}\n            };\n        } catch(eWorker1459) { window.__tiBatch706TimerWorker = null; }\n        var rb=ensureReply(), db=resolveDb();\n        var scope=norm(tableName||'Prodotti');\n        \/\/ 30.9.1386: la diagnostica precedente (1384) inviava una richiesta di rete separata al server per ogni\n        \/\/ singolo passaggio - durante un processo bloccato su 46 elementi, questo poteva generare centinaia di\n        \/\/ richieste aggiuntive, aggravando il carico sul server invece di limitarsi a osservarlo. Ora la\n        \/\/ diagnostica e' puramente locale (nessuna richiesta di rete), visibile direttamente a schermo.\n        var diagT0_1383 = Date.now();\n        var showDiag1383 = window.tiStrictAdminLog1488 === true;\n        window.__tiBatch706DiagLog = [];\n        function copyFullDiagLog1389(){\n            try {\n                var fullText = window.__tiBatch706DiagLog.join('\\n');\n                if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(fullText);\n                else { var ta=document.createElement('textarea'); ta.value=fullText; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); }\n            } catch(e) {}\n        }\n        function diag1383(msg){\n            try {\n                var line = '+' + (Date.now()-diagT0_1383) + 'ms: ' + msg;\n                window.__tiBatch706DiagLog.push(line);\n                if (window.__tiBatch706DiagLog.length > 400) window.__tiBatch706DiagLog.shift();\n                \/\/ 30.9.1388: il riquadro precedente (in rb) risultava coperto\/non visibile dietro il popup di\n                \/\/ avanzamento, che e' l'unico elemento realmente visibile durante il processo - ora la\n                \/\/ diagnostica viene iniettata direttamente nel popup stesso (sotto il testo esistente),\n                \/\/ aggiungendo un piccolo elemento dedicato se non gia' presente, senza toccare il testo\n                \/\/ originale del popup (percentuale\/titolo) gestito separatamente.\n                var loaderSub = showDiag1383 ? document.getElementById('ti-loader-sub') : null;\n                if (loaderSub) {\n                    var diagWrap = document.getElementById('ti-batch706-diag-wrap');\n                    if (!diagWrap) {\n                        diagWrap = document.createElement('div');\n                        diagWrap.id = 'ti-batch706-diag-wrap';\n                        diagWrap.style.cssText = 'margin-top:8px;text-align:left;';\n                        var diagCopyBtn = document.createElement('button');\n                        diagCopyBtn.type = 'button';\n                        diagCopyBtn.textContent = 'Copia log';\n                        diagCopyBtn.style.cssText = 'font-size:10px;padding:3px 8px;border-radius:5px;border:1px solid #475569;background:#334155;color:#e5e7eb;cursor:pointer;margin-bottom:4px;';\n                        \/\/ 30.9.1389: tasto per copiare l'intera traccia diagnostica accumulata (non solo le\n                        \/\/ ultime righe visibili), cosi' l'utente puo' condividerla facilmente per intero.\n                        diagCopyBtn.onclick = copyFullDiagLog1389;\n                        diagWrap.appendChild(diagCopyBtn);\n                        var diagBox = document.createElement('div');\n                        diagBox.id = 'ti-batch706-diag-box';\n                        diagBox.style.cssText = 'font-size:10px;color:#94a3b8;max-height:110px;overflow-y:auto;background:#0b1220;border:1px solid #374151;border-radius:6px;padding:5px;';\n                        diagWrap.appendChild(diagBox);\n                        loaderSub.parentNode.insertBefore(diagWrap, loaderSub.nextSibling);\n                    }\n                    var diagBoxEl = document.getElementById('ti-batch706-diag-box');\n                    if (diagBoxEl) diagBoxEl.innerHTML = window.__tiBatch706DiagLog.slice(-20).join('<br>');\n                }\n                var diagBoxRb = showDiag1383 ? byId('ti-batch706-diag-box-rb') : null;\n                if (diagBoxRb) diagBoxRb.innerHTML = window.__tiBatch706DiagLog.slice(-30).join('<br>');\n                var diagCopyBtnRb = byId('ti-batch706-diag-copy-rb');\n                if (diagCopyBtnRb && !diagCopyBtnRb.__tiBound1389) { diagCopyBtnRb.__tiBound1389 = true; diagCopyBtnRb.onclick = copyFullDiagLog1389; }\n            } catch(e) {}\n        }\n        \/\/ 30.9.1394: cattura GLOBALE di qualsiasi errore JavaScript non gestito sulla pagina, attiva per tutta\n        \/\/ la durata del processo - un setTimeout di soli 80ms che non scatta mai (con la pagina attivamente\n        \/\/ sotto osservazione, quindi non in background) e' comportamento anomalo del browser; questo rivela se\n        \/\/ qualcos'altro, anche completamente estraneo a questa funzione, sta interferendo con l'esecuzione.\n        if (!window.__tiGlobalErrorCapture1394Installed) {\n            window.__tiGlobalErrorCapture1394Installed = true;\n            window.addEventListener('error', function(ev){\n                try {\n                    var msg = 'ERRORE GLOBALE JS: ' + (ev.message||'sconosciuto') + ' | file=' + (ev.filename||'n\/d') + ':' + (ev.lineno||'?') + ' | stack=' + (ev.error && ev.error.stack ? String(ev.error.stack).slice(0,200) : 'n\/d');\n                    if (window.__tiBatch706DiagLog) {\n                        window.__tiBatch706DiagLog.push('+' + (Date.now()-diagT0_1383) + 'ms: ' + msg);\n                        var diagBoxD2 = document.getElementById('ti-batch706-diag-box');\n                        if (diagBoxD2) diagBoxD2.innerHTML = window.__tiBatch706DiagLog.slice(-20).join('<br>');\n                        var diagBoxRbD2 = document.getElementById('ti-batch706-diag-box-rb');\n                        if (diagBoxRbD2) diagBoxRbD2.innerHTML = window.__tiBatch706DiagLog.slice(-30).join('<br>');\n                    }\n                } catch(e) {}\n            });\n        }\n        diag1383('avvio tabella=' + scope);\n        \/\/ 30.9.1465: rimossa la diagnostica 1395 (rilevamento ricaricamento pagina durante il processo) - aveva\n        \/\/ gia' assolto il suo scopo confermando la causa del blocco, ormai affrontata con il nuovo motore\n        \/\/ server-side; la sua notifica visibile all'utente non era piu' necessaria.\n        if(\/prodotti\\s*e\\s*servizi\/i.test(scope) || \/,\/.test(scope) || scope==='SEPARATI'){\n            setButtonBusy(false);\n            rb.innerHTML='<span style=\"color:#fbbf24;\">Prodotti e Servizi devono essere generati con funzioni separate.<\/span><br>Usa il pulsante <b>Genera immagini AI Prodotti<\/b> oppure <b>Genera immagini AI Servizi<\/b>.';\n            if(window.tiAlert) window.tiAlert('Prodotti e Servizi devono essere generati con pulsanti separati.');\n            return false;\n        }\n        scope=\/^servizi$\/i.test(scope)?'Servizi':'Prodotti';\n        if(!db){ rb.innerHTML='<span style=\"color:#fca5a5;\">Seleziona prima una ditta valida.<\/span>'; return false; }\n        if(window.tiBatchAIGenState && window.tiBatchAIGenState.active){\n            var age=Date.now()-(window.tiBatchAIGenState.startedAt||0);\n            if(age<30000){ rb.innerHTML='Generazione foto AI gia in corso.<br>DB: <b>'+esc(window.tiBatchAIGenState.db||db)+'<\/b><br>Tabella: <b>'+esc(window.tiBatchAIGenState.tableName||scope)+'<\/b>.'; return false; }\n            window.tiBatchAIGenState.active=false;\n        }\n        var detailEl=byId('ti-conf-ai-photo-detail'); var photoDetail=detailEl?norm(detailEl.value):'';\n        \/\/ 30.9.1672: limite volontario per lavorare la generazione immagini in blocchi precisi.\n        \/\/ Vuoto o 0 = tutte le voci della modalita scelta; N > 0 = prime N voci.\n        function requestedImageCount1672(){\n            var el1672=byId('ti-conf-ai-image-count-1672');\n            if(!el1672) return 0;\n            var raw1672=norm(el1672.value);\n            if(raw1672==='') return 0;\n            var n1672=parseInt(raw1672,10);\n            return isFinite(n1672)&&n1672>0?n1672:0;\n        }\n        function applyImageLimit1672(list1672){\n            var arr1672=Array.isArray(list1672)?list1672.slice():[];\n            var n1672=requestedImageCount1672();\n            if(n1672>0 && arr1672.length>n1672){\n                diag1383('1672 limite immagini applicato: richieste='+n1672+' disponibili='+arr1672.length);\n                return arr1672.slice(0,n1672);\n            }\n            if(n1672>0) diag1383('1672 limite immagini: richieste='+n1672+' disponibili='+arr1672.length+' (elaborate tutte le disponibili)');\n            return arr1672;\n        }\n        window.tiBatchAIGenState={active:true,preparing:true,db:db,tableName:scope,total:0,generated:[],startedAt:Date.now(),source:'706',cancelToken1546:window.__tiActiveBatch706Token1546,jobId:window.__tiActiveBatch706Token1546};\n        setButtonBusy(true);\n        rb.innerHTML='Avvio generazione foto AI.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Preparazione elenco record locale, senza chiamata server pesante...'+(showDiag1383?'<br><br><b>Traccia diagnostica:<\/b> <button type=\"button\" id=\"ti-batch706-diag-copy-rb\" style=\"font-size:10px;padding:3px 8px;border-radius:5px;border:1px solid #475569;background:#334155;color:#e5e7eb;cursor:pointer;\">Copia log<\/button><div id=\"ti-batch706-diag-box-rb\" style=\"font-size:11px;color:#94a3b8;max-height:150px;overflow-y:auto;background:#0b1220;border:1px solid #374151;border-radius:6px;padding:6px;margin-top:4px;\"><\/div>':'');\n        try{ if(window.showProgressPopup) window.showProgressPopup('Generazione foto AI','Preparazione elenco record per '+scope+'.',{startPercent:3,targetPercent:12,stepMs:350,cancellable:true}); }catch(e){}\n        diag1383('popup mostrato, avvio prepareTargetsLocal');\n        var prep=prepareTargetsLocal(scope);\n        diag1383('prepareTargetsLocal completata ok=' + prep.ok + ' targets=' + (prep.targets ? prep.targets.length : 0));\n        try {\n        if(!prep.ok){\n            setButtonBusy(false); window.tiBatchAIGenState.active=false;\n            try{ if(window.hideProgressPopup) window.hideProgressPopup(false,'Errore preparazione generazione foto AI'); }catch(e){}\n            rb.innerHTML='<span style=\"color:#fca5a5;\">'+esc(prep.message)+'<\/span>';\n            if(window.tiAlert) window.tiAlert(prep.message);\n            return false;\n        }\n        var targets=prep.targets||[];\n        if(!targets.length){\n            setButtonBusy(false); window.tiBatchAIGenState.active=false;\n            try{ if(window.hideProgressPopup) window.hideProgressPopup(true,'Nessun record da elaborare',{notifyUser:false,remindSave:false}); }catch(e){}\n            rb.innerHTML='Nessun record trovato per <b>'+esc(scope)+'<\/b> nel database <b>'+esc(db)+'<\/b>.';\n            return false;\n        }\n        } catch(errFatal1391) {\n            diag1383('ERRORE FATALE catturato: ' + (errFatal1391 && errFatal1391.message ? errFatal1391.message : String(errFatal1391)) + ' | stack: ' + (errFatal1391 && errFatal1391.stack ? String(errFatal1391.stack).slice(0,300) : 'n\/d'));\n            try{ setButtonBusy(false); if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false; }catch(e){}\n            try{ if(window.hideProgressPopup) window.hideProgressPopup(false,'Errore imprevisto durante la preparazione'); }catch(e){}\n            return false;\n        }\n        \/\/ condivisa tra i due motori (server-side e client-side) - dipende solo da db, gia' nello scope esterno\n        \/\/ comune a entrambi.\n        function refreshDb(){\n            if(window.refreshCurrentConfigDb) return Promise.resolve(window.refreshCurrentConfigDb(db)).catch(function(){});\n            return ajax706('ti_ai_get_db_data',{db:db},30000).then(function(r){ if(r && r.success && r.data){ window.currentDbData=r.data; if(window.renderConfig) window.renderConfig(); } }).catch(function(){});\n        }\n        \/\/ 30.9.1460: nuovo motore server-side, richiesto esplicitamente dall'utente dopo aver confermato che anche\n\/\/ con il web worker (v1459) un cambio prolungato di scheda\/app poteva causare ritardi residui. Con questo\n\/\/ motore il lavoro reale avviene interamente sul server tramite WP-Cron (vedi funzioni PHP\n\/\/ ti_ai_batch706_*); questa funzione avvia il job e poi si limita a interrogare periodicamente lo stato per\n\/\/ aggiornare l'interfaccia. Se l'avvio non viene confermato, il token viene annullato e l utente deve\n\/\/ ripetere il processo dall inizio: nessun fallback automatico, per evitare job duplicati o orfani.\nfunction proceedWithTargetsServer1460(finalTargets){\n            var total = finalTargets.length;\n            var serverWatchStarted1580 = Date.now ? Date.now() : (new Date()).getTime();\n            var fallbackActivated1580 = false;\n            window.tiBatchAIGenState = {active:true, preparing:false, db:db, tableName:scope, total:total, generated:[], startedAt:Date.now(), source:'706-server',cancelToken1546:window.__tiActiveBatch706Token1546,jobId:window.__tiActiveBatch706Token1546};\n            diag1383('avvio motore server-side, total=' + total);\n            rb.innerHTML = 'Avvio elaborazione lato server...<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b>';\n            try{ if(window.showProgressPopup) window.showProgressPopup('Generazione foto AI','Avvio elaborazione lato server per '+scope+'.',{startPercent:3,targetPercent:8,stepMs:350,cancellable:true}); }catch(e){}\n            var targetsForServer = finalTargets.map(function(t){ return {table:(t.table||scope), row_index:t.row_index, name:(t.name||'Elemento')}; });\n            function stopUnconfirmedStart1546(detail){\n                var token1546=(window.tiBatchAIGenState&&window.tiBatchAIGenState.jobId)||window.__tiActiveBatch706Token1546||'';\n                try{ajax706('ti_ai_batch706_cancel_job',{db:db,table:scope,job_id:token1546},15000).catch(function(){});}catch(e){}\n                setButtonBusy(false);\n                if(window.tiBatchAIGenState){window.tiBatchAIGenState.active=false;window.tiBatchAIGenState.cancelled=true;}\n                var msg1546='Avvio del processo non confermato. Il job e stato annullato per evitare duplicazioni. Devi ripetere la generazione dall inizio.'+(detail?'<br><small>'+esc(detail)+'<\/small>':'');\n                rb.innerHTML=msg1546;\n                try{if(window.hideProgressPopup)window.hideProgressPopup(false,msg1546.replace(\/<br>\/g,' ').replace(\/<[^>]+>\/g,''),{notifyUser:false});}catch(e){}\n            }\n            \/\/ 30.9.1580: se WP-Cron registra il job ma il worker non entra realmente in esecuzione,\n            \/\/ passa automaticamente al motore diretto per-riga gia collaudato, dopo avere annullato il job\n            \/\/ server e creato un token nuovo. In questo modo non ci sono doppie generazioni.\n            function fallbackToDirect1580(reason){\n                if(fallbackActivated1580 || cancelled()) return;\n                fallbackActivated1580 = true;\n                var oldToken1580=(window.tiBatchAIGenState&&window.tiBatchAIGenState.jobId)||window.__tiActiveBatch706Token1546||'';\n                diag1383('1580 fallback motore diretto: '+(reason||'worker server non partito'));\n                rb.innerHTML='Worker server non entrato in esecuzione.<br>Passaggio automatico alla generazione diretta per <b>'+esc(scope)+'<\/b>...';\n                try{if(window.updateProgressPopup)window.updateProgressPopup(6,'Generazione foto AI','Worker server non partito: attivo motore diretto.');}catch(e){}\n                function beginDirect1580(){\n                    if(cancelled()) return;\n                    var rnd1580='';try{rnd1580=(window.crypto&&window.crypto.randomUUID)?window.crypto.randomUUID():Math.random().toString(36).slice(2)+Math.random().toString(36).slice(2);}catch(e){rnd1580=Math.random().toString(36).slice(2);}\n                    window.__tiActiveBatch706Token1546='batch706-direct-'+Date.now()+'-'+rnd1580;\n                    window.__tiProcessAbortConfirmed1546=false;\n                    if(window.tiBatchAIGenState){window.tiBatchAIGenState.active=false;window.tiBatchAIGenState.cancelled=false;}\n                    proceedWithTargets1450(finalTargets);\n                }\n                try{\n                    ajax706('ti_ai_batch706_cancel_job',{db:db,table:scope,job_id:oldToken1580},15000).then(beginDirect1580,function(){beginDirect1580();});\n                }catch(e){beginDirect1580();}\n            }\n            ajax706('ti_ai_batch706_start_job',{db:db, table:scope, targets:JSON.stringify(targetsForServer), detail_prompt:photoDetail, requested_count:requestedImageCount1672(), job_id:window.__tiActiveBatch706Token1546},30000).then(function(startRes){\n                if(cancelled()) return;\n                if(!startRes || !startRes.success){\n                    var startMsg1581 = startRes && startRes.data && startRes.data.message ? String(startRes.data.message) : 'Risposta server non valida.';\n                    diag1383('1705 avvio server-side non disponibile: chiusura prudenziale senza fallback automatico. '+startMsg1581);\n                    stopUnconfirmedStart1546(startMsg1581 + ' Nessun secondo tentativo automatico viene eseguito.');\n                    return;\n                }\n                if(startRes.data && startRes.data.fallback_direct){\n                    diag1383('1581 server richiede fallback diretto: '+String(startRes.data.fallback_reason||'preflight server non compatibile'));\n                    fallbackToDirect1580(String(startRes.data.fallback_reason||'preflight server non compatibile'));\n                    return;\n                }\n                if(window.tiBatchAIGenState) window.tiBatchAIGenState.jobId = (startRes.data&&startRes.data.job_id)||window.__tiActiveBatch706Token1546;\n                if(startRes.data&&startRes.data.cancelled){\n                    setButtonBusy(false);if(window.tiBatchAIGenState){window.tiBatchAIGenState.active=false;window.tiBatchAIGenState.cancelled=true;}\n                    rb.innerHTML='Generazione immagini AI interrotta prima dell avvio. Per eseguirla devi ripetere il processo dall inizio.';\n                    try{if(window.hideProgressPopup)window.hideProgressPopup(true,'Processo interrotto',{notifyUser:false,remindSave:false});}catch(e){}\n                    return;\n                }\n                diag1383('job server-side avviato con successo');\n                pollStatus1460();\n            }).catch(function(err){\n                if(cancelled() || (err&&err.userCancelled)){ diag1383('avvio server-side interrotto dall utente: nessun fallback'); return; }\n                var errMsg1581=err&&err.message?err.message:'Errore di rete.';\n                diag1383('1705 avvio server-side non confermato per errore\/timeout: chiusura prudenziale senza fallback automatico. '+errMsg1581);\n                stopUnconfirmedStart1546(errMsg1581 + ' Nessun secondo tentativo automatico viene eseguito.');\n            });\n            function pollStatus1460(){\n                if(window.tiBatchAIGenState && window.tiBatchAIGenState.source==='706-server' && !window.tiBatchAIGenState.active){\n                    try{ ajax706('ti_ai_batch706_cancel_job',{db:db,table:scope,job_id:(window.tiBatchAIGenState&&window.tiBatchAIGenState.jobId)||''},15000).catch(function(){}); }catch(e){}\n                    return;\n                }\n                ajax706('ti_ai_batch706_get_status',{db:db,table:scope,job_id:(window.tiBatchAIGenState&&window.tiBatchAIGenState.jobId)||window.__tiActiveBatch706Token1546||''},20000).then(function(res){\n                    if(cancelled()) return; if(!res || !res.success){ if(!cancelled()) window.__tiBatch706PollTimer1546=setTimeout(pollStatus1460, 4000); return; }\n                    var d = res.data || {};\n                    if(d.status==='superseded'){\n                        setButtonBusy(false);if(window.tiBatchAIGenState){window.tiBatchAIGenState.active=false;window.tiBatchAIGenState.cancelled=true;}\n                        rb.innerHTML='Questo processo non e piu quello attivo ed e stato chiuso. Per eseguirlo devi ripetere la generazione dall inizio.';\n                        try{if(window.hideProgressPopup)window.hideProgressPopup(false,'Processo sostituito: ripetere dall inizio',{notifyUser:false});}catch(e){}\n                        return;\n                    }\n                    var doneCount = (d.ok||0) + (d.fail||0) + (d.skip||0);\n                    var workerStarted1580 = parseInt(d.worker_started_at||0,10)||0;\n                    var elapsedServer1580 = (Date.now?Date.now():(new Date()).getTime()) - serverWatchStarted1580;\n                    if(!fallbackActivated1580 && d.status==='running' && doneCount===0 && workerStarted1580<=0 && elapsedServer1580>=12000){\n                        stopUnconfirmedStart1546('Worker non confermato dopo '+Math.round(elapsedServer1580\/1000)+'s. Nessun passaggio automatico al motore diretto: evita una seconda generazione dello stesso elemento.');\n                        return;\n                    }\n                    if(fallbackActivated1580) return;\n                    var pct = Math.max(5, Math.min(98, Math.round((doneCount\/Math.max(1,total))*100)));\n                    try{ if(window.updateProgressPopup) window.updateProgressPopup(pct,'Generazione foto AI', doneCount+' \/ '+total+(d.current_item?': '+d.current_item:''), d.current_item||''); }catch(e){}\n                    rb.innerHTML='Generazione foto AI in corso (motore server)...<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Completati: <b>'+doneCount+'<\/b> \/ '+total+'<br><br>'+(d.logs_tail||[]).slice(-20).join('<br>');\n                    if(d.status==='done'){\n                        setButtonBusy(false); if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n                        try{ if(window.updateProgressPopup) window.updateProgressPopup(100,'Generazione foto AI','Completamento generazione.'); }catch(e){}\n                        Promise.resolve(refreshDb()).finally(function(){\n                            try{ if(window.hideProgressPopup) window.hideProgressPopup(true,'Generazione foto AI completata',{remindSave:false,successMessage:'Immagini generate\/verificate: '+(d.ok||0)+' su '+total+'. Errori: '+(d.fail||0)+'.'}); }catch(e){}\n                            rb.innerHTML='\u2705 Generazione foto AI completata.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Immagini associate\/verificate: <b>'+(d.ok||0)+'<\/b> \/ '+total+'<br>Gia presenti\/saltate: <b>'+(d.skip||0)+'<\/b><br>Errori: <b>'+(d.fail||0)+'<\/b><br><br>'+(d.logs_tail||[]).slice(0,120).join('<br>');\n                        });\n                        return;\n                    }\n                    if(d.status==='cancelled' || d.status==='error'){\n                        setButtonBusy(false); if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n                        var esitoMsg1460 = d.status==='cancelled' ? ('Generazione foto AI interrotta.<br>Completate: '+doneCount+' \/ '+total+'.') : ('Generazione foto AI terminata con un errore lato server.<br>Completate: '+doneCount+' \/ '+total+'.');\n                        rb.innerHTML = esitoMsg1460;\n                        try{ if(window.hideProgressPopup) window.hideProgressPopup(d.status!=='error', esitoMsg1460.replace(\/<br>\/g,' ').replace(\/<[^>]+>\/g,'')); }catch(e){}\n                        return;\n                    }\n                    if(!cancelled()) window.__tiBatch706PollTimer1546=setTimeout(pollStatus1460, 3000);\n                }).catch(function(err){ if(!fallbackActivated1580 && !cancelled() && !(err&&err.userCancelled)) window.__tiBatch706PollTimer1546=setTimeout(pollStatus1460, 5000); });\n            }\n        }\n        \/\/ 30.9.1450: CORREZIONE CRITICA - la versione precedente (1449) usava window.confirm(), una finestra\n        \/\/ NATIVA E BLOCCANTE che ferma l'intera esecuzione JavaScript della pagina finche' l'utente non\n        \/\/ risponde. Questo interferiva con il meccanismo esterno \"watchdog 715\" (che monitora se la pagina\n        \/\/ sembra bloccata), causandone lo scatto automatico e l'interruzione forzata del processo - confermato\n        \/\/ con un caso reale. Ora la richiesta di conferma usa una finestra personalizzata NON bloccante (come\n        \/\/ gli altri popup gia' presenti nel codice), che non ferma l'esecuzione della pagina.\n        function proceedWithTargets1450(finalTargets){\n        var targets = finalTargets;\n        var total=targets.length,index=0,ok=0,fail=0,skip=0,logs=[];\n        \/\/ 30.9.1705: guardia client aggiuntiva contro target duplicati nello stesso job.\n        var attemptedRows1705=Object.create(null);\n        window.tiBatchAIGenState={active:true,preparing:false,db:db,tableName:scope,total:total,generated:[],startedAt:Date.now(),source:'706',cancelToken1546:window.__tiActiveBatch706Token1546,jobId:window.__tiActiveBatch706Token1546};\n        diag1383('stato aggiornato, total=' + total + ', costruzione UI elenco pronto');\n        rb.innerHTML='Elenco record pronto.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Record totali: <b>'+total+'<\/b><br>Avvio generazione separata '+esc(scope)+'...';\n        diag1383('UI elenco pronto aggiornata correttamente');\n        function finish(){\n            if(cancelled()) return;\n            diag1383('finish() chiamata - ok=' + ok + ' fail=' + fail + ' skip=' + skip);\n            setButtonBusy(false); if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n            try { if (window.__tiBatch706TimerWorker) { window.__tiBatch706TimerWorker.terminate(); window.__tiBatch706TimerWorker=null; window.__tiBatch706PendingFire=null; } } catch(eW1459) {}\n            try{ if(window.updateProgressPopup) window.updateProgressPopup(100,'Generazione foto AI','Completamento generazione.'); }catch(e){}\n            Promise.resolve(refreshDb()).finally(function(){\n                try{ if(window.hideProgressPopup) window.hideProgressPopup(true,'Generazione foto AI completata',{remindSave:false,successMessage:'Immagini generate\/verificate: '+ok+' su '+total+'. Errori: '+fail+'.'}); }catch(e){}\n                rb.innerHTML='\u2705 Generazione foto AI completata.<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Immagini associate\/verificate: <b>'+ok+'<\/b> \/ '+total+'<br>Gia presenti\/saltate: <b>'+skip+'<\/b><br>Errori: <b>'+fail+'<\/b><br><br>'+logs.slice(0,120).join('<br>');\n            });\n        }\n        \/\/ 30.9.1448: versione riutilizzabile dello stesso meccanismo multi-via usato sopra per il primo avvio -\n        \/\/ confermato con un caso reale che SOLO la primissima chiamata a next() era protetta da questi tre\n        \/\/ meccanismi paralleli; ogni transizione SUCCESSIVA (da un elemento al successivo, dentro .finally())\n        \/\/ si affidava ancora al singolo, fragile setTimeout(next,250) gia' noto per non scattare mai in questo\n        \/\/ specifico ambiente utente - motivo per cui il processo si bloccava sempre subito dopo il primo\n        \/\/ elemento, indipendentemente da quante volte si riprovasse. Questa funzione va richiamata ad ogni\n        \/\/ transizione, non solo alla primissima.\n        function scheduleNext1448(delayMs){\n            var fired1448 = false;\n            function fireOnce1448(source){\n                if (fired1448 || cancelled()) return;\n                fired1448 = true;\n                try { next(); } catch(errNext1448){ diag1383('ERRORE FATALE dentro next() (scheduleNext1448): ' + (errNext1448 && errNext1448.message ? errNext1448.message : String(errNext1448))); }\n            }\n            try { setTimeout(function(){ fireOnce1448('setTimeout'); }, delayMs); } catch(e1448a) {}\n            try { if (typeof requestAnimationFrame === 'function') requestAnimationFrame(function(){ setTimeout(function(){ fireOnce1448('requestAnimationFrame'); }, 0); }); } catch(e1448b) {}\n            try {\n                var startedAt1448 = Date.now ? Date.now() : (new Date()).getTime();\n                var intervalCheck1448 = setInterval(function(){\n                    if (fired1448) { clearInterval(intervalCheck1448); return; }\n                    if ((Date.now?Date.now():(new Date()).getTime()) - startedAt1448 >= delayMs) fireOnce1448('controllo-periodico');\n                }, 300);\n                var catchup1448 = function(){ if (!fired1448) fireOnce1448('visibilitychange-o-focus'); };\n                document.addEventListener('visibilitychange', catchup1448, {once:true});\n                window.addEventListener('focus', catchup1448, {once:true});\n            } catch(e1448c) {}\n            \/\/ 30.9.1459: quinto meccanismo, su thread separato (web worker) - molto meno soggetto al\n            \/\/ rallentamento del thread principale quando la scheda passa in secondo piano.\n            try {\n                if (window.__tiBatch706TimerWorker) {\n                    window.__tiBatch706PendingFire = {\n                        fireAt: (Date.now?Date.now():(new Date()).getTime()) + delayMs,\n                        callback: fireOnce1448\n                    };\n                }\n            } catch(e1459) {}\n        }\n        function next(){\n            \/\/ 30.9.1390: controllo diretto ed esplicito dello stato del processo (oltre al gia' presente\n            \/\/ cancelled()) - riconosce anche lo stop segnalato dal watchdog generale a 180 secondi, che ora\n            \/\/ imposta esplicitamente questo flag.\n            var externallyStopped1390 = window.tiBatchAIGenState && window.tiBatchAIGenState.source==='706' && !window.tiBatchAIGenState.active;\n            diag1383('next() chiamata index=' + index + '\/' + total + ' cancelled=' + cancelled() + ' stop_esterno=' + externallyStopped1390);\n            if(cancelled() || externallyStopped1390){\n                if(window.__tiProcessAbortConfirmed1546){ setButtonBusy(false); return; }\n                \/\/ 30.9.1455: se l'interruzione NON e' stata richiesta esplicitamente dall'utente (pulsante\n                \/\/ \"Esci\", rilevato da cancelled()) ma e' dovuta a un blocco esterno inatteso, e il processo non\n                \/\/ ha ancora completato tutti gli elementi, riavvia automaticamente elaborando SOLO gli elementi\n                \/\/ ancora mancanti - su richiesta esplicita dell'utente. Limitato a un numero massimo di\n                \/\/ tentativi automatici per evitare cicli infiniti in caso di problema persistente (es. chiave\n                \/\/ API scaduta), e con una breve pausa prima di ogni nuovo tentativo.\n                var maxAutoRetry1455 = 0; \/\/ 30.9.1705: nessun riavvio automatico dopo un arresto inatteso.\n                window.__tiBatch706AutoRetryCount = window.__tiBatch706AutoRetryCount || 0;\n                if(!cancelled() && index<total && window.__tiBatch706AutoRetryCount < maxAutoRetry1455){\n                    window.__tiBatch706AutoRetryCount++;\n                    var remaining1455 = targets.slice(index);\n                    diag1383('riavvio automatico tentativo ' + window.__tiBatch706AutoRetryCount + '\/' + maxAutoRetry1455 + ' - elementi rimanenti: ' + remaining1455.length);\n                    rb.innerHTML='Processo interrotto inaspettatamente.<br>Completate finora: '+ok+'. Errori: '+fail+'.<br><br>\u23f3 Riavvio automatico in corso (tentativo '+window.__tiBatch706AutoRetryCount+'\/'+maxAutoRetry1455+') per i '+remaining1455.length+' elementi rimanenti...';\n                    (function(){\n                        var fired1455 = false;\n                        function doRestart1455(){ if(fired1455) return; fired1455=true; proceedWithTargets1450(remaining1455); }\n                        try { setTimeout(doRestart1455, 3000); } catch(e) {}\n                        try {\n                            var start1455 = Date.now ? Date.now() : (new Date()).getTime();\n                            var iv1455 = setInterval(function(){ if(fired1455){ clearInterval(iv1455); return; } if((Date.now?Date.now():(new Date()).getTime())-start1455>=3000) doRestart1455(); }, 500);\n                        } catch(e) {}\n                        try {\n                            var catchup1455 = function(){ if(!fired1455) doRestart1455(); };\n                            document.addEventListener('visibilitychange', catchup1455, {once:true});\n                            window.addEventListener('focus', catchup1455, {once:true});\n                        } catch(e) {}\n                    })();\n                    return;\n                }\n                setButtonBusy(false); if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n                try { if (window.__tiBatch706TimerWorker) { window.__tiBatch706TimerWorker.terminate(); window.__tiBatch706TimerWorker=null; window.__tiBatch706PendingFire=null; } } catch(eW1459b) {}\n                var esitoMsg1455 = 'Generazione foto AI interrotta.<br>Completate: '+ok+'. Errori: '+fail+'.<br><br>Nessun tentativo automatico aggiuntivo viene eseguito. Se vuoi riprovare, avvia manualmente un nuovo job.';\n                rb.innerHTML=esitoMsg1455;\n                try{ if(window.hideProgressPopup) window.hideProgressPopup(false, esitoMsg1455.replace(\/<br>\/g,' ').replace(\/<[^>]+>\/g,'')); }catch(e){}\n                return;\n            }\n            window.__tiBatch706AutoRetryCount = 0;\n            if(index>=total) return finish();\n            var item=targets[index]||{}, name=item.name||'Elemento';\n            var pct=Math.max(5,Math.min(98,Math.round(((index+0.1)\/total)*100)));\n            try{ if(window.updateProgressPopup) window.updateProgressPopup(pct,'Generazione foto AI','Elaborazione '+(index+1)+' \/ '+total+': '+name,name); }catch(e){}\n            rb.innerHTML='Generazione foto AI in corso...<br>DB: <b>'+esc(db)+'<\/b><br>Tabella: <b>'+esc(scope)+'<\/b><br>Elaborazione <b>'+(index+1)+'<\/b> \/ '+total+': <b>'+esc(name)+'<\/b><br><br>'+logs.slice(-20).join('<br>');\n            var attemptKey1705=String(item.table||scope).toLowerCase()+'#'+String(item.row_index);\n            if(attemptedRows1705[attemptKey1705]){\n                skip++; logs.push('\u23ed\ufe0f '+esc(name)+': tentativo gia eseguito in questo job; nessuna seconda generazione.');\n                index++; scheduleNext1448(50); return;\n            }\n            attemptedRows1705[attemptKey1705]=true;\n            diag1383('avvio ajax706 per item ' + (index+1) + '\/' + total + ' nome=' + name + ' tentativo=1\/1');\n            ajax706('ti_ai_batch_ai_image_one_698',{db:db,table:item.table||scope,row_index:item.row_index,detail_prompt:photoDetail,source:'batch706',job_id:(window.tiBatchAIGenState&&window.tiBatchAIGenState.jobId)||window.__tiActiveBatch706Token1546||''},75000).then(function(one){\n                diag1383('ajax706 RISOLTA per item ' + (index+1) + ' success=' + (one && one.success));\n                var d=one && one.data ? one.data : {};\n                if(one && one.success && d.generated){ ok++; logs.push('\u2705 '+esc(d.name||name)+': '+(d.fallback_logo?'usato logo ditta':'immagine generata e associazione salvata')); }\n                else if(one && one.success && d.skipped){ skip++; logs.push('\u23ed\ufe0f '+esc(d.name||name)+': gia presente'); }\n                else { fail++; logs.push('\u274c '+esc(d.name||name)+': '+esc(d.message||'errore generazione')); }\n            }).catch(function(err){ if(cancelled() || (err&&err.userCancelled)) return; diag1383('ajax706 ERRORE per item ' + (index+1) + ' msg=' + (err && err.message)); fail++; logs.push('\u274c '+esc(name)+': '+esc(err && err.message ? err.message : 'errore rete\/timeout')); }).finally(function(){ if(cancelled()) return; index++; scheduleNext1448(250); });\n        }\n        diag1383('prima di avvio next() - total=' + total);\n        \/\/ 30.9.1431: il precedente setTimeout(next,80) risultava confermato (tramite log diagnostico dedicato)\n        \/\/ non scattare mai in certi ambienti (desktop remoto\/macchina virtuale), lasciando il processo bloccato\n        \/\/ subito dopo la preparazione, prima ancora del primo elemento. Invece di affidarsi a un singolo\n        \/\/ meccanismo, ora tre meccanismi indipendenti tentano in parallelo di avviare next() - un'unica guardia\n        \/\/ (startedNext1431) garantisce che parta una sola volta, indipendentemente da quanti di questi\n        \/\/ effettivamente scattino. Se anche uno solo funziona nell'ambiente dell'utente, il processo si avvia\n        \/\/ correttamente.\n        var startedNext1431 = false;\n        function startNextOnce1431(source){\n            if (startedNext1431 || cancelled()) return;\n            startedNext1431 = true;\n            diag1383('avvio next() riuscito tramite: ' + source);\n            try { next(); } catch(errNext1391){ diag1383('ERRORE FATALE dentro next(): ' + (errNext1391 && errNext1391.message ? errNext1391.message : String(errNext1391))); }\n        }\n        try { setTimeout(function(){ startNextOnce1431('setTimeout-80'); }, 80); } catch(e1431a) {}\n        try { if (typeof requestAnimationFrame === 'function') requestAnimationFrame(function(){ setTimeout(function(){ startNextOnce1431('requestAnimationFrame'); }, 0); }); } catch(e1431b) {}\n        try {\n            var rafCatchup1431 = function(){ if (!startedNext1431) startNextOnce1431('visibilitychange-o-focus'); };\n            document.addEventListener('visibilitychange', rafCatchup1431, {once:false});\n            window.addEventListener('focus', rafCatchup1431, {once:false});\n            \/\/ Rete di sicurezza finale basata sul tempo, indipendente da cambi di scheda\/focus.\n            setInterval(function(){ if (!startedNext1431) startNextOnce1431('controllo-periodico-1431'); }, 500);\n        } catch(e1431c) {}\n        \/\/ 30.9.1459: stesso meccanismo su thread separato usato in scheduleNext1448, applicato anche qui per coerenza.\n        try {\n            if (window.__tiBatch706TimerWorker) {\n                window.__tiBatch706PendingFire = { fireAt: (Date.now?Date.now():(new Date()).getTime()) + 80, callback: startNextOnce1431 };\n            }\n        } catch(e1459b) {}\n        } \/\/ fine proceedWithTargets1450\n        \/\/ 30.9.1450: se alcuni elementi hanno gia' un'immagine associata (es. dopo un'interruzione precedente),\n        \/\/ chiede all'utente (con una finestra personalizzata NON bloccante, non window.confirm()) se rigenerare\n        \/\/ comunque tutto o elaborare solo gli elementi ancora mancanti - evita di riprocessare inutilmente\n        \/\/ elementi gia' completati con successo (tempo e costo di generazione).\n        if((prep.with_associations||0) > 0){\n            try{ if(window.hideProgressPopup) window.hideProgressPopup(true,'In attesa di conferma',{notifyUser:false,remindSave:false}); }catch(e){}\n            var ov1450 = document.createElement('div');\n            ov1450.style.cssText = 'position:fixed;inset:0;z-index:2147483647;background:rgba(0,0,0,0.6);display:flex;align-items:center;justify-content:center;';\n            var box1450 = document.createElement('div');\n            box1450.style.cssText = 'background:#111827;border:1px solid #374151;border-radius:10px;padding:18px;width:min(440px,92vw);box-sizing:border-box;color:#e5e7eb;font-size:13px;';\n            box1450.innerHTML = '<div style=\"font-weight:700;margin-bottom:10px;\">Alcune immagini valide sono gia\\' presenti<\/div><div style=\"margin-bottom:14px;line-height:1.5;\">Trovati <b>'+esc(prep.with_associations)+'<\/b> elementi su <b>'+targets.length+'<\/b> che hanno gia\\' una vera immagine associata. Il logo della ditta non viene considerato immagine valida.'+((prep.logo_placeholders||0)>0?'<br><br><b>'+esc(prep.logo_placeholders)+'<\/b> elementi contengono solo il logo ditta e saranno trattati come immagini mancanti.':'')+'<br><br>Le immagini gia completate sono salvate progressivamente: per continuare un processo svolto in piu fasi usa <b>Solo mancanti<\/b>.<\/div>';\n            var btnRow1450 = document.createElement('div');\n            btnRow1450.style.cssText = 'display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;';\n            var btnMissing1450 = document.createElement('button');\n            btnMissing1450.type = 'button';\n            btnMissing1450.textContent = 'Solo mancanti ('+esc(prep.without_associations||0)+')';\n            btnMissing1450.style.cssText = 'background:#059669;color:#fff;border:none;border-radius:6px;padding:8px 14px;font-size:13px;cursor:pointer;';\n            var btnAll1450 = document.createElement('button');\n            btnAll1450.type = 'button';\n            btnAll1450.textContent = 'Rigenera tutti ('+targets.length+')';\n            btnAll1450.style.cssText = 'background:#374151;color:#e5e7eb;border:none;border-radius:6px;padding:8px 14px;font-size:13px;cursor:pointer;';\n            \/\/ 30.9.1462: pulsante \"Chiudi\" aggiunto su richiesta esplicita dell'utente, per i casi in cui apre\n            \/\/ questa finestra ma non necessita di alcuna azione immediata (es. apertura per errore, o vuole\n            \/\/ solo controllare la situazione senza avviare nulla).\n            var btnClose1462 = document.createElement('button');\n            btnClose1462.type = 'button';\n            btnClose1462.textContent = 'Chiudi';\n            btnClose1462.style.cssText = 'background:transparent;color:#9ca3af;border:1px solid #4b5563;border-radius:6px;padding:8px 14px;font-size:13px;cursor:pointer;';\n            btnClose1462.onclick = function(){\n                try { ov1450.remove(); } catch(e) {}\n                setButtonBusy(false);\n                if(window.tiBatchAIGenState) window.tiBatchAIGenState.active=false;\n                try{ if(window.hideProgressPopup) window.hideProgressPopup(true,'Operazione annullata',{notifyUser:false,remindSave:false}); }catch(e){}\n                rb.innerHTML='Generazione foto AI non avviata.';\n            };\n            function chiudiEProsegui1450(soloMancanti){\n                try { ov1450.remove(); } catch(e) {}\n                var finalTargets1450 = targets;\n                if(soloMancanti){\n                    finalTargets1450 = targets.filter(function(t){ return !t.has_associations; });\n                    diag1383('filtro solo mancanti attivato: ' + finalTargets1450.length + ' elementi rimasti');\n                }\n                if(!finalTargets1450.length){\n                    setButtonBusy(false); window.tiBatchAIGenState.active=false;\n                    rb.innerHTML='Tutti gli elementi di <b>'+esc(scope)+'<\/b> hanno gia\\' una immagine valida diversa dal logo ditta. Nessuna generazione necessaria.';\n                    return;\n                }\n                finalTargets1450 = applyImageLimit1672(finalTargets1450);\n                var requested1672=requestedImageCount1672();\n                if(requested1672>0) rb.innerHTML='Preparazione generazione di <b>'+finalTargets1450.length+'<\/b> immagini su richiesta ('+requested1672+'). Salvataggio e associazione progressivi attivi.';\n                try{ if(window.showProgressPopup) window.showProgressPopup('Generazione foto AI','Ripresa preparazione per '+scope+'.'+(requested1672>0?' Numero immagini: '+finalTargets1450.length+'.':''),{startPercent:12,targetPercent:15,stepMs:250,cancellable:true}); }catch(e){}\n                proceedWithTargetsServer1460(finalTargets1450);\n            }\n            btnMissing1450.onclick = function(){ chiudiEProsegui1450(true); };\n            btnAll1450.onclick = function(){ chiudiEProsegui1450(false); };\n            btnRow1450.appendChild(btnClose1462);\n            btnRow1450.appendChild(btnAll1450);\n            btnRow1450.appendChild(btnMissing1450);\n            box1450.appendChild(btnRow1450);\n            ov1450.appendChild(box1450);\n            document.body.appendChild(ov1450);\n        } else {\n            var limitedTargets1672=applyImageLimit1672(targets);\n            var requestedDirect1672=requestedImageCount1672();\n            if(requestedDirect1672>0) rb.innerHTML='Preparazione generazione di <b>'+limitedTargets1672.length+'<\/b> immagini su richiesta ('+requestedDirect1672+'). Salvataggio e associazione progressivi attivi.';\n            proceedWithTargetsServer1460(limitedTargets1672);\n        }\n        return false;\n    };\n    window.tiRunBatchAIGen706.__tiFullDb1712=true;\n    window.tiRunBatchAIGen698=window.tiRunBatchAIGen706;\n    window.tiRunBatchAIGen693=window.tiRunBatchAIGen706;\n    window.runBatchAIGen=function(tableName){ return window.tiRunBatchAIGen706(tableName||'Prodotti'); };\n    try{console.info('[Shop-Service] generazione immagini 1712: FULL DB obbligatorio, cache UI ignorata');}catch(e){}\n    window.runBatchAIGen.__tiBatch706=true;\n    \/\/ 30.9.1580: router unico e prioritario. Il listener su window riceve il click prima dei vecchi\n    \/\/ listener document 693\/698\/706 e usa l'attributo stabile data-ti-batch-ai-btn invece del testo tradotto.\n    if(!window.__tiBatch706WindowRouter1580){\n        window.__tiBatch706WindowRouter1580=true;\n        window.addEventListener('click',function(ev){\n            try{\n                var target=ev&&ev.target;\n                var b=target&&target.closest?target.closest('button[data-ti-batch-ai-btn]'):null;\n                if(!b)return;\n                var scope1580=String(b.getAttribute('data-ti-batch-ai-btn')||'').trim();\n                if(!\/^(Prodotti|Servizi)$\/i.test(scope1580))return;\n                ev.preventDefault();ev.stopPropagation();if(ev.stopImmediatePropagation)ev.stopImmediatePropagation();\n                var now1580=Date.now?Date.now():(new Date()).getTime();\n                if(window.__tiBatch706ClickGuardUntil1580&&now1580<window.__tiBatch706ClickGuardUntil1580)return false;\n                window.__tiBatch706ClickGuardUntil1580=now1580+700;\n                if(typeof window.tiRunBatchAIGen706==='function')return window.tiRunBatchAIGen706(\/^servizi$\/i.test(scope1580)?'Servizi':'Prodotti');\n            }catch(err1580){\n                try{if(window.tiAlert)window.tiAlert('Errore avvio generazione immagini: '+(err1580&&err1580.message?err1580.message:String(err1580)));}catch(e){}\n            }\n            return false;\n        },true);\n    }\n    document.addEventListener('click',function(ev){\n        var t=ev && ev.target; if(!t || !t.closest) return;\n        var b=t.closest('button'); if(!b) return;\n        var label=String(b.textContent||'').replace(\/\\s+\/g,' ').trim();\n        if(\/^Genera (?:foto|immagini) AI Prodotti e Servizi$\/i.test(label)){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); if(window.tiAlert) window.tiAlert('Prodotti e Servizi devono essere generati con pulsanti separati.'); return false; }\n        if(\/^Genera immagini AI Prodotti$\/i.test(label)){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); return window.tiRunBatchAIGen706('Prodotti'); }\n        if(\/^Genera immagini AI Servizi$\/i.test(label)){ ev.preventDefault(); ev.stopPropagation(); if(ev.stopImmediatePropagation) ev.stopImmediatePropagation(); return window.tiRunBatchAIGen706('Servizi'); }\n    }, true);\n})();\n<\/script>\n\n\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"Pagina_base_vuota.php","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_kadence_starter_templates_imported_post":false,"_kad_post_transparent":"default","_kad_post_title":"default","_kad_post_layout":"default","_kad_post_sidebar_id":"","_kad_post_content_style":"default","_kad_post_vertical_padding":"default","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"class_list":["post-1165","page","type-page","status-publish","hentry"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO Pro 5.0.3 - aioseo.com -->\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"google-site-verification\" content=\"BqeY9R53B2HkBp_g3d5fh-yHxyeD5uEk2HT7-cmQ8Uw\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/www.tisoft.it\/en\/shop-service\/\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO Pro (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_GB\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Shop - Quello che facciamo meglio \u00e8 dare forma alle vostre idee\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Shop &amp; Service\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/www.tisoft.it\/en\/shop-service\/\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/www.tisoft.it\/wp-content\/uploads\/2024\/04\/cropped-LogoTarget-carico.gif\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/www.tisoft.it\/wp-content\/uploads\/2024\/04\/cropped-LogoTarget-carico.gif\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2026-04-14T08:48:53+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-04-17T08:14:20+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/TargetInformaticaTerni\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Shop &amp; Service\" \/>\n\t\t<meta name=\"twitter:image\" content=\"https:\/\/www.tisoft.it\/wp-content\/uploads\/2024\/04\/cropped-LogoTarget-carico.gif\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/#listItem\",\"name\":\"Shop &#038; Service\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/#listItem\",\"position\":2,\"name\":\"Shop &#038; Service\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/#listItem\",\"name\":\"Home\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/#organization\",\"name\":\"Target Informatica Shop\",\"description\":\"Quello che facciamo meglio \\u00e8 dare forma alle vostre idee\",\"url\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/\",\"telephone\":\"+390744288410\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/www.tisoft.it\\\/wp-content\\\/uploads\\\/2024\\\/04\\\/Target-Informatica-logo.png\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/#organizationLogo\",\"width\":3951,\"height\":1154},\"image\":{\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/#organizationLogo\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/TargetInformaticaTerni\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/targetinformatica\\\/?viewAsMember=true\"]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/#webpage\",\"url\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/\",\"name\":\"Shop & Service\",\"inLanguage\":\"en-GB\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/shop-service\\\/#breadcrumblist\"},\"datePublished\":\"2026-04-14T10:48:53+02:00\",\"dateModified\":\"2026-04-17T10:14:20+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/\",\"name\":\"Shop\",\"description\":\"Quello che facciamo meglio \\u00e8 dare forma alle vostre idee\",\"inLanguage\":\"en-GB\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.tisoft.it\\\/en\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO Pro -->\r\n\t\t<title>Shop &amp; Service<\/title>\n\n","aioseo_head_json":{"title":"Shop &amp; Service","description":"","canonical_url":"https:\/\/www.tisoft.it\/en\/shop-service\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"google-site-verification":"BqeY9R53B2HkBp_g3d5fh-yHxyeD5uEk2HT7-cmQ8Uw","miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BreadcrumbList","@id":"https:\/\/www.tisoft.it\/en\/shop-service\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/www.tisoft.it\/en\/#listItem","position":1,"name":"Home","item":"https:\/\/www.tisoft.it\/en\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.tisoft.it\/en\/shop-service\/#listItem","name":"Shop &#038; Service"}},{"@type":"ListItem","@id":"https:\/\/www.tisoft.it\/en\/shop-service\/#listItem","position":2,"name":"Shop &#038; Service","previousItem":{"@type":"ListItem","@id":"https:\/\/www.tisoft.it\/en\/#listItem","name":"Home"}}]},{"@type":"Organization","@id":"https:\/\/www.tisoft.it\/en\/#organization","name":"Target Informatica Shop","description":"Quello che facciamo meglio \u00e8 dare forma alle vostre idee","url":"https:\/\/www.tisoft.it\/en\/","telephone":"+390744288410","logo":{"@type":"ImageObject","url":"https:\/\/www.tisoft.it\/wp-content\/uploads\/2024\/04\/Target-Informatica-logo.png","@id":"https:\/\/www.tisoft.it\/en\/shop-service\/#organizationLogo","width":3951,"height":1154},"image":{"@id":"https:\/\/www.tisoft.it\/en\/shop-service\/#organizationLogo"},"sameAs":["https:\/\/www.facebook.com\/TargetInformaticaTerni","https:\/\/www.linkedin.com\/company\/targetinformatica\/?viewAsMember=true"]},{"@type":"WebPage","@id":"https:\/\/www.tisoft.it\/en\/shop-service\/#webpage","url":"https:\/\/www.tisoft.it\/en\/shop-service\/","name":"Shop & Service","inLanguage":"en-GB","isPartOf":{"@id":"https:\/\/www.tisoft.it\/en\/#website"},"breadcrumb":{"@id":"https:\/\/www.tisoft.it\/en\/shop-service\/#breadcrumblist"},"datePublished":"2026-04-14T10:48:53+02:00","dateModified":"2026-04-17T10:14:20+02:00"},{"@type":"WebSite","@id":"https:\/\/www.tisoft.it\/en\/#website","url":"https:\/\/www.tisoft.it\/en\/","name":"Shop","description":"Quello che facciamo meglio \u00e8 dare forma alle vostre idee","inLanguage":"en-GB","publisher":{"@id":"https:\/\/www.tisoft.it\/en\/#organization"}}]},"og:locale":"en_GB","og:site_name":"Shop - Quello che facciamo meglio \u00e8 dare forma alle vostre idee","og:type":"article","og:title":"Shop &amp; Service","og:url":"https:\/\/www.tisoft.it\/en\/shop-service\/","og:image":"https:\/\/www.tisoft.it\/wp-content\/uploads\/2024\/04\/cropped-LogoTarget-carico.gif","og:image:secure_url":"https:\/\/www.tisoft.it\/wp-content\/uploads\/2024\/04\/cropped-LogoTarget-carico.gif","article:published_time":"2026-04-14T08:48:53+00:00","article:modified_time":"2026-04-17T08:14:20+00:00","article:publisher":"https:\/\/www.facebook.com\/TargetInformaticaTerni","twitter:card":"summary_large_image","twitter:title":"Shop &amp; Service","twitter:image":"https:\/\/www.tisoft.it\/wp-content\/uploads\/2024\/04\/cropped-LogoTarget-carico.gif"},"aioseo_meta_data":{"post_id":"1165","title":"#post_title","description":null,"keywords":null,"keyphrases":{"focus":{"keyphrase":"","score":0,"analysis":{"keyphraseInTitle":{"score":0,"maxScore":9,"error":1}}},"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"WebPage","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":null,"frequency":"default","local_seo":null,"seo_analyzer_scan_date":"2026-04-17 10:27:07","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":"0","open_ai":null,"ai":{"faqs":[],"keyPoints":[],"titles":[],"descriptions":[],"socialPosts":{"email":[],"linkedin":[],"twitter":[],"facebook":[],"instagram":[]}},"created":"2026-04-14 08:42:06","updated":"2026-04-17 10:27:17","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t<a href=\"https:\/\/www.tisoft.it\/en\/\" title=\"Home\">Home<\/a>\n<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\tShop &amp; Service\n<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/www.tisoft.it\/en\/"},{"label":"Shop &#038; Service","link":"https:\/\/www.tisoft.it\/en\/shop-service\/"}],"_links":{"self":[{"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/pages\/1165","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/comments?post=1165"}],"version-history":[{"count":4,"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/pages\/1165\/revisions"}],"predecessor-version":[{"id":1202,"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/pages\/1165\/revisions\/1202"}],"wp:attachment":[{"href":"https:\/\/www.tisoft.it\/en\/wp-json\/wp\/v2\/media?parent=1165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}