myio-js-library 0.1.48 → 0.1.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- (function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?factory(exports):typeof define==="function"&&define.amd?define(["exports"],factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,factory(global.MyIOLibrary={}))})(this,function(exports){"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __esm=(fn,res)=>function __init(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var template_card_exports={};__export(template_card_exports,{renderCardComponent:()=>renderCardComponent});function renderCardComponent({entityObject:entityObject,handleActionDashboard:handleActionDashboard,handleActionReport:handleActionReport,handleActionSettings:handleActionSettings,handleSelect:handleSelect,handInfo:handInfo,handleClickCard:handleClickCard}){const{entityId:entityId,labelOrName:labelOrName,deviceIdentifier:deviceIdentifier,entityType:entityType,deviceType:deviceType,slaveId:slaveId,ingestionId:ingestionId,val:val,centralId:centralId,updatedIdentifiers:updatedIdentifiers={},perc:perc=0,connectionStatus:connectionStatus,centralName:centralName,connectionStatusTime:connectionStatusTime,timaVal:timaVal,valType:valType}=entityObject;const DeviceStatus={CONNECTED:"connected",OFFLINE:"offline",POWER_ON:"power_on",STANDBY:"standby",POWER_OFF:"power_off",WARNING:"warning",DANGER:"danger",MAINTENANCE:"maintenance"};const statusIcons={[DeviceStatus.CONNECTED]:"✅",[DeviceStatus.OFFLINE]:"🔌",[DeviceStatus.POWER_ON]:"⚡",[DeviceStatus.STANDBY]:"⏸️",[DeviceStatus.POWER_OFF]:"⏹️",[DeviceStatus.WARNING]:"⚠️",[DeviceStatus.DANGER]:"🚨",[DeviceStatus.MAINTENANCE]:"🛠️"};const isOfflineOrDanger=connectionStatus===DeviceStatus.OFFLINE||connectionStatus===DeviceStatus.DANGER;const shouldFlashIcon=connectionStatus===DeviceStatus.OFFLINE||connectionStatus===DeviceStatus.WARNING||connectionStatus===DeviceStatus.DANGER||connectionStatus===DeviceStatus.MAINTENANCE;const icon=statusIcons[connectionStatus]||statusIcons[DeviceStatus.POWER_ON];const MyIO=typeof MyIOLibrary!=="undefined"&&MyIOLibrary||typeof window!=="undefined"&&window.MyIOLibrary||{formatEnergy:(v,g)=>`${v} kWh`,formatNumberReadable:n=>Number(n??0).toFixed(1)};let valFormatted=MyIO.formatEnergy(val);if(valType==="ENERGY"){valFormatted=MyIO.formatEnergy(val)}else if(valType==="WATER"){valFormatted=`${val} m³`}else if(valType==="TANK"){valFormatted=`${val} m.c.a`}else{valFormatted=val}const percFormatted=MyIO.formatNumberReadable(perc);if(!document.getElementById("myio-card-styles")){const style=document.createElement("style");style.id="myio-card-styles";style.textContent=` \n.device-card-centered,\n.clickable {\n width: 100%;\n border-radius: 10px;\n padding: 8px 12px;\n background: #fff;\n box-shadow: 0 4px 10px rgba(0, 0, 0, .05);\n /* display: flex; REMOVIDO */\n /* align-items: center; REMOVIDO */\n /* justify-content: center; REMOVIDO */\n cursor: pointer;\n transition: transform .2s;\n /* min-height: 140px; REMOVIDO (movido para .device-card-inner) */\n box-sizing: border-box;\n overflow: hidden;\n}\n\n.device-card-centered:hover,\n.clickable:hover {\n transform: scale(1.05);\n}\n\n.device-title-row {\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-bottom: 4px;\n padding: 0 4px;\n min-height: 22px;\n}\n\n.device-title {\n font-weight: 700;\n font-size: .85rem;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 90%;\n line-height: 1.1;\n}\n\n.device-subtitle {\n font-size: 0.7rem; \n font-weight: 500;\n color: #888; /* Cinza */\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 90%;\n line-height: 1.1;\n margin-top: 2px;\n}\n\n.device-image {\n max-height: 44px;\n width: auto;\n margin: 4px 0;\n display: block;\n}\n\n.device-data-row {\n display: flex;\n justify-content: center;\n align-items: center;\n margin-top: auto;\n margin-bottom: 6px;\n gap: 6px;\n width: 100%;\n}\n\n.consumption-main {\n font-size: .9rem;\n font-weight: 700;\n color: #28a745;\n display: flex;\n align-items: center;\n gap: 6px;\n justify-content: center;\n white-space: nowrap;\n}\n\n.device-title-percent {\n font-size: .75rem;\n color: rgba(0, 0, 0, .45);\n font-weight: 500;\n}\n\n.flash {\n animation: flash 1s infinite;\n color: #ff9800;\n}\n\n@keyframes flash {\n 0% { opacity: 1; }\n 50% { opacity: .2; }\n 100% { opacity: 1; }\n}\n\n.card-actions {\n flex-shrink: 0;\n height: 100%;\n box-shadow: 1px 0 2px rgba(0, 0, 0, .1);\n display: flex;\n flex-direction: column;\n padding: 0 4px;\n justify-content: space-around;\n align-items: center;\n}\n\n.card-action img {\n width: 24px;\n height: 24px;\n transition: transform .2s ease;\n cursor: pointer;\n}\n\n.card-action img:hover {\n transform: scale(1.15);\n}\n\n.device-card-centered.offline {\n border: 2px solid #ff4d4f;\n animation: border-blink 1s infinite;\n}\n\n.device-card-centered.flipped .device-card-inner {\n transform: rotateY(180deg);\n}\n\n@keyframes border-blink {\n 0%, 100% { box-shadow: 0 0 8px rgba(255, 77, 79, 0.9); }\n 50% { box-shadow: 0 0 16px rgba(255, 0, 0, 0.6); }\n}\n\n.device-card-centered.offline .flash-icon {\n color: #ff4d4f !important;\n font-size: 1.2rem;\n} \n.device-card-centered {\n perspective: 1000px;\n}\n\n.device-card-inner {\n position: relative;\n width: 100%;\n height: 100%;\n transform-style: preserve-3d;\n min-height: 140px; /* ATUALIZADO: A altura mínima agora é controlada aqui */\n}\n\n.device-card-front {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: flex-start; /* Agora isso vai funcionar */\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n backface-visibility: hidden;\n gap: 4px;\n}\n\n.device-card-back {\n transform: rotateY(180deg);\n}\n\n.device-card-front .device-info,\n.device-card-back .device-info {\n position: absolute;\n top: 8px;\n right: 12px;\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 4px;\n border-radius: 50%;\n cursor: pointer;\n z-index: 10;\n background: none;\n border: none;\n transition: background 0.2s;\n}\n.device-card-front .device-info:hover,\n.device-card-back .device-info:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n\n.device-card-back {\n display: flex;\n flex-direction: column;\n justify-content: space-around; /* Mantido para preencher o verso */\n align-items: stretch;\n padding: 10px;\n gap: 5px;\n height: 100%;\n width: 100%;\n box-sizing: border-box;\n \n /* Posições para o flip */\n position: absolute;\n top: 0;\n left: 0;\n backface-visibility: hidden;\n transform: rotateY(180deg);\n}\n\n.device-card-back #status-bar {\n position: relative;\n width: 100%;\n padding-top: 10px;\n}\n\n.device-card-back .value-container {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 5px;\n color: #c19efc;\n align-self: center;\n}\n\n.device-card-back #lastconsumptionTime {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n font-size: 11px;\n font-weight: bold;\n color: black;\n width: 100%;\n padding-bottom: 10px;\n}\n\n\n.device-card-centered.flipped .device-card-inner {\n transform: rotateY(180deg);\n}\n\n.flash-icon.flash {\n animation: icon-blink 1s infinite;\n}\n\n@keyframes icon-blink {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.2; transform: scale(1.2); }\n}\n\n.device-card-centered.offline .flash-icon {\n color: #ff4d4f !important;\n}\n\n.device-card-centered.online .flash-icon {\n color: #28a745 !important;\n}\n `;document.head.appendChild(style)}let formattedDateVal;let formattedDate;let Infcolor="#5cb85c";if(connectionStatusTime){const date=new Date(connectionStatusTime);const day=String(date.getDate()).padStart(2,"0");const month=String(date.getMonth()+1).padStart(2,"0");const year=date.getFullYear();const hours=String(date.getHours()).padStart(2,"0");const minutes=String(date.getMinutes()).padStart(2,"0");formattedDate=`Online: (${day}/${month}/${year} - ${hours}:${minutes})`;const datVal=new Date(timaVal);const dayVal=String(datVal.getDate()).padStart(2,"0");const monthVal=String(datVal.getMonth()+1).padStart(2,"0");const yearVal=date.getFullYear();const hoursVal=String(date.getHours()).padStart(2,"0");const minutesVal=String(date.getMinutes()).padStart(2,"0");const now=new Date;const diffMs=now-datVal;const diffMinutes=Math.floor(diffMs/(1e3*60));const diffHours=Math.floor(diffMs/(1e3*60*60));const diffDays=Math.floor(diffMs/(1e3*60*60*24));let diffText="";if(diffMinutes<60){diffText=`${diffMinutes} minuto${diffMinutes!==1?"s":""}`}else if(diffHours<24){diffText=`${diffHours} hora${diffHours!==1?"s":""}`}else{diffText=`${diffDays} dia${diffDays!==1?"s":""} `}formattedDateVal=`${dayVal}/${monthVal}/${yearVal} - ${hoursVal}:${minutesVal} (${diffText})`;if(diffHours>=24){Infcolor="#cc2900"}else if(diffMinutes>=30){Infcolor="#e89105"}}else{Infcolor="#d6dcdd"}function normalizeString(str){if(typeof str!=="string"){str=""}return str.normalize("NFD").replace(/[\u0300-\u036f]/g,"").toUpperCase()}const deviceImages={MOTOR:"https://dashboard.myio-bas.com/api/images/public/8Ezn8qVBJ3jXD0iDfnEAZ0MZhAP1b5Ts","3F_MEDIDOR":"https://dashboard.myio-bas.com/api/images/public/f9Ce4meybsdaAhAkUlAfy5ei3I4kcN4k",RELOGIO:"https://dashboard.myio-bas.com/api/images/public/ljHZostWg0G5AfKiyM8oZixWRIIGRASB",HIDROMETRO:"https://dashboard.myio-bas.com/api/images/public/aMQYFJbGHs9gQbQkMn6XseAlUZHanBR4",ENTRADA:"https://dashboard.myio-bas.com/api/images/public/TQHPFqiejMW6lOSVsb8Pi85WtC0QKOLU",CAIXA_DAGUA:"https://dashboard.myio-bas.com/api/images/public/3t6WVhMQJFsrKA8bSZmrngDsNPkZV7fq"};const defaultImage="https://cdn-icons-png.flaticon.com/512/1178/1178428.png";const nameType=normalizeString(deviceType);const img=deviceImages[nameType]||defaultImage;const html=`\n <div class="device-card-centered clickable ${isOfflineOrDanger?"offline":""}"\n data-entity-id="${entityId}"\n data-entity-label="${labelOrName}"\n data-entity-type="${entityType}"\n data-entity-slaveid="${slaveId}"\n data-entity-ingestionid="${ingestionId}"\n data-entity-consumption="${val}"\n data-entity-centralid="${centralId}"\n data-entity-updated-identifiers='${JSON.stringify(updatedIdentifiers)}'>\n <div class="device-card-inner" style="width:100%; height:100%; transform-style: preserve-3d; transition: transform 0.6s;">\n <div class="device-card-front">\n\n <div class="card-actions" >\n ${typeof handleActionDashboard==="function"?`\n <div class="card-action action-dashboard" data-action="dashboard" title="Dashboard">\n <img src="https://dashboard.myio-bas.com/api/images/public/TAVXE0sTbCZylwGsMF9lIWdllBB3iFtS"/>\n </div>`:``}\n ${typeof handleActionReport==="function"?`\n <div class="card-action action-report" data-action="report" title="Relatório">\n <img src="https://dashboard.myio-bas.com/api/images/public/d9XuQwMYQCG2otvtNSlqUHGavGaSSpz4"/>\n </div>`:``}\n ${typeof handleActionSettings==="function"?`\n <div class="card-action action-settings" data-action="settings" title="Configurações">\n <img src="https://dashboard.myio-bas.com/api/images/public/5n9tze6vED2uwIs5VvJxGzNNZ9eV4yoz"/>\n </div>`:``}\n ${typeof handleSelect==="function"?`\n <input class="card-action action-checker" data-action="checker" title="Selecionar" type="checkbox">`:``}\n </div>\n\n <div style="display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%; flex-grow: 1; min-width: 0; padding: 0 12px;">\n \n <div class="device-title-row" style="flex-direction: column; min-height: 38px;">\n <span class="device-title" title="${labelOrName}">\n ${String(labelOrName??"").length>15?String(labelOrName).slice(0,15)+"…":String(labelOrName??"")}\n </span>\n ${deviceIdentifier?`\n <span class="device-subtitle" title="${deviceIdentifier}">\n ${deviceIdentifier}\n </span>\n `:""}\n </div>\n\n <img class="device-image" src="${img}" />\n <div class="device-data-row">\n <div class="consumption-main">\n \n <span class="flash-icon ${shouldFlashIcon?"flash":""}">\n ${icon}\n </span>\n\n <span class="consumption-value" data-entity-consumption="${val}">${valFormatted}</span>\n <span class="device-title-percent">(${percFormatted}%)</span>\n </div>\n </div>\n </div>\n \n ${handInfo?`\n <button id="infoButtom-front" class="device-info info-button">\n <svg xmlns="http://www.w3.org/2000/svg" height="17px" viewBox="0 -960 960 960" width="17px" fill=${Infcolor}>\n <path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/>\n </svg>\n </button>`:``}\n </div>\n <div class="device-card-back" >\n <div id="status-bar"> \n <div id="status-information">\n <div style="font-size: 0.85rem; font-weight: bold; line-height: 1;"><span>Central: ${centralName}</span></div>\n <div style="display: flex; flex-direction: row; gap: 4px; font-weight: bold; align-items: center;">\n <div style="font-size: 12px; font-weight: bold; line-height: 1;"><span> ${formattedDate}</span></div>\n <div style="font-size: 10px; line-height: 1;"><span></span></div> \n </div>\n </div>\n <button id="infoButtom-back" class="device-info" style="background:none; border:none; cursor:pointer;">\n <svg xmlns="http://www.w3.org/2000/svg" height="17px" viewBox="0 -960 960 960" width="17px" fill=${Infcolor}>\n <path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/>\n </svg>\n </button>\n </div>\n\n <div class="value-container">\n <svg xmlns="http://www.w3.org/2000/svg" height="30px" viewBox="0 -960 960 960" width="30px" fill="#dea404">\n <path d="m456-200 174-340H510v-220L330-420h126v220Zm24 120q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/>\n </svg>\n <div><span>${MyIO.formatEnergy(val/1e3)||"-"}</span></div>\n </div>\n\n <div id="lastconsumptionTime">\n <div style="font-size: 12px; font-weight: bold; color: black; line-height: 1;">Ultima Telemetria:</div>\n <div style="font-size: 11px; font-weight: bold; color: black; line-height: 1;">${formattedDateVal}</div>\n </div>\n </div>\n </div>\n </div> \n </div>\n \n `;const $card=$(html);if(typeof handleActionDashboard==="function"){$card.find(".action-dashboard").on("click",e=>{e.stopPropagation();handleActionDashboard(entityObject)})}if(typeof handleActionReport==="function"){$card.find(".action-report").on("click",e=>{e.stopPropagation();handleActionReport(entityObject)})}if(typeof handleActionSettings==="function"){$card.find(".action-settings").on("click",e=>{e.stopPropagation();handleActionSettings(entityObject)})}if(typeof handleSelect==="function"){$card.find(".action-checker").on("click",e=>{e.stopPropagation();handleSelect(entityObject)})}if(typeof handleClickCard==="function"){$card.find(".action-checker").on("click",e=>{e.stopPropagation();handleClickCard(entityObject)})}$card.on("click",e=>{if(!$(e.target).closest(".card-action").length){if(typeof handleClickCard==="function"){handleClickCard(entityObject)}else if(typeof handleActionDashboard==="function"){handleActionDashboard(entityObject)}}});$card.find("#infoButtom-front").on("click",function(e){e.stopPropagation();$(this).closest(".device-card-centered").addClass("flipped")});$card.find("#infoButtom-back").on("click",function(e){e.stopPropagation();$(this).closest(".device-card-centered").removeClass("flipped")});return $card}var init_template_card=__esm({"src/thingsboard/main-dashboard-shopping/v-4.0.0/card/template-card.js"(){}});function formatEnergy(value,unit){if(value===null||value===void 0||isNaN(value)){return"-"}let adjustedValue=value;let adjustedUnit=unit;if(!adjustedUnit){if(value>=1e6){adjustedValue=value/1e6;adjustedUnit="GWh"}else if(value>=1e3){adjustedValue=value/1e3;adjustedUnit="MWh"}else{adjustedUnit="kWh"}}const formattedValue=adjustedValue.toLocaleString("pt-BR",{minimumFractionDigits:2,maximumFractionDigits:2});return`${formattedValue} ${adjustedUnit}`}function formatAllInSameUnit(values,targetUnit,sourceUnit="kWh"){const unitMultipliers={kWh:1,MWh:1e3,GWh:1e6};const targetMultiplier=unitMultipliers[targetUnit]||1;if(typeof values[0]==="number"){const numberValues=values;const sourceMultiplier=unitMultipliers[sourceUnit]||1;return numberValues.map(value=>{if(value===null||value===void 0||isNaN(value)){return"-"}const convertedValue=value*sourceMultiplier/targetMultiplier;return formatEnergy(convertedValue,targetUnit)})}const objectValues=values;return objectValues.map(item=>{if(item.value===null||item.value===void 0||isNaN(item.value)){return"-"}const sourceMultiplier=unitMultipliers[item.unit]||1;const convertedValue=item.value*sourceMultiplier/targetMultiplier;return formatEnergy(convertedValue,targetUnit)})}function fmtPerc(value){if(value===null||value===void 0||isNaN(value)||!isFinite(value)){return"-"}const percentage=value*100;return percentage.toLocaleString("pt-BR",{minimumFractionDigits:2,maximumFractionDigits:2})+"%"}function formatNumberReadable(value,locale="pt-BR",minimumFractionDigits=2,maximumFractionDigits=2){const n=typeof value==="string"?Number(value.replace(",",".")):Number(value);if(!Number.isFinite(n)){return"-"}const safe=Object.is(n,-0)?0:n;return safe.toLocaleString(locale,{minimumFractionDigits:minimumFractionDigits,maximumFractionDigits:maximumFractionDigits})}function formatWaterVolumeM3(value,locale="pt-BR"){if(value===null||value===void 0||isNaN(value)){return"-"}const formattedValue=value.toLocaleString(locale,{minimumFractionDigits:2,maximumFractionDigits:2});return`${formattedValue} M³`}function formatTankHeadFromCm(valueCm,locale="pt-BR"){if(valueCm===null||valueCm===void 0||isNaN(valueCm)){return"-"}const valueMeters=valueCm/100;const formattedValue=valueMeters.toLocaleString(locale,{minimumFractionDigits:2,maximumFractionDigits:2});return`${formattedValue} m.c.a.`}function calcDeltaPercent(prev,current){if(prev===null||prev===void 0||isNaN(prev)||current===null||current===void 0||isNaN(current)){return{value:0,type:"neutral"}}if(prev===0&&current===0){return{value:0,type:"neutral"}}if(prev===0&&current>0){return{value:100,type:"increase"}}if(prev===0&&current<0){return{value:100,type:"decrease"}}const percentChange=(current-prev)/prev*100;if(percentChange>0){return{value:percentChange,type:"increase"}}else if(percentChange<0){return{value:Math.abs(percentChange),type:"decrease"}}else{return{value:0,type:"neutral"}}}function formatWaterByGroup(value,group){if(value===null||value===void 0||isNaN(value)){return"-"}if(group==="Caixas D'Água"){return formatTankHeadFromCm(value)}if(value>=1e3){return formatWaterVolumeM3(value/1e3)+" x 10³ "}return formatWaterVolumeM3(value)}function formatAllInSameWaterUnit(values){const max=Math.max(...values.filter(v=>!isNaN(v)&&v!==null&&v!==void 0));let divisor=1;let unit="M³";if(max>=1e6){divisor=1e6;unit="M³"}else if(max>=1e3){divisor=1e3;unit="M³"}return{format:val=>{if(val===null||val===void 0||isNaN(val)){return"-"}return(val/divisor).toFixed(2)+" "+unit},unit:unit}}function formatDateToYMD(date){if(!date){return""}const dateObj=new Date(date);if(isNaN(dateObj.getTime())){return""}const year=dateObj.getFullYear();const month=String(dateObj.getMonth()+1).padStart(2,"0");const day=String(dateObj.getDate()).padStart(2,"0");return`${year}-${month}-${day}`}function determineInterval(startDate,endDate){const start=new Date(startDate);const end=new Date(endDate);if(isNaN(start.getTime())||isNaN(end.getTime())){return"day"}const diffMs=end.getTime()-start.getTime();const diffDays=diffMs/(1e3*60*60*24);if(diffDays<=1){return"hour"}else if(diffDays<=7){return"day"}else if(diffDays<=31){return"week"}else if(diffDays<=365){return"month"}else{return"year"}}function getSaoPauloISOString(date,edge="start"){const dateObj=new Date(date);if(isNaN(dateObj.getTime())){return""}const saoPauloOffset=-3;const saoPauloDate=new Date(dateObj.getTime()+saoPauloOffset*60*60*1e3);if(edge==="start"){saoPauloDate.setHours(0,0,0,0)}else{saoPauloDate.setHours(23,59,59,999)}const utcDate=new Date(saoPauloDate.getTime()-saoPauloOffset*60*60*1e3);return utcDate.toISOString()}function getDateRangeArray(startDate,endDate,interval="day"){const start=new Date(startDate);const end=new Date(endDate);const dates=[];if(isNaN(start.getTime())||isNaN(end.getTime())||start>end){return dates}const current=new Date(start);while(current<=end){dates.push(new Date(current));switch(interval){case"day":current.setDate(current.getDate()+1);break;case"week":current.setDate(current.getDate()+7);break;case"month":current.setMonth(current.getMonth()+1);break;case"year":current.setFullYear(current.getFullYear()+1);break;default:current.setDate(current.getDate()+1)}}return dates}function formatDateForInput(date){if(!date||isNaN(date.getTime())){return""}const year=date.getFullYear();const month=String(date.getMonth()+1).padStart(2,"0");const day=String(date.getDate()).padStart(2,"0");return`${year}-${month}-${day}`}function parseInputDateToDate(inputDateStr){if(!inputDateStr){return null}const parts=inputDateStr.split("-");if(parts.length!==3){return null}const year=parseInt(parts[0],10);const month=parseInt(parts[1],10)-1;const day=parseInt(parts[2],10);if(isNaN(year)||isNaN(month)||isNaN(day)){return null}return new Date(year,month,day,0,0,0,0)}function timeWindowFromInputYMD(startYmd,endYmd,tzOffset="-03:00"){if(!startYmd||!endYmd){return{startTs:0,endTs:0}}const startParts=startYmd.split("-");const endParts=endYmd.split("-");if(startParts.length!==3||endParts.length!==3){return{startTs:0,endTs:0}}const startDate=new Date(parseInt(startParts[0],10),parseInt(startParts[1],10)-1,parseInt(startParts[2],10),0,0,0,0);const endDate=new Date(parseInt(endParts[0],10),parseInt(endParts[1],10)-1,parseInt(endParts[2],10),23,59,59,999);return{startTs:startDate.getTime(),endTs:endDate.getTime()}}function formatDateWithTimezoneOffset(date,endOfDay=false,tzOffset="-03:00"){if(!date||isNaN(date.getTime())){return""}const year=date.getFullYear();const month=String(date.getMonth()+1).padStart(2,"0");const day=String(date.getDate()).padStart(2,"0");let hours,minutes,seconds,milliseconds;if(endOfDay){hours="23";minutes="59";seconds="59";milliseconds="999"}else{hours=String(date.getHours()).padStart(2,"0");minutes=String(date.getMinutes()).padStart(2,"0");seconds=String(date.getSeconds()).padStart(2,"0");milliseconds=String(date.getMilliseconds()).padStart(3,"0")}return`${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${tzOffset}`}function getSaoPauloISOStringFixed(dateStr,endOfDay=false){if(!dateStr)return"";if(endOfDay){return`${dateStr}T23:59:59.999-03:00`}else{return`${dateStr}T00:00:00.000-03:00`}}function averageByDay(data){if(!data||data.length===0){return[]}const grouped={};data.forEach(item=>{if(!item||item.value===null||item.value===void 0||isNaN(item.value)){return}const date=new Date(item.ts);if(isNaN(date.getTime())){return}const day=date.toISOString().split("T")[0];if(!grouped[day]){grouped[day]=[]}grouped[day].push(Number(item.value))});const result=Object.entries(grouped).map(([day,values])=>{const sum=values.reduce((acc,val)=>acc+val,0);const average=sum/values.length;return{day:day,average:average}});result.sort((a,b)=>a.day.localeCompare(b.day));return result}function groupByDay(data){if(!data||data.length===0){return{}}const grouped={};data.forEach(item=>{if(!item||item.value===null||item.value===void 0||isNaN(item.value)){return}const date=new Date(item.ts);if(isNaN(date.getTime())){return}const day=date.toISOString().split("T")[0];if(!grouped[day]){grouped[day]=[]}grouped[day].push(Number(item.value))});return grouped}function exportToCSV(data,headers,filename){if(!data||data.length===0){return""}const csvHeaders=headers.join(",");const csvRows=data.map(row=>headers.map(header=>{const value=row[header];if(value===null||value===void 0){return""}const stringValue=String(value);if(stringValue.includes(",")||stringValue.includes('"')||stringValue.includes("\n")){return`"${stringValue.replace(/"/g,'""')}"`}return stringValue}).join(","));const csvContent=[csvHeaders,...csvRows].join("\n");return csvContent}function exportToCSVAll(storesData,headers,filename){if(!storesData||Object.keys(storesData).length===0){return""}const csvRows=[];const csvHeaders=["Store",...headers].join(",");csvRows.push(csvHeaders);Object.entries(storesData).forEach(([storeName,storeData])=>{if(!storeData||storeData.length===0){return}storeData.forEach(row=>{let formattedStoreName=storeName;if(storeName.includes(",")||storeName.includes('"')||storeName.includes("\n")){formattedStoreName=`"${storeName.replace(/"/g,'""')}"`}const csvRow=[formattedStoreName,...headers.map(header=>{const value=row[header];if(value===null||value===void 0){return""}const stringValue=String(value);if(stringValue.includes(",")||stringValue.includes('"')||stringValue.includes("\n")){return`"${stringValue.replace(/"/g,'""')}"`}return stringValue})].join(",");csvRows.push(csvRow)})});return csvRows.join("\n")}function buildWaterReportCSV(rows,meta){if(!rows||rows.length===0){return""}const csvRows=[];let totalConsumption=0;rows.forEach(row=>{const consumptionStr=String(row.totalConsumption).replace(",",".");const consumption=Number(consumptionStr)||0;totalConsumption+=consumption});const finalTotal=meta.total!==void 0?meta.total:totalConsumption;csvRows.push(["DATA EMISSÃO",meta.issueDate]);csvRows.push(["Total",finalTotal.toFixed(2)]);if(meta.name&&meta.identifier){csvRows.push(["Loja:",meta.name,meta.identifier])}csvRows.push(["Data","Dia da Semana","Consumo Médio (m³)","Consumo Mínimo (m³)","Consumo Máximo (m³)","Consumo (m³)"]);rows.forEach(row=>{csvRows.push([row.formattedDate,row.day,String(row.avgConsumption),String(row.minDemand),String(row.maxDemand),String(row.totalConsumption)])});return csvRows.map(row=>row.join(";")).join("\n")}function buildWaterStoresCSV(rows,meta){if(!rows||rows.length===0){return""}const csvRows=[];let totalConsumption=0;rows.forEach(row=>{const consumption=row.consumptionM3!==void 0?row.consumptionM3:row.consumptionKwh||0;totalConsumption+=consumption});const finalTotal=meta.total!==void 0?meta.total:totalConsumption;csvRows.push(["DATA EMISSÃO",meta.issueDate]);csvRows.push(["Total",finalTotal.toFixed(2)]);csvRows.push(["Loja","Identificador","Consumo"]);rows.forEach(row=>{const label=row.entityLabel||row.deviceName||"-";const deviceId=row.deviceId||"-";const consumption=row.consumptionM3!==void 0?row.consumptionM3:row.consumptionKwh||0;const formattedConsumption=consumption!==null&&consumption!==void 0?formatNumberReadable(consumption):"0,00";csvRows.push([label,deviceId,formattedConsumption])});return csvRows.map(row=>row.join(";")).join("\n")}function toCSV(rows,delimiter=";"){if(!rows||rows.length===0){return""}return rows.map(row=>row.map(cell=>{const value=String(cell);if(value.includes(delimiter)||value.includes('"')||value.includes("\n")){return`"${value.replace(/"/g,'""')}"`}return value}).join(delimiter)).join("\n")}function classify(entity,criteria){if(!entity||!criteria){return{category:"unknown",confidence:0}}let category="unknown";let subcategory;let confidence=0;if(entity.type){switch(entity.type.toLowerCase()){case"consumption":category="energy_consumption";confidence=.9;break;case"generation":category="energy_generation";confidence=.9;break;case"storage":category="energy_storage";confidence=.9;break;case"distribution":category="energy_distribution";confidence=.8;break;default:category="energy_other";confidence=.5}}if(entity.powerRating){const power=parseFloat(entity.powerRating);if(!isNaN(power)){if(power<1e3){subcategory="small_scale"}else if(power<1e4){subcategory="medium_scale"}else{subcategory="large_scale"}confidence=Math.min(confidence+.1,1)}}return{category:category,subcategory:subcategory,confidence:confidence}}function classifyWaterLabel(label){if(!label){console.warn('classifyWaterLabel: empty label, defaulting to "Lojas"');return"Lojas"}const normalizedLabel=label.toLowerCase().trim();if(/rel[óo]gio|caixa|superior|inferior|nível_terraço/.test(normalizedLabel)){return"Caixas D'Água"}if(/administra|bomba|chiller|adm/.test(normalizedLabel)){return"Área Comum"}return"Lojas"}function classifyWaterLabels(labels){const counts={"Caixas D'Água":0,Lojas:0,"Área Comum":0,total:0};labels.forEach(label=>{const category=classifyWaterLabel(label);counts[category]++;counts.total++});return counts}function getWaterCategories(){return["Caixas D'Água","Lojas","Área Comum"]}function isWaterCategory(label,category){return classifyWaterLabel(label)===category}function getValueByDatakey(data,datakey){if(!data||!datakey){return void 0}if(Array.isArray(data)){for(const item of data){const value=getValueByDatakey(item,datakey);if(value!==void 0){return value}}return void 0}if(typeof data==="object"&&data!==null){const keys=datakey.split(".");let current=data;for(const key of keys){if(current===null||current===void 0){return void 0}if(key.includes("[")&&key.includes("]")){const arrayKey=key.substring(0,key.indexOf("["));const indexMatch=key.match(/\[(\d+)\]/);if(indexMatch){const index=parseInt(indexMatch[1],10);current=current[arrayKey];if(Array.isArray(current)&&index>=0&&index<current.length){current=current[index]}else{return void 0}}else{return void 0}}else{current=current[key]}}return current}return void 0}function getValueByDatakeyLegacy(dataList,dataSourceNameTarget,dataKeyTarget){if(!Array.isArray(dataList)||!dataSourceNameTarget||!dataKeyTarget){return void 0}for(const item of dataList){if(item&&item.dataSourceName===dataSourceNameTarget&&item.dataKey===dataKeyTarget){return item.value}}return void 0}function findValue(data,keyOrPath,legacyDataKey){if(legacyDataKey!==void 0){return getValueByDatakeyLegacy(data,keyOrPath,legacyDataKey)}return getValueByDatakey(data,keyOrPath)}function normalize(str){if(typeof str!=="string")return"";let normalized=str.toUpperCase().trim();normalized=normalized.replace(/[ÀÁÂÃÄÅ]/g,"A").replace(/[ÈÉÊË]/g,"E").replace(/[ÌÍÎÏ]/g,"I").replace(/[ÒÓÔÕÖ]/g,"O").replace(/[ÙÚÛÜ]/g,"U").replace(/[Ç]/g,"C").replace(/[Ñ]/g,"N");normalized=normalized.replace(/\s+/g," ");return normalized}function matchCaixaDAgua(normalizedStr){if(normalizedStr.includes("SCD"))return true;const caixaVariants=["CAIXA D'AGUA","CAIXA D AGUA","CAIXA_D_AGUA","CAIXA DAGUA"];return caixaVariants.some(variant=>normalizedStr.includes(variant))}var contexts={building:name=>{const normalized=normalize(name);const rules=[{test:s=>s.includes("COMPRESSOR"),type:"COMPRESSOR"},{test:s=>s.includes("VENT"),type:"VENTILADOR"},{test:s=>s.includes("AUTOMATICO"),type:"SELETOR_AUTO_MANUAL"},{test:s=>s.includes("ESRL"),type:"ESCADA_ROLANTE"},{test:s=>s.includes("ESCADA"),type:"ESCADA_ROLANTE"},{test:s=>s.includes("ELEV"),type:"ELEVADOR"},{test:s=>s.includes("MOTR")||s.includes("RECALQUE"),type:"MOTOR"},{test:s=>s.includes("TERMOSTATO"),type:"TERMOSTATO"},{test:s=>s.includes("TERMO")||s.includes("TEMP"),type:"TERMOSTATO"},{test:s=>s.includes("3F"),type:"3F_MEDIDOR"},{test:s=>s.includes("HIDR"),type:"HIDROMETRO"},{test:s=>s.includes("ABRE"),type:"SOLENOIDE"},{test:s=>matchCaixaDAgua(s),type:"CAIXA_D_AGUA"},{test:s=>s.includes("AUTOMACAO")||s.includes("GW_AUTO"),type:"GLOBAL_AUTOMACAO"},{test:s=>s.includes("AC"),type:"CONTROLE REMOTO"}];for(const rule of rules){if(rule.test(normalized)){return rule.type}}return"default"},mall:name=>{const normalized=normalize(name);const rules=[{test:s=>s.includes("CHILLER"),type:"CHILLER"},{test:s=>s.includes("ESCADA"),type:"ESCADA_ROLANTE"},{test:s=>s.includes("LOJA"),type:"LOJA_SENSOR"},{test:s=>s.includes("ILUMINACAO"),type:"ILUMINACAO"}];for(const rule of rules){if(rule.test(normalized)){return rule.type}}return"default"}};var warnedContexts=new Set;function detectDeviceType(name,context="building"){if(typeof name!=="string"){throw new Error("Device name must be a string.")}const detectFunction=contexts[context];if(!detectFunction){if(!warnedContexts.has(context)){console.warn(`[myio-js-library] Context "${context}" not found. Using default fallback.`);warnedContexts.add(context)}return contexts.building(name)}return detectFunction(name)}function getAvailableContexts(){return Object.keys(contexts)}function addDetectionContext(contextName,detectFunction){if(typeof contextName!=="string"){throw new Error("Context name must be a string.")}if(typeof detectFunction!=="function"){throw new Error("Detection function must be a function.")}contexts[contextName]=detectFunction}function addNamespace(payload,namespace=""){if(!payload||typeof payload!=="object"||Array.isArray(payload)){throw new Error("Payload must be an object.")}const keys=Object.keys(payload);const suffix=namespace.trim()?` (${namespace.trim()})`:"";return keys.reduce((acc,key)=>{acc[`${key}${suffix}`]=payload[key];return acc},{})}var numbers_exports={};__export(numbers_exports,{fmtPerc:()=>fmtPerc2,toFixedSafe:()=>toFixedSafe});function fmtPerc2(x,digits=2){if(!Number.isFinite(x))return"—";return(x*100).toFixed(digits)+"%"}function toFixedSafe(x,digits=2){if(!Number.isFinite(x))return"—";return x.toFixed(digits)}var strings_exports={};__export(strings_exports,{normalizeRecipients:()=>normalizeRecipients});function normalizeRecipients(val){if(val===null||val===void 0||val==="")return"";if(Object.prototype.toString.call(val)==="[object Array]"){return val.filter(Boolean).join(",")}let s=String(val).trim();if(/^\s*\[/.test(s)){try{const arr=JSON.parse(s);if(Object.prototype.toString.call(arr)==="[object Array]"){return arr.filter(Boolean).join(",")}}catch{}}s=s.replace(/[;\s]+/g,",");s=s.replace(/,+/g,",").replace(/^,|,$/g,"");return s}function decodePayload(encoded,key){const bytes=base64ToBytesStrict(encoded);if(bytes.length===0)return"";if(key===""||key===void 0||key===null){return(new TextDecoder).decode(bytes)}if(typeof key==="number"&&Number.isFinite(key)){const k=key&255;for(let i=0;i<bytes.length;i++)bytes[i]^=k;return(new TextDecoder).decode(bytes)}const keyStr=String(key);const keyBytes=(new TextEncoder).encode(keyStr);if(keyBytes.length===0){return(new TextDecoder).decode(bytes)}for(let i=0;i<bytes.length;i++){bytes[i]^=keyBytes[i%keyBytes.length]}return(new TextDecoder).decode(bytes)}function decodePayloadBase64Xor(encoded,xorKey=73){const bytes=base64ToBytesStrict(encoded);for(let i=0;i<bytes.length;i++)bytes[i]^=xorKey&255;return(new TextDecoder).decode(bytes)}function base64ToBytesStrict(b64){if(b64===""||b64===void 0||b64===null)return new Uint8Array;const s=String(b64).replace(/\s+/g,"");const re=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;if(!re.test(s))throw new Error("Invalid base64");if(typeof Buffer!=="undefined"&&Buffer.from){return Uint8Array.from(Buffer.from(s,"base64"))}const bin=atob(s);const out=new Uint8Array(bin.length);for(let i=0;i<bin.length;i++)out[i]=bin.charCodeAt(i);return out}init_template_card();var MyIOSelectionStoreClass=class{constructor(){this.selectedIds=new Set;this.entities=new Map;this.eventListeners=new Map;this.analytics=null;this.timeSeriesCache=new Map;this.cacheExpiry=5*60*1e3;this.eventListeners.set("selection:change",[]);this.eventListeners.set("selection:totals",[]);this.eventListeners.set("comparison:open",[]);this.eventListeners.set("comparison:too_many",[])}add(id){if(typeof id!=="string"||!id.trim())return;const wasSelected=this.selectedIds.has(id);this.selectedIds.add(id);if(!wasSelected){this._emitSelectionChange("add",id);this._trackEvent("footer_dock.drop_add",{entityId:id})}}remove(id){if(typeof id!=="string"||!this.selectedIds.has(id))return;this.selectedIds.delete(id);this._emitSelectionChange("remove",id);this._trackEvent("footer_dock.remove_chip",{entityId:id})}toggle(id){if(this.isSelected(id)){this.remove(id)}else{this.add(id)}}clear(){if(this.selectedIds.size===0)return;this.selectedIds.clear();this._emitSelectionChange("clear");this._trackEvent("footer_dock.clear_all",{count:0})}syncFromCheckbox(id,checked){if(typeof id!=="string"||typeof checked!=="boolean")return;if(checked&&!this.isSelected(id)){this.add(id)}else if(!checked&&this.isSelected(id)){this.remove(id)}this._trackEvent("card.checkbox_toggle",{entityId:id,checked:checked})}registerEntity(entity){if(!entity||typeof entity!=="object"||!entity.id){throw new Error("Entity must be an object with an id property")}const normalizedEntity={id:entity.id,name:entity.name||"",icon:entity.icon||"generic",group:entity.group||"",lastValue:Number(entity.lastValue)||0,unit:entity.unit||"",status:entity.status||"unknown"};this.entities.set(entity.id,normalizedEntity)}unregisterEntity(id){if(typeof id!=="string")return;this.entities.delete(id);this.remove(id)}getSelectedIds(){return Array.from(this.selectedIds)}getSelectedEntities(){return this.getSelectedIds().map(id=>this.entities.get(id)).filter(entity=>entity!==void 0)}getTotals(){const selectedEntities=this.getSelectedEntities();const totals={energyKwh:0,waterM3:0,tempC:0,percentage:0,count:selectedEntities.length,unitBreakdown:{}};selectedEntities.forEach(entity=>{const value=entity.lastValue||0;const unit=entity.unit||"";if(!totals.unitBreakdown[unit]){totals.unitBreakdown[unit]=0}totals.unitBreakdown[unit]+=value;switch(unit.toLowerCase()){case"kwh":case"mwh":case"gwh":totals.energyKwh+=this._convertToKwh(value,unit);break;case"m³":case"m3":totals.waterM3+=value;break;case"°c":case"celsius":totals.tempC+=value;break;case"%":case"percent":totals.percentage+=value;break}});return totals}isSelected(id){return this.selectedIds.has(id)}getSelectionCount(){return this.selectedIds.size}getMultiUnitTotalDisplay(){const totals=this.getTotals();const parts=[];if(totals.energyKwh>0){parts.push(`Energy: ${this._formatNumber(totals.energyKwh)} kWh`)}if(totals.waterM3>0){parts.push(`Water: ${this._formatNumber(totals.waterM3)} m³`)}if(totals.tempC>0){parts.push(`Temp: ${this._formatNumber(totals.tempC)} °C`)}if(totals.percentage>0){parts.push(`${this._formatNumber(totals.percentage)}%`)}return parts.join(" | ")||"No selection"}on(event,callback){if(typeof event!=="string"||typeof callback!=="function")return;if(!this.eventListeners.has(event)){this.eventListeners.set(event,[])}this.eventListeners.get(event).push(callback)}off(event,callback){if(!this.eventListeners.has(event))return;const listeners=this.eventListeners.get(event);const index=listeners.indexOf(callback);if(index>-1){listeners.splice(index,1)}}async getTimeSeriesData(entityIds,startDate,endDate){if(!Array.isArray(entityIds)||entityIds.length===0){return{}}const cacheKey=`${entityIds.join(",")}_${startDate.getTime()}_${endDate.getTime()}`;const cached=this.timeSeriesCache.get(cacheKey);if(cached&&Date.now()-cached.timestamp<this.cacheExpiry){return cached.data}const mockData={};entityIds.forEach(id=>{mockData[id]=this._generateMockTimeSeriesData(startDate,endDate)});this.timeSeriesCache.set(cacheKey,{data:mockData,timestamp:Date.now()});return mockData}invalidateCache(reason="manual"){this.timeSeriesCache.clear();this._trackEvent("cache.invalidated",{reason:reason})}setAnalytics(analyticsInstance){if(!analyticsInstance||typeof analyticsInstance.track!=="function"){throw new Error("Analytics instance must have a track method")}this.analytics=analyticsInstance}trackEvent(eventName,payload={}){this._trackEvent(eventName,payload)}openComparison(){const count=this.getSelectionCount();if(count===0){this.announceToScreenReader("No items selected for comparison");return false}if(count>20){this._emit("comparison:too_many",{count:count,maxAllowed:20,selectedIds:this.getSelectedIds()});this._trackEvent("chart_modal.too_many_entities",{count:count});return false}const data={entities:this.getSelectedEntities(),totals:this.getTotals(),count:count};this._emit("comparison:open",data);this._trackEvent("chart_modal.open",{entityCount:count});return true}startDrag(id){if(typeof id!=="string")return;this._trackEvent("drag.start",{entityId:id})}announceToScreenReader(message){if(typeof message!=="string"||typeof document==="undefined")return;let announcer=document.getElementById("myio-sr-announcer");if(!announcer){announcer=document.createElement("div");announcer.id="myio-sr-announcer";announcer.setAttribute("aria-live","polite");announcer.setAttribute("aria-atomic","true");announcer.style.position="absolute";announcer.style.left="-10000px";announcer.style.width="1px";announcer.style.height="1px";announcer.style.overflow="hidden";document.body.appendChild(announcer)}announcer.textContent=message}_emitSelectionChange(action,id=null){const data={action:action,id:id,selectedIds:this.getSelectedIds(),totals:this.getTotals()};this._emit("selection:change",data);this._emit("selection:totals",data.totals);this._trackEvent("footer_dock.total_update",{action:action,count:data.selectedIds.length,totals:data.totals})}_emit(event,data){if(!this.eventListeners.has(event))return;this.eventListeners.get(event).forEach(callback=>{try{callback(data)}catch(error){console.error(`Error in ${event} listener:`,error)}})}_trackEvent(eventName,payload={}){if(!this.analytics)return;try{this.analytics.track(eventName,{timestamp:Date.now(),...payload})}catch(error){console.error("Analytics tracking error:",error)}}_convertToKwh(value,unit){switch(unit.toLowerCase()){case"mwh":return value*1e3;case"gwh":return value*1e6;case"kwh":default:return value}}_formatNumber(value){if(typeof value!=="number"||isNaN(value))return"0";return new Intl.NumberFormat("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2}).format(value)}_generateMockTimeSeriesData(startDate,endDate){const data=[];const current=new Date(startDate);const end=new Date(endDate);while(current<=end){data.push({timestamp:current.getTime(),value:Math.random()*100+50,unit:"kWh"});current.setHours(current.getHours()+1)}return data}};var MyIOSelectionStore=new MyIOSelectionStoreClass;if(typeof globalThis!=="undefined"&&typeof globalThis.window!=="undefined"){globalThis.window.MyIOSelectionStore=MyIOSelectionStore;globalThis.window.MyIOSelectionStoreClass=MyIOSelectionStoreClass}if(typeof module!=="undefined"&&module.exports){module.exports={MyIOSelectionStore:MyIOSelectionStore,MyIOSelectionStoreClass:MyIOSelectionStoreClass}}var MyIODraggableCard=class{constructor(container,entity,options={}){if(!container||!entity||!entity.id){throw new Error("Container and entity with id are required")}this.container=container;this.entity=entity;this.options={showCheckbox:true,draggable:true,className:"",...options};this.cardElement=null;this.checkbox=null;this.isDragging=false;this.touchStartTime=0;this.touchTimer=null;this.destroyed=false;this._init()}destroy(){if(this.destroyed)return;this._removeEventListeners();if(this.cardElement&&this.cardElement.parentNode){this.cardElement.parentNode.removeChild(this.cardElement)}this.destroyed=true}updateEntity(newEntity){if(this.destroyed)return;this.entity={...this.entity,...newEntity};this._updateCardContent()}setSelected(selected){if(this.destroyed)return;if(this.checkbox){this.checkbox.checked=selected}this._updateSelectionState(selected)}_init(){this._createCardElement();this._attachEventListeners();this._updateSelectionState(this._getSelectionStore()?.isSelected(this.entity.id)||false)}_createCardElement(){if(typeof document==="undefined")return;const card=document.createElement("div");card.className=`myio-draggable-card ${this.options.className}`.trim();card.setAttribute("data-entity-id",this.entity.id);card.setAttribute("role","article");card.setAttribute("tabindex","0");if(this.options.draggable){card.draggable=true;card.setAttribute("aria-grabbed","false")}card.innerHTML=this._generateCardHTML();this.cardElement=card;this.checkbox=card.querySelector(".card-checkbox");this.container.appendChild(card)}_generateCardHTML(){const{id:id,name:name,icon:icon,group:group,lastValue:lastValue,unit:unit,status:status}=this.entity;const checkboxHtml=this.options.showCheckbox?`<input type="checkbox" class="card-checkbox" aria-label="Select ${name}">`:"";return`\n <div class="card-header">\n ${checkboxHtml}\n <div class="card-icon card-icon-${icon}">\n ${this._getIconSvg(icon)}\n </div>\n <div class="card-status card-status-${status}"></div>\n </div>\n <div class="card-body">\n <h3 class="card-title">${this._escapeHtml(name)}</h3>\n <p class="card-group">${this._escapeHtml(group)}</p>\n <div class="card-value">\n <span class="value">${this._formatValue(lastValue)}</span>\n <span class="unit">${this._escapeHtml(unit)}</span>\n </div>\n </div>\n <div class="card-footer">\n <span class="card-id">${this._escapeHtml(id)}</span>\n </div>\n `}_attachEventListeners(){if(!this.cardElement)return;this.cardElement.addEventListener("dragstart",this._handleDragStart.bind(this));this.cardElement.addEventListener("dragend",this._handleDragEnd.bind(this));this.cardElement.addEventListener("click",this._handleClick.bind(this));this.cardElement.addEventListener("touchstart",this._handleTouchStart.bind(this),{passive:false});this.cardElement.addEventListener("touchmove",this._handleTouchMove.bind(this),{passive:false});this.cardElement.addEventListener("touchend",this._handleTouchEnd.bind(this));this.cardElement.addEventListener("keydown",this._handleKeyDown.bind(this));if(this.checkbox){this.checkbox.addEventListener("change",this._handleCheckboxChange.bind(this));this.checkbox.addEventListener("click",this._handleCheckboxClick.bind(this))}const store=this._getSelectionStore();if(store){this._selectionChangeHandler=data=>{const isSelected=data.selectedIds.includes(this.entity.id);this._updateSelectionState(isSelected)};store.on("selection:change",this._selectionChangeHandler)}}_removeEventListeners(){if(!this.cardElement)return;const store=this._getSelectionStore();if(store&&this._selectionChangeHandler){store.off("selection:change",this._selectionChangeHandler)}this._selectionChangeHandler=null}_handleDragStart(event){if(!this.options.draggable){event.preventDefault();return}this.isDragging=true;this.cardElement.setAttribute("aria-grabbed","true");this.cardElement.classList.add("dragging");event.dataTransfer.setData("text/myio-id",this.entity.id);event.dataTransfer.setData("text/plain",this.entity.id);event.dataTransfer.effectAllowed="copy";const store=this._getSelectionStore();if(store){store.startDrag(this.entity.id)}this._announceToScreenReader(`Started dragging ${this.entity.name}`)}_handleDragEnd(event){this.isDragging=false;this.cardElement.setAttribute("aria-grabbed","false");this.cardElement.classList.remove("dragging");this._announceToScreenReader(`Finished dragging ${this.entity.name}`)}_handleTouchStart(event){if(!this.options.draggable)return;this.touchStartTime=Date.now();this.touchTimer=setTimeout(()=>{this._startTouchDrag(event)},500)}_handleTouchMove(event){if(this.touchTimer){clearTimeout(this.touchTimer);this.touchTimer=null}if(this.isDragging){event.preventDefault()}}_handleTouchEnd(event){if(this.touchTimer){clearTimeout(this.touchTimer);this.touchTimer=null}if(this.isDragging){this._endTouchDrag(event)}}_startTouchDrag(event){if(!this.options.draggable)return;this.isDragging=true;this.cardElement.classList.add("touch-dragging");if(navigator.vibrate){navigator.vibrate(50)}this._announceToScreenReader(`Touch drag started for ${this.entity.name}`)}_endTouchDrag(event){this.isDragging=false;this.cardElement.classList.remove("touch-dragging");this._announceToScreenReader(`Touch drag ended for ${this.entity.name}`)}_handleClick(event){if(event.target===this.checkbox)return;if(this.isDragging)return;const store=this._getSelectionStore();if(store){store.toggle(this.entity.id)}}_handleKeyDown(event){switch(event.key){case"Enter":case" ":event.preventDefault();if(event.shiftKey){const store=this._getSelectionStore();if(store){store.openComparison()}}else{const store=this._getSelectionStore();if(store){store.toggle(this.entity.id)}}break;case"Delete":case"Backspace":{event.preventDefault();const store=this._getSelectionStore();if(store){store.remove(this.entity.id)}break}}}_handleCheckboxChange(event){event.stopPropagation();const store=this._getSelectionStore();if(store){store.syncFromCheckbox(this.entity.id,event.target.checked)}}_handleCheckboxClick(event){event.stopPropagation()}_updateSelectionState(isSelected){if(this.destroyed)return;if(this.checkbox){this.checkbox.checked=isSelected}this.cardElement.classList.toggle("selected",isSelected);this.cardElement.setAttribute("aria-selected",isSelected.toString());const action=isSelected?"selected":"not selected";this.cardElement.setAttribute("aria-label",`${this.entity.name}, ${this.entity.group}, ${action}`)}_updateCardContent(){if(this.destroyed)return;const titleElement=this.cardElement.querySelector(".card-title");const groupElement=this.cardElement.querySelector(".card-group");const valueElement=this.cardElement.querySelector(".value");const unitElement=this.cardElement.querySelector(".unit");const idElement=this.cardElement.querySelector(".card-id");if(titleElement)titleElement.textContent=this.entity.name||"";if(groupElement)groupElement.textContent=this.entity.group||"";if(valueElement)valueElement.textContent=this._formatValue(this.entity.lastValue);if(unitElement)unitElement.textContent=this.entity.unit||"";if(idElement)idElement.textContent=this.entity.id||"";const iconElement=this.cardElement.querySelector(".card-icon");const statusElement=this.cardElement.querySelector(".card-status");if(iconElement){iconElement.className=`card-icon card-icon-${this.entity.icon||"generic"}`;iconElement.innerHTML=this._getIconSvg(this.entity.icon||"generic")}if(statusElement){statusElement.className=`card-status card-status-${this.entity.status||"unknown"}`}}_getSelectionStore(){if(typeof globalThis!=="undefined"&&globalThis.window?.MyIOSelectionStore){return globalThis.window.MyIOSelectionStore}if(typeof globalThis!=="undefined"&&globalThis.window&&globalThis.window.MyIOSelectionStore){return globalThis.window.MyIOSelectionStore}return null}_formatValue(value){if(value===null||value===void 0||isNaN(value)){return"-"}return new Intl.NumberFormat("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2}).format(Number(value))}_escapeHtml(text){if(typeof text!=="string")return"";if(typeof document==="undefined")return text;const div=document.createElement("div");div.textContent=text;return div.innerHTML}_getIconSvg(iconType){const icons={energy:'<svg viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>',water:'<svg viewBox="0 0 24 24"><path d="M12 2c-5.33 4.55-8 8.48-8 11.8 0 4.98 3.8 8.2 8 8.2s8-3.22 8-8.2c0-3.32-2.67-7.25-8-11.8z"/></svg>',temp:'<svg viewBox="0 0 24 24"><path d="M15 13V5c0-1.66-1.34-3-3-3S9 3.34 9 5v8c-1.21.91-2 2.37-2 4 0 2.76 2.24 5 5 5s5-2.24 5-5c0-1.63-.79-3.09-2-4z"/></svg>',net:'<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/></svg>',alert:'<svg viewBox="0 0 24 24"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',generic:'<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>'};return icons[iconType]||icons.generic}_announceToScreenReader(message){const store=this._getSelectionStore();if(store&&store.announceToScreenReader){store.announceToScreenReader(message)}}};if(typeof globalThis!=="undefined"&&typeof globalThis.window!=="undefined"){globalThis.window.MyIODraggableCard=MyIODraggableCard}if(typeof module!=="undefined"&&module.exports){module.exports={MyIODraggableCard:MyIODraggableCard}}function renderCardComponentV2({entityObject:entityObject,handleActionDashboard:handleActionDashboard,handleActionReport:handleActionReport,handleActionSettings:handleActionSettings,handleSelect:handleSelect,handInfo:handInfo,handleClickCard:handleClickCard,useNewComponents:useNewComponents=true,enableSelection:enableSelection=true,enableDragDrop:enableDragDrop=true}){const{entityId:entityId,labelOrName:labelOrName,deviceIdentifier:deviceIdentifier,entityType:entityType,deviceType:deviceType,slaveId:slaveId,ingestionId:ingestionId,val:val,centralId:centralId,updatedIdentifiers:updatedIdentifiers={},perc:perc=0,deviceStatus:deviceStatus,centralName:centralName,connectionStatusTime:connectionStatusTime,timeVal:timeVal,valType:valType}=entityObject;const MyIOToast=function(){let toastContainer=null;let toastTimeout=null;const TOAST_CSS=`\n #myio-global-toast-container {\n position: fixed;\n top: 25px;\n right: 25px;\n z-index: 99999;\n width: 320px;\n padding: 16px;\n border-radius: 8px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n font-size: 15px;\n color: #fff;\n transform: translateX(120%);\n transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);\n border-left: 5px solid transparent;\n display: flex;\n align-items: center;\n }\n #myio-global-toast-container.show {\n transform: translateX(0);\n }\n #myio-global-toast-container.warning {\n background-color: #ff9800; /* Laranja para alerta */\n border-color: #f57c00;\n }\n #myio-global-toast-container.error {\n background-color: #d32f2f; /* Vermelho para erro */\n border-color: #b71c1c;\n }\n #myio-global-toast-container::before {\n content: '⚠️'; /* Ícone de alerta */\n margin-right: 12px;\n font-size: 20px;\n }\n #myio-global-toast-container.error::before {\n content: '🚫'; /* Ícone de erro */\n }\n `;function createToastElement(){if(document.getElementById("myio-global-toast-container")){toastContainer=document.getElementById("myio-global-toast-container");return}const style=document.createElement("style");style.id="myio-global-toast-styles";style.textContent=TOAST_CSS;document.head.appendChild(style);toastContainer=document.createElement("div");toastContainer.id="myio-global-toast-container";document.body.appendChild(toastContainer)}function show(message,type="warning",duration=3500){if(!toastContainer){createToastElement()}clearTimeout(toastTimeout);toastContainer.textContent=message;toastContainer.className="";toastContainer.classList.add(type);setTimeout(()=>{toastContainer.classList.add("show")},10);toastTimeout=setTimeout(()=>{toastContainer.classList.remove("show")},duration)}if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",createToastElement)}else{createToastElement()}return{show:show}}();if(!useNewComponents){return renderCardComponentLegacy({entityObject:entityObject,handleActionDashboard:handleActionDashboard,handleActionReport:handleActionReport,handleActionSettings:handleActionSettings,handleSelect:handleSelect,handInfo:handInfo,handleClickCard:handleClickCard})}const DeviceStatusType={POWER_ON:"power_on",STANDBY:"standby",POWER_OFF:"power_off",WARNING:"warning",DANGER:"danger",MAINTENANCE:"maintenance",NO_INFO:"no_info"};const connectionStatusType={CONNECTED:"connected",OFFLINE:"offline"};const mapDeviceToConnectionStatus=deviceStatus2=>{if(deviceStatus2===DeviceStatusType.NO_INFO){return connectionStatusType.OFFLINE}return connectionStatusType.CONNECTED};const connectionStatus=mapDeviceToConnectionStatus(deviceStatus);const deviceStatusIcons={[DeviceStatusType.POWER_ON]:"⚡",[DeviceStatusType.STANDBY]:"🔌",[DeviceStatusType.POWER_OFF]:"🔴",[DeviceStatusType.WARNING]:"⚠️",[DeviceStatusType.DANGER]:"🚨",[DeviceStatusType.MAINTENANCE]:"🛠️",[DeviceStatusType.NO_INFO]:"❓️"};const shouldFlashIcon=deviceStatus===DeviceStatusType.OFFLINE||deviceStatus===DeviceStatusType.WARNING||deviceStatus===DeviceStatusType.DANGER||deviceStatus===DeviceStatusType.MAINTENANCE;const icon=deviceStatusIcons[deviceStatus]||deviceStatusIcons[DeviceStatusType.POWER_ON];const mapDeviceStatus=status=>{const statusMap={power_on:"ok",standby:"alert",power_off:"fail",warning:"alert",danger:"fail",maintenance:"alert"};return statusMap[status]||"unknown"};const mapDeviceTypeToIcon=deviceType2=>{const typeMap={MOTOR:"energy","3F_MEDIDOR":"energy",RELOGIO:"energy",HIDROMETRO:"water",ENTRADA:"energy",CAIXA_DAGUA:"water",TANK:"water"};const normalizedType=deviceType2?.toUpperCase()||"";return typeMap[normalizedType]||"generic"};const isEnergyDevice=(valType2,deviceType2)=>{if(valType2==="ENERGY"){return true}const energyDeviceTypes=["MOTOR","3F_MEDIDOR","RELOGIO","ENTRADA"];const normalizedType=deviceType2?.toUpperCase()||"";return energyDeviceTypes.includes(normalizedType)};const formatCardValue=(value,valType2,deviceType2)=>{const numValue=Number(value)||0;if(isEnergyDevice(valType2,deviceType2)){return formatEnergy(numValue)}else{const unit=determineUnit(valType2);const formattedValue=numValue.toLocaleString("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2});return`${formattedValue} ${unit}`}};const determineUnit=(valType2,val2,deviceType2)=>{switch(valType2){case"ENERGY":return"";case"WATER":return"m³";case"TANK":return"m.c.a";default:return""}};const cardEntity={id:entityId,name:labelOrName||"Dispositivo",icon:mapDeviceTypeToIcon(deviceType),group:deviceIdentifier||entityType||"Dispositivo",lastValue:Number(val)||0,unit:determineUnit(valType),status:mapDeviceStatus(deviceStatus)};if(enableSelection&&MyIOSelectionStore){MyIOSelectionStore.registerEntity(cardEntity)}const container=document.createElement("div");container.className="myio-enhanced-card-container";if(!document.getElementById("myio-enhanced-card-styles")){const style=document.createElement("style");style.id="myio-enhanced-card-styles";style.textContent=`\n .myio-enhanced-card-container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .myio-enhanced-card-container .myio-draggable-card {\n width: 100%;\n border-radius: 10px;\n padding: 8px 12px; \n background: #fff;\n box-shadow: 0 4px 10px rgba(0, 0, 0, .05);\n cursor: pointer;\n \n transition: transform .2s;\n box-sizing: border-box;\n overflow: hidden;\n min-height: 140px;\n display: flex;\n flex-direction: row;\n align-items: stretch;\n }\n \n .myio-enhanced-card-container .myio-draggable-card:hover {\n transform: scale(1.05);\n }\n \n .myio-enhanced-card-container .myio-draggable-card.selected {\n border: 2px solid #00e09e;\n box-shadow: 0 4px 12px rgba(0,224,158,0.2);\n background: linear-gradient(135deg, #f0fdf9, #ecfdf5);\n }\n \n .myio-enhanced-card-container .myio-draggable-card.offline {\n border: 2px solid #ff4d4f;\n animation: border-blink 1s infinite;\n }\n \n @keyframes border-blink {\n 0%, 100% { box-shadow: 0 0 8px rgba(255, 77, 79, 0.9); }\n 50% { box-shadow: 0 0 16px rgba(255, 0, 0, 0.6); }\n }\n \n .myio-enhanced-card-container .card-actions {\n flex-shrink: 0;\n height: 100%;\n box-shadow: 1px 0 2px rgba(0, 0, 0, .1);\n display: flex;\n flex-direction: column;\n padding: 0 4px;\n justify-content: space-around;\n align-items: center;\n gap: 8px;\n }\n \n .myio-enhanced-card-container .card-action {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: all 0.2s ease;\n cursor: pointer;\n border: none;\n background: rgba(0, 0, 0, 0.05);\n }\n \n .myio-enhanced-card-container .card-action:hover {\n background: rgba(0, 224, 158, 0.1);\n transform: scale(1.1);\n }\n \n .myio-enhanced-card-container .card-action img {\n width: 20px;\n height: 20px;\n }\n \n .myio-enhanced-card-container .card-checkbox {\n width: 16px;\n height: 16px;\n cursor: pointer;\n }\n \n .myio-enhanced-card-container .card-body {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n padding: 0 12px;\n text-align: center;\n }\n \n .myio-enhanced-card-container .card-title {\n font-weight: 700;\n font-size: 0.85rem;\n margin-bottom: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n }\n \n .myio-enhanced-card-container .card-group {\n font-size: 0.7rem;\n color: #888;\n margin-bottom: 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n }\n \n .myio-enhanced-card-container .card-value {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 0.9rem;\n font-weight: 700;\n color: #28a745;\n }\n \n .myio-enhanced-card-container .card-unit {\n font-size: 0.75rem;\n color: rgba(0, 0, 0, 0.6);\n }\n \n .myio-enhanced-card-container .card-percentage {\n font-size: 0.75rem;\n color: rgba(0, 0, 0, 0.45);\n margin-left: 4px;\n }\n \n .myio-enhanced-card-container .card-icon {\n width: 24px;\n height: 24px;\n margin-bottom: 8px;\n }\n \n .myio-enhanced-card-container .card-icon svg {\n width: 100%;\n height: 100%;\n fill: currentColor;\n }\n \n .myio-enhanced-card-container .card-status-indicator {\n position: absolute;\n top: 8px;\n right: 8px;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n z-index: 10;\n }\n \n .myio-enhanced-card-container .card-status-ok {\n background: #28a745;\n }\n \n .myio-enhanced-card-container .card-status-alert {\n background: #ffc107;\n }\n \n .myio-enhanced-card-container .card-status-fail,\n .myio-enhanced-card-container .card-status-offline {\n background: #dc3545;\n }\n \n .myio-enhanced-card-container .card-status-unknown {\n background: #6c757d;\n }\n \n .myio-enhanced-card-container .info-panel {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(4px);\n display: none;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n padding: 16px;\n border-radius: 10px;\n z-index: 20;\n }\n \n .myio-enhanced-card-container .info-panel.active {\n display: flex;\n }\n \n .myio-enhanced-card-container .info-close {\n position: absolute;\n top: 8px;\n right: 8px;\n background: none;\n border: none;\n font-size: 18px;\n cursor: pointer;\n color: #666;\n }\n \n .myio-enhanced-card-container .info-content {\n text-align: center;\n font-size: 0.8rem;\n line-height: 1.4;\n }\n \n .myio-enhanced-card-container .info-content strong {\n display: block;\n margin-bottom: 8px;\n color: #333;\n }\n `;document.head.appendChild(style)}const getDeviceImageUrl=deviceType2=>{function normalizeString(str){if(typeof str!=="string"){str=""}return str.normalize("NFD").replace(/[\u0300-\u036f]/g,"").toUpperCase()}const deviceImages={MOTOR:"https://dashboard.myio-bas.com/api/images/public/8Ezn8qVBJ3jXD0iDfnEAZ0MZhAP1b5Ts","3F_MEDIDOR":"https://dashboard.myio-bas.com/api/images/public/f9Ce4meybsdaAhAkUlAfy5ei3I4kcN4k",RELOGIO:"https://dashboard.myio-bas.com/api/images/public/ljHZostWg0G5AfKiyM8oZixWRIIGRASB",HIDROMETRO:"https://dashboard.myio-bas.com/api/images/public/aMQYFJbGHs9gQbQkMn6XseAlUZHanBR4",ENTRADA:"https://dashboard.myio-bas.com/api/images/public/TQHPFqiejMW6lOSVsb8Pi85WtC0QKOLU",CAIXA_DAGUA:"https://dashboard.myio-bas.com/api/images/public/3t6WVhMQJFsrKA8bSZmrngDsNPkZV7fq"};const defaultImage="https://cdn-icons-png.flaticon.com/512/1178/1178428.png";const nameType=normalizeString(deviceType2);return deviceImages[nameType]||defaultImage};const deviceImageUrl=getDeviceImageUrl(deviceType);const cardHTML=`\n <div class="device-card-centered clickable ${cardEntity.status==="offline"?"offline":""}" \n data-entity-id="${entityId}"\n draggable="${enableDragDrop}"\n tabindex="0"\n role="article"\n aria-label="${cardEntity.name}, ${cardEntity.group}">\n \n <div class="device-card-inner">\n <div class="device-card-front">\n ${enableSelection&&typeof handleSelect==="function"?`<input type="checkbox" class="card-checkbox action-checker" aria-label="Select ${cardEntity.name}" style="position: absolute; top: 8px; right: 8px; z-index: 10;">`:""}\n \n <div style="display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%; flex-grow: 1; min-width: 0; padding: 0 12px 0 20px; margin-left: 16px;">\n \n <div class="device-title-row" style="flex-direction: column; min-height: 38px; text-align: center; width: 100%;">\n <span class="device-title" title="${cardEntity.name}">\n ${cardEntity.name.length>15?cardEntity.name.slice(0,15)+"…":cardEntity.name}\n </span>\n ${deviceIdentifier?`\n <span class="device-subtitle" title="${deviceIdentifier}">\n ${deviceIdentifier}\n </span>\n `:""}\n </div>\n\n <img class="device-image" src="${deviceImageUrl}" alt="${deviceType}" />\n \n <div class="device-data-row">\n <div class="consumption-main">\n <span class="flash-icon ${shouldFlashIcon?"flash":""}">\n ${icon}\n </span>\n <span class="consumption-value">${formatCardValue(cardEntity.lastValue,valType,deviceType)}</span>\n <span class="device-title-percent">(${perc.toFixed(1)}%)</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class="connection-status-icon" data-conn="${connectionStatus}" data-state="${deviceStatus}" aria-label="${connectionStatus}"></div>\n \n </div>\n `;container.innerHTML=cardHTML;const enhancedCardElement=container.querySelector(".device-card-centered");if(!document.getElementById("myio-enhanced-card-layout-styles")){const layoutStyle=document.createElement("style");layoutStyle.id="myio-enhanced-card-layout-styles";layoutStyle.textContent=`\n /* ===== MYIO Card v2 — Clean Piano Keys & Flat Status ===== */\n\n /* Card shell (kept) */\n .device-card-centered.clickable {\n width: 90% !important;\n max-width: 280px !important;\n border-radius: 14px !important;\n padding: 18px !important;\n background: linear-gradient(145deg, #ffffff 0%, #f8fafc 100%) !important;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04) !important;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;\n border: 1px solid rgba(226, 232, 240, 0.8) !important;\n position: relative;\n overflow: hidden;\n backdrop-filter: blur(10px);\n min-height: 126px !important;\n margin: 0 auto;\n }\n \n .device-card-centered.clickable::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: linear-gradient(90deg, #00e09e 0%, #00b4d8 50%, #7209b7 100%);\n opacity: 0;\n transition: opacity 0.3s ease;\n }\n \n .device-card-centered.clickable:hover {\n transform: translateY(-4px) scale(1.02) !important;\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.12), 0 8px 16px rgba(0, 0, 0, 0.08) !important;\n border-color: rgba(0, 224, 158, 0.3) !important;\n }\n \n .device-card-centered.clickable:hover::before {\n opacity: 1;\n }\n\n /* Selected / Offline (kept) */\n .device-card-centered.selected {\n border: 2px solid #00e09e !important;\n box-shadow: 0 12px 40px rgba(0, 224, 158, 0.25), 0 4px 12px rgba(0, 224, 158, 0.15) !important;\n background: linear-gradient(145deg, #f0fdf9 0%, #ecfdf5 50%, #f0fdf9 100%) !important;\n transform: translateY(-2px) !important;\n }\n \n .device-card-centered.selected::before {\n opacity: 1;\n background: linear-gradient(90deg, #00e09e 0%, #00d4aa 100%);\n }\n \n .device-card-centered.offline {\n border: 2px solid #ef4444 !important;\n background: linear-gradient(145deg, #fef2f2 0%, #fee2e2 50%, #fef2f2 100%) !important;\n animation: premium-offline-pulse 2s infinite !important;\n }\n \n .device-card-centered.offline::before {\n opacity: 1;\n background: linear-gradient(90deg, #ef4444 0%, #dc2626 100%);\n }\n \n @keyframes premium-offline-pulse {\n 0%, 100% { \n box-shadow: 0 8px 32px rgba(239, 68, 68, 0.15), 0 2px 8px rgba(239, 68, 68, 0.1);\n }\n 50% { \n box-shadow: 0 12px 40px rgba(239, 68, 68, 0.25), 0 4px 12px rgba(239, 68, 68, 0.2);\n }\n }\n\n /* Device image & titles (kept) */\n .device-card-centered .device-image {\n max-height: 47px !important;\n width: auto;\n margin: 10px 0 !important;\n display: block;\n filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.1));\n transition: all 0.3s ease;\n border-radius: 7px;\n }\n \n .device-card-centered:hover .device-image {\n filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.15));\n transform: scale(1.05);\n }\n \n .device-card-centered .device-title-row {\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n justify-content: center !important;\n text-align: center !important;\n width: 100% !important;\n min-height: 38px !important;\n margin-bottom: 8px !important;\n }\n \n .device-card-centered .device-title {\n font-weight: 700 !important;\n font-size: 0.85rem !important;\n color: #1e293b !important;\n margin: 0 0 4px 0 !important;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n letter-spacing: -0.025em;\n display: block !important;\n width: 100% !important;\n text-align: center !important;\n }\n \n .device-card-centered .device-subtitle {\n font-size: 0.67rem !important;\n color: #64748b !important;\n font-weight: 500 !important;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n opacity: 0.8;\n display: block !important;\n width: 100% !important;\n text-align: center !important;\n margin: 0 !important;\n padding: 0 !important;\n }\n\n /* Value pill (kept) */\n .device-card-centered .consumption-main {\n background: linear-gradient(135deg, rgba(0, 224, 158, 0.1) 0%, rgba(0, 180, 216, 0.1) 100%);\n border-radius: 10px;\n padding: 7px 10px;\n margin-top: 7px;\n border: 1px solid rgba(0, 224, 158, 0.2);\n backdrop-filter: blur(10px);\n }\n \n .device-card-centered .consumption-value {\n font-weight: 700 !important;\n font-size: 0.9rem !important;\n color: #059669 !important;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n }\n \n .device-card-centered .device-title-percent {\n font-size: 0.72rem !important;\n color: #6b7280 !important;\n font-weight: 600 !important;\n margin-left: 5px;\n }\n \n .device-card-centered .flash-icon {\n font-size: 1rem !important;\n margin-right: 7px;\n transition: all 0.3s ease;\n }\n \n .device-card-centered:hover .flash-icon {\n transform: scale(1.1);\n }\n \n .device-card-centered .flash-icon.flash {\n animation: premium-flash 1.5s infinite;\n }\n \n @keyframes premium-flash {\n 0%, 100% { \n opacity: 1; \n transform: scale(1);\n filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));\n }\n 50% { \n opacity: 0.3; \n transform: scale(1.15);\n filter: drop-shadow(0 4px 8px rgba(239, 68, 68, 0.3));\n }\n }\n\n /* Checkbox (kept) */\n .device-card-centered .card-checkbox {\n width: 16px !important;\n height: 16px !important;\n cursor: pointer;\n background: rgba(255, 255, 255, 0.9) !important;\n border: 2px solid #e2e8f0 !important;\n border-radius: 5px !important;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n backdrop-filter: blur(10px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n position: relative;\n }\n \n .device-card-centered .card-checkbox:hover {\n border-color: #00e09e !important;\n box-shadow: 0 3px 6px rgba(0, 224, 158, 0.15);\n transform: scale(1.05);\n }\n \n .device-card-centered .card-checkbox:checked {\n background: linear-gradient(135deg, #00e09e 0%, #00d4aa 100%) !important;\n border-color: #00e09e !important;\n box-shadow: 0 3px 10px rgba(0, 224, 158, 0.3);\n }\n \n .device-card-centered .card-checkbox:checked::after {\n content: '✓';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: white;\n font-size: 10px;\n font-weight: bold;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);\n }\n\n /* ——— NEW: Piano-Key Actions (flat by default, full height) ——— */\n .device-card-centered .card-actions {\n position: absolute;\n left: 12px;\n top: 12px;\n bottom: 12px;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 0;\n border: 1px solid rgba(226, 232, 240, 0.9);\n border-radius: 8px;\n background: #fff;\n overflow: visible;\n box-shadow: none !important;\n z-index: 10;\n }\n \n .device-card-centered .card-action {\n width: 36px !important;\n height: 36px !important;\n border: 0;\n border-bottom: 1px solid rgba(226, 232, 240, 0.9);\n background: #fff !important;\n box-shadow: none !important;\n backdrop-filter: none !important;\n transform: translateZ(0);\n transition: transform 0.18s ease, box-shadow 0.18s ease;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0;\n border-radius: 0;\n }\n \n .device-card-centered .card-action:first-child {\n border-top-left-radius: 7px;\n border-top-right-radius: 7px;\n }\n \n .device-card-centered .card-action:last-child {\n border-bottom: 0;\n border-bottom-left-radius: 7px;\n border-bottom-right-radius: 7px;\n }\n \n .device-card-centered .card-action img {\n width: 16px !important;\n height: 16px !important;\n filter: grayscale(0.2) brightness(0.85);\n transition: transform 0.18s ease, filter 0.18s ease;\n }\n\n /* Lift on interaction only */\n .device-card-centered .card-action:hover,\n .device-card-centered .card-action:focus-visible {\n transform: translateY(-2px) scale(1.05);\n box-shadow: 0 6px 14px rgba(16, 24, 40, 0.12), 0 2px 6px rgba(16, 24, 40, 0.08);\n outline: none;\n }\n \n .device-card-centered .card-action:hover img,\n .device-card-centered .card-action:focus-visible img {\n filter: grayscale(0) brightness(1);\n transform: scale(1.08);\n }\n\n /* ——— NEW: Flat Status (CSS dot, never clipped) ——— */\n .device-card-centered .connection-status-icon {\n position: absolute;\n bottom: 18px;\n right: 18px;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: #22c55e;\n border: 1px solid rgba(0, 0, 0, 0.06);\n box-shadow: none !important;\n backdrop-filter: none !important;\n z-index: 5;\n }\n\n /* Map colors by connection or device state */\n .device-card-centered .connection-status-icon[data-conn="offline"] {\n background: #94a3b8;\n }\n .device-card-centered .connection-status-icon[data-state="warning"] {\n background: #f59e0b;\n }\n .device-card-centered .connection-status-icon[data-state="danger"] {\n background: #ef4444;\n }\n .device-card-centered .connection-status-icon[data-state="no_info"] {\n background: #94a3b8;\n }\n .device-card-centered .connection-status-icon[data-state="maintenance"] {\n background: #0ea5e9;\n }\n \n .myio-enhanced-card-container .info-close:hover {\n background: rgba(239, 68, 68, 0.2) !important;\n transform: scale(1.1);\n }\n\n /* Responsive / Dark mode (kept) */\n @media (max-width: 768px) {\n .device-card-centered.clickable {\n padding: 16px !important;\n border-radius: 12px !important;\n }\n \n .device-card-centered .device-image {\n max-height: 44px !important;\n }\n \n .device-card-centered .card-action {\n width: 36px !important;\n height: 36px !important;\n }\n }\n \n @media (prefers-color-scheme: dark) {\n .device-card-centered.clickable {\n background: linear-gradient(145deg, #1e293b 0%, #334155 100%) !important;\n border-color: rgba(71, 85, 105, 0.8) !important;\n color: #f1f5f9 !important;\n }\n \n .device-card-centered .device-title {\n color: #f1f5f9 !important;\n }\n \n .device-card-centered .device-subtitle {\n color: #94a3b8 !important;\n }\n \n .device-card-centered .card-actions {\n border-color: rgba(71, 85, 105, 0.8);\n background: #1e293b;\n }\n \n .device-card-centered .card-action {\n background: #1e293b !important;\n border-bottom: 1px solid rgba(71, 85, 105, 0.8);\n }\n }\n `;document.head.appendChild(layoutStyle)}const actionsContainer=document.createElement("div");actionsContainer.className="card-actions";if(typeof handleActionDashboard==="function"){const dashboardBtn=document.createElement("button");dashboardBtn.className="card-action action-dashboard";dashboardBtn.title="Dashboard";dashboardBtn.innerHTML='<img src="https://dashboard.myio-bas.com/api/images/public/TAVXE0sTbCZylwGsMF9lIWdllBB3iFtS"/>';dashboardBtn.addEventListener("click",e=>{e.stopPropagation();handleActionDashboard(entityObject)});actionsContainer.appendChild(dashboardBtn)}if(typeof handleActionReport==="function"){const reportBtn=document.createElement("button");reportBtn.className="card-action action-report";reportBtn.title="Relatório";reportBtn.innerHTML='<img src="https://dashboard.myio-bas.com/api/images/public/d9XuQwMYQCG2otvtNSlqUHGavGaSSpz4"/>';reportBtn.addEventListener("click",e=>{e.stopPropagation();handleActionReport(entityObject)});actionsContainer.appendChild(reportBtn)}if(typeof handleActionSettings==="function"){const settingsBtn=document.createElement("button");settingsBtn.className="card-action action-settings";settingsBtn.title="Configurações";settingsBtn.innerHTML='<img src="https://dashboard.myio-bas.com/api/images/public/5n9tze6vED2uwIs5VvJxGzNNZ9eV4yoz"/>';settingsBtn.addEventListener("click",e=>{e.stopPropagation();handleActionSettings(entityObject)});actionsContainer.appendChild(settingsBtn)}if(handInfo){const infoPanel=document.createElement("div");infoPanel.className="info-panel";const closeBtn=document.createElement("button");closeBtn.className="info-close";closeBtn.innerHTML="×";closeBtn.addEventListener("click",()=>{infoPanel.classList.remove("active")});const infoContent=document.createElement("div");infoContent.className="info-content";let connectionInfo="";if(connectionStatusTime){const date=new Date(connectionStatusTime);connectionInfo=`<strong>Central:</strong> ${centralName||"N/A"}<br>`;connectionInfo+=`<strong>Última Conexão:</strong> ${date.toLocaleString("pt-BR")}<br>`}if(timeVal){const telemetryDate=new Date(timeVal);const now=new Date;const diffMs=now-telemetryDate;const diffHours=Math.floor(diffMs/(1e3*60*60));connectionInfo+=`<strong>Última Telemetria:</strong> ${telemetryDate.toLocaleString("pt-BR")}`;if(diffHours>0){connectionInfo+=` (${diffHours}h atrás)`}}infoContent.innerHTML=connectionInfo||"<strong>Informações não disponíveis</strong>";infoPanel.appendChild(closeBtn);infoPanel.appendChild(infoContent);container.appendChild(infoPanel);const infoBtn=document.createElement("button");infoBtn.className="card-action action-info";infoBtn.title="Informações";infoBtn.innerHTML="📊";infoBtn.addEventListener("click",e=>{e.stopPropagation();infoPanel.classList.toggle("active")});actionsContainer.appendChild(infoBtn)}if(enhancedCardElement&&actionsContainer.children.length>0){enhancedCardElement.insertBefore(actionsContainer,enhancedCardElement.firstChild)}if(enableSelection&&MyIOSelectionStore){const checkbox=enhancedCardElement.querySelector(".card-checkbox");if(checkbox){checkbox.addEventListener("change",e=>{e.stopPropagation();if(e.target.checked){const currentCount=MyIOSelectionStore.getSelectedEntities().length;const isTryingToAdd=e.target.checked;if(isTryingToAdd&&currentCount>=6){e.preventDefault();e.target.checked=false;MyIOToast.show("Não é possível selecionar mais de 6 itens.","warning");return}MyIOSelectionStore.add(entityId)}else{MyIOSelectionStore.remove(entityId)}})}const handleSelectionChange=data=>{const isSelected=data.selectedIds.includes(entityId);if(checkbox){checkbox.checked=isSelected}enhancedCardElement.classList.toggle("selected",isSelected);if(typeof handleSelect==="function"){handleSelect(entityObject)}};MyIOSelectionStore.on("selection:change",handleSelectionChange);const isInitiallySelected=MyIOSelectionStore.isSelected(entityId);if(checkbox){checkbox.checked=isInitiallySelected}enhancedCardElement.classList.toggle("selected",isInitiallySelected);container._cleanup=()=>{MyIOSelectionStore.off("selection:change",handleSelectionChange)}}if(enableDragDrop){enhancedCardElement.addEventListener("dragstart",e=>{e.dataTransfer.setData("text/myio-id",entityId);e.dataTransfer.setData("application/json",JSON.stringify(entityObject));e.dataTransfer.effectAllowed="copy";if(MyIOSelectionStore){MyIOSelectionStore.startDrag(entityId)}});enhancedCardElement.addEventListener("dragend",()=>{})}if(typeof handleClickCard==="function"){enhancedCardElement.addEventListener("click",e=>{if(!e.target.closest(".card-action")&&!e.target.closest(".card-checkbox")){handleClickCard(entityObject)}})}const jQueryLikeObject={get:index=>index===0?container:void 0,0:container,length:1,find:selector=>{const found=container.querySelector(selector);return{get:index=>index===0?found:void 0,0:found,length:found?1:0,on:(event,handler)=>{if(found)found.addEventListener(event,handler);return this}}},on:(event,handler)=>{container.addEventListener(event,handler);return this},addClass:className=>{container.classList.add(className);return this},removeClass:className=>{container.classList.remove(className);return this},destroy:()=>{if(container._cleanup){container._cleanup()}}};return jQueryLikeObject}function renderCardComponentLegacy(options){const{renderCardComponent:renderCardComponent3}=(init_template_card(),__toCommonJS(template_card_exports));return renderCardComponent3(options)}function renderCardComponent2(options){const useNewComponents=options.useNewComponents!==false&&typeof MyIOSelectionStore!=="undefined"&&typeof MyIODraggableCard!=="undefined";if(useNewComponents){return renderCardComponentV2(options)}else{return renderCardComponentLegacy(options)}}var CSS_STRING=`\n/* CSS Variables for theming */\n:root {\n --myio-card-radius: 16px;\n --myio-card-shadow: 0 2px 8px rgba(10, 31, 68, .06);\n --myio-card-bg: #fff;\n --myio-card-border: #e9eef5;\n\n --myio-chip-ok-bg: #e8f7ff;\n --myio-chip-ok-fg: #007ecc;\n --myio-chip-alert-bg: #fff4e5;\n --myio-chip-alert-fg: #b96b00;\n --myio-chip-failure-bg: #ffeaea;\n --myio-chip-failure-fg: #b71c1c;\n --myio-chip-offline-bg: #f1f5f9;\n --myio-chip-offline-fg: #64748b;\n\n --myio-text-1: #0f172a;\n --myio-text-2: #4b5563;\n --myio-muted: #94a3b8;\n\n --myio-eff-bar-bg: #e6edf5;\n --myio-eff-bar-a: #1e90ff;\n --myio-eff-bar-b: #a3d1ff;\n\n --myio-badge-border: rgba(255, 153, 0, .35);\n --myio-badge-border-failure: rgba(244, 67, 54, .45);\n}\n\n/* Main card container */\n.myio-ho-card {\n background: var(--myio-card-bg);\n border: 1px solid var(--myio-card-border);\n border-radius: var(--myio-card-radius);\n box-shadow: var(--myio-card-shadow);\n padding: 16px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n line-height: 1.4;\n color: var(--myio-text-1);\n position: relative;\n cursor: pointer;\n transition: all 0.2s ease;\n min-width: 280px;\n max-width: 320px;\n}\n\n.myio-ho-card:hover {\n box-shadow: 0 4px 12px rgba(10, 31, 68, .12);\n transform: translateY(-1px);\n}\n\n.myio-ho-card:focus-within {\n outline: 2px solid #007ecc;\n outline-offset: 2px;\n}\n\n/* Selected state with light green background */\n.myio-ho-card.is-selected {\n border: 2px solid #00e09e;\n box-shadow: 0 12px 40px rgba(0, 224, 158, 0.25), 0 4px 12px rgba(0, 224, 158, 0.15);\n background: linear-gradient(145deg, #f0fdf9 0%, #ecfdf5 50%, #f0fdf9 100%);\n transform: translateY(-2px);\n}\n\n.myio-ho-card.is-selected:hover {\n box-shadow: 0 16px 48px rgba(0, 224, 158, 0.3), 0 8px 16px rgba(0, 224, 158, 0.2);\n}\n\n/* Alert and failure states */\n.myio-ho-card.is-alert {\n border-color: var(--myio-badge-border);\n box-shadow: 0 0 0 1px var(--myio-badge-border), var(--myio-card-shadow);\n}\n\n.myio-ho-card.is-failure {\n border-color: var(--myio-badge-border-failure);\n box-shadow: 0 0 0 1px var(--myio-badge-border-failure), var(--myio-card-shadow);\n}\n\n/* Header section */\n.myio-ho-card__header {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 12px;\n}\n\n.myio-ho-card__icon {\n width: 28px;\n height: 28px;\n color: #4b6bfb;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.myio-ho-card.is-alert .myio-ho-card__icon {\n color: var(--myio-chip-alert-fg);\n}\n\n.myio-ho-card.is-failure .myio-ho-card__icon {\n color: var(--myio-chip-failure-fg);\n}\n\n.myio-ho-card__title {\n flex: 1;\n min-width: 0;\n}\n\n.myio-ho-card__name {\n font-weight: 600;\n font-size: 15px;\n color: var(--myio-text-1);\n margin-bottom: 2px;\n word-wrap: break-word;\n line-height: 1.3;\n}\n\n.myio-ho-card__code {\n font-size: 12px;\n color: var(--myio-muted);\n font-weight: 500;\n}\n\n.myio-ho-card__actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.myio-ho-card__kebab {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n border-radius: 4px;\n color: var(--myio-muted);\n transition: all 0.15s ease;\n position: relative;\n}\n\n.myio-ho-card__kebab:hover {\n background: #f1f5f9;\n color: var(--myio-text-2);\n}\n\n.myio-ho-card__kebab:focus {\n outline: 2px solid #007ecc;\n outline-offset: 1px;\n}\n\n.myio-ho-card__menu {\n position: absolute;\n top: 100%;\n right: 0;\n background: white;\n border: 1px solid var(--myio-card-border);\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n min-width: 140px;\n padding: 4px 0;\n margin-top: 4px;\n}\n\n.myio-ho-card__menu[hidden] {\n display: none;\n}\n\n.myio-ho-card__menu button {\n width: 100%;\n background: none;\n border: none;\n padding: 8px 12px;\n text-align: left;\n cursor: pointer;\n font-size: 13px;\n color: var(--myio-text-1);\n transition: background-color 0.15s ease;\n}\n\n.myio-ho-card__menu button:hover {\n background: #f8fafc;\n}\n\n.myio-ho-card__menu button:focus {\n background: #e2e8f0;\n outline: none;\n}\n\n.myio-ho-card__select {\n display: flex;\n align-items: center;\n cursor: pointer;\n}\n\n.myio-ho-card__select[hidden] {\n display: none;\n}\n\n.myio-ho-card__select input[type="checkbox"] {\n width: 16px;\n height: 16px;\n margin: 0;\n cursor: pointer;\n}\n\n/* Status chip */\n.myio-ho-card__status {\n margin-bottom: 16px;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n padding: 4px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 500;\n gap: 4px;\n}\n\n.chip--ok {\n background: var(--myio-chip-ok-bg);\n color: var(--myio-chip-ok-fg);\n}\n\n.chip--alert {\n background: var(--myio-chip-alert-bg);\n color: var(--myio-chip-alert-fg);\n}\n\n.chip--failure {\n background: var(--myio-chip-failure-bg);\n color: var(--myio-chip-failure-fg);\n}\n\n.chip--offline {\n background: var(--myio-chip-offline-bg);\n color: var(--myio-chip-offline-fg);\n}\n\n/* Primary metric */\n.myio-ho-card__primary {\n margin-bottom: 16px;\n padding: 8px 0;\n border-radius: 8px;\n transition: background-color 0.15s ease;\n}\n\n.myio-ho-card__primary:hover {\n background: #f8fafc;\n}\n\n.myio-ho-card__primary:focus {\n outline: 2px solid #007ecc;\n outline-offset: 2px;\n}\n\n.myio-ho-card__value {\n display: flex;\n align-items: baseline;\n gap: 4px;\n flex-wrap: wrap;\n}\n\n.myio-ho-card__value .num {\n font-size: 24px;\n font-weight: 700;\n color: var(--myio-text-1);\n line-height: 1;\n}\n\n.myio-ho-card__value .unit {\n font-size: 16px;\n font-weight: 600;\n color: var(--myio-text-2);\n line-height: 1;\n}\n\n.myio-ho-card__value .suffix {\n font-size: 12px;\n color: var(--myio-muted);\n margin-left: 4px;\n}\n\n/* Efficiency bar */\n.myio-ho-card__eff {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 16px;\n}\n\n.myio-ho-card__eff .label {\n font-size: 12px;\n color: var(--myio-text-2);\n font-weight: 500;\n min-width: 60px;\n}\n\n.myio-ho-card__eff .bar {\n flex: 1;\n height: 6px;\n background: var(--myio-eff-bar-bg);\n border-radius: 3px;\n position: relative;\n overflow: hidden;\n}\n\n.myio-ho-card__eff .bar__fill {\n height: 100%;\n background: linear-gradient(90deg, var(--myio-eff-bar-a) 0%, var(--myio-eff-bar-b) 100%);\n border-radius: 3px;\n transition: width 0.3s ease;\n min-width: 2px;\n}\n\n.myio-ho-card__eff .perc {\n font-size: 12px;\n font-weight: 600;\n color: var(--myio-text-1);\n min-width: 32px;\n text-align: right;\n}\n\n/* Footer metrics */\n.myio-ho-card__footer {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 12px;\n}\n\n.myio-ho-card__footer .metric {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n gap: 4px;\n}\n\n.myio-ho-card__footer .metric .ico {\n width: 16px;\n height: 16px;\n color: var(--myio-muted);\n flex-shrink: 0;\n}\n\n.myio-ho-card__footer .metric .label {\n font-size: 10px;\n color: var(--myio-muted);\n font-weight: 500;\n line-height: 1.2;\n}\n\n.myio-ho-card__footer .metric .val {\n font-size: 12px;\n font-weight: 600;\n color: var(--myio-text-1);\n line-height: 1;\n}\n\n/* Drag and drop states */\n.myio-ho-card[draggable="true"] {\n cursor: grab;\n}\n\n.myio-ho-card[draggable="true"]:active {\n cursor: grabbing;\n}\n\n.myio-ho-card.is-dragging {\n opacity: 0.5;\n transform: rotate(2deg);\n}\n\n/* Responsive adjustments */\n@media (max-width: 320px) {\n .myio-ho-card {\n min-width: 260px;\n padding: 14px;\n }\n \n .myio-ho-card__value .num {\n font-size: 20px;\n }\n \n .myio-ho-card__footer {\n gap: 8px;\n }\n}\n\n/* High contrast mode support */\n@media (prefers-contrast: high) {\n .myio-ho-card {\n border-width: 2px;\n }\n \n .chip {\n border: 1px solid currentColor;\n }\n \n .myio-ho-card__eff .bar {\n border: 1px solid var(--myio-text-2);\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .myio-ho-card,\n .myio-ho-card__primary,\n .myio-ho-card__kebab,\n .myio-ho-card__eff .bar__fill {\n transition: none;\n }\n}\n`;var Icons={gear:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M19.14 12.94c.04-.31.06-.63.06-.94s-.02-.63-.06-.94l2.03-1.58a.5.5 0 0 0 .12-.66l-1.92-3.32a.5.5 0 0 0-.62-.22l-2.39.96a7.36 7.36 0 0 0-1.63-.94l-.36-2.55A.5.5 0 0 0 13.89 1h-3.78a.5.5 0 0 0-.49.41l-.36 2.55c-.58.23-1.12.53-1.63.94l-2.39-.96a.5.5 0 0 0-.62.22L2.7 7.48a.5.5 0 0 0 .12.66l2.03 1.58c-.04.31-.06.63-.06.94s.02.63.06.94L2.82 13.18a.5.5 0 0 0-.12.66l1.92 3.32c.13.23.4.32.62.22l2.39-.96c.5.4 1.05.71 1.63.94l.36 2.55c.05.23.26.41.49.41h3.78c.23 0 .44-.18.49-.41l.36-2.55c.58-.23 1.12-.53 1.63-.94l2.39.96c.22.1.49 0 .62-.22l1.92-3.32a.5.5 0 0 0-.12-.66l-2.03-1.58ZM12 15.5A3.5 3.5 0 1 1 12 8.5a3.5 3.5 0 0 1 0 7Z"/>\n</svg>`,elevator:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M6 3h12a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Zm0 2v14h12V5H6Z"/>\n <path d="M11 17h2v-5h-2v5Zm-2.5-7.5 2-2-2-2v4Zm7 0v-4l-2 2 2 2Z"/>\n</svg>`,escalator:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M3 16a3 3 0 0 1 3-3h3.6l4.4-6H20a2 2 0 1 1 0 4h-3.6l-4.4 6H6a3 3 0 0 1-3-3Z"/>\n <circle cx="8.5" cy="6" r="1.5"/>\n</svg>`,chiller:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"\n stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">\n <path d="M12 2v20M4 7l16 10M4 17L20 7"/>\n <path d="M8 4l4 3 4-3M8 20l4-3 4 3M3 12h18"/>\n</svg>`,pump:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" aria-hidden="true" focusable="false">\n <path fill="currentColor" d="M12 3s-5 5.6-5 9a5 5 0 0 0 10 0c0-3.4-5-9-5-9Zm0 12a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z"/>\n <path fill="currentColor" d="M12 9.3c.9 0 1.7.8 1.7 1.7S12.9 12.7 12 12.7 10.3 12 10.3 11 11.1 9.3 12 9.3Z"/>\n</svg>`,fan:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <circle cx="12" cy="12" r="2.2"/>\n <path d="M12 4c2.5 0 4 1.5 4 3.3 0 1.3-.7 2.4-1.7 3.2-1.3 1-3 .7-3-.9V4Z"/>\n <path d="M20 12c0 2.5-1.5 4-3.3 4-1.3 0-2.4-.7-3.2-1.7-1-1.3-.7-3 .9-3H20Z"/>\n <path d="M12 20c-2.5 0-4-1.5-4-3.3 0-1.3.7-2.4 1.7-3.2 1.3-1 3-.7 3 .9V20Z"/>\n <path d="M4 12c0-2.5 1.5-4 3.3-4 1.3 0 2.4.7 3.2 1.7 1 1.3.7 3-.9 3H4Z"/>\n</svg>`,motor:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="3" y="7" width="14" height="10" rx="3"/>\n <rect x="17" y="10" width="4" height="4" rx="1"/>\n <circle cx="10" cy="12" r="2.5" fill="none" stroke="currentColor" stroke-width="1.6"/>\n</svg>`,thermometer:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M11 5a3 3 0 0 1 6 0v6.1a5 5 0 1 1-6 0V5Z"/>\n <rect x="13" y="4" width="2" height="9" rx="1"/>\n</svg>`,switch:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="2" y="7" width="20" height="10" rx="5"/>\n <circle cx="9" cy="12" r="3.5" fill="#fff"/>\n</svg>`,energyMeter:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="3" y="4" width="18" height="14" rx="2"/>\n <path d="M6 16h12v2H6z"/>\n <path d="M12 8a5 5 0 0 0-5 5h2a3 3 0 0 1 6 0h2a5 5 0 0 0-5-5Z"/>\n</svg>`,waterTank:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="5" y="4" width="14" height="16" rx="2"/>\n <path d="M7 12c1.5 1 3 .9 5-.3s3.5-1.3 5 .3v4H7v-4Z" fill="#fff" fill-opacity=".25"/>\n</svg>`,dot:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <circle cx="12" cy="12" r="5"/>\n</svg>`,kebab:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/>\n</svg>`};var ICON_MAP={ESCADA_ROLANTE:Icons.escalator,ELEVADOR:Icons.elevator,ELEVADOR_SERVICO:Icons.elevator,CHILLER:Icons.chiller,PUMP:Icons.pump,COMPRESSOR:Icons.motor,VENTILADOR:Icons.fan,MOTOR:Icons.motor,TERMOSTATO:Icons.thermometer,SELETOR_AUTO_MANUAL:Icons.switch,"3F_MEDIDOR":Icons.energyMeter,CAIXA_D_AGUA:Icons.waterTank,DEFAULT:Icons.gear};var DEFAULT_I18N={in_operation:"Em operação",alert:"Alerta",failure:"Falha",offline:"Offline",efficiency:"Eficiência",temperature:"Temperatura",operation_time:"Tempo de operação",updated:"Atualizado",current_suffix:"Atual",menu_dashboard:"Dashboard",menu_report:"Relatório",menu_settings:"Configurações"};var CSS_TAG="head-office-card-v1";function ensureCss(){if(!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)){const style=document.createElement("style");style.setAttribute("data-myio-css",CSS_TAG);style.textContent=CSS_STRING;document.head.appendChild(style)}}function normalizeParams(params){if(!params||!params.entityObject){throw new Error("renderCardCompenteHeadOffice: entityObject is required")}const entityObject=params.entityObject;if(!entityObject.entityId){console.warn("renderCardCompenteHeadOffice: entityId is missing, generating temporary ID");entityObject.entityId=`temp-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}return{entityObject:entityObject,i18n:{...DEFAULT_I18N,...params.i18n||{}},enableSelection:Boolean(params.enableSelection),enableDragDrop:Boolean(params.enableDragDrop),useNewComponents:Boolean(params.useNewComponents),callbacks:{handleActionDashboard:params.handleActionDashboard,handleActionReport:params.handleActionReport,handleActionSettings:params.handleActionSettings,handleSelect:params.handleSelect,handInfo:params.handInfo,handleClickCard:params.handleClickCard}}}function getIconSvg(deviceType){return ICON_MAP[deviceType]||ICON_MAP.DEFAULT}function formatPrimaryValue(val,valType){if(val===null||val===void 0||isNaN(val)){return{num:"—",unit:"",suffix:""}}switch(valType){case"power_kw":return{num:val.toFixed(1),unit:"kW",suffix:""};case"flow_m3h":return{num:val.toFixed(1),unit:"m³/h",suffix:""};case"temp_c":return{num:val.toFixed(1),unit:"°C",suffix:""};default:return{num:val.toFixed(1),unit:"",suffix:""}}}function formatTemperature(temp){if(temp===null||temp===void 0||isNaN(temp)){return"—"}return`${temp.toFixed(0)}°C`}function formatOperationHours(hours){if(hours===null||hours===void 0||isNaN(hours)){return"—"}return`${hours.toFixed(3)}h`}function formatRelativeTime(timestamp){if(!timestamp)return"—";const now=Date.now();const diff=now-timestamp;const minutes=Math.floor(diff/(1e3*60));const hours=Math.floor(minutes/60);const days=Math.floor(hours/24);if(days>0)return`${days}d`;if(hours>0)return`${hours}h`;if(minutes>0)return`${minutes}m`;return"agora"}function getStatusInfo(connectionStatus,i18n){switch(connectionStatus){case"RUNNING":case"ONLINE":return{chipClass:"chip--ok",label:i18n.in_operation};case"ALERT":return{chipClass:"chip--alert",label:i18n.alert};case"FAILURE":return{chipClass:"chip--failure",label:i18n.failure};case"OFFLINE":case"PAUSED":default:return{chipClass:"chip--offline",label:i18n.offline}}}function getCardStateClass(connectionStatus){switch(connectionStatus){case"ALERT":return"is-alert";case"FAILURE":return"is-failure";default:return""}}function buildDOM(state){const{entityObject:entityObject,i18n:i18n,enableSelection:enableSelection,enableDragDrop:enableDragDrop}=state;const root=document.createElement("div");root.className="myio-ho-card";root.setAttribute("role","group");root.setAttribute("data-entity-id",entityObject.entityId);if(enableDragDrop){root.setAttribute("draggable","true")}const header=document.createElement("div");header.className="myio-ho-card__header";const iconContainer=document.createElement("div");iconContainer.className="myio-ho-card__icon";iconContainer.innerHTML=getIconSvg(entityObject.deviceType);header.appendChild(iconContainer);const titleSection=document.createElement("div");titleSection.className="myio-ho-card__title";const nameEl=document.createElement("div");nameEl.className="myio-ho-card__name";nameEl.textContent=entityObject.labelOrName||"Unknown Device";titleSection.appendChild(nameEl);if(entityObject.deviceIdentifier){const codeEl=document.createElement("div");codeEl.className="myio-ho-card__code";codeEl.textContent=entityObject.deviceIdentifier;titleSection.appendChild(codeEl)}header.appendChild(titleSection);const actionsSection=document.createElement("div");actionsSection.className="myio-ho-card__actions";const kebabBtn=document.createElement("button");kebabBtn.className="myio-ho-card__kebab";kebabBtn.setAttribute("aria-label","Open actions");kebabBtn.setAttribute("aria-haspopup","menu");kebabBtn.innerHTML=Icons.kebab;actionsSection.appendChild(kebabBtn);const menu=document.createElement("div");menu.className="myio-ho-card__menu";menu.setAttribute("role","menu");menu.setAttribute("hidden","");const dashboardBtn=document.createElement("button");dashboardBtn.setAttribute("role","menuitem");dashboardBtn.setAttribute("data-action","dashboard");dashboardBtn.textContent=i18n.menu_dashboard;menu.appendChild(dashboardBtn);const reportBtn=document.createElement("button");reportBtn.setAttribute("role","menuitem");reportBtn.setAttribute("data-action","report");reportBtn.textContent=i18n.menu_report;menu.appendChild(reportBtn);const settingsBtn=document.createElement("button");settingsBtn.setAttribute("role","menuitem");settingsBtn.setAttribute("data-action","settings");settingsBtn.textContent=i18n.menu_settings;menu.appendChild(settingsBtn);actionsSection.appendChild(menu);if(enableSelection){const selectLabel=document.createElement("label");selectLabel.className="myio-ho-card__select";const checkbox=document.createElement("input");checkbox.type="checkbox";selectLabel.appendChild(checkbox);actionsSection.appendChild(selectLabel)}header.appendChild(actionsSection);root.appendChild(header);const statusSection=document.createElement("div");statusSection.className="myio-ho-card__status";const chip=document.createElement("span");chip.className="chip";statusSection.appendChild(chip);root.appendChild(statusSection);const primarySection=document.createElement("div");primarySection.className="myio-ho-card__primary";primarySection.setAttribute("role","button");primarySection.setAttribute("tabindex","0");const valueContainer=document.createElement("div");valueContainer.className="myio-ho-card__value";const numSpan=document.createElement("span");numSpan.className="num";valueContainer.appendChild(numSpan);const unitSpan=document.createElement("span");unitSpan.className="unit";valueContainer.appendChild(unitSpan);const suffixSpan=document.createElement("span");suffixSpan.className="suffix";suffixSpan.textContent=i18n.current_suffix;valueContainer.appendChild(suffixSpan);primarySection.appendChild(valueContainer);root.appendChild(primarySection);const effSection=document.createElement("div");effSection.className="myio-ho-card__eff";const effLabel=document.createElement("div");effLabel.className="label";effLabel.textContent=i18n.efficiency;effSection.appendChild(effLabel);const barContainer=document.createElement("div");barContainer.className="bar";barContainer.setAttribute("role","progressbar");barContainer.setAttribute("aria-valuemin","0");barContainer.setAttribute("aria-valuemax","100");const barFill=document.createElement("div");barFill.className="bar__fill";barContainer.appendChild(barFill);effSection.appendChild(barContainer);const percSpan=document.createElement("div");percSpan.className="perc";effSection.appendChild(percSpan);root.appendChild(effSection);const footer=document.createElement("div");footer.className="myio-ho-card__footer";const tempMetric=document.createElement("div");tempMetric.className="metric";const tempIcon=document.createElement("i");tempIcon.className="ico ico-temp";tempIcon.innerHTML=Icons.thermometer;tempMetric.appendChild(tempIcon);const tempLabel=document.createElement("div");tempLabel.className="label";tempLabel.textContent=i18n.temperature;tempMetric.appendChild(tempLabel);const tempVal=document.createElement("div");tempVal.className="val";tempMetric.appendChild(tempVal);footer.appendChild(tempMetric);const opTimeMetric=document.createElement("div");opTimeMetric.className="metric";const opTimeIcon=document.createElement("i");opTimeIcon.className="ico ico-clock";opTimeIcon.innerHTML=Icons.dot;opTimeMetric.appendChild(opTimeIcon);const opTimeLabel=document.createElement("div");opTimeLabel.className="label";opTimeLabel.textContent=i18n.operation_time;opTimeMetric.appendChild(opTimeLabel);const opTimeVal=document.createElement("div");opTimeVal.className="val";opTimeMetric.appendChild(opTimeVal);footer.appendChild(opTimeMetric);const updatedMetric=document.createElement("div");updatedMetric.className="metric";const updatedIcon=document.createElement("i");updatedIcon.className="ico ico-sync";updatedIcon.innerHTML=Icons.dot;updatedMetric.appendChild(updatedIcon);const updatedLabel=document.createElement("div");updatedLabel.className="label";updatedLabel.textContent=i18n.updated;updatedMetric.appendChild(updatedLabel);const updatedVal=document.createElement("div");updatedVal.className="val";updatedMetric.appendChild(updatedVal);footer.appendChild(updatedMetric);root.appendChild(footer);return root}function paint(root,state){const{entityObject:entityObject,i18n:i18n}=state;const stateClass=getCardStateClass(entityObject.connectionStatus);root.className=`myio-ho-card ${stateClass}`;const statusInfo=getStatusInfo(entityObject.connectionStatus,i18n);const chip=root.querySelector(".chip");chip.className=`chip ${statusInfo.chipClass}`;chip.textContent=statusInfo.label;const primaryValue=formatPrimaryValue(entityObject.val,entityObject.valType);const numSpan=root.querySelector(".myio-ho-card__value .num");const unitSpan=root.querySelector(".myio-ho-card__value .unit");numSpan.textContent=primaryValue.num;unitSpan.textContent=primaryValue.unit;const perc=entityObject.perc||0;const barFill=root.querySelector(".bar__fill");const percSpan=root.querySelector(".myio-ho-card__eff .perc");const barContainer=root.querySelector(".bar");barFill.style.width=`${Math.max(0,Math.min(100,perc))}%`;percSpan.textContent=`${Math.round(perc)}%`;barContainer.setAttribute("aria-valuenow",Math.round(perc).toString());barContainer.setAttribute("aria-label",`${i18n.efficiency} ${Math.round(perc)}%`);const tempVal=root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .val");tempVal.textContent=formatTemperature(entityObject.temperatureC);const opTimeVal=root.querySelector(".myio-ho-card__footer .metric:nth-child(2) .val");opTimeVal.textContent=formatOperationHours(entityObject.operationHours);const updatedVal=root.querySelector(".myio-ho-card__footer .metric:nth-child(3) .val");updatedVal.textContent=formatRelativeTime(entityObject.timaVal)}function bindEvents(root,state,callbacks){const{entityObject:entityObject}=state;const kebabBtn=root.querySelector(".myio-ho-card__kebab");const menu=root.querySelector(".myio-ho-card__menu");function toggleMenu(){const isHidden=menu.hasAttribute("hidden");if(isHidden){menu.removeAttribute("hidden");kebabBtn.setAttribute("aria-expanded","true")}else{menu.setAttribute("hidden","");kebabBtn.setAttribute("aria-expanded","false")}}function closeMenu(){menu.setAttribute("hidden","");kebabBtn.setAttribute("aria-expanded","false")}kebabBtn.addEventListener("click",e=>{e.stopPropagation();toggleMenu()});document.addEventListener("click",closeMenu);document.addEventListener("keydown",e=>{if(e.key==="Escape"){closeMenu()}});const dashboardBtn=menu.querySelector('[data-action="dashboard"]');const reportBtn=menu.querySelector('[data-action="report"]');const settingsBtn=menu.querySelector('[data-action="settings"]');if(callbacks.handleActionDashboard){dashboardBtn.addEventListener("click",e=>{e.stopPropagation();closeMenu();callbacks.handleActionDashboard(e,entityObject)})}if(callbacks.handleActionReport){reportBtn.addEventListener("click",e=>{e.stopPropagation();closeMenu();callbacks.handleActionReport(e,entityObject)})}if(callbacks.handleActionSettings){settingsBtn.addEventListener("click",e=>{e.stopPropagation();closeMenu();callbacks.handleActionSettings(e,entityObject)})}const checkbox=root.querySelector('.myio-ho-card__select input[type="checkbox"]');if(checkbox&&callbacks.handleSelect){checkbox.addEventListener("change",e=>{e.stopPropagation();const isSelected=checkbox.checked;root.classList.toggle("is-selected",isSelected);callbacks.handleSelect(isSelected,entityObject)})}const primarySection=root.querySelector(".myio-ho-card__primary");if(callbacks.handleClickCard){let handleCardClick=function(e){if(e.target.closest(".myio-ho-card__actions"))return;callbacks.handleClickCard(e,entityObject)};root.addEventListener("click",handleCardClick);primarySection.addEventListener("keydown",e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();callbacks.handleClickCard(e,entityObject)}})}if(state.enableDragDrop){root.addEventListener("dragstart",e=>{root.classList.add("is-dragging");e.dataTransfer.setData("text/plain",entityObject.entityId);const customEvent=new CustomEvent("myio:dragstart",{detail:{entityObject:entityObject},bubbles:true});root.dispatchEvent(customEvent)});root.addEventListener("dragend",()=>{root.classList.remove("is-dragging")});root.addEventListener("drop",e=>{e.preventDefault();const draggedId=e.dataTransfer.getData("text/plain");const customEvent=new CustomEvent("myio:drop",{detail:{draggedId:draggedId,targetEntity:entityObject},bubbles:true});root.dispatchEvent(customEvent)});root.addEventListener("dragover",e=>{e.preventDefault()})}root._cleanup=()=>{document.removeEventListener("click",closeMenu);document.removeEventListener("keydown",closeMenu)}}function unbindEvents(root){if(root._cleanup){root._cleanup();delete root._cleanup}}function renderCardCompenteHeadOffice(containerEl,params){if(!containerEl){throw new Error("renderCardCompenteHeadOffice: containerEl is required")}ensureCss();const state=normalizeParams(params);const root=buildDOM(state);containerEl.appendChild(root);bindEvents(root,state,state.callbacks);paint(root,state);return{update(next){if(next){Object.assign(state.entityObject,next);paint(root,state)}},destroy(){unbindEvents(root);if(root.parentNode){root.parentNode.removeChild(root)}},getRoot(){return root}}}var MyIOChartModalClass=class{constructor(){this.isOpen=false;this.modalElement=null;this.chartInstance=null;this.currentData=null;this.chartConfig={type:"line",timeRange:7,maxEntities:20};this._init()}async open(data){if(!data||!data.entities||data.entities.length===0){console.warn("ChartModal: No data provided for comparison");return}if(data.count>this.chartConfig.maxEntities){this._showTooManyEntitiesWarning(data);return}this.currentData=data;this.isOpen=true;await this._createModal();await this._loadChartJS();await this._renderChart();this._trackEvent("chart_modal.open",{entityCount:data.count,chartType:this.chartConfig.type,timeRange:this.chartConfig.timeRange})}close(){if(!this.isOpen)return;this.isOpen=false;if(this.chartInstance){this.chartInstance.destroy();this.chartInstance=null}if(this.modalElement){this.modalElement.remove();this.modalElement=null}if(typeof document!=="undefined"){document.body.focus()}this._trackEvent("chart_modal.close",{entityCount:this.currentData?.count||0})}exportCsv(){if(!this.currentData)return;const timestamp=(new Date).toISOString().slice(0,19).replace(/:/g,"-");const filename=`comparativo_${timestamp}.csv`;const csvData=this._generateCsvData();this._downloadFile(csvData,filename,"text/csv");this._trackEvent("chart_modal.export",{format:"csv",entityCount:this.currentData.count})}exportPng(){if(!this.chartInstance)return;const timestamp=(new Date).toISOString().slice(0,19).replace(/:/g,"-");const filename=`grafico_comparativo_${timestamp}.png`;const canvas=this.chartInstance.canvas;const url=canvas.toDataURL("image/png");this._downloadFile(url,filename,"image/png",true);this._trackEvent("chart_modal.export",{format:"png",entityCount:this.currentData.count})}exportPdf(){this._showNotImplementedNotice("PDF export");this._trackEvent("chart_modal.export",{format:"pdf",entityCount:this.currentData?.count||0,status:"not_implemented"})}_init(){const store=this._getSelectionStore();if(store){store.on("comparison:open",data=>this.open(data));store.on("comparison:too_many",data=>this._showTooManyEntitiesWarning(data))}}async _createModal(){if(typeof document==="undefined")return;const existing=document.getElementById("myio-chart-modal");if(existing){existing.remove()}const modal=document.createElement("div");modal.id="myio-chart-modal";modal.className="chart-modal-overlay";modal.setAttribute("role","dialog");modal.setAttribute("aria-modal","true");modal.setAttribute("aria-labelledby","chart-modal-title");modal.innerHTML=this._generateModalHTML();document.body.appendChild(modal);this.modalElement=modal;this._attachModalEventListeners();this._trapFocus();this._announceToScreenReader("Chart comparison modal opened")}_generateModalHTML(){const{entities:entities,totals:totals,count:count}=this.currentData;return`\n <div class="chart-modal-container" \n style="\n background: rgba(20, 20, 20, 0.95);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 16px;\n padding: 20px;\n max-width: 900px;\n margin: auto;\n color: #fff;\n font-family: Arial, sans-serif;\n box-shadow: 0 8px 30px rgba(0,0,0,0.5);\n ">\n \n <div class="chart-modal-header" \n style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">\n <h2 id="chart-modal-title" \n style="font-size: 20px; font-weight: bold; margin: 0; color: #fff;">\n Comparativo de Dispositivos (${count} selecionados)\n </h2>\n <button class="chart-modal-close" aria-label="Fechar modal"\n style="background: none; border: none; color: #fff; font-size: 24px; cursor: pointer; padding: 5px; transition: 0.3s;">\n ×\n </button>\n </div>\n \n <div class="chart-modal-controls" \n style="display: flex; gap: 20px; flex-wrap: wrap; margin-bottom: 20px;">\n \n <div class="chart-type-controls" style="flex: 1; min-width: 180px;">\n <label style="display: block; margin-bottom: 6px; color: rgba(255,255,255,0.8); font-size: 14px;">\n Tipo de Gráfico:\n </label>\n <select class="chart-type-select" aria-label="Selecionar tipo de gráfico"\n style="width: 100%; padding: 8px 12px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.08); \n background: rgba(255,255,255,0.08); color: #fff; outline: none; cursor: pointer;">\n <option value="line" ${this.chartConfig.type==="line"?"selected":""}>Linha</option>\n <option value="bar" ${this.chartConfig.type==="bar"?"selected":""}>Barras</option>\n </select>\n </div>\n \n <div class="chart-range-controls" style="flex: 1; min-width: 180px;">\n <label style="display: block; margin-bottom: 6px; color: rgba(255,255,255,0.8); font-size: 14px;">\n Período:\n </label>\n <select class="chart-range-select" aria-label="Selecionar período"\n style="width: 100%; padding: 8px 12px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.08); \n background: rgba(255,255,255,0.08); color: #fff; outline: none; cursor: pointer;">\n <option value="7" ${this.chartConfig.timeRange===7?"selected":""}>7 dias</option>\n <option value="14" ${this.chartConfig.timeRange===14?"selected":""}>14 dias</option>\n <option value="30" ${this.chartConfig.timeRange===30?"selected":""}>30 dias</option>\n </select>\n </div>\n \n <div class="chart-export-controls" style="display: flex; gap: 10px; align-items: end;">\n <button class="export-csv-btn"\n style="padding: 8px 14px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; transition: 0.3s;">\n Exportar CSV\n </button>\n <button class="export-png-btn"\n style="padding: 8px 14px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; transition: 0.3s;">\n Exportar PNG\n </button>\n <button class="export-pdf-btn"\n style="padding: 8px 14px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; transition: 0.3s;">\n Exportar PDF\n </button>\n </div>\n </div>\n \n <div class="chart-modal-body" style="display: flex; flex-direction: column; gap: 20px;">\n <div class="chart-container" \n style="background: rgba(255,255,255,0.05); border-radius: 12px; padding: 15px;">\n <canvas id="comparison-chart" aria-label="Gráfico comparativo de dispositivos"></canvas>\n </div>\n \n <div class="chart-summary" \n style="background: rgba(255,255,255,0.05); border-radius: 12px; padding: 15px;">\n <h3 style="margin: 0 0 12px; font-size: 16px; font-weight: bold;">Resumo da Seleção</h3>\n <div class="summary-grid" \n style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;">\n ${this._generateSummaryHTML(totals)}\n </div>\n </div>\n </div>\n \n <div class="chart-modal-footer" \n style="display: flex; justify-content: flex-end; margin-top: 20px;">\n <button class="chart-modal-close-btn"\n style="padding: 10px 20px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; font-weight: bold; transition: 0.3s;">\n Fechar\n </button>\n </div>\n </div>\n `}_generateSummaryHTML(totals){const items=[];if(totals.energyKwh>0){items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Energia Total:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(totals.energyKwh)} kWh</span>\n </div>`)}if(totals.waterM3>0){items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Água Total:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(totals.waterM3)} m³</span>\n </div>`)}if(totals.tempC>0){items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Temperatura Média:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(totals.tempC/totals.count)} °C</span>\n </div>`)}items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Dispositivos:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${totals.count}</span>\n </div>`);return items.join("")}_generateSummaryHTML(totals){const items=[];if(totals.energyKwh>0){items.push(`<div class="summary-item">\n <span class="summary-label">Energia Total:</span>\n <span class="summary-value">${this._formatNumber(totals.energyKwh)} kWh</span>\n </div>`)}if(totals.waterM3>0){items.push(`<div class="summary-item">\n <span class="summary-label">Água Total:</span>\n <span class="summary-value">${this._formatNumber(totals.waterM3)} m³</span>\n </div>`)}if(totals.tempC>0){items.push(`<div class="summary-item">\n <span class="summary-label">Temperatura Média:</span>\n <span class="summary-value">${this._formatNumber(totals.tempC/totals.count)} °C</span>\n </div>`)}items.push(`<div class="summary-item">\n <span class="summary-label">Dispositivos:</span>\n <span class="summary-value">${totals.count}</span>\n </div>`);return items.join("")}_attachModalEventListeners(){if(!this.modalElement)return;const closeButtons=this.modalElement.querySelectorAll(".chart-modal-close, .chart-modal-close-btn");closeButtons.forEach(btn=>{btn.addEventListener("click",()=>this.close())});const typeSelect=this.modalElement.querySelector(".chart-type-select");if(typeSelect){typeSelect.addEventListener("change",e=>{this.chartConfig.type=e.target.value;this._renderChart();this._trackEvent("chart_modal.type_change",{newType:e.target.value,entityCount:this.currentData.count})})}const rangeSelect=this.modalElement.querySelector(".chart-range-select");if(rangeSelect){rangeSelect.addEventListener("change",e=>{this.chartConfig.timeRange=parseInt(e.target.value);this._renderChart();this._trackEvent("chart_modal.range_change",{newRange:e.target.value,entityCount:this.currentData.count})})}const csvBtn=this.modalElement.querySelector(".export-csv-btn");const pngBtn=this.modalElement.querySelector(".export-png-btn");const pdfBtn=this.modalElement.querySelector(".export-pdf-btn");if(csvBtn)csvBtn.addEventListener("click",()=>this.exportCsv());if(pngBtn)pngBtn.addEventListener("click",()=>this.exportPng());if(pdfBtn)pdfBtn.addEventListener("click",()=>this.exportPdf());this.modalElement.addEventListener("keydown",e=>{if(e.key==="Escape"){this.close()}});this.modalElement.addEventListener("click",e=>{if(e.target===this.modalElement){this.close()}})}async _loadChartJS(){if(typeof globalThis!=="undefined"&&globalThis.Chart){return}return new Promise((resolve,reject)=>{if(typeof document==="undefined"){resolve();return}const script=document.createElement("script");script.src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js";script.onload=resolve;script.onerror=reject;document.head.appendChild(script)})}async _renderChart(){if(typeof globalThis==="undefined"||!globalThis.Chart){console.error("Chart.js not loaded");return}const canvas=this.modalElement?.querySelector("#comparison-chart");if(!canvas)return;if(this.chartInstance){this.chartInstance.destroy()}const store=this._getSelectionStore();const entityIds=this.currentData.entities.map(e=>e.id);const endDate=new Date;const startDate=new Date;startDate.setDate(startDate.getDate()-this.chartConfig.timeRange);let timeSeriesData={};if(store&&store.getTimeSeriesData){timeSeriesData=await store.getTimeSeriesData(entityIds,startDate,endDate)}const chartData=this._prepareChartData(timeSeriesData);this.chartInstance=new globalThis.Chart(canvas,{type:this.chartConfig.type,data:chartData,options:this._getChartOptions()})}_prepareChartData(timeSeriesData){const datasets=[];const colors=["#FF6384","#36A2EB","#FFCE56","#4BC0C0","#9966FF","#FF9F40","#FF6384","#C9CBCF","#4BC0C0","#FF6384"];this.currentData.entities.forEach((entity,index)=>{const data=timeSeriesData[entity.id]||[];const color=colors[index%colors.length];datasets.push({label:entity.name,data:data.map(point=>({x:point.timestamp,y:point.value})),borderColor:color,backgroundColor:color+"20",fill:this.chartConfig.type==="line"?false:true})});return{datasets:datasets}}_getChartOptions(){return{responsive:true,maintainAspectRatio:false,scales:{x:{type:"time",time:{unit:"day"},title:{display:true,text:"Data"}},y:{title:{display:true,text:"Valor"}}},plugins:{title:{display:true,text:`Comparativo - ${this.chartConfig.timeRange} dias`},legend:{display:true,position:"top"},tooltip:{mode:"index",intersect:false}},interaction:{mode:"nearest",axis:"x",intersect:false}}}_generateCsvData(){const headers=["Data","Dispositivo","Valor","Unidade"];const rows=[headers];this.currentData.entities.forEach(entity=>{const today=new Date;for(let i=0;i<this.chartConfig.timeRange;i++){const date=new Date(today);date.setDate(date.getDate()-i);const value=Math.random()*100+50;rows.push([date.toLocaleDateString("pt-BR"),entity.name,this._formatNumber(value),entity.unit||""])}});return rows.map(row=>row.join(";")).join("\n")}_downloadFile(data,filename,mimeType,isDataUrl=false){if(typeof document==="undefined")return;const link=document.createElement("a");if(isDataUrl){link.href=data}else{const blob=new Blob([data],{type:mimeType});link.href=URL.createObjectURL(blob)}link.download=filename;document.body.appendChild(link);link.click();document.body.removeChild(link);if(!isDataUrl){URL.revokeObjectURL(link.href)}}_showTooManyEntitiesWarning(data){if(typeof document==="undefined")return;const message=`Muitos dispositivos selecionados (${data.count}). Máximo permitido: ${this.chartConfig.maxEntities}.`;if(typeof globalThis!=="undefined"&&globalThis.alert){globalThis.alert(message)}this._announceToScreenReader(message)}_showNotImplementedNotice(feature){const message=`${feature} será implementado em uma versão futura.`;if(typeof globalThis!=="undefined"&&globalThis.alert){globalThis.alert(message)}this._announceToScreenReader(message)}_trapFocus(){if(!this.modalElement||typeof document==="undefined")return;const focusableElements=this.modalElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');const firstElement=focusableElements[0];const lastElement=focusableElements[focusableElements.length-1];if(firstElement){firstElement.focus()}this.modalElement.addEventListener("keydown",e=>{if(e.key==="Tab"&&typeof document!=="undefined"){if(e.shiftKey){if(document.activeElement===firstElement){e.preventDefault();lastElement?.focus()}}else{if(document.activeElement===lastElement){e.preventDefault();firstElement?.focus()}}}})}_getSelectionStore(){if(typeof globalThis!=="undefined"&&globalThis.window?.MyIOSelectionStore){return globalThis.window.MyIOSelectionStore}return null}_trackEvent(eventName,payload={}){const store=this._getSelectionStore();if(store&&store.trackEvent){store.trackEvent(eventName,payload)}}_announceToScreenReader(message){const store=this._getSelectionStore();if(store&&store.announceToScreenReader){store.announceToScreenReader(message)}}_formatNumber(value){if(typeof value!=="number"||isNaN(value))return"0";return new Intl.NumberFormat("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2}).format(value)}};var MyIOChartModal=new MyIOChartModalClass;if(typeof globalThis!=="undefined"&&typeof globalThis.window!=="undefined"){globalThis.window.MyIOChartModal=MyIOChartModal}if(typeof module!=="undefined"&&module.exports){module.exports={MyIOChartModal:MyIOChartModal}}function openDashboardPopupEnergy(params){console.log("Opening energy modal with params:",params);return{close:()=>{console.log("Closing energy modal")},on:(event,handler)=>{console.log(`Registering ${event} handler for energy modal`)}}}var CSS_TOKENS=`\n:root {\n /* Brand Colors */\n --myio-brand-700: #3e1a7d;\n --myio-brand-600: #2d1458;\n --myio-accent: #2d1458;\n --myio-danger: #d32f2f;\n --myio-success: #388E3C;\n --myio-warning: #f57c00;\n --myio-info: #1976d2;\n \n /* Neutral Colors */\n --myio-bg: #f7f7f7;\n --myio-card: #ffffff;\n --myio-border: #e0e0e0;\n --myio-text: #333333;\n --myio-text-muted: #666666;\n --myio-text-light: #999999;\n \n /* Layout */\n --myio-shadow: 0 2px 6px rgba(0,0,0,0.08);\n --myio-shadow-lg: 0 4px 12px rgba(0,0,0,0.15);\n --myio-radius: 10px;\n --myio-radius-sm: 6px;\n --myio-spacing: 16px;\n --myio-spacing-sm: 8px;\n --myio-spacing-lg: 24px;\n \n /* Typography */\n --myio-font: 'Roboto', Arial, sans-serif;\n --myio-font-size: 14px;\n --myio-font-size-sm: 12px;\n --myio-font-size-lg: 16px;\n --myio-line-height: 1.4;\n \n /* Z-index */\n --myio-z-modal: 9999;\n --myio-z-backdrop: 9998;\n --myio-z-sticky: 100;\n \n /* Animation */\n --myio-transition: 0.2s ease;\n --myio-transition-slow: 0.3s ease;\n}\n\n/* Dark theme tokens */\n[data-theme="dark"] {\n --myio-bg: #1a1a1a;\n --myio-card: #2d2d2d;\n --myio-border: #404040;\n --myio-text: #ffffff;\n --myio-text-muted: #cccccc;\n --myio-text-light: #999999;\n --myio-shadow: 0 2px 6px rgba(0,0,0,0.3);\n --myio-shadow-lg: 0 4px 12px rgba(0,0,0,0.4);\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n :root {\n --myio-transition: 0s;\n --myio-transition-slow: 0s;\n }\n}\n`;var MODAL_STYLES=`\n.myio-modal-scope {\n font-family: var(--myio-font);\n font-size: var(--myio-font-size);\n line-height: var(--myio-line-height);\n color: var(--myio-text);\n box-sizing: border-box;\n}\n\n.myio-modal-scope *,\n.myio-modal-scope *::before,\n.myio-modal-scope *::after {\n box-sizing: inherit;\n}\n\n.myio-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(2px);\n z-index: var(--myio-z-backdrop);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--myio-spacing);\n}\n\n.myio-modal {\n background: var(--myio-card);\n border-radius: var(--myio-radius);\n box-shadow: var(--myio-shadow-lg);\n max-width: 90vw;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transform: scale(0.95);\n opacity: 0;\n transition: transform var(--myio-transition), opacity var(--myio-transition);\n}\n\n.myio-modal.myio-modal-open {\n transform: scale(1);\n opacity: 1;\n}\n\n.myio-modal-header {\n padding: var(--myio-spacing);\n border-bottom: none;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--myio-brand-700);\n color: white;\n border-radius: var(--myio-radius) var(--myio-radius) 0 0;\n}\n\n.myio-modal-title {\n font-size: var(--myio-font-size-lg);\n font-weight: 600;\n margin: 0;\n color: white;\n}\n\n.myio-modal-close {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--myio-radius-sm);\n color: rgba(255, 255, 255, 0.8);\n transition: background-color var(--myio-transition);\n}\n\n.myio-modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n color: white;\n}\n\n.myio-modal-close:focus-visible {\n outline: 2px solid rgba(255, 255, 255, 0.5);\n outline-offset: 2px;\n}\n\n.myio-modal-body {\n flex: 1;\n overflow: auto;\n padding: var(--myio-spacing);\n}\n\n.myio-modal-footer {\n padding: var(--myio-spacing);\n border-top: 1px solid var(--myio-border);\n display: flex;\n gap: var(--myio-spacing-sm);\n justify-content: flex-end;\n}\n\n/* Button styles */\n.myio-btn {\n padding: 8px 16px;\n border: none;\n border-radius: var(--myio-radius-sm);\n font-family: inherit;\n font-size: var(--myio-font-size);\n cursor: pointer;\n transition: background-color var(--myio-transition);\n display: inline-flex;\n align-items: center;\n gap: var(--myio-spacing-sm);\n}\n\n.myio-btn-primary {\n background: var(--myio-brand-700);\n color: white;\n}\n\n.myio-btn-primary:hover {\n background: var(--myio-brand-600);\n}\n\n.myio-btn-secondary {\n background: var(--myio-bg);\n color: var(--myio-text);\n border: 1px solid var(--myio-border);\n}\n\n.myio-btn-secondary:hover {\n background: var(--myio-border);\n}\n\n.myio-btn:focus-visible {\n outline: 2px solid var(--myio-brand-700);\n outline-offset: 2px;\n}\n\n.myio-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Form styles */\n.myio-form-group {\n margin-bottom: var(--myio-spacing);\n}\n\n.myio-label {\n display: block;\n margin-bottom: var(--myio-spacing-sm);\n font-weight: 500;\n color: var(--myio-text);\n}\n\n.myio-input {\n width: 100%;\n padding: var(--myio-spacing-sm);\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius-sm);\n font-family: inherit;\n font-size: var(--myio-font-size);\n transition: border-color var(--myio-transition);\n}\n\n.myio-input:focus {\n outline: none;\n border-color: var(--myio-brand-700);\n}\n\n/* Table styles */\n.myio-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--myio-font-size);\n}\n\n.myio-table th,\n.myio-table td {\n padding: var(--myio-spacing-sm) var(--myio-spacing);\n text-align: left;\n border-bottom: 1px solid var(--myio-border);\n}\n\n.myio-table th:first-child,\n.myio-table td:first-child {\n padding-left: var(--myio-spacing-lg);\n}\n\n.myio-table th:last-child,\n.myio-table td:last-child {\n padding-right: var(--myio-spacing-lg);\n}\n\n.myio-table th {\n background: var(--myio-brand-700);\n color: white;\n font-weight: 600;\n position: sticky;\n top: 0;\n z-index: var(--myio-z-sticky);\n}\n\n.myio-table tbody tr:nth-child(even) {\n background: var(--myio-bg);\n}\n\n.myio-table tbody tr:hover {\n background: var(--myio-border);\n}\n\n/* Loading spinner */\n.myio-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid var(--myio-border);\n border-top: 2px solid var(--myio-brand-700);\n border-radius: 50%;\n animation: myio-spin 1s linear infinite;\n}\n\n@keyframes myio-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n/* Utility classes */\n.myio-text-center { text-align: center; }\n.myio-text-right { text-align: right; }\n.myio-text-muted { color: var(--myio-text-muted); }\n.myio-text-success { color: var(--myio-success); }\n.myio-text-danger { color: var(--myio-danger); }\n.myio-mb-0 { margin-bottom: 0; }\n.myio-mt-0 { margin-top: 0; }\n.myio-p-0 { padding: 0; }\n`;var DATERANGEPICKER_STYLES=`\n/* MyIO Premium DateRangePicker Styling */\n.myio-modal-scope .daterangepicker {\n font-family: var(--myio-font);\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius);\n box-shadow: var(--myio-shadow-lg);\n background: var(--myio-card);\n z-index: var(--myio-z-popover, 10000);\n}\n\n.myio-modal-scope .daterangepicker .calendar-table {\n background: var(--myio-card);\n border: none;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table th,\n.myio-modal-scope .daterangepicker .calendar-table td {\n border: none;\n padding: 8px;\n text-align: center;\n font-size: 13px;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table th {\n background: var(--myio-bg);\n color: var(--myio-text);\n font-weight: 600;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.available:hover {\n background: var(--myio-bg);\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.in-range {\n background: rgba(74, 20, 140, 0.1);\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.start-date,\n.myio-modal-scope .daterangepicker .calendar-table td.end-date {\n background: var(--myio-brand-700);\n color: white;\n border-radius: 4px;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.active {\n background: var(--myio-brand-700);\n color: white;\n border-radius: 4px;\n}\n\n/* Premium button styling for Aplicar/Cancelar */\n.myio-modal-scope .daterangepicker .drp-buttons {\n border-top: 1px solid var(--myio-border);\n padding: 12px 16px;\n background: var(--myio-bg);\n text-align: right;\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .btn {\n margin-left: 8px;\n padding: 8px 16px;\n border-radius: var(--myio-radius-sm);\n font-family: var(--myio-font);\n font-size: 14px;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all var(--myio-transition);\n min-width: 80px;\n}\n\n/* Aplicar button - MyIO Primary */\n.myio-modal-scope .daterangepicker .drp-buttons .applyBtn {\n background: linear-gradient(135deg, var(--myio-brand-700) 0%, var(--myio-accent) 100%);\n color: white;\n box-shadow: 0 2px 4px rgba(74, 20, 140, 0.2);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .applyBtn:hover {\n background: linear-gradient(135deg, var(--myio-brand-600) 0%, var(--myio-brand-700) 100%);\n box-shadow: 0 4px 8px rgba(74, 20, 140, 0.3);\n transform: translateY(-1px);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .applyBtn:active {\n transform: translateY(0);\n box-shadow: 0 2px 4px rgba(74, 20, 140, 0.2);\n}\n\n/* Cancelar button - MyIO Secondary */\n.myio-modal-scope .daterangepicker .drp-buttons .cancelBtn {\n background: var(--myio-card);\n color: var(--myio-text);\n border: 1px solid var(--myio-border);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .cancelBtn:hover {\n background: var(--myio-bg);\n border-color: var(--myio-brand-700);\n color: var(--myio-brand-700);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .cancelBtn:active {\n transform: translateY(0);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n/* Ranges (preset buttons) styling */\n.myio-modal-scope .daterangepicker .ranges {\n background: var(--myio-bg);\n border-right: 1px solid var(--myio-border);\n}\n\n.myio-modal-scope .daterangepicker .ranges li {\n padding: 10px 16px;\n margin: 2px 8px;\n border-radius: var(--myio-radius-sm);\n cursor: pointer;\n transition: all var(--myio-transition);\n font-size: 13px;\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .ranges li:hover {\n background: rgba(74, 20, 140, 0.1);\n color: var(--myio-brand-700);\n}\n\n.myio-modal-scope .daterangepicker .ranges li.active {\n background: var(--myio-brand-700);\n color: white;\n font-weight: 500;\n}\n\n/* Time picker styling */\n.myio-modal-scope .daterangepicker .calendar-time {\n border-top: 1px solid var(--myio-border);\n background: var(--myio-bg);\n padding: 8px;\n}\n\n.myio-modal-scope .daterangepicker .calendar-time select {\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius-sm);\n padding: 4px 8px;\n font-family: var(--myio-font);\n background: var(--myio-card);\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .calendar-time select:focus {\n outline: none;\n border-color: var(--myio-brand-700);\n box-shadow: 0 0 0 2px rgba(74, 20, 140, 0.2);\n}\n\n/* Header styling */\n.myio-modal-scope .daterangepicker .drp-calendar {\n background: var(--myio-card);\n}\n\n.myio-modal-scope .daterangepicker .month {\n color: var(--myio-brand-700);\n font-weight: 600;\n font-size: 14px;\n}\n\n.myio-modal-scope .daterangepicker .prev,\n.myio-modal-scope .daterangepicker .next {\n color: var(--myio-brand-700);\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius-sm);\n background: var(--myio-card);\n transition: all var(--myio-transition);\n}\n\n.myio-modal-scope .daterangepicker .prev:hover,\n.myio-modal-scope .daterangepicker .next:hover {\n background: var(--myio-brand-700);\n color: white;\n border-color: var(--myio-brand-700);\n}\n`;var ModalPremiumShell=class{constructor(options){this.options=options;this.originalActiveElement=document.activeElement;this.originalBodyOverflow=document.body.style.overflow;this.injectStyles();this.createElements();this.setupEventListeners();this.setupFocusTrap();this.lockBodyScroll();this.setInertBackground()}backdrop;modal;header;body;footer;closeButton;styleElement;focusTrap;originalBodyOverflow;originalActiveElement;closeHandlers=[];injectStyles(){this.styleElement=document.createElement("style");this.styleElement.textContent=CSS_TOKENS+MODAL_STYLES;document.head.appendChild(this.styleElement)}createElements(){this.backdrop=document.createElement("div");this.backdrop.className="myio-modal-backdrop myio-modal-scope";this.backdrop.setAttribute("role","dialog");this.backdrop.setAttribute("aria-modal","true");this.backdrop.setAttribute("aria-labelledby","myio-modal-title");if(this.options.theme==="dark"){this.backdrop.setAttribute("data-theme","dark")}this.modal=document.createElement("div");this.modal.className="myio-modal";if(this.options.width){const width=typeof this.options.width==="number"?`${this.options.width}px`:this.options.width;this.modal.style.width=width}if(this.options.height){const height=typeof this.options.height==="number"?`${this.options.height}px`:this.options.height;this.modal.style.height=height}this.header=document.createElement("div");this.header.className="myio-modal-header";const title=document.createElement("h2");title.id="myio-modal-title";title.className="myio-modal-title";title.textContent=this.options.title;this.closeButton=document.createElement("button");this.closeButton.className="myio-modal-close";this.closeButton.innerHTML="×";this.closeButton.setAttribute("aria-label","Fechar modal");this.closeButton.type="button";this.header.appendChild(title);this.header.appendChild(this.closeButton);this.body=document.createElement("div");this.body.className="myio-modal-body";this.footer=document.createElement("div");this.footer.className="myio-modal-footer";this.footer.style.display="none";this.modal.appendChild(this.header);this.modal.appendChild(this.body);this.modal.appendChild(this.footer);this.backdrop.appendChild(this.modal)}setupEventListeners(){this.closeButton.addEventListener("click",()=>this.close());if(this.options.closeOnBackdrop!==false){this.backdrop.addEventListener("click",e=>{if(e.target===this.backdrop){this.close()}})}if(this.options.closeOnEscape!==false){document.addEventListener("keydown",this.handleKeyDown)}}handleKeyDown=e=>{if(e.key==="Escape"){this.close()}};setupFocusTrap(){this.focusTrap=new FocusTrap(this.modal)}lockBodyScroll(){document.body.style.overflow="hidden"}unlockBodyScroll(){document.body.style.overflow=this.originalBodyOverflow}setInertBackground(){const topLevelElements=Array.from(document.body.children);topLevelElements.forEach(element=>{if(element!==this.backdrop&&element.tagName!=="SCRIPT"&&element.tagName!=="STYLE"){element.inert=true}})}removeInertBackground(){const topLevelElements=Array.from(document.body.children);topLevelElements.forEach(element=>{element.inert=false})}show(){document.body.appendChild(this.backdrop);requestAnimationFrame(()=>{this.modal.classList.add("myio-modal-open");this.focusTrap.activate()});return{element:this.body,close:()=>this.close(),setContent:content=>this.setContent(content),setFooter:footer=>this.setFooter(footer),on:(event,handler)=>this.on(event,handler)}}setContent(content){if(typeof content==="string"){this.body.innerHTML=content}else{this.body.innerHTML="";this.body.appendChild(content)}}setFooter(footer){if(typeof footer==="string"){this.footer.innerHTML=footer}else{this.footer.innerHTML="";this.footer.appendChild(footer)}this.footer.style.display="flex"}on(event,handler){if(event==="close"){this.closeHandlers.push(handler)}}close(){this.modal.classList.remove("myio-modal-open");setTimeout(()=>{this.cleanup();this.closeHandlers.forEach(handler=>handler())},200)}cleanup(){document.removeEventListener("keydown",this.handleKeyDown);if(this.originalActiveElement&&"focus"in this.originalActiveElement){this.originalActiveElement.focus()}this.focusTrap.deactivate();this.unlockBodyScroll();this.removeInertBackground();if(this.backdrop.parentNode){this.backdrop.parentNode.removeChild(this.backdrop)}if(this.styleElement.parentNode){this.styleElement.parentNode.removeChild(this.styleElement)}}};var FocusTrap=class{constructor(container){this.container=container}focusableElements=[];firstFocusable=null;lastFocusable=null;activate(){this.updateFocusableElements();this.container.addEventListener("keydown",this.handleTabKey);if(this.firstFocusable){this.firstFocusable.focus()}}deactivate(){this.container.removeEventListener("keydown",this.handleTabKey)}updateFocusableElements(){const focusableSelectors=["button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","a[href]",'[tabindex]:not([tabindex="-1"])'].join(", ");this.focusableElements=Array.from(this.container.querySelectorAll(focusableSelectors));this.firstFocusable=this.focusableElements[0]||null;this.lastFocusable=this.focusableElements[this.focusableElements.length-1]||null}handleTabKey=e=>{if(e.key!=="Tab")return;if(e.shiftKey){if(document.activeElement===this.firstFocusable){e.preventDefault();this.lastFocusable?.focus()}}else{if(document.activeElement===this.lastFocusable){e.preventDefault();this.firstFocusable?.focus()}}}};function createModal(options){const shell=new ModalPremiumShell(options);return shell.show()}var rangeDaysInclusive=(start,end)=>{const out=[];let cur=new Date(start);const last=new Date(end);while(cur<=last){out.push(cur.toISOString().slice(0,10));cur.setDate(cur.getDate()+1)}return out};var toCsv=(rows,locale="pt-BR",sep=";")=>{const fmt=new Intl.NumberFormat(locale,{minimumFractionDigits:2,maximumFractionDigits:2});const esc=v=>(typeof v==="number"?fmt.format(v):String(v)).replace(/"/g,'""');return rows.map(r=>r.map(c=>`"${esc(c)}"`).join(sep)).join("\r\n")};var fmtPt=n=>new Intl.NumberFormat("pt-BR",{minimumFractionDigits:2,maximumFractionDigits:2}).format(n);var AuthClient=class{constructor(cfg){this.cfg=cfg}token;async getBearer(){const now=Date.now()/1e3;if(this.token&&this.token.exp-now>60)return this.token.value;this.token={value:"",exp:now+300};return this.token.value}clearCache(){this.token=void 0}};var CDN_RESOURCES=[{id:"jquery-3.7.1",src:"https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js",integrity:"sha384-1H217gwSVyLSIfaLxHbE7dRb3v4mYCKbpQvzx0cegeju1MVsGrX5xXxAvs/HgeFs",crossorigin:"anonymous"},{id:"moment-2.29.4",src:"https://cdn.jsdelivr.net/npm/moment@2.29.4/min/moment.min.js",integrity:"sha384-2xoILS8hBHw+Atyv/qJLEdk8dFdW1hbGjfeQ3G0GU3pGNPlqck0chRqjMTZ5blGf",crossorigin:"anonymous"},{id:"daterangepicker-3.1.0",src:"https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js",integrity:"sha384-IbJFThFkdkMvvxP0U8wOffxBHPYEJE65UtA/l25/jJQUt/hft6OdAuKLxGjtOVnL",crossorigin:"anonymous"}];var CSS_RESOURCE={href:"https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.css",integrity:"sha384-zLkQsiLfAQqGeIJeKLC+rcCR1YoYaQFLCL7cLDUoKE1ajKJzySpjzWGfYS2vjSG+"};var FALLBACK_PATHS=["/assets/vendor/jquery.min.js","/assets/vendor/moment.min.js","/assets/vendor/daterangepicker.min.js"];var PT_BR_LOCALE={format:"DD/MM/YY HH:mm",separator:" até ",applyLabel:"Aplicar",cancelLabel:"Cancelar",fromLabel:"De",toLabel:"Até",customRangeLabel:"Personalizado",daysOfWeek:["Do","Se","Te","Qa","Qi","Se","Sa"],monthNames:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],firstDay:1};var CDNLoader=class{static jQueryInstance=null;static loadingPromise=null;static loaded=false;static async ensureLoaded(){if(this.loaded&&this.jQueryInstance){return this.jQueryInstance}if(this.loadingPromise){return this.loadingPromise}this.loadingPromise=this.loadResources();return this.loadingPromise}static async loadResources(){if(window.jQuery&&window.moment&&window.jQuery.fn.daterangepicker){this.jQueryInstance=window.jQuery.noConflict(true);this.loaded=true;return this.jQueryInstance}try{await this.loadFromCDN();console.log("DateRangePicker: CDN loaded successfully")}catch(cdnError){console.warn("DateRangePicker: CDN failed, trying local assets:",cdnError);try{await this.loadFromLocal();console.log("DateRangePicker: Local assets loaded successfully")}catch(localError){console.warn("DateRangePicker: Local assets failed, using native inputs:",localError);throw new Error("DateRangePicker unavailable - using native inputs")}}this.jQueryInstance=window.jQuery?.noConflict(true);this.loaded=true;if(!this.jQueryInstance){throw new Error("jQuery not available after loading")}return this.jQueryInstance}static async loadFromCDN(){await this.loadCSS(CSS_RESOURCE.href,CSS_RESOURCE.integrity);for(const resource of CDN_RESOURCES){await this.loadScript(resource.src,resource.integrity)}}static async loadFromLocal(){for(const path of FALLBACK_PATHS){await this.loadScript(path)}}static loadScript(src,integrity){return new Promise((resolve,reject)=>{if(document.querySelector(`script[src="${src}"]`)){resolve();return}const script=document.createElement("script");script.src=src;script.async=false;if(integrity){script.integrity=integrity;script.crossOrigin="anonymous"}script.onload=()=>resolve();script.onerror=()=>reject(new Error(`Failed to load script: ${src}`));document.head.appendChild(script)})}static loadCSS(href,integrity){return new Promise((resolve,reject)=>{if(document.querySelector(`link[href="${href}"]`)){resolve();return}const link=document.createElement("link");link.rel="stylesheet";link.href=href;if(integrity){link.integrity=integrity;link.crossOrigin="anonymous"}link.onload=()=>resolve();link.onerror=()=>reject(new Error(`Failed to load CSS: ${href}`));document.head.appendChild(link)})}};function injectPremiumStyling(){const styleId="myio-daterangepicker-styles";if(document.getElementById(styleId)){return}const style=document.createElement("style");style.id=styleId;style.textContent=DATERANGEPICKER_STYLES;document.head.appendChild(style)}async function attach(input,opts={}){try{const $2=await CDNLoader.ensureLoaded();return createDateRangePicker($2,input,opts)}catch(error){console.error("DateRangePicker: Failed to load dependencies. Native date inputs are forbidden in this project.",error);throw new Error("DateRangePicker dependencies unavailable. Please ensure jQuery, moment.js, and daterangepicker are accessible.")}}function createDateRangePicker($2,input,opts){const $input=$2(input);const maxRangeDays=opts.maxRangeDays??31;injectPremiumStyling();input.readOnly=true;input.setAttribute("aria-label","Período de datas");const helpText=document.createElement("div");helpText.className="myio-text-muted";helpText.style.fontSize="12px";helpText.style.marginTop="4px";helpText.style.display="flex";helpText.style.alignItems="center";input.parentNode?.appendChild(helpText);const moment=window.moment;const startDate=opts.presetStart?moment(opts.presetStart).startOf("day"):moment().startOf("month");const endDate=opts.presetEnd?moment(opts.presetEnd).endOf("day"):moment().endOf("day");$input.daterangepicker({parentEl:opts.parentEl||document.body,timePicker:true,timePicker24Hour:true,timePickerIncrement:1,autoApply:true,autoUpdateInput:true,linkedCalendars:true,showCustomRangeLabel:true,maxSpan:{days:maxRangeDays},maxDate:moment().endOf("day"),startDate:startDate,endDate:endDate,opens:"right",drops:"down",locale:PT_BR_LOCALE,applyButtonClasses:"btn btn-primary",cancelClass:"btn btn-muted",ranges:{Hoje:[moment().startOf("day"),moment().endOf("day")],"Últimos 7 dias":[moment().subtract(6,"days").startOf("day"),moment().endOf("day")],"Últimos 30 dias":[moment().subtract(29,"days").startOf("day"),moment().endOf("day")],"Mês Anterior":[moment().subtract(1,"month").startOf("month"),moment().subtract(1,"month").endOf("month")]}});updateInputDisplay();$input.on("apply.daterangepicker.myio",()=>{updateInputDisplay();if(opts.onApply){const result=getDates();opts.onApply(result)}});$input.on("cancel.daterangepicker.myio",()=>{$input.val("");if(opts.onApply){opts.onApply({startISO:"",endISO:"",startLabel:"",endLabel:""})}});function updateInputDisplay(){const picker=$input.data("daterangepicker");if(picker){const formatted=`${picker.startDate.format(PT_BR_LOCALE.format)}${PT_BR_LOCALE.separator}${picker.endDate.format(PT_BR_LOCALE.format)}`;$input.val(formatted)}}function getDates(){const picker=$input.data("daterangepicker");const startISO=picker.startDate.format("YYYY-MM-DD[T]HH:mm:ssZ");const endISO=picker.endDate.format("YYYY-MM-DD[T]HH:mm:ssZ");const startLabel=picker.startDate.format(PT_BR_LOCALE.format);const endLabel=picker.endDate.format(PT_BR_LOCALE.format);return{startISO:startISO,endISO:endISO,startLabel:startLabel,endLabel:endLabel}}function setDates(startISO,endISO){const picker=$input.data("daterangepicker");picker.setStartDate(moment(startISO));picker.setEndDate(moment(endISO));updateInputDisplay()}function destroy(){const picker=$input.data("daterangepicker");$input.off(".daterangepicker.myio");picker?.remove?.();$input.removeData("daterangepicker");helpText?.remove()}return{getDates:getDates,setDates:setDates,destroy:destroy}}var DateRangePickerJQ={attach:attach};var createDefaultEnergyFetcher=params=>async({baseUrl:baseUrl,ingestionId:ingestionId,startISO:startISO,endISO:endISO})=>{const url=`${baseUrl}/api/v1/telemetry/devices/${ingestionId}/energy?startTime=${encodeURIComponent(startISO)}&endTime=${encodeURIComponent(endISO)}&granularity=1d&page=1&pageSize=1000&deep=0`;const token=params.api.ingestionToken;if(!token){throw new Error("ingestionToken is required for Data API calls to data.apps.myio-bas.com")}const response=await fetch(url,{headers:{Authorization:`Bearer ${token}`,"Content-Type":"application/json"}});if(!response.ok){throw new Error(`HTTP ${response.status}: ${response.statusText}`)}return response.json()};var DeviceReportModal=class{constructor(params){this.params=params;this.authClient=new AuthClient({clientId:params.api.clientId,clientSecret:params.api.clientSecret,base:params.api.dataApiBaseUrl});this.energyFetcher=params.fetcher||createDefaultEnergyFetcher(params)}modal;authClient;energyFetcher;data=[];isLoading=false;eventHandlers={};dateRangePicker=null;sortState={key:null,direction:"asc"};show(){this.modal=createModal({title:`Relatório - ${this.params.identifier||"SEM IDENTIFICADOR"} - ${this.params.label||"SEM ETIQUETA"}`,width:"80vw",height:"90vh",theme:this.params.ui?.theme||"light"});this.renderContent();this.modal.on("close",()=>{if(this.dateRangePicker){this.dateRangePicker.destroy();this.dateRangePicker=null}this.authClient.clearCache();this.emit("close")});return{close:()=>this.modal.close(),on:(event,handler)=>this.on(event,handler)}}renderContent(){const content=document.createElement("div");content.innerHTML=`\n <div class="myio-modal-scope">\n <div style="margin-bottom: 16px;">\n <div style="display: flex; gap: 16px; align-items: end; margin-bottom: 16px;">\n <div class="myio-form-group" style="margin-bottom: 0;">\n <label class="myio-label" for="date-range">Período</label>\n <input type="text" id="date-range" class="myio-input" readonly placeholder="Selecione o período" style="width: 300px;">\n </div>\n <button id="load-btn" class="myio-btn myio-btn-primary">\n <span class="myio-spinner" id="load-spinner" style="display: none;"></span>\n Carregar\n </button>\n <button id="export-btn" class="myio-btn myio-btn-secondary" disabled>\n Exportar CSV\n </button>\n </div>\n </div>\n \n <div id="error-container" style="display: none; background: #ffebee; color: #c62828; padding: 12px; border-radius: 6px; margin-bottom: 16px;">\n </div>\n \n <div id="table-container">\n <div style="text-align: center; padding: 40px; color: var(--myio-text-muted);">\n Selecione um período e clique em "Carregar" para visualizar os dados.\n </div>\n </div>\n </div>\n `;this.modal.setContent(content);this.setupEventListeners()}async setupEventListeners(){const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const dateRangeInput=document.getElementById("date-range");loadBtn?.addEventListener("click",()=>this.loadData());exportBtn?.addEventListener("click",()=>this.exportCSV());try{this.dateRangePicker=await attach(dateRangeInput,{presetStart:this.getDefaultStartDate(),presetEnd:this.getDefaultEndDate(),maxRangeDays:31,parentEl:this.modal.element,onApply:({startISO:startISO,endISO:endISO})=>{this.hideError();console.log("Date range selected:",{startISO:startISO,endISO:endISO})}})}catch(error){console.warn("DateRangePicker initialization failed, using fallback:",error)}}async loadData(){if(this.isLoading)return;const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const spinner=document.getElementById("load-spinner");if(!this.dateRangePicker){this.showError("Seletor de data não inicializado");return}this.isLoading=true;loadBtn.disabled=true;exportBtn.disabled=true;spinner.style.display="inline-block";try{const{startISO:startISO,endISO:endISO}=this.dateRangePicker.getDates();if(!startISO||!endISO){this.showError("Selecione um período válido");return}const startDate=startISO.split("T")[0];const endDate=endISO.split("T")[0];const dateRange=rangeDaysInclusive(startDate,endDate);const apiResponse=await this.energyFetcher({baseUrl:this.params.api.dataApiBaseUrl||"https://api.data.apps.myio-bas.com",ingestionId:this.params.ingestionId,startISO:startISO,endISO:endISO});this.data=this.processApiResponse(apiResponse,dateRange);this.renderTable();exportBtn.disabled=false;this.emit("loaded",{date:{start:startDate,end:endDate},count:this.data.length,total:this.calculateTotal()})}catch(error){this.showError("Erro ao carregar dados: "+error.message);console.error("Error loading data:",error);this.emit("error",{message:error.message,context:"loadData"})}finally{this.isLoading=false;loadBtn.disabled=false;spinner.style.display="none"}}processApiResponse(apiResponse,dateRange){const dataArray=Array.isArray(apiResponse)?apiResponse:apiResponse.data||[];if(!Array.isArray(dataArray)||dataArray.length===0){console.warn("[DeviceReportModal] API returned empty or invalid response, zero-filling date range");return dateRange.map(date=>({date:date,consumption:0}))}const deviceData=dataArray[0];const consumption=deviceData.consumption||[];const dailyMap={};consumption.forEach(item=>{if(item.timestamp&&item.value!=null){const date=item.timestamp.slice(0,10);const value=Number(item.value);if(!dailyMap[date])dailyMap[date]=0;dailyMap[date]+=value}});return dateRange.map(date=>({date:date,consumption:dailyMap[date]||0}))}generateMockData(dateRange){return dateRange.map(date=>({date:date,consumption:Math.random()*50+10}))}renderTable(){const container=document.getElementById("table-container");if(!container)return;const total=this.calculateTotal();const getSortIndicator=columnKey=>{if(this.sortState.key===columnKey){return this.sortState.direction==="asc"?"↑":"↓"}return"↕"};container.innerHTML=`\n <div style="margin-bottom: 16px; padding: 12px; background: var(--myio-bg); border-radius: 6px;">\n <strong>Total: ${fmtPt(total)} kWh</strong>\n </div>\n \n <div style="max-height: 400px; overflow-y: auto; border: 1px solid var(--myio-border); border-radius: 6px;">\n <table class="myio-table">\n <thead>\n <tr>\n <th style="cursor: pointer;" data-sort="date">\n Data\n <span style="margin-left: 4px; opacity: ${this.sortState.key==="date"?"1":"0.5"};">${getSortIndicator("date")}</span>\n </th>\n <th style="cursor: pointer; text-align: right;" data-sort="consumption">\n Consumo (kWh)\n <span style="margin-left: 4px; opacity: ${this.sortState.key==="consumption"?"1":"0.5"};">${getSortIndicator("consumption")}</span>\n </th>\n </tr>\n </thead>\n <tbody>\n ${this.data.map(row=>`\n <tr>\n <td>${this.formatDate(row.date)}</td>\n <td style="text-align: right;">${fmtPt(row.consumption)}</td>\n </tr>\n `).join("")}\n </tbody>\n </table>\n </div>\n `;this.setupTableSorting()}setupTableSorting(){const headers=document.querySelectorAll("[data-sort]");headers.forEach(header=>{header.addEventListener("click",()=>{const sortKey=header.getAttribute("data-sort");this.sortData(sortKey);this.renderTable()})})}sortData(key){if(this.sortState.key===key){this.sortState.direction=this.sortState.direction==="asc"?"desc":"asc"}else{this.sortState.key=key;this.sortState.direction="asc"}this.data.sort((a,b)=>{let comparison=0;if(key==="date"){comparison=new Date(a.date).getTime()-new Date(b.date).getTime()}else{comparison=a.consumption-b.consumption}return this.sortState.direction==="desc"?-comparison:comparison})}calculateTotal(){return this.data.reduce((sum,row)=>sum+row.consumption,0)}formatDate(dateStr){const date=new Date(dateStr+"T00:00:00");return date.toLocaleDateString("pt-BR")}exportCSV(){const total=this.calculateTotal();const now=new Date;const timestamp=now.toLocaleDateString("pt-BR")+" - "+now.toLocaleTimeString("pt-BR",{hour:"2-digit",minute:"2-digit"});const csvData=[["Dispositivo/Loja",this.params.identifier||"N/A",this.params.label||""],["DATA EMISSÃO",timestamp,""],["Total",fmtPt(total),""],["Data","Consumo",""],...this.data.map(row=>[this.formatDate(row.date),fmtPt(row.consumption)])];const csvContent=toCsv(csvData);this.downloadCSV(csvContent,`relatorio-${this.params.identifier||"dispositivo"}-${(new Date).toISOString().split("T")[0]}.csv`)}downloadCSV(content,filename){const BOM="\ufeff";const csvWithBOM=BOM+content;const blob=new Blob([csvWithBOM],{type:"text/csv;charset=utf-8;"});const link=document.createElement("a");const url=URL.createObjectURL(blob);link.setAttribute("href",url);link.setAttribute("download",filename);link.style.visibility="hidden";document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(url)}getDefaultStartDate(){const date=new Date;date.setDate(1);return date.toISOString().split("T")[0]}getDefaultEndDate(){return(new Date).toISOString().split("T")[0]}showError(message){const container=document.getElementById("error-container");if(container){container.textContent=message;container.style.display="block"}}hideError(){const container=document.getElementById("error-container");if(container){container.style.display="none"}}on(event,handler){if(!this.eventHandlers[event]){this.eventHandlers[event]=[]}this.eventHandlers[event].push(handler)}emit(event,payload){if(this.eventHandlers[event]){this.eventHandlers[event].forEach(handler=>handler())}}};function openDashboardPopupReport(params){const modal=new DeviceReportModal(params);return modal.show()}var defaultI18n={selectAll:"Selecionar todas",clear:"Limpar",searchPlaceholder:"Buscar lojas...",sortingTitle:"Ordenação",consumptionDesc:"Consumo ↓ (padrão)",consumptionAsc:"Consumo ↑",aToZ:"A → Z",zToA:"Z → A",tieNote:"Caso o consumo seja o mesmo é considerada a ordem alfabética.",apply:"Aplicar",reset:"Resetar",totalLabel:"Lojas",selectedLabel:"Selecionadas",closeLabel:"Fechar"};var FilterOrderingModal=class{state;props;i18n;dom=null;searchTimeout=null;itemsById;initialState;openerEl=null;constructor(props){this.props=props;this.i18n={...defaultI18n,...props.i18n};this.itemsById=new Map(props.items.map(item=>[item.id,item]));const initialSelected=new Set(props.initialSelected||[]);const initialSort=props.initialSort||"CONSUMPTION_DESC";this.state={allIds:props.items.map(item=>item.id),selected:new Set(initialSelected),query:"",sort:initialSort};this.initialState={selected:new Set(initialSelected),sort:initialSort}}open(){if(!this.dom){this.createDOM()}this.openerEl=document.activeElement instanceof HTMLElement?document.activeElement:null;this.updateCounters();this.renderList();this.dom.overlay.setAttribute("aria-hidden","false");this.dom.root.setAttribute("aria-hidden","false");this.lockBodyScroll();this.dom.root.addEventListener("keydown",this.trapFocus);setTimeout(()=>{const search=this.dom.searchInput||this.dom.root.querySelector("button, input");if(search)search.focus()},200);this.emit("myio:filter:open",{})}close(){if(this.dom){this.dom.overlay.setAttribute("aria-hidden","true");this.dom.root.setAttribute("aria-hidden","true");if(this.openerEl&&document.contains(this.openerEl)){this.openerEl.focus()}this.openerEl=null;this.unlockBodyScroll();this.dom.root.removeEventListener("keydown",this.trapFocus)}this.emit("myio:filter:close",{});this.props.onClose?.()}lockBodyScroll(){const hasScrollbar=document.documentElement.scrollHeight>document.documentElement.clientHeight;if(hasScrollbar){const scrollBarW=window.innerWidth-document.documentElement.clientWidth;document.documentElement.style.paddingRight=`${scrollBarW}px`}document.body.classList.add("body--myio-modal-open")}unlockBodyScroll(){document.body.classList.remove("body--myio-modal-open");document.documentElement.style.paddingRight=""}getState(){return{selected:Array.from(this.state.selected),sort:this.state.sort}}setSelection(ids){this.state.selected=new Set(ids);this.updateCounters();this.renderList()}setSort(sort){this.state.sort=sort;this.renderList();if(this.dom){this.dom.sortRadios.forEach(radio=>{radio.checked=radio.value===sort})}}destroy(){if(this.dom){this.close();this.dom.overlay.remove();this.dom.root.remove();this.dom=null}}trapFocus=e=>{if(e.isComposing)return;if(!this.dom||e.key!=="Tab"||this.dom.root.getAttribute("aria-hidden")==="true")return;const focusable=[...this.dom.root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')].filter(el=>{const htmlEl=el;return!htmlEl.hasAttribute("disabled")&&htmlEl.tabIndex!==-1&&htmlEl.offsetParent!==null});if(!focusable.length)return;const first=focusable[0];const last=focusable[focusable.length-1];if(e.shiftKey&&document.activeElement===first){last.focus();e.preventDefault()}else if(!e.shiftKey&&document.activeElement===last){first.focus();e.preventDefault()}};createDOM(){const existing=document.querySelector(".myio-modal-root");if(existing){existing.remove()}const overlay=document.createElement("div");overlay.className="myio-modal-overlay";overlay.setAttribute("aria-hidden","true");const root=document.createElement("div");root.className="myio-modal-root myio-modal-portal";root.setAttribute("aria-hidden","true");root.setAttribute("role","dialog");root.setAttribute("aria-modal","true");root.setAttribute("aria-labelledby","myioFilterTitle");const card=document.createElement("div");card.className="myio-modal-card";card.setAttribute("role","document");root.appendChild(card);card.addEventListener("click",e=>e.stopPropagation());card.innerHTML=`\n <header class="myio-header">\n <h2 id="myioFilterTitle">${this.props.title||"Filtros & Ordenação"}</h2>\n <div class="myio-counters" aria-live="polite">\n <span class="counter">\n <strong class="value" data-total>0</strong> <span>${this.i18n.totalLabel}</span>\n </span>\n <span class="sep">•</span>\n <span class="counter">\n <strong class="value" data-selected>0</strong> <span>${this.i18n.selectedLabel}</span>\n </span>\n </div>\n <button class="icon-btn close" aria-label="${this.i18n.closeLabel}" data-close>×</button>\n </header>\n\n <section class="myio-toolbar">\n <div class="actions">\n <button class="btn ghost" data-select-all>${this.i18n.selectAll}</button>\n <button class="btn ghost" data-clear>${this.i18n.clear}</button>\n </div>\n <div class="search">\n <div class="search-input-wrapper">\n <span class="search-icon">🔍</span>\n <input type="text" placeholder="${this.i18n.searchPlaceholder}" aria-label="Buscar" data-search />\n <button class="icon-btn clear-search" aria-label="Limpar busca" data-clear-search hidden>✕</button>\n </div>\n </div>\n </section>\n\n <section class="myio-list" role="listbox" aria-multiselectable="true" data-virtualized>\n \x3c!-- Items will be rendered here --\x3e\n </section>\n\n <section class="myio-sorting">\n <h3>${this.i18n.sortingTitle}</h3>\n <div class="radio-group">\n <label><input type="radio" name="sort" value="CONSUMPTION_DESC" checked /> ${this.i18n.consumptionDesc}</label>\n <label><input type="radio" name="sort" value="CONSUMPTION_ASC" /> ${this.i18n.consumptionAsc}</label>\n <label><input type="radio" name="sort" value="ALPHA_ASC" /> ${this.i18n.aToZ}</label>\n <label><input type="radio" name="sort" value="ALPHA_DESC" /> ${this.i18n.zToA}</label>\n </div>\n <p class="hint">${this.i18n.tieNote}</p>\n </section>\n\n <footer class="myio-footer">\n <button class="btn secondary" data-reset>${this.i18n.reset}</button>\n <button class="btn primary" data-apply>${this.i18n.apply}</button>\n </footer>\n `;this.addStyles();document.body.appendChild(overlay);document.body.appendChild(root);const totalCounter=card.querySelector("[data-total]");const selectedCounter=card.querySelector("[data-selected]");const searchInput=card.querySelector("[data-search]");const listContainer=card.querySelector(".myio-list");const sortRadios=card.querySelectorAll('input[name="sort"]');const clearSearchBtn=card.querySelector("[data-clear-search]");this.dom={overlay:overlay,root:root,card:card,totalCounter:totalCounter,selectedCounter:selectedCounter,searchInput:searchInput,listContainer:listContainer,sortRadios:sortRadios,clearSearchBtn:clearSearchBtn};this.attachEventListeners()}addStyles(){if(document.getElementById("myio-filter-styles"))return;const style=document.createElement("style");style.id="myio-filter-styles";style.textContent=`\n /* === Overlay / Scrim ==================================================== */\n .myio-modal-overlay {\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n background: rgba(0, 0, 0, 0.50); /* 50% dim */\n backdrop-filter: saturate(100%) blur(2px);\n z-index: 10000; /* above app UI */\n opacity: 0;\n pointer-events: none;\n transition: opacity 160ms ease-out;\n margin: 0 !important; /* Reset any inherited margins */\n width: auto !important; /* Reset any inherited width */\n height: auto !important; /* Reset any inherited height */\n touch-action: none; /* iOS overscroll prevention */\n }\n .myio-modal-overlay[aria-hidden="false"] {\n opacity: 1;\n pointer-events: auto;\n }\n\n /* === Card container ====================================================== */\n .myio-modal-root {\n position: fixed !important; /* Force fixed positioning relative to viewport */\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n z-index: 10001; /* above overlay */\n opacity: 0;\n pointer-events: none;\n transition: opacity 160ms ease-out;\n padding: 20px; /* Add padding for better mobile positioning */\n margin: 0 !important; /* Reset any inherited margins */\n width: auto !important; /* Reset any inherited width */\n height: auto !important; /* Reset any inherited height */\n touch-action: none; /* iOS overscroll prevention */\n }\n .myio-modal-root[aria-hidden="false"] {\n opacity: 1;\n pointer-events: auto;\n }\n\n /* === Card ================================================================ */\n .myio-modal-card {\n width: min(960px, 94vw);\n max-height: calc(100vh - 40px); /* Account for padding */\n overflow: auto;\n background: #fff;\n border-radius: 16px;\n box-shadow: 0 24px 64px rgba(0,0,0,.28);\n transform: translateY(-12px) scale(0.98);\n transition: transform 160ms ease-out;\n }\n .myio-modal-root[aria-hidden="false"] .myio-modal-card {\n transform: translateY(0) scale(1);\n }\n\n /* Reduced motion support */\n @media (prefers-reduced-motion: reduce) {\n .myio-modal-overlay,\n .myio-modal-root,\n .myio-modal-card {\n transition: none !important;\n transform: none !important;\n }\n .myio-modal-root[aria-hidden="false"] .myio-modal-card {\n transform: none !important;\n }\n }\n\n /* Header stays purple (MYIO palette) and sticky */\n .myio-modal-card header.myio-header {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: 16px 20px;\n background: var(--myio-purple-600, #4A148C);\n color: #fff;\n border-radius: 16px 16px 0 0;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .myio-modal-card footer.myio-footer {\n position: sticky;\n bottom: 0;\n background: #fff;\n border-top: 1px solid var(--myio-border, #E5E7EB);\n padding: 12px 20px;\n border-radius: 0 0 16px 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n\n /* Prevent accidental stacking-context issues inside transformed parents */\n .myio-modal-portal {\n position: relative;\n z-index: 10000;\n }\n\n /* Optional: body lock when open */\n .body--myio-modal-open {\n overflow: hidden;\n overscroll-behavior: contain;\n }\n\n .myio-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 20px;\n color: #fff;\n background: #4A148C;\n position: sticky;\n top: 0;\n z-index: 1;\n border-radius: 16px 16px 0 0;\n }\n\n .myio-header h2 {\n font-size: 18px;\n font-weight: 700;\n margin: 0;\n flex: 1;\n }\n\n .myio-counters {\n display: flex;\n align-items: center;\n gap: 8px;\n opacity: 0.95;\n }\n\n .myio-header .close {\n background: transparent;\n color: #fff;\n font-size: 20px;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 4px;\n }\n\n .myio-header .close:hover {\n background: rgba(255,255,255,0.1);\n }\n\n .myio-toolbar {\n display: flex;\n gap: 12px;\n align-items: center;\n padding: 12px 20px;\n flex-wrap: wrap;\n border-bottom: 1px solid #E5E7EB;\n }\n\n .myio-toolbar .actions {\n display: flex;\n gap: 8px;\n }\n\n .myio-toolbar .search {\n margin-left: auto;\n flex: 1 1 320px;\n max-width: 400px;\n }\n\n .search-input-wrapper {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-icon {\n position: absolute;\n left: 12px;\n z-index: 1;\n opacity: 0.5;\n }\n\n .myio-toolbar .search input {\n width: 100%;\n height: 40px;\n padding: 0 40px;\n border-radius: 12px;\n border: 1px solid #E5E7EB;\n font-size: 14px;\n }\n\n .clear-search {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 4px;\n opacity: 0.5;\n }\n\n .clear-search:hover {\n opacity: 1;\n }\n\n .myio-list {\n display: grid;\n grid-template-columns: repeat(2, minmax(0,1fr));\n gap: 12px;\n padding: 16px 20px;\n max-height: 300px;\n overflow-y: auto;\n }\n\n @media (max-width: 768px) {\n .myio-list {\n grid-template-columns: 1fr;\n }\n }\n\n .chip {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 44px;\n border-radius: 12px;\n border: 2px solid #4A148C;\n background: #fff;\n padding: 0 14px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s ease;\n }\n\n .chip:hover {\n background: #EDE7F3;\n }\n\n .chip.selected {\n background: #EDE7F3;\n border-color: #4A148C;\n }\n\n .chip .checkbox {\n width: 22px;\n height: 22px;\n border-radius: 6px;\n border: 2px solid #4A148C;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n font-weight: bold;\n color: #4A148C;\n }\n\n .chip.selected .checkbox {\n background: #4A148C;\n color: white;\n }\n\n .myio-sorting {\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n }\n\n .myio-sorting h3 {\n margin: 0 0 12px 0;\n font-size: 16px;\n font-weight: 600;\n color: #1F2937;\n }\n\n .radio-group {\n display: flex;\n flex-wrap: wrap;\n gap: 16px;\n margin-bottom: 8px;\n }\n\n .myio-sorting label {\n display: flex;\n gap: 8px;\n align-items: center;\n cursor: pointer;\n font-size: 14px;\n }\n\n .myio-sorting input[type="radio"] {\n margin: 0;\n }\n\n .hint {\n font-size: 12px;\n color: #6B7280;\n margin: 8px 0 0 0;\n font-style: italic;\n }\n\n .myio-footer {\n position: sticky;\n bottom: 0;\n background: #fff;\n border-top: 1px solid #E5E7EB;\n padding: 12px 20px;\n border-radius: 0 0 16px 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n\n .btn {\n border: none;\n border-radius: 8px;\n padding: 10px 16px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .btn.primary {\n background: #4A148C;\n color: #fff;\n }\n\n .btn.primary:hover {\n background: #3A0E5C;\n }\n\n .btn.secondary {\n background: #fff;\n border: 1px solid #D1D5DB;\n color: #374151;\n }\n\n .btn.secondary:hover {\n background: #F9FAFB;\n }\n\n .btn.ghost {\n background: transparent;\n border: 1px solid #D1D5DB;\n color: #374151;\n padding: 8px 12px;\n font-size: 13px;\n }\n\n .btn.ghost:hover {\n background: #F3F4F6;\n }\n\n .empty-state {\n text-align: center;\n padding: 40px 20px;\n color: #6B7280;\n }\n `;document.head.appendChild(style)}attachEventListeners(){if(!this.dom)return;const{overlay:overlay,root:root,searchInput:searchInput,clearSearchBtn:clearSearchBtn,sortRadios:sortRadios}=this.dom;overlay.addEventListener("click",()=>this.close());root.querySelector("[data-close]")?.addEventListener("click",()=>this.close());root.addEventListener("keydown",e=>{if(e.key==="Escape"){this.close()}});searchInput.addEventListener("input",e=>{const query=e.target.value;this.debounceSearch(query);if(query){clearSearchBtn.hidden=false}else{clearSearchBtn.hidden=true}});clearSearchBtn.addEventListener("click",()=>{searchInput.value="";clearSearchBtn.hidden=true;this.updateQuery("")});root.querySelector("[data-select-all]")?.addEventListener("click",()=>{this.selectAllVisible()});root.querySelector("[data-clear]")?.addEventListener("click",()=>{this.clearSelection()});sortRadios.forEach(radio=>{radio.addEventListener("change",()=>{if(radio.checked){this.setSort(radio.value)}})});root.querySelector("[data-apply]")?.addEventListener("click",()=>{this.apply()});root.querySelector("[data-reset]")?.addEventListener("click",()=>{this.reset()})}debounceSearch(query){if(this.searchTimeout){clearTimeout(this.searchTimeout)}this.searchTimeout=window.setTimeout(()=>{this.updateQuery(query)},200)}updateQuery(query){this.state.query=query;this.renderList()}selectAllVisible(){const visibleIds=this.getVisibleItems();visibleIds.forEach(id=>this.state.selected.add(id));this.updateCounters();this.renderList();this.emit("myio:filter:select_all",{scope:this.state.query?"visible":"all"})}clearSelection(){const visibleIds=this.getVisibleItems();const queryActive=this.state.query.length>0;if(queryActive){visibleIds.forEach(id=>this.state.selected.delete(id))}else{this.state.selected.clear()}this.updateCounters();this.renderList();this.emit("myio:filter:clear",{scope:queryActive?"visible":"all"})}apply(){const startTime=performance.now();this.props.onApply({selected:Array.from(this.state.selected),sort:this.state.sort});this.emit("myio:filter:apply",{selectedCount:this.state.selected.size,sort:this.state.sort,queryLength:this.state.query.length,durationMs:performance.now()-startTime});if(this.props.autoCloseOnApply!==false){this.close()}}reset(){this.state.selected=new Set(this.initialState.selected);this.state.sort=this.initialState.sort;this.state.query="";if(this.dom){this.dom.searchInput.value="";this.dom.clearSearchBtn.hidden=true;this.dom.sortRadios.forEach(radio=>{radio.checked=radio.value===this.state.sort})}this.updateCounters();this.renderList()}getVisibleItems(){const sorted=this.sortItems([...this.itemsById.values()],this.state.sort);if(!this.state.query){return sorted.map(x=>x.id)}const query=this.normalize(this.state.query);return sorted.filter(x=>this.normalize(x.label).includes(query)).map(x=>x.id)}normalize(s){return s.normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase().trim()}sortItems(list,mode){const byLabelAsc=(a,b)=>a.label.localeCompare(b.label,void 0,{sensitivity:"base"})||(a.id>b.id?1:-1);const byLabelDesc=(a,b)=>-byLabelAsc(a,b);const num=x=>x==null?Number.NEGATIVE_INFINITY:x;switch(mode){case"CONSUMPTION_DESC":return[...list].sort((a,b)=>num(b.consumption)-num(a.consumption)||byLabelAsc(a,b));case"CONSUMPTION_ASC":return[...list].sort((a,b)=>num(a.consumption)-num(b.consumption)||byLabelAsc(a,b));case"ALPHA_ASC":return[...list].sort(byLabelAsc);case"ALPHA_DESC":return[...list].sort(byLabelDesc);default:return[...list]}}updateCounters(){if(!this.dom)return;this.dom.totalCounter.textContent=this.state.allIds.length.toString();this.dom.selectedCounter.textContent=this.state.selected.size.toString()}renderList(){if(!this.dom)return;const visibleIds=this.getVisibleItems();if(visibleIds.length===0){this.dom.listContainer.innerHTML=`\n <div class="empty-state">\n ${this.state.query?"Nenhuma loja encontrada com o filtro aplicado.":"Nenhuma loja disponível."}\n </div>\n `;return}this.dom.listContainer.innerHTML=visibleIds.map(id=>this.renderChip(id)).join("");this.dom.listContainer.querySelectorAll(".chip").forEach(chip=>{chip.addEventListener("click",()=>{const id=chip.getAttribute("data-id");this.toggleItem(id)})})}renderChip(id){const item=this.itemsById.get(id);const isSelected=this.state.selected.has(id);return`\n <button role="option" aria-selected="${isSelected}"\n class="chip ${isSelected?"selected":""}"\n data-id="${id}">\n <span class="checkbox" aria-hidden="true">${isSelected?"✓":""}</span>\n <span class="label" title="${item.label}">${item.label}</span>\n </button>\n `}toggleItem(id){if(this.state.selected.has(id)){this.state.selected.delete(id)}else{this.state.selected.add(id)}this.updateCounters();this.renderList()}emit(eventType,detail){if(this.dom){const event=new CustomEvent(eventType,{detail:detail});this.dom.card.dispatchEvent(event)}}};function attachFilterOrderingModal(props){const modal=new FilterOrderingModal(props);return{open:()=>modal.open(),close:()=>modal.close(),getState:()=>modal.getState(),setSelection:ids=>modal.setSelection(ids),setSort:sort=>modal.setSort(sort),destroy:()=>modal.destroy()}}var AllReportModal=class{constructor(params){this.params=params;this.authClient=new AuthClient({clientId:params.api.clientId,clientSecret:params.api.clientSecret,base:params.api.dataApiBaseUrl});this.debugEnabled=params.debug===1;this.debugLog("🚀 AllReportModal initialized",{customerId:params.customerId,itemsListLength:params.itemsList?.length||0,itemsList:params.itemsList,debugEnabled:this.debugEnabled,debugParam:params.debug,apiConfig:{hasIngestionToken:!!params.api.ingestionToken,dataApiBaseUrl:params.api.dataApiBaseUrl}})}modal;authClient;data=[];isLoading=false;eventHandlers={};dateRangePicker=null;currentPage=1;itemsPerPage=10;sortField="consumption";sortDirection="desc";searchFilter="";filterModal=null;selectedStoreIds=new Set;currentSortMode="CONSUMPTION_DESC";debugEnabled;debugLog(message,data){console.log(`[AllReportModal DEBUG] ${message}`,data||"")}normalizeId(v){return(v||"").toString().normalize("NFKC").toUpperCase().replace(/\s+/g,"").replace(/[^A-Z0-9]/g,"")}resolveStoreIdentifierFromApi(item){if(item?.assetName){return item.assetName}const name=item?.name||"";if(!name)return null;const tokens=name.trim().split(/\s+/);const last=tokens[tokens.length-1]||"";if(/[A-Za-z0-9]{3,}/.test(last)){return last}const maybe=tokens.find(t=>/[A-Za-z0-9]{3,}/.test(t));return maybe||null}pickConsumption(item){const fields=["total_value","totalValue","consumption","value","total","energy","kwh"];for(const f of fields){if(item?.[f]!==void 0&&item?.[f]!==null){const n=typeof item[f]==="string"?parseFloat(item[f].replace(",",".")):Number(item[f]);if(!Number.isNaN(n))return n}}return 0}show(){this.debugLog("🎭 Modal show() called - creating modal UI");this.modal=createModal({title:`Relatório Geral - Todas as Lojas${this.debugEnabled?" [DEBUG MODE]":""}`,width:"85vw",height:"90vh",theme:this.params.ui?.theme||"light"});this.renderContent();this.modal.on("close",()=>{this.debugLog("🚪 Modal closing - cleaning up resources");if(this.dateRangePicker){this.dateRangePicker.destroy();this.dateRangePicker=null}if(this.filterModal){this.filterModal.destroy();this.filterModal=null}this.authClient.clearCache();this.emit("close")});this.debugLog("✅ Modal created and ready to use");return{close:()=>this.modal.close(),on:(event,handler)=>this.on(event,handler)}}renderContent(){const content=document.createElement("div");content.innerHTML=`\n <div class="myio-modal-scope">\n <div style="margin-bottom: 16px;">\n <div style="display: flex; gap: 16px; align-items: end; margin-bottom: 16px; flex-wrap: wrap;">\n <div class="myio-form-group" style="margin-bottom: 0;">\n <label class="myio-label" for="date-range">Período</label>\n <input type="text" id="date-range" class="myio-input" readonly placeholder="Selecione o período" style="width: 300px;">\n </div>\n <button id="load-btn" class="myio-btn myio-btn-primary">\n <span class="myio-spinner" id="load-spinner" style="display: none;"></span>\n Carregar\n </button>\n <button id="export-btn" class="myio-btn myio-btn-secondary" disabled>\n Exportar CSV\n </button>\n <button id="filter-btn" class="myio-btn myio-btn-secondary" style="background: var(--myio-brand-700); color: white;">\n 🔍 Filtros & Ordenação\n </button>\n <div class="myio-form-group" style="margin-bottom: 0; margin-left: auto;">\n <label class="myio-label" for="search-input">Busca rápida</label>\n <input type="text" id="search-input" class="myio-input" placeholder="Digite para filtrar..." style="width: 200px;">\n </div>\n </div>\n </div>\n\n <div id="error-container" style="display: none; background: #ffebee; color: #c62828; padding: 12px; border-radius: 6px; margin-bottom: 16px;">\n </div>\n\n <div id="summary-container" style="display: none; margin-bottom: 16px;">\n </div>\n\n <div id="table-container">\n <div style="text-align: center; padding: 40px; color: var(--myio-text-muted);">\n Selecione um período e clique em "Carregar" para visualizar os dados de todas as lojas.\n </div>\n </div>\n\n <div id="pagination-container" style="display: none; margin-top: 16px; text-align: center;">\n </div>\n </div>\n `;this.modal.setContent(content);this.setupEventListeners()}async setupEventListeners(){const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const filterBtn=document.getElementById("filter-btn");const dateRangeInput=document.getElementById("date-range");const searchInput=document.getElementById("search-input");loadBtn?.addEventListener("click",()=>this.loadData());exportBtn?.addEventListener("click",()=>this.exportCSV());filterBtn?.addEventListener("click",()=>this.openFilterModal());if(searchInput){searchInput.addEventListener("input",e=>{this.searchFilter=e.target.value.toLowerCase();this.currentPage=1;this.renderTable();this.renderPagination()});searchInput.addEventListener("keyup",e=>{this.searchFilter=e.target.value.toLowerCase();this.currentPage=1;this.renderTable();this.renderPagination()})}try{this.dateRangePicker=await attach(dateRangeInput,{presetStart:this.getDefaultStartDate(),presetEnd:this.getDefaultEndDate(),maxRangeDays:31,parentEl:this.modal.element,onApply:({startISO:startISO,endISO:endISO})=>{this.hideError();console.log("Date range selected:",{startISO:startISO,endISO:endISO})}})}catch(error){console.warn("DateRangePicker initialization failed, using fallback:",error)}}async loadData(){if(this.isLoading)return;this.debugLog("📊 Starting loadData process");const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const spinner=document.getElementById("load-spinner");if(!this.dateRangePicker){this.showError("Seletor de data não inicializado");return}this.isLoading=true;loadBtn.disabled=true;exportBtn.disabled=true;spinner.style.display="inline-block";try{const{startISO:startISO,endISO:endISO}=this.dateRangePicker.getDates();this.debugLog("📅 Date range selected",{startISO:startISO,endISO:endISO});if(!startISO||!endISO){this.showError("Selecione um período válido");return}const startDate=startISO.split("T")[0];const endDate=endISO.split("T")[0];this.debugLog("🌐 Fetching customer totals from API...");const customerTotalsData=await this.fetchCustomerTotals(startISO,endISO);this.debugLog("✅ API response received",customerTotalsData);this.debugLog("🔄 Processing API response...");this.data=this.mapCustomerTotalsResponse(customerTotalsData);this.debugLog("✅ Data mapping completed",{mappedDataLength:this.data.length,mappedData:this.data,totalConsumption:this.calculateTotalConsumption()});this.selectedStoreIds=new Set(this.data.map(store=>this.generateStoreId(store.name)));this.debugLog("🎯 Store IDs initialized",{selectedStoreIdsSize:this.selectedStoreIds.size,selectedStoreIds:Array.from(this.selectedStoreIds)});this.currentPage=1;this.debugLog("🎨 Rendering UI components...");this.renderSummary();this.renderTable();this.renderPagination();exportBtn.disabled=false;this.debugLog("🎉 Load process completed successfully");this.emit("loaded",{date:{start:startDate,end:endDate},stores:this.data.length,totalConsumption:this.calculateTotalConsumption()})}catch(error){this.debugLog("❌ Error in loadData",error);this.showError("Erro ao carregar dados: "+error.message);console.error("Error loading data:",error);this.emit("error",{message:error.message,context:"loadData"})}finally{this.isLoading=false;loadBtn.disabled=false;spinner.style.display="none"}}getFilteredData(){let filtered=this.data;if(this.selectedStoreIds.size>0){filtered=this.data.filter(store=>{const storeId=this.generateStoreId(store.name);return this.selectedStoreIds.has(storeId)})}if(this.searchFilter){filtered=filtered.filter(store=>store.name.toLowerCase().includes(this.searchFilter)||store.identifier.toLowerCase().includes(this.searchFilter))}return filtered.sort((a,b)=>{const aVal=a[this.sortField];const bVal=b[this.sortField];if(typeof aVal==="string"&&typeof bVal==="string"){return this.sortDirection==="asc"?aVal.localeCompare(bVal):bVal.localeCompare(aVal)}else{return this.sortDirection==="asc"?aVal-bVal:bVal-aVal}})}getPaginatedData(){const filtered=this.getFilteredData();const startIndex=(this.currentPage-1)*this.itemsPerPage;return filtered.slice(startIndex,startIndex+this.itemsPerPage)}renderSummary(){const container=document.getElementById("summary-container");if(!container)return;const totalConsumption=this.calculateTotalConsumption();const storeCount=Math.max(1,this.data.length);container.innerHTML=`\n <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; padding: 16px; background: var(--myio-bg); border-radius: 6px;">\n <div style="text-align: center;">\n <div style="font-size: 24px; font-weight: bold; color: var(--myio-primary);">${storeCount}</div>\n <div style="color: var(--myio-text-muted);">Lojas</div>\n </div>\n <div style="text-align: center;">\n <div style="font-size: 24px; font-weight: bold; color: var(--myio-primary);">${fmtPt(totalConsumption)}</div>\n <div style="color: var(--myio-text-muted);">Total kWh</div>\n </div>\n <div style="text-align: center;">\n <div style="font-size: 24px; font-weight: bold; color: var(--myio-primary);">${fmtPt(totalConsumption/storeCount)}</div>\n <div style="color: var(--myio-text-muted);">Média por Loja</div>\n </div>\n </div>\n `;container.style.display="block"}renderTable(){const container=document.getElementById("table-container");if(!container)return;const paginatedData=this.getPaginatedData();this.getFilteredData();if(paginatedData.length===0){container.innerHTML=`\n <div style="text-align: center; padding: 40px; color: var(--myio-text-muted);">\n ${this.searchFilter?"Nenhuma loja encontrada com o filtro aplicado.":"Nenhum dado encontrado."}\n </div>\n `;return}container.innerHTML=`\n <div style="max-height: 500px; overflow-y: auto; border: 1px solid var(--myio-border); border-radius: 6px;">\n <style>\n @media (max-width: 768px) {\n .myio-table-mobile {\n display: block !important;\n }\n .myio-table-mobile thead,\n .myio-table-mobile tbody,\n .myio-table-mobile th,\n .myio-table-mobile td,\n .myio-table-mobile tr {\n display: block !important;\n }\n .myio-table-mobile thead tr {\n position: absolute !important;\n top: -9999px !important;\n left: -9999px !important;\n }\n .myio-table-mobile tbody tr {\n border: 1px solid var(--myio-border) !important;\n border-radius: 8px !important;\n margin-bottom: 16px !important;\n padding: 16px !important;\n background: white !important;\n }\n .myio-table-mobile tbody td {\n border: none !important;\n padding: 8px 0 !important;\n position: relative !important;\n }\n .myio-table-mobile tbody td:before {\n content: attr(data-label) ": " !important;\n font-weight: bold !important;\n display: inline-block !important;\n width: 120px !important;\n color: var(--myio-text-muted) !important;\n }\n }\n </style>\n <table class="myio-table myio-table-mobile" style="table-layout: fixed; width: 100%;">\n <thead style="position: sticky; top: 0; background: var(--myio-bg); z-index: 1;">\n <tr>\n <th style="cursor: pointer; width: 25%;" data-sort="identifier">\n Identifier\n <span style="margin-left: 4px; opacity: ${this.getSortOpacity("identifier")};">${this.getSortIcon("identifier")}</span>\n </th>\n <th style="cursor: pointer; width: 45%;" data-sort="name">\n Name\n <span style="margin-left: 4px; opacity: ${this.getSortOpacity("name")};">${this.getSortIcon("name")}</span>\n </th>\n <th style="cursor: pointer; text-align: right; width: 30%;" data-sort="consumption">\n Consumption (kWh)\n <span style="margin-left: 4px; opacity: ${this.getSortOpacity("consumption")};">${this.getSortIcon("consumption")}</span>\n </th>\n </tr>\n </thead>\n <tbody>\n ${paginatedData.map(row=>`\n <tr>\n <td data-label="Identifier" style="font-family: monospace; font-weight: bold; text-transform: uppercase;">${row.identifier}</td>\n <td data-label="Name"><strong>${row.name}</strong></td>\n <td data-label="Consumption (kWh)" style="text-align: right; font-weight: bold;">${row.consumption.toFixed(2)}</td>\n </tr>\n `).join("")}\n </tbody>\n </table>\n </div>\n `;this.setupTableSorting()}getSortIcon(field){if(this.sortField!==field)return"↕";return this.sortDirection==="asc"?"↑":"↓"}getSortOpacity(field){return this.sortField===field?"1":"0.5"}setupTableSorting(){const headers=document.querySelectorAll("[data-sort]");headers.forEach(header=>{header.addEventListener("click",()=>{const sortKey=header.getAttribute("data-sort");if(this.sortField===sortKey){this.sortDirection=this.sortDirection==="asc"?"desc":"asc"}else{this.sortField=sortKey;this.sortDirection=sortKey==="identifier"||sortKey==="name"?"asc":"desc"}this.currentPage=1;this.renderTable();this.renderPagination()})})}renderPagination(){const container=document.getElementById("pagination-container");if(!container)return;const filteredData=this.getFilteredData();const totalPages=Math.ceil(filteredData.length/this.itemsPerPage);if(totalPages<=1){container.style.display="none";return}const startItem=(this.currentPage-1)*this.itemsPerPage+1;const endItem=Math.min(this.currentPage*this.itemsPerPage,filteredData.length);container.innerHTML=`\n <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">\n <div style="color: var(--myio-text-muted);">\n Mostrando ${startItem}-${endItem} de ${filteredData.length} lojas\n </div>\n <div style="display: flex; gap: 8px; align-items: center;">\n <button id="prev-page" class="myio-btn myio-btn-outline" ${this.currentPage===1?"disabled":""}>\n Anterior\n </button>\n <span style="padding: 0 12px; font-weight: bold;">\n ${this.currentPage} / ${totalPages}\n </span>\n <button id="next-page" class="myio-btn myio-btn-outline" ${this.currentPage===totalPages?"disabled":""}>\n Próximo\n </button>\n </div>\n </div>\n `;document.getElementById("prev-page")?.addEventListener("click",()=>{if(this.currentPage>1){this.currentPage--;this.renderTable();this.renderPagination()}});document.getElementById("next-page")?.addEventListener("click",()=>{if(this.currentPage<totalPages){this.currentPage++;this.renderTable();this.renderPagination()}});container.style.display="block"}calculateTotalConsumption(){return this.data.reduce((sum,row)=>sum+row.consumption,0)}openFilterModal(){if(!this.filterModal){this.filterModal=attachFilterOrderingModal({title:"Filtros & Ordenação - Lojas",items:this.convertToStoreItems(),initialSelected:Array.from(this.selectedStoreIds),initialSort:this.currentSortMode,onApply:({selected:selected,sort:sort})=>{this.applyFiltersAndSort(selected,sort)},onClose:()=>{}})}else{this.filterModal.setSelection(Array.from(this.selectedStoreIds));this.filterModal.setSort(this.currentSortMode)}this.filterModal.open()}convertToStoreItems(){return this.data.map(store=>({id:this.generateStoreId(store.name),identifier:store.identifier,label:store.name,consumption:store.consumption}))}generateStoreId(storeName){return storeName.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"")}applyFiltersAndSort(selectedIds,sortMode){this.selectedStoreIds=new Set(selectedIds);this.currentSortMode=sortMode;switch(sortMode){case"CONSUMPTION_DESC":this.sortField="consumption";this.sortDirection="desc";break;case"CONSUMPTION_ASC":this.sortField="consumption";this.sortDirection="asc";break;case"ALPHA_ASC":this.sortField="name";this.sortDirection="asc";break;case"ALPHA_DESC":this.sortField="name";this.sortDirection="desc";break}this.currentPage=1;this.renderSummary();this.renderTable();this.renderPagination();const filterBtn=document.getElementById("filter-btn");if(filterBtn&&selectedIds.length>0&&selectedIds.length<this.data.length){filterBtn.innerHTML=`🔍 Filtros & Ordenação (${selectedIds.length})`;filterBtn.style.background="var(--myio-brand-600)"}else{filterBtn.innerHTML="🔍 Filtros & Ordenação";filterBtn.style.background="var(--myio-brand-700)"}}exportCSV(){const totalConsumption=this.calculateTotalConsumption();const now=new Date;const timestamp=now.toLocaleDateString("pt-BR")+" - "+now.toLocaleTimeString("pt-BR",{hour:"2-digit",minute:"2-digit"});const sortedData=[...this.data].sort((a,b)=>b.consumption-a.consumption);const csvData=[["RELATÓRIO GERAL - TODAS AS LOJAS","","",""],["DATA EMISSÃO",timestamp,"",""],["RESUMO","","",""],["Total de Lojas",this.data.length.toString(),"",""],["Consumo Total",totalConsumption.toFixed(2),"kWh",""],["Consumo Médio por Loja",(totalConsumption/this.data.length).toFixed(2),"kWh",""],["","","",""],["DETALHAMENTO POR LOJA","","",""],["Identifier","Name","Consumption (kWh)",""],...sortedData.map(row=>[row.identifier,row.name,row.consumption.toFixed(2),""])];const csvContent=toCsv(csvData);this.downloadCSV(csvContent,`relatorio-geral-lojas-${(new Date).toISOString().split("T")[0]}.csv`)}async fetchCustomerTotals(startISO,endISO){if(this.params.fetcher){const token2=this.params.api.ingestionToken||await this.authClient.getBearer();return await this.params.fetcher({baseUrl:this.params.api.dataApiBaseUrl||"https://api.data.apps.myio-bas.com",token:token2,customerId:this.params.customerId,startISO:startISO,endISO:endISO})}const token=this.params.api.ingestionToken;if(!token){throw new Error("ingestionToken is required for Data API calls to data.apps.myio-bas.com")}const baseUrl=this.params.api.dataApiBaseUrl||"https://api.data.apps.myio-bas.com";const startTime=encodeURIComponent(startISO);const endTime=encodeURIComponent(endISO);const url=`${baseUrl}/api/v1/telemetry/customers/${this.params.customerId}/energy/devices/totals?startTime=${startTime}&endTime=${endTime}`;console.log("[AllReportModal] Fetching customer totals:",{url:url,customerId:this.params.customerId});const response=await fetch(url,{method:"GET",headers:{Authorization:`Bearer ${token}`,"Content-Type":"application/json"}});if(!response.ok){throw new Error(`Erro na API: ${response.status} ${response.statusText}`)}const data=await response.json();console.log("[AllReportModal] Customer totals response:",data);return data}mapCustomerTotalsResponse(apiResponse){this.debugLog("🔍 Starting mapCustomerTotalsResponse",{apiResponse:apiResponse});const apiArray=Array.isArray(apiResponse?.data)?apiResponse.data:Array.isArray(apiResponse)?apiResponse:[];console.log("[AllReportModal] NEW MAPPING - API array length:",apiArray.length);console.log("[AllReportModal] NEW MAPPING - ItemsList length:",this.params.itemsList.length);this.debugLog("📋 API data array extracted",{isDataProperty:!!apiResponse?.data,isDirectArray:Array.isArray(apiResponse),apiArrayLength:apiArray.length,firstFewItems:apiArray.slice(0,3)});if(!apiArray.length){this.debugLog("⚠️ Empty API array, returning empty result");console.warn("[AllReportModal] Empty/invalid API response:",apiResponse);return[]}const sumByApiId=new Map;let apiItemsWithoutId=0;let totalApiConsumption=0;this.debugLog("🔨 Building ID index from API data...");for(const[index,item]of apiArray.entries()){const consumption=this.pickConsumption(item);totalApiConsumption+=consumption;if(index<3){console.log(`[AllReportModal] NEW MAPPING - API item ${index}:`,{id:item?.id,name:item?.name,assetName:item?.assetName,total_value:item?.total_value,extractedConsumption:consumption})}this.debugLog(`📊 Processing API item ${index}`,{item:item,extractedConsumption:consumption,hasId:!!item?.id});if(item?.id){const id=String(item.id);const previousSum=sumByApiId.get(id)||0;sumByApiId.set(id,previousSum+consumption);this.debugLog(`✅ Added to ID index: ${id} = ${previousSum} + ${consumption} = ${previousSum+consumption}`)}else{apiItemsWithoutId++;this.debugLog(`❌ API item without ID:`,item)}}console.log("[AllReportModal] NEW MAPPING - Total API consumption:",totalApiConsumption);console.log("[AllReportModal] NEW MAPPING - Unique API IDs:",sumByApiId.size);this.debugLog("📊 ID index built",{sumByApiIdSize:sumByApiId.size,sumByApiIdEntries:Array.from(sumByApiId.entries()),apiItemsWithoutId:apiItemsWithoutId});let matchedById=0,matchedBySubstring=0;let totalMappedConsumption=0;this.debugLog("🎯 Starting itemsList mapping...");const rows=this.params.itemsList.map((listItem,index)=>{this.debugLog(`🔍 Processing listItem ${index}`,listItem);let consumption=sumByApiId.get(listItem.id)??0;this.debugLog(`🎯 Primary ID match for ${listItem.id}: ${consumption}`);if(index<3){console.log(`[AllReportModal] NEW MAPPING - ItemsList item ${index}:`,{id:listItem.id,identifier:listItem.identifier,label:listItem.label,idMatchConsumption:consumption})}if(consumption>0){matchedById++;this.debugLog(`✅ Matched by ID: ${listItem.id} -> ${consumption}`)}else{this.debugLog(`🔄 No ID match, trying substring fallback for identifier: ${listItem.identifier}`);for(const[apiIndex,apiItem]of apiArray.entries()){const assetName=apiItem?.assetName||"";const name=apiItem?.name||"";const assetNameMatch=assetName.includes(listItem.identifier);const nameMatch=name.includes(listItem.identifier);if(assetNameMatch||nameMatch){const itemConsumption=this.pickConsumption(apiItem);consumption+=itemConsumption;if(index<3){console.log(`[AllReportModal] NEW MAPPING - Substring match for ${listItem.identifier}:`,{apiItemName:name,apiItemAssetName:assetName,itemConsumption:itemConsumption,totalConsumption:consumption})}this.debugLog(`✅ Substring match found in API item ${apiIndex}`,{listItemIdentifier:listItem.identifier,apiItemAssetName:assetName,apiItemName:name,assetNameMatch:assetNameMatch,nameMatch:nameMatch,itemConsumption:itemConsumption,totalConsumption:consumption})}}if(consumption>0){matchedBySubstring++;this.debugLog(`✅ Matched by substring: ${listItem.identifier} -> ${consumption}`)}else{this.debugLog(`❌ No match found for: ${listItem.identifier}`)}}const result={identifier:listItem.identifier,name:listItem.label,consumption:Math.round(consumption*100)/100};totalMappedConsumption+=result.consumption;this.debugLog(`📝 Final row for ${listItem.identifier}:`,result);return result});const stats={apiItems:apiArray.length,uniqueApiIds:sumByApiId.size,itemsInList:this.params.itemsList.length,matchedById:matchedById,matchedBySubstring:matchedBySubstring,unmatched:this.params.itemsList.length-matchedById-matchedBySubstring,apiItemsWithoutId:apiItemsWithoutId,totalApiConsumption:totalApiConsumption,totalMappedConsumption:totalMappedConsumption};console.log("[AllReportModal] NEW MAPPING - Final stats:",stats);this.debugLog("📊 Final mapping stats:",stats);console.log("[AllReportModal] Mapping stats:",stats);return rows}parseConsumptionValue(item){const possibleFields=["total_value","totalValue","consumption","value","total","energy","kwh"];for(const field of possibleFields){if(item[field]!==void 0&&item[field]!==null){const value=typeof item[field]==="string"?parseFloat(item[field].replace(",",".")):Number(item[field]);if(!isNaN(value)){return Math.round(value*100)/100}}}console.warn("[AllReportModal] No valid consumption value found in item:",item);return 0}downloadCSV(content,filename){const BOM="\ufeff";const csvWithBOM=BOM+content;const blob=new Blob([csvWithBOM],{type:"text/csv;charset=utf-8;"});const link=document.createElement("a");const url=URL.createObjectURL(blob);link.setAttribute("href",url);link.setAttribute("download",filename);link.style.visibility="hidden";document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(url)}getDefaultStartDate(){const date=new Date;date.setDate(1);return date.toISOString().split("T")[0]}getDefaultEndDate(){return(new Date).toISOString().split("T")[0]}showError(message){const container=document.getElementById("error-container");if(container){container.textContent=message;container.style.display="block"}}hideError(){const container=document.getElementById("error-container");if(container){container.style.display="none"}}on(event,handler){if(!this.eventHandlers[event]){this.eventHandlers[event]=[]}this.eventHandlers[event].push(handler)}emit(event,payload){if(this.eventHandlers[event]){this.eventHandlers[event].forEach(handler=>handler())}}};function openDashboardPopupAllReport(params){const modal=new AllReportModal(params);return modal.show()}function openDashboardPopup(params){console.log("Opening settings modal with params:",params);return{close:()=>{console.log("Closing settings modal")},on:(event,handler)=>{console.log(`Registering ${event} handler for settings modal`)}}}var SettingsModalView=class{container;modal;form;config;focusTrapElements=[];originalActiveElement=null;constructor(config){this.config=config;this.createModal()}render(initialData){this.originalActiveElement=document.activeElement;document.body.appendChild(this.container);this.populateForm(initialData);this.attachEventListeners();this.setupAccessibility();this.setupFocusTrap();this.applyTheme()}close(){this.teardownFocusTrap();if(this.originalActiveElement&&"focus"in this.originalActiveElement){this.originalActiveElement.focus()}if(this.container.parentNode){this.container.parentNode.removeChild(this.container)}}showError(message){const errorEl=this.modal.querySelector(".error-message");if(errorEl){errorEl.textContent=message;errorEl.style.display="block";errorEl.setAttribute("role","alert");errorEl.setAttribute("aria-live","polite")}}hideError(){const errorEl=this.modal.querySelector(".error-message");if(errorEl){errorEl.style.display="none";errorEl.removeAttribute("role");errorEl.removeAttribute("aria-live")}}showLoadingState(isLoading){const saveBtn=this.modal.querySelector(".btn-save");const cancelBtn=this.modal.querySelector(".btn-cancel");const formInputs=this.modal.querySelectorAll("input, select, textarea");if(saveBtn){saveBtn.disabled=isLoading;saveBtn.textContent=isLoading?"Salvando...":"Salvar"}if(cancelBtn){cancelBtn.disabled=isLoading}formInputs.forEach(input=>{input.disabled=isLoading})}getFormData(){const formData=new FormData(this.form);const data={};for(const[key,value]of formData.entries()){if(typeof value==="string"){if(["maxDailyKwh","maxNightKwh","maxBusinessKwh"].includes(key)){const num=parseFloat(value);if(!isNaN(num)&&num>=0){data[key]=num}}else if(value.trim()){data[key]=value.trim()}}}return data}createModal(){this.container=document.createElement("div");this.container.className="myio-settings-modal-overlay";this.container.innerHTML=this.getModalHTML();this.modal=this.container.querySelector(".myio-settings-modal");this.form=this.modal.querySelector("form")}getModalHTML(){const width=typeof this.config.width==="number"?`${this.config.width}px`:this.config.width;return`\n <div class="myio-settings-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="modal-title">\n <div class="myio-settings-modal" style="width: ${width}">\n <div class="modal-header">\n <h3 id="modal-title">Configurações</h3>\n <button type="button" class="close-btn" aria-label="Fechar">&times;</button>\n </div>\n <div class="modal-body">\n <div class="error-message" style="display: none;" role="alert" aria-live="polite"></div>\n <form novalidate>\n ${this.getFormHTML()}\n </form>\n </div>\n <div class="modal-footer">\n <button type="button" class="btn-cancel">Fechar</button>\n <button type="button" class="btn-save btn-primary">Salvar</button>\n </div>\n </div>\n </div>\n ${this.getModalCSS()}\n `}getFormHTML(){return`\n <div class="form-columns">\n \x3c!-- Left Column: Outback --\x3e\n <div class="form-column">\n <div class="form-card">\n <h4 class="section-title">${this.config.deviceLabel||"Outback"}</h4>\n \n <div class="form-group">\n <label for="label">Etiqueta</label>\n <input type="text" id="label" name="label" required maxlength="255">\n </div>\n \n <div class="form-group">\n <label for="floor">Andar</label>\n <input type="text" id="floor" name="floor" maxlength="50">\n </div>\n \n <div class="form-group">\n <label for="identifier">Número da Loja</label>\n <input type="text" id="identifier" name="identifier" maxlength="20" readonly>\n </div>\n </div>\n </div>\n\n \x3c!-- Right Column: Energy Alarms --\x3e\n <div class="form-column">\n <div class="form-card">\n <h4 class="section-title">Alarmes Energia - ${this.config.deviceLabel||"Outback"}</h4>\n \n <div class="form-group">\n <label for="maxDailyKwh">Consumo Máximo Diário (kWh)</label>\n <input type="number" id="maxDailyKwh" name="maxDailyKwh" min="0" step="0.1">\n </div>\n \n <div class="form-group">\n <label for="maxNightKwh">Consumo Máximo na Madrugada (0h–06h)</label>\n <input type="number" id="maxNightKwh" name="maxNightKwh" min="0" step="0.1">\n </div>\n \n <div class="form-group">\n <label for="maxBusinessKwh">Consumo Máximo Horário Comercial (09h–22h)</label>\n <input type="number" id="maxBusinessKwh" name="maxBusinessKwh" min="0" step="0.1">\n </div>\n </div>\n </div>\n </div>\n `}getModalCSS(){return`\n <style>\n .myio-settings-modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n \n .myio-settings-modal {\n background: white;\n border-radius: 8px;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);\n max-width: 95vw;\n max-height: 90vh;\n width: 1000px;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n \n .modal-header {\n background: #3e1a7d;\n color: white;\n padding: 20px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n \n .modal-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: white;\n }\n \n .close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: white;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n }\n \n .close-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n }\n \n .modal-body {\n padding: 24px;\n overflow-y: auto;\n flex: 1;\n background: #f8f9fa;\n }\n \n .error-message {\n background: #fee;\n border: 1px solid #fcc;\n color: #c33;\n padding: 12px;\n border-radius: 4px;\n margin-bottom: 16px;\n font-size: 14px;\n }\n \n .form-columns {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 20px;\n }\n \n .form-column {\n display: flex;\n flex-direction: column;\n }\n \n .form-card {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n padding: 20px;\n height: fit-content;\n }\n \n .section-title {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #3e1a7d;\n }\n \n .form-group {\n display: flex;\n flex-direction: column;\n margin-bottom: 16px;\n }\n \n .form-group:last-child {\n margin-bottom: 0;\n }\n \n .form-group label {\n font-weight: 500;\n margin-bottom: 6px;\n color: #333;\n font-size: 14px;\n }\n \n .form-group input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n transition: border-color 0.2s, box-shadow 0.2s;\n box-sizing: border-box;\n }\n \n .form-group input:focus {\n outline: none;\n border-color: #3e1a7d;\n box-shadow: 0 0 0 2px rgba(62, 26, 125, 0.25);\n }\n \n .form-group input:invalid {\n border-color: #dc3545;\n }\n \n .form-group input[readonly] {\n background-color: #f8f9fa;\n color: #6c757d;\n cursor: not-allowed;\n }\n \n .modal-footer {\n padding: 16px 24px;\n border-top: 1px solid #e0e0e0;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: white;\n }\n \n .modal-footer button {\n padding: 10px 20px;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n }\n \n .btn-cancel {\n background: #6c757d;\n color: white;\n }\n \n .btn-cancel:hover:not(:disabled) {\n background: #545b62;\n }\n \n .btn-primary {\n background: #3e1a7d;\n color: white;\n }\n \n .btn-primary:hover:not(:disabled) {\n background: #2d1458;\n }\n \n .modal-footer button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n \n /* Responsive design */\n @media (max-width: 1700px) {\n .myio-settings-modal {\n width: 95vw !important;\n }\n }\n \n @media (max-width: 1024px) {\n .myio-settings-modal {\n width: 90vw !important;\n }\n \n .form-columns {\n gap: 16px;\n }\n \n .form-card {\n padding: 16px;\n }\n }\n \n @media (max-width: 768px) {\n .myio-settings-modal {\n width: 95vw !important;\n margin: 10px;\n }\n \n .form-columns {\n grid-template-columns: 1fr;\n gap: 16px;\n }\n \n .modal-header, .modal-body, .modal-footer {\n padding-left: 16px;\n padding-right: 16px;\n }\n \n .form-card {\n padding: 16px;\n }\n }\n \n /* Scrollbar styling for modal body */\n .modal-body::-webkit-scrollbar {\n width: 6px;\n }\n \n .modal-body::-webkit-scrollbar-track {\n background: #f1f1f1;\n border-radius: 3px;\n }\n \n .modal-body::-webkit-scrollbar-thumb {\n background: #c1c1c1;\n border-radius: 3px;\n }\n \n .modal-body::-webkit-scrollbar-thumb:hover {\n background: #a8a8a8;\n }\n </style>\n `}populateForm(data){for(const[key,value]of Object.entries(data)){const input=this.form.querySelector(`[name="${key}"]`);if(input&&value!==void 0&&value!==null){input.value=String(value)}}}setupAccessibility(){const firstInput=this.modal.querySelector("input");if(firstInput){setTimeout(()=>firstInput.focus(),100)}this.modal.setAttribute("aria-labelledby","modal-title")}setupFocusTrap(){this.focusTrapElements=Array.from(this.modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'));this.modal.addEventListener("keydown",this.handleKeyDown.bind(this))}teardownFocusTrap(){this.modal.removeEventListener("keydown",this.handleKeyDown.bind(this))}handleKeyDown(event){if(event.key==="Escape"&&this.config.closeOnBackdrop!==false){event.preventDefault();this.config.onClose();return}if(event.key==="Tab"){const firstElement=this.focusTrapElements[0];const lastElement=this.focusTrapElements[this.focusTrapElements.length-1];if(event.shiftKey){if(document.activeElement===firstElement){event.preventDefault();lastElement.focus()}}else{if(document.activeElement===lastElement){event.preventDefault();firstElement.focus()}}}}attachEventListeners(){this.form.addEventListener("submit",event=>{event.preventDefault();this.hideError();const formData=this.getFormData();this.config.onSave(formData)});const closeBtn=this.modal.querySelector(".close-btn");if(closeBtn){closeBtn.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.config.onClose()})}const cancelBtn=this.modal.querySelector(".btn-cancel");if(cancelBtn){cancelBtn.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.config.onClose()})}const saveBtn=this.modal.querySelector(".btn-save");if(saveBtn){saveBtn.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.hideError();const formData=this.getFormData();this.config.onSave(formData)})}this.container.addEventListener("click",event=>{const target=event.target;if(target.classList.contains("myio-settings-modal-overlay")&&this.config.closeOnBackdrop!==false){this.config.onClose()}});this.form.addEventListener("input",this.handleInputValidation.bind(this))}handleInputValidation(event){const input=event.target;input.classList.remove("is-invalid");if(input.name==="guid"&&input.value){const guidPattern=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!guidPattern.test(input.value)){input.classList.add("is-invalid");input.setCustomValidity("Invalid GUID format")}else{input.setCustomValidity("")}}if(input.type==="number"&&input.value){const num=parseFloat(input.value);if(isNaN(num)||num<0){input.classList.add("is-invalid");input.setCustomValidity("Must be a positive number")}else{input.setCustomValidity("")}}}applyTheme(){if(this.config.themeTokens){const style=document.createElement("style");let css="";for(const[property,value]of Object.entries(this.config.themeTokens)){css+=`--myio-${property}: ${value};\n`}style.textContent=`.myio-settings-modal { ${css} }`;this.container.appendChild(style)}}getI18nText(key,defaultText){return this.config.i18n?.t(key,defaultText)||defaultText}};var DefaultSettingsPersister=class{jwtToken;tbBaseUrl;constructor(jwtToken,apiConfig){this.jwtToken=jwtToken;this.tbBaseUrl=apiConfig?.tbBaseUrl||window.location.origin}async saveEntityLabel(deviceId,label){try{const getRes=await fetch(`${this.tbBaseUrl}/api/device/${deviceId}`,{headers:{"X-Authorization":`Bearer ${this.jwtToken}`}});if(!getRes.ok){throw this.createHttpError(getRes.status,await getRes.text().catch(()=>""))}const device=await getRes.json();const postRes=await fetch(`${this.tbBaseUrl}/api/device`,{method:"POST",headers:{"X-Authorization":`Bearer ${this.jwtToken}`,"Content-Type":"application/json"},body:JSON.stringify({...device,label:this.sanitizeLabel(label)})});if(!postRes.ok){throw this.createHttpError(postRes.status,await postRes.text().catch(()=>""))}return{ok:true}}catch(error){console.error("[SettingsPersister] Entity label save failed:",error);return{ok:false,error:this.mapError(error)}}}async saveServerScopeAttributes(deviceId,attributes){try{const namespacedAttrs=this.addNamespaceAndVersion(attributes);const res=await fetch(`${this.tbBaseUrl}/api/plugins/telemetry/DEVICE/${deviceId}/attributes/SERVER_SCOPE`,{method:"POST",headers:{"X-Authorization":`Bearer ${this.jwtToken}`,"Content-Type":"application/json"},body:JSON.stringify(namespacedAttrs)});if(!res.ok){throw this.createHttpError(res.status,await res.text().catch(()=>""))}return{ok:true,updatedKeys:Object.keys(namespacedAttrs)}}catch(error){console.error("[SettingsPersister] Attributes save failed:",error);return{ok:false,error:this.mapError(error)}}}addNamespaceAndVersion(attributes){const namespaced={"myio.settings.energy.__version":1};for(const[key,value]of Object.entries(attributes)){if(key!=="label"){namespaced[`myio.settings.energy.${key}`]=value}}return namespaced}sanitizeLabel(label){return label.trim().slice(0,255).replace(/[\x00-\x1F\x7F]/g,"")}createHttpError(status,body){const error=new Error(`HTTP ${status}: ${body}`);error.status=status;error.body=body;return error}mapError(error){const status=error.status;if(status===400){return{code:"VALIDATION_ERROR",message:"Invalid input data",userAction:"FIX_INPUT",cause:error}}if(status===401){return{code:"TOKEN_EXPIRED",message:"Authentication token has expired",userAction:"RE_AUTH",cause:error}}if(status===403){return{code:"AUTH_ERROR",message:"Insufficient permissions",userAction:"RE_AUTH",cause:error}}if(status===404){return{code:"NETWORK_ERROR",message:"Device not found",userAction:"CONTACT_ADMIN",cause:error}}if(status===409){return{code:"VALIDATION_ERROR",message:"Concurrent modification detected",userAction:"RETRY",cause:error}}if(status>=500){return{code:"NETWORK_ERROR",message:"Server error occurred",userAction:"RETRY",cause:error}}return{code:"UNKNOWN_ERROR",message:error.message||"Unknown error occurred",userAction:"CONTACT_ADMIN",cause:error}}};var DefaultSettingsFetcher=class{jwtToken;tbBaseUrl;constructor(jwtToken,apiConfig){this.jwtToken=jwtToken;this.tbBaseUrl=apiConfig?.tbBaseUrl||window.location.origin}async fetchCurrentSettings(deviceId,jwtToken,scope="SERVER_SCOPE"){try{const[entityResult,attributesResult]=await Promise.allSettled([this.fetchDeviceEntity(deviceId),this.fetchDeviceAttributes(deviceId,scope)]);const result={};if(entityResult.status==="fulfilled"){result.entity=entityResult.value}else{console.warn("[SettingsFetcher] Failed to fetch device entity:",entityResult.reason)}if(attributesResult.status==="fulfilled"){result.attributes=attributesResult.value}else{console.warn("[SettingsFetcher] Failed to fetch device attributes:",attributesResult.reason)}return result}catch(error){console.error("[SettingsFetcher] Failed to fetch current settings:",error);return{}}}async fetchDeviceEntity(deviceId){const response=await fetch(`${this.tbBaseUrl}/api/device/${deviceId}`,{headers:{"X-Authorization":`Bearer ${this.jwtToken}`}});if(!response.ok){throw new Error(`Failed to fetch device entity: ${response.status} ${response.statusText}`)}const device=await response.json();return{label:device.label||device.name||""}}async fetchDeviceAttributes(deviceId,scope){const response=await fetch(`${this.tbBaseUrl}/api/plugins/telemetry/DEVICE/${deviceId}/values/attributes/${scope}`,{headers:{"X-Authorization":`Bearer ${this.jwtToken}`}});if(!response.ok){throw new Error(`Failed to fetch device attributes: ${response.status} ${response.statusText}`)}const attributesArray=await response.json();const attributes={};const settingsNamespace="myio.settings.energy.";for(const attr of attributesArray){if(attr.key&&attr.value!==void 0&&attr.value!==null&&attr.value!==""){if(attr.key.startsWith(settingsNamespace)){const key=attr.key.replace(settingsNamespace,"");if(key!=="__version"){attributes[key]=attr.value}}else if(attr.key==="floor"){attributes.floor=attr.value}else if(attr.key==="identifier"){attributes.identifier=attr.value}}}return attributes}static mergeWithSeed(fetchedData,seedData){const merged={};if(seedData){Object.assign(merged,seedData)}if(fetchedData.entity?.label){merged.label=fetchedData.entity.label}if(fetchedData.attributes){Object.assign(merged,fetchedData.attributes)}return merged}static sanitizeFetchedData(data){const sanitized={};const stringFields=["label","floor","identifier"];for(const field of stringFields){if(data[field]&&typeof data[field]==="string"){sanitized[field]=data[field].trim()}}const numericFields=["maxDailyKwh","maxNightKwh","maxBusinessKwh"];for(const field of numericFields){if(data[field]!==void 0&&data[field]!==null){const num=Number(data[field]);if(!isNaN(num)&&num>=0){sanitized[field]=num}}}return sanitized}};var SettingsController=class{view;persister;fetcher;params;constructor(params){this.params=params;this.validateParams();this.persister=params.persister||new DefaultSettingsPersister(params.jwtToken,params.api);this.fetcher=params.fetcher||new DefaultSettingsFetcher(params.jwtToken,params.api);this.view=new SettingsModalView({title:params.ui?.title||`Settings - ${params.label||params.deviceId}`,width:params.ui?.width||600,theme:"light",closeOnBackdrop:params.ui?.closeOnBackdrop!==false,themeTokens:params.ui?.themeTokens,i18n:params.ui?.i18n,deviceLabel:params.label,onSave:this.handleSave.bind(this),onClose:this.handleClose.bind(this)})}async show(){console.info("[SettingsModal] Opening modal",{deviceId:this.params.deviceId,ingestionId:this.params.ingestionId});this.emitEvent("modal_opened");let initialData=this.params.seed||{};if(!this.params.seed){try{const fetchedData=await this.fetcher.fetchCurrentSettings(this.params.deviceId,this.params.jwtToken,this.params.scope||"SERVER_SCOPE");initialData=DefaultSettingsFetcher.mergeWithSeed(fetchedData,this.params.seed);initialData=DefaultSettingsFetcher.sanitizeFetchedData(initialData)}catch(error){console.warn("[SettingsModal] Failed to fetch current settings:",error);if(this.params.onError){this.params.onError({code:"NETWORK_ERROR",message:"Failed to load current settings",cause:error})}}}this.view.render(initialData)}validateParams(){if(!this.params.jwtToken){throw new Error("jwtToken is required for settings persistence")}if(!this.params.deviceId){throw new Error("deviceId is required")}if(!this.params.ingestionId){console.warn("[SettingsModal] ingestionId not provided - using deviceId for display")}}async handleSave(formData){console.info("[SettingsModal] Save initiated",{deviceId:this.params.deviceId,formData:formData});this.emitEvent("save_started",{formData:formData});this.view.showLoadingState(true);try{const result=await this.saveSettings(formData);if(result.ok){console.info("[SettingsModal] Settings saved successfully",result);this.emitEvent("save_completed",{result:result});if(this.params.onSaved){this.params.onSaved(result)}setTimeout(()=>{this.view.close()},500)}else{console.error("[SettingsModal] Save failed:",result);this.emitEvent("save_failed",{result:result});const errorMessage=this.getErrorMessage(result);this.view.showError(errorMessage);if(this.params.onError){this.params.onError({code:"VALIDATION_ERROR",message:errorMessage,cause:result})}}}catch(error){console.error("[SettingsModal] Save error:",error);this.emitEvent("save_failed",{error:error.message});const errorMessage="Network error occurred while saving settings";this.view.showError(errorMessage);if(this.params.onError){this.params.onError({code:"NETWORK_ERROR",message:errorMessage,cause:error})}}finally{this.view.showLoadingState(false)}}async saveSettings(formData){const result={ok:true,timestamp:(new Date).toISOString()};if(formData.label){try{const labelResult=await this.persister.saveEntityLabel(this.params.deviceId,formData.label);result.entity={ok:labelResult.ok,updated:labelResult.ok?["label"]:void 0,error:labelResult.error?{code:labelResult.error.code,message:labelResult.error.message,cause:labelResult.error.cause}:void 0};if(!labelResult.ok){result.ok=false}}catch(error){result.entity={ok:false,error:{code:"UNKNOWN_ERROR",message:error.message||"Failed to save device label",cause:error}};result.ok=false}}const attributes=this.extractAttributes(formData);if(Object.keys(attributes).length>0){try{const attributesResult=await this.persister.saveServerScopeAttributes(this.params.deviceId,attributes);result.serverScope={ok:attributesResult.ok,updatedKeys:attributesResult.updatedKeys,error:attributesResult.error?{code:attributesResult.error.code,message:attributesResult.error.message,cause:attributesResult.error.cause}:void 0};if(!attributesResult.ok){result.ok=false}}catch(error){result.serverScope={ok:false,error:{code:"UNKNOWN_ERROR",message:error.message||"Failed to save device attributes",cause:error}};result.ok=false}}return result}extractAttributes(formData){const attributes={};for(const[key,value]of Object.entries(formData)){if(key!=="label"&&value!==void 0&&value!==null&&value!==""){attributes[key]=value}}return attributes}getErrorMessage(result){const errors=[];if(result.entity?.error){errors.push(`Device label: ${result.entity.error.message}`)}if(result.serverScope?.error){errors.push(`Settings: ${result.serverScope.error.message}`)}return errors.length>0?errors.join("; "):"Failed to save settings"}handleClose(){console.info("[SettingsModal] Modal closed");this.emitEvent("modal_closed");if(this.params.onClose){this.params.onClose()}}emitEvent(type,data){if(this.params.onEvent){const event={type:type,deviceId:this.params.deviceId,timestamp:(new Date).toISOString(),data:data};try{this.params.onEvent(event)}catch(error){console.warn("[SettingsModal] Event handler error:",error)}}}validateFormData(formData){const errors=[];if(formData.guid){const guidPattern=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!guidPattern.test(formData.guid)){errors.push("GUID must be in valid UUID format")}}const numericFields=["maxDailyKwh","maxNightKwh","maxBusinessKwh"];for(const field of numericFields){if(formData[field]!==void 0){const num=Number(formData[field]);if(isNaN(num)||num<0){errors.push(`${field} must be a positive number`)}}}if(formData.label&&formData.label.length>255){errors.push("Device label must be 255 characters or less")}if(formData.floor&&formData.floor.length>50){errors.push("Floor must be 50 characters or less")}if(formData.storeNumber&&formData.storeNumber.length>20){errors.push("Store number must be 20 characters or less")}return{valid:errors.length===0,errors:errors}}closeModal(){this.view.close()}getCurrentFormData(){return this.view.getFormData()}};async function openDashboardPopupSettings(params){if(!params.jwtToken){throw new Error("jwtToken is required for settings persistence")}if(!params.deviceId){throw new Error("deviceId is required")}console.info("[openDashboardPopupSettings] Initializing settings modal",{deviceId:params.deviceId,ingestionId:params.ingestionId,hasJwtToken:!!params.jwtToken,hasSeedData:!!params.seed,apiConfig:params.api?Object.keys(params.api):void 0});const controller=new SettingsController(params);try{await controller.show()}catch(error){console.error("[openDashboardPopupSettings] Error:",error);if(params.onError){params.onError({code:"UNKNOWN_ERROR",message:error.message||"Unknown error occurred while opening settings modal",cause:error})}throw error}}async function createDateRangePicker2(input,options={}){const defaultOptions={maxRangeDays:31,...options};return await DateRangePickerJQ.attach(input,defaultOptions)}var PREMIUM_STYLES=`\n .myio-daterange-wrapper {\n font-family: 'Roboto', Arial, sans-serif;\n background: #f9f9f9;\n padding: 20px;\n border-radius: 8px;\n margin-bottom: 20px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n transition: all 0.2s ease;\n }\n \n .myio-daterange-wrapper:hover {\n box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n }\n \n .myio-daterange-label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n color: #333;\n font-size: 14px;\n line-height: 1.4;\n }\n \n .myio-daterange-input {\n width: 100%;\n max-width: 300px;\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n background: white;\n font-size: 14px;\n color: #333;\n cursor: pointer;\n transition: all 0.2s ease;\n font-family: inherit;\n line-height: 1.4;\n }\n \n .myio-daterange-input:hover {\n border-color: #4A148C;\n box-shadow: 0 0 0 2px rgba(74, 20, 140, 0.1);\n }\n \n .myio-daterange-input:focus {\n outline: none;\n border-color: #4A148C;\n box-shadow: 0 0 0 3px rgba(74, 20, 140, 0.2);\n }\n \n .myio-daterange-input::placeholder {\n color: #999;\n opacity: 1;\n }\n \n .myio-daterange-helper {\n font-size: 12px;\n color: #666;\n margin-top: 4px;\n line-height: 1.3;\n transition: color 0.2s ease;\n }\n \n .myio-daterange-helper.success {\n color: #28a745;\n font-weight: 500;\n }\n \n .myio-daterange-helper.error {\n color: #dc3545;\n font-weight: 500;\n }\n \n /* Responsive design */\n @media (max-width: 768px) {\n .myio-daterange-wrapper {\n padding: 16px;\n margin-bottom: 16px;\n }\n \n .myio-daterange-input {\n max-width: 100%;\n font-size: 16px; /* Prevents zoom on iOS */\n }\n }\n \n /* High contrast mode support */\n @media (prefers-contrast: high) {\n .myio-daterange-wrapper {\n border: 2px solid #000;\n }\n \n .myio-daterange-input {\n border: 2px solid #000;\n }\n }\n \n /* Reduced motion support */\n @media (prefers-reduced-motion: reduce) {\n .myio-daterange-wrapper,\n .myio-daterange-input,\n .myio-daterange-helper {\n transition: none;\n }\n }\n`;function injectPremiumStyles(){const styleId="myio-daterange-premium-styles";if(document.getElementById(styleId)){return}const styleEl=document.createElement("style");styleEl.id=styleId;styleEl.textContent=PREMIUM_STYLES;document.head.appendChild(styleEl);console.log("[MyIO] Premium date range styles injected")}function validateId(id,context){if(!id||typeof id!=="string"){throw new Error(`[createInputDateRangePickerInsideDIV] ${context} must be a non-empty string`)}if(!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(id)){throw new Error(`[createInputDateRangePickerInsideDIV] ${context} '${id}' is not a valid HTML ID`)}}async function createInputDateRangePickerInsideDIV(params){const{containerId:containerId,inputId:inputId,label:label="Período de Datas",placeholder:placeholder="Clique para selecionar período",pickerOptions:pickerOptions={},classNames:classNames={},injectStyles:injectStyles=true,showHelper:showHelper=true}=params;validateId(containerId,"containerId");validateId(inputId,"inputId");const container=document.getElementById(containerId);if(!container){throw new Error(`[createInputDateRangePickerInsideDIV] Container '#${containerId}' not found`)}if(injectStyles){injectPremiumStyles()}let inputEl=document.getElementById(inputId);if(inputEl&&inputEl.tagName.toLowerCase()!=="input"){throw new Error(`[createInputDateRangePickerInsideDIV] Element '#${inputId}' exists but is not an input element`)}const wrapper=document.createElement("div");wrapper.className=classNames.wrapper||"myio-daterange-wrapper";wrapper.setAttribute("data-myio-component","daterange-input");wrapper.setAttribute("data-version","1.0.0");let labelEl=null;if(label){labelEl=document.createElement("label");labelEl.className=classNames.label||"myio-daterange-label";labelEl.textContent=label;labelEl.setAttribute("for",inputId);wrapper.appendChild(labelEl)}if(!inputEl){inputEl=document.createElement("input");inputEl.type="text";inputEl.id=inputId;inputEl.name=inputId}inputEl.className=classNames.input||"myio-daterange-input";inputEl.readOnly=true;inputEl.placeholder=placeholder;inputEl.autocomplete="off";inputEl.setAttribute("aria-label",label||"Date range selector");if(showHelper){inputEl.setAttribute("aria-describedby",`${inputId}-helper`)}let helperEl=null;if(showHelper){helperEl=document.createElement("div");helperEl.id=`${inputId}-helper`;helperEl.className=classNames.helper||"myio-daterange-helper";helperEl.setAttribute("aria-live","polite");helperEl.style.display="flex";helperEl.style.alignItems="center"}wrapper.appendChild(inputEl);if(helperEl){wrapper.appendChild(helperEl)}const existingWrapper=container.querySelector('[data-myio-component="daterange-input"]');if(existingWrapper){console.warn(`[createInputDateRangePickerInsideDIV] Replacing existing daterange input in container '#${containerId}'`);existingWrapper.remove()}container.appendChild(wrapper);const enhancedOptions={maxRangeDays:31,onApply:result=>{if(helperEl){const startDate=new Date(result.startISO);const endDate=new Date(result.endISO);const days=Math.ceil((endDate.getTime()-startDate.getTime())/(1e3*60*60*24))+1;helperEl.textContent=`Período selecionado: ${days} dia${days!==1?"s":""}`;helperEl.className=(classNames.helper||"myio-daterange-helper")+" success";setTimeout(()=>{if(helperEl){helperEl.className=classNames.helper||"myio-daterange-helper"}},3e3)}if(pickerOptions.onApply){pickerOptions.onApply(result)}},...pickerOptions};let picker;try{picker=await createDateRangePicker2(inputEl,enhancedOptions);console.log(`[createInputDateRangePickerInsideDIV] Successfully initialized for input '#${inputId}'`)}catch(error){wrapper.remove();throw new Error(`[createInputDateRangePickerInsideDIV] Failed to initialize date picker: ${error.message}`)}const controller={input:inputEl,container:container,wrapper:wrapper,picker:picker,getDisplayValue:()=>inputEl.value,getDates:()=>picker.getDates(),setDates:(startISO,endISO)=>{try{picker.setDates(startISO,endISO)}catch(error){console.error(`[createInputDateRangePickerInsideDIV] Error setting dates:`,error);throw error}},setHelperText:(text,type="default")=>{if(helperEl){helperEl.textContent=text;const baseClass=classNames.helper||"myio-daterange-helper";helperEl.className=type==="default"?baseClass:`${baseClass} ${type}`}},destroy:()=>{try{picker.destroy();console.log(`[createInputDateRangePickerInsideDIV] Date picker destroyed for input '#${inputId}'`)}catch(error){console.warn(`[createInputDateRangePickerInsideDIV] Error destroying picker:`,error)}try{wrapper.remove();console.log(`[createInputDateRangePickerInsideDIV] Wrapper removed for input '#${inputId}'`)}catch(error){console.warn(`[createInputDateRangePickerInsideDIV] Error removing wrapper:`,error)}}};return controller}var DEFAULT_STYLES={primaryColor:"#4A148C",accentColor:"#EDE7F3",dangerColor:"#f44336",infoColor:"#2196F3",textPrimary:"#212121",textSecondary:"#757575",backgroundColor:"#ffffff",overlayColor:"rgba(0, 0, 0, 0.5)",borderRadius:"8px",buttonRadius:"6px",pillRadius:"20px",zIndex:1e4,spacingXs:"4px",spacingSm:"8px",spacingMd:"16px",spacingLg:"24px",spacingXl:"32px",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',fontSizeXs:"12px",fontSizeSm:"14px",fontSizeMd:"16px",fontSizeLg:"18px",fontSizeXl:"20px",fontWeight:"400",fontWeightBold:"600"};var CHART_JS_CDN="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js";var ZOOM_PLUGIN_CDN="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom@2.0.1/dist/chartjs-plugin-zoom.min.js";var JSPDF_VERSION="2.5.1";var JSPDF_CDN=`https://cdnjs.cloudflare.com/ajax/libs/jspdf/${JSPDF_VERSION}/jspdf.umd.min.js`;var chartJsLoaded=false;var zoomPluginLoaded=false;var jsPdfLoaded=false;var _jspdfPromise=null;var cssInjected=false;var STRINGS={"pt-BR":{title:"Demanda",period:"Período",maximum:"Máxima",at:"no dia",atTime:"ás",timeUnit:"hs",exportPdf:"Exportar PDF",fullscreen:"Tela cheia",close:"Fechar",resetZoom:"Reset Zoom",loading:"Carregando dados...",noData:"Sem pontos de demanda no período selecionado",error:"Erro ao carregar dados",zoomHelp:"Scroll: zoom | Drag: selecionar | Ctrl+Drag: mover",demand:"Demanda (kW)",reportTitle:"Relatório de Demanda",reportFooter:"MyIO Energy Management System"},"en-US":{title:"Demand",period:"Period",maximum:"Maximum",at:"on",atTime:"at",timeUnit:"",exportPdf:"Export PDF",fullscreen:"Fullscreen",close:"Close",resetZoom:"Reset Zoom",loading:"Loading data...",noData:"No demand points in the selected period",error:"Error loading data",zoomHelp:"Scroll: zoom | Drag: select | Ctrl+Drag: pan",demand:"Demand (kW)",reportTitle:"Demand Report",reportFooter:"MyIO Energy Management System"}};async function loadScript(url,checkGlobal){return new Promise((resolve,reject)=>{if(window[checkGlobal]){resolve();return}const existingScript=document.querySelector(`script[src="${url}"]`);if(existingScript){existingScript.addEventListener("load",()=>{if(window[checkGlobal]){resolve()}else{reject(new Error(`Library ${checkGlobal} not available after loading ${url}`))}});existingScript.addEventListener("error",()=>reject(new Error(`Failed to load ${url}`)));return}const script=document.createElement("script");script.src=url;script.onload=()=>{if(window[checkGlobal]){resolve()}else{reject(new Error(`Library ${checkGlobal} not available after loading ${url}`))}};script.onerror=()=>reject(new Error(`Failed to load ${url}`));document.head.appendChild(script)})}async function loadExternalLibraries(){try{if(!chartJsLoaded){await loadScript(CHART_JS_CDN,"Chart");chartJsLoaded=true}if(!zoomPluginLoaded){await loadScript(ZOOM_PLUGIN_CDN,"ChartZoom");zoomPluginLoaded=true}if(!jsPdfLoaded){await ensureJsPDF();jsPdfLoaded=true}}catch(error){throw new Error(`Failed to load external libraries: ${error}`)}}function ensureJsPDF(){if(window.jspdf?.jsPDF){console.info("jsPDF already loaded.");return Promise.resolve()}if(_jspdfPromise){console.info("jsPDF loading already in progress.");return _jspdfPromise}_jspdfPromise=new Promise((resolve,reject)=>{const existing=document.querySelector('script[data-lib="jspdf"]');if(existing){existing.addEventListener("load",()=>{if(window.jspdf?.jsPDF){console.info("jsPDF loaded via existing script.");resolve()}else{reject(new Error("jsPDF loaded but window.jspdf.jsPDF missing"))}});existing.addEventListener("error",()=>reject(new Error("Failed to load jsPDF via existing script")));return}const s=document.createElement("script");s.src=JSPDF_CDN;s.async=true;s.defer=true;s.dataset.lib="jspdf";s.onload=()=>{if(window.jspdf?.jsPDF){console.info("jsPDF loaded successfully.");resolve()}else{reject(new Error("jsPDF loaded but window.jspdf.jsPDF missing"))}};s.onerror=()=>reject(new Error("Failed to load jsPDF from CDN"));document.head.appendChild(s)}).finally(()=>{_jspdfPromise=null});return _jspdfPromise}function getJsPDFCtor(){if(window.jspdf?.jsPDF)return window.jspdf.jsPDF;if(window.jsPDF?.jsPDF)return window.jsPDF.jsPDF;if(window.jsPDF)return window.jsPDF;throw new Error("jsPDF constructor not found on window")}function savePdfSafe(doc,filename){try{doc.save(filename)}catch(e){console.warn("doc.save() failed, attempting Blob URL fallback:",e);const blob=doc.output("blob");const url=URL.createObjectURL(blob);window.open(url,"_blank")||alert("Pop-up blocked. Allow pop-ups to download the PDF.");setTimeout(()=>URL.revokeObjectURL(url),3e4)}}function addCanvasToPdf(doc,canvas,x=10,y=20,maxWmm=190){const img=canvas.toDataURL("image/png",1);const pageWmm=doc.internal.pageSize.getWidth();const mmW=Math.min(maxWmm,pageWmm-x*2);const mmH=canvas.height/canvas.width*mmW;doc.addImage(img,"PNG",x,y,mmW,mmH,void 0,"FAST");return y+mmH}function ensureRoom(doc,nextY,minRoom=40){const h=doc.internal.pageSize.getHeight();if(nextY+minRoom>h){doc.addPage();return 20}return nextY}function injectCSS(styles){if(cssInjected)return;const css=`\n .myio-demand-modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: ${styles.overlayColor};\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${styles.zIndex};\n font-family: ${styles.fontFamily};\n font-size: ${styles.fontSizeMd};\n color: ${styles.textPrimary};\n }\n\n .myio-demand-modal-card {\n background: ${styles.backgroundColor};\n border-radius: ${styles.borderRadius};\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 90vw;\n max-height: 90vh;\n width: 800px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .myio-demand-modal-card.fullscreen {\n width: 100vw;\n height: 100vh;\n max-width: 100vw;\n max-height: 100vh;\n border-radius: 0;\n }\n\n .myio-demand-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: ${styles.spacingMd};\n background: #4A148C;\n color: white;\n }\n\n .myio-demand-modal-title-section {\n display: flex;\n align-items: center;\n gap: ${styles.spacingSm};\n }\n\n .myio-demand-modal-icon {\n font-size: ${styles.fontSizeLg};\n }\n\n .myio-demand-modal-title {\n margin: 0;\n font-size: ${styles.fontSizeLg};\n font-weight: ${styles.fontWeightBold};\n }\n\n .myio-demand-modal-actions {\n display: flex;\n gap: ${styles.spacingSm};\n }\n\n .myio-demand-modal-btn {\n background: rgba(255, 255, 255, 0.2);\n border: 1px solid rgba(255, 255, 255, 0.3);\n color: white;\n padding: ${styles.spacingSm} ${styles.spacingMd};\n border-radius: ${styles.buttonRadius};\n cursor: pointer;\n font-size: ${styles.fontSizeSm};\n font-family: inherit;\n transition: background-color 0.2s;\n }\n\n .myio-demand-modal-btn:hover {\n background: rgba(255, 255, 255, 0.3);\n }\n\n .myio-demand-modal-btn:focus {\n outline: 2px solid white;\n outline-offset: 2px;\n }\n\n .myio-demand-modal-btn-close {\n font-size: ${styles.fontSizeLg};\n padding: ${styles.spacingSm};\n min-width: 32px;\n background: ${styles.dangerColor} !important;\n }\n\n .myio-demand-modal-btn-close:hover {\n background: #d32f2f !important;\n }\n\n .myio-demand-modal-period {\n padding: ${styles.spacingMd} ${styles.spacingLg};\n background: #f5f5f5;\n font-size: ${styles.fontSizeSm};\n color: ${styles.textSecondary};\n border-bottom: 1px solid #e0e0e0;\n }\n\n .myio-demand-modal-peak {\n margin: ${styles.spacingMd} ${styles.spacingLg} 0;\n padding: ${styles.spacingSm} ${styles.spacingMd};\n background: ${styles.accentColor};\n color: #333;\n border-radius: ${styles.pillRadius};\n font-size: ${styles.fontSizeSm};\n font-weight: ${styles.fontWeightBold};\n display: inline-block;\n width: fit-content;\n }\n\n .myio-demand-modal-content {\n flex: 1;\n padding: ${styles.spacingLg};\n display: flex;\n flex-direction: column;\n min-height: 400px;\n }\n\n .myio-demand-modal-chart-container {\n flex: 1;\n position: relative;\n min-height: 300px;\n }\n\n .myio-demand-modal-chart {\n width: 100% !important;\n height: 100% !important;\n }\n\n .myio-demand-modal-zoom-controls {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: ${styles.spacingMd};\n padding-top: ${styles.spacingMd};\n border-top: 1px solid #e0e0e0;\n }\n\n .myio-demand-modal-btn-reset {\n background: ${styles.infoColor};\n border: none;\n color: white;\n padding: ${styles.spacingSm} ${styles.spacingMd};\n border-radius: ${styles.buttonRadius};\n cursor: pointer;\n font-size: ${styles.fontSizeSm};\n font-family: inherit;\n }\n\n .myio-demand-modal-btn-reset:hover {\n background: #1976D2;\n }\n\n .myio-demand-modal-zoom-help {\n font-size: ${styles.fontSizeXs};\n color: ${styles.textSecondary};\n }\n\n .myio-demand-modal-loading,\n .myio-demand-modal-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: ${styles.spacingXl};\n text-align: center;\n }\n\n .myio-demand-modal-spinner {\n font-size: 2rem;\n animation: spin 1s linear infinite;\n margin-bottom: ${styles.spacingMd};\n }\n\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n .myio-demand-modal-loading-text {\n color: ${styles.textSecondary};\n }\n\n .myio-demand-modal-error-icon {\n font-size: 2rem;\n color: ${styles.dangerColor};\n margin-bottom: ${styles.spacingMd};\n }\n\n .myio-demand-modal-error-text {\n color: ${styles.dangerColor};\n }\n\n /* Responsive design */\n @media (max-width: 768px) {\n .myio-demand-modal-card {\n width: 95vw;\n height: 90vh;\n max-height: 90vh;\n }\n\n .myio-demand-modal-header {\n padding: ${styles.spacingMd};\n }\n\n .myio-demand-modal-title {\n font-size: ${styles.fontSizeMd};\n }\n\n .myio-demand-modal-actions {\n gap: ${styles.spacingXs};\n }\n\n .myio-demand-modal-btn {\n padding: ${styles.spacingXs} ${styles.spacingSm};\n font-size: ${styles.fontSizeXs};\n }\n\n .myio-demand-modal-content {\n padding: ${styles.spacingMd};\n }\n }\n `;const style=document.createElement("style");style.textContent=css;document.head.appendChild(style);cssInjected=true}function formatDate(date,locale){return date.toLocaleDateString(locale,{day:"2-digit",month:"2-digit",year:"numeric"})}function formatDateTime(date,locale){return date.toLocaleDateString(locale,{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"})}async function fetchTelemetryData(token,deviceId,startDate,endDate,queryParams){const startTs=new Date(startDate).getTime();const endTs=new Date(endDate).getTime();const keys=queryParams?.keys||"consumption";const limit=queryParams?.limit||5e4;const intervalType=queryParams?.intervalType||"MILLISECONDS";const interval=queryParams?.interval||54e6;const agg=queryParams?.agg||"SUM";const orderBy=queryParams?.orderBy||"ASC";const url=`/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=${keys}&startTs=${startTs}&endTs=${endTs}&limit=${limit}&intervalType=${intervalType}&interval=${interval}&agg=${agg}&orderBy=${orderBy}`;const response=await fetch(url,{headers:{"X-Authorization":`Bearer ${token}`,"Content-Type":"application/json"}});if(!response.ok){throw new Error(`HTTP ${response.status}: ${response.statusText}`)}const data=await response.json();return data}function processMultiSeriesChartData(rawData,keys,correctionFactor,locale){const seriesKeys=keys.split(",").map(k=>k.trim());const seriesData=[];let globalPeak=null;let isEmpty=true;const colors=["#4A148C","#2196F3","#4CAF50","#FF9800","#F44336","#9C27B0","#795548","#607D8B"];seriesKeys.forEach((key,index)=>{const rawSeries=rawData[key]||[];if(rawSeries.length===0){seriesData.push({key:key,label:key,points:[],peak:null,color:colors[index%colors.length]});return}isEmpty=false;const sortedData=rawSeries.sort((a,b)=>a.ts-b.ts);const points=[];let previousValue=0;let previousTs=0;for(let i=0;i<sortedData.length;i++){const current=sortedData[i];const currentValue=parseFloat(current.value);const currentTs=current.ts;if(i>0){const deltaWh=currentValue-previousValue;const deltaHours=(currentTs-previousTs)/(1e3*60*60);if(deltaWh>0&&deltaHours>0){const demandKw=deltaWh/1e3/deltaHours*correctionFactor;points.push({x:currentTs,y:demandKw})}}previousValue=currentValue;previousTs=currentTs}let seriesPeak=null;if(points.length>0){const maxPoint=points.reduce((max,point)=>point.y>max.y?point:max);seriesPeak={value:maxPoint.y,timestamp:maxPoint.x,formattedValue:maxPoint.y.toFixed(2),formattedTime:formatDateTime(new Date(maxPoint.x),locale),key:key};if(!globalPeak||seriesPeak.value>globalPeak.value){globalPeak=seriesPeak}}seriesData.push({key:key,label:key,points:points,peak:seriesPeak,color:colors[index%colors.length]})});return{series:seriesData,globalPeak:globalPeak,isEmpty:isEmpty}}function createFocusTrap(container){const focusableElements=container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');const firstElement=focusableElements[0];const lastElement=focusableElements[focusableElements.length-1];function handleTabKey(e){if(e.key!=="Tab")return;if(e.shiftKey){if(document.activeElement===firstElement){lastElement.focus();e.preventDefault()}}else{if(document.activeElement===lastElement){firstElement.focus();e.preventDefault()}}}container.addEventListener("keydown",handleTabKey);firstElement?.focus();return()=>{container.removeEventListener("keydown",handleTabKey)}}async function openDemandModal(params){if(!params.token||!params.deviceId||!params.startDate||!params.endDate){throw new Error("Missing required parameters: token, deviceId, startDate, endDate")}const styles={...DEFAULT_STYLES,...params.styles};const locale=params.locale||"pt-BR";const strings=STRINGS[locale]||STRINGS["pt-BR"];await loadExternalLibraries();injectCSS(styles);const container=typeof params.container==="string"?document.querySelector(params.container):params.container||document.body;if(!container){throw new Error("Container element not found")}const overlay=document.createElement("div");overlay.className="myio-demand-modal-overlay";overlay.setAttribute("role","dialog");overlay.setAttribute("aria-modal","true");overlay.setAttribute("aria-labelledby","modal-title");const label=params.label||"Dispositivo";const startDateFormatted=formatDate(new Date(params.startDate),locale);const endDateFormatted=formatDate(new Date(params.endDate),locale);overlay.innerHTML=`\n <div class="myio-demand-modal-card">\n <div class="myio-demand-modal-header">\n <div class="myio-demand-modal-title-section">\n <span class="myio-demand-modal-icon">⚡</span>\n <h2 id="modal-title" class="myio-demand-modal-title">${strings.title} – ${label}</h2>\n </div>\n <div class="myio-demand-modal-actions">\n <button class="myio-demand-modal-btn myio-demand-modal-btn-pdf" type="button">\n ${strings.exportPdf}\n </button>\n <button class="myio-demand-modal-btn myio-demand-modal-btn-fullscreen" type="button" aria-label="${strings.fullscreen}">\n ⛶\n </button>\n <button class="myio-demand-modal-btn myio-demand-modal-btn-close" type="button" aria-label="${strings.close}">\n ×\n </button>\n </div>\n </div>\n \n <div class="myio-demand-modal-period">\n ${strings.period}: ${startDateFormatted} → ${endDateFormatted}\n </div>\n \n <div class="myio-demand-modal-peak" style="display: none;"></div>\n \n <div class="myio-demand-modal-content">\n <div class="myio-demand-modal-chart-container">\n <canvas class="myio-demand-modal-chart"></canvas>\n </div>\n \n <div class="myio-demand-modal-zoom-controls">\n <button class="myio-demand-modal-btn-reset" type="button">\n ${strings.resetZoom}\n </button>\n <div class="myio-demand-modal-zoom-help">\n <small>${strings.zoomHelp}</small>\n </div>\n </div>\n </div>\n \n <div class="myio-demand-modal-loading">\n <div class="myio-demand-modal-spinner">⧗</div>\n <div class="myio-demand-modal-loading-text">${strings.loading}</div>\n </div>\n \n <div class="myio-demand-modal-error" style="display: none;">\n <div class="myio-demand-modal-error-icon">⚠</div>\n <div class="myio-demand-modal-error-text"></div>\n </div>\n </div>\n `;container.appendChild(overlay);const card=overlay.querySelector(".myio-demand-modal-card");const closeBtn=overlay.querySelector(".myio-demand-modal-btn-close");const fullscreenBtn=overlay.querySelector(".myio-demand-modal-btn-fullscreen");const pdfBtn=overlay.querySelector(".myio-demand-modal-btn-pdf");const resetBtn=overlay.querySelector(".myio-demand-modal-btn-reset");const chartCanvas=overlay.querySelector(".myio-demand-modal-chart");const loadingEl=overlay.querySelector(".myio-demand-modal-loading");const errorEl=overlay.querySelector(".myio-demand-modal-error");const errorText=overlay.querySelector(".myio-demand-modal-error-text");const peakEl=overlay.querySelector(".myio-demand-modal-peak");const contentEl=overlay.querySelector(".myio-demand-modal-content");let chart=null;let chartData=null;let isFullscreen=false;const originalOverflow=document.body.style.overflow;document.body.style.overflow="hidden";const releaseFocusTrap=createFocusTrap(overlay);function closeModal(){if(chart){chart.destroy()}overlay.remove();document.body.style.overflow=originalOverflow;releaseFocusTrap();params.onClose?.()}function toggleFullscreen(){isFullscreen=!isFullscreen;card.classList.toggle("fullscreen",isFullscreen);if(chart){setTimeout(()=>chart.resize(),100)}}function resetZoom(){if(chart){chart.resetZoom()}}async function exportPdf(){if(!chartData||!chart){alert("Nenhum dado disponível para exportar");return}const btn=pdfBtn;const originalHtml=btn.innerHTML;btn.disabled=true;btn.innerHTML="<span>⏳</span> Gerando PDF...";try{await ensureJsPDF();await(document.fonts?.ready?.catch(e=>console.warn("Font loading interrupted or failed:",e)));const JsPDF=getJsPDFCtor();const doc=new JsPDF("p","mm","a4");doc.setFontSize(20);doc.setTextColor(74,20,140);doc.text(strings.reportTitle,20,20);doc.setFontSize(14);doc.setTextColor(0,0,0);const label2=params.label||"Dispositivo";doc.text(`${strings.title} - ${label2}`,20,35);const startDate=formatDate(new Date(params.startDate),params.locale||"pt-BR");const endDate=formatDate(new Date(params.endDate),params.locale||"pt-BR");doc.text(`${strings.period}: ${startDate} - ${endDate}`,20,45);let currentY=55;if(chartData.globalPeak){const peak=chartData.globalPeak;doc.setFontSize(12);doc.setTextColor(255,152,0);doc.text(`${strings.maximum}: ${peak.formattedValue} kW ${peak.key?`(${peak.key}) `:""}${strings.at} ${peak.formattedTime}`,20,currentY);currentY+=10}currentY=ensureRoom(doc,currentY,120);currentY=addCanvasToPdf(doc,chartCanvas,20,currentY);currentY+=10;if(chartData.series.length>0&&chartData.series[0].points.length>0){currentY=ensureRoom(doc,currentY,60);doc.setFontSize(12);doc.setTextColor(0,0,0);doc.text("Amostra de Dados:",20,currentY);currentY+=10;const samplePoints=chartData.series[0].points.slice(0,10);doc.setFontSize(10);doc.text("Data/Hora",20,currentY);doc.text(params.yAxisLabel||strings.demand,100,currentY);currentY+=7;samplePoints.forEach(point=>{currentY=ensureRoom(doc,currentY,10);const dateStr=formatDateTime(new Date(point.x),params.locale||"pt-BR");doc.text(dateStr,20,currentY);doc.text(point.y.toFixed(2),100,currentY);currentY+=7})}currentY=ensureRoom(doc,currentY,20);doc.setFontSize(8);doc.setTextColor(128,128,128);doc.text(`${strings.reportFooter}`,20,doc.internal.pageSize.getHeight()-15);doc.text(`Gerado em: ${(new Date).toLocaleString(params.locale||"pt-BR")}`,20,doc.internal.pageSize.getHeight()-10);const fileName=params.pdf?.fileName||`demanda_${label2.replace(/\s+/g,"_")}_${(new Date).toISOString().slice(0,10)}.pdf`;savePdfSafe(doc,fileName)}catch(error){console.error("[PDF Export] Error:",error);alert("Erro ao gerar PDF. Por favor, tente novamente. Verifique o console para mais detalhes.")}finally{btn.disabled=false;btn.innerHTML=originalHtml}}closeBtn.addEventListener("click",closeModal);fullscreenBtn.addEventListener("click",toggleFullscreen);resetBtn.addEventListener("click",resetZoom);pdfBtn.addEventListener("click",exportPdf);overlay.addEventListener("click",e=>{if(e.target===overlay){closeModal()}});overlay.addEventListener("keydown",e=>{if(e.key==="Escape"){closeModal()}});async function loadData(){try{loadingEl.style.display="flex";contentEl.style.display="none";errorEl.style.display="none";const startDateObj=new Date(params.startDate);const endDateObj=new Date(params.endDate);const diffTime=Math.abs(endDateObj.getTime()-startDateObj.getTime());const diffDays=Math.ceil(diffTime/(1e3*60*60*24));if(diffDays>30){loadingEl.style.display="none";errorEl.style.display="flex";errorText.textContent="O Limite de busca é de 30 dias de intervalo.";return}const rawData=params.fetcher?await params.fetcher({token:params.token,deviceId:params.deviceId,startDate:params.startDate,endDate:params.endDate,telemetryQuery:params.telemetryQuery}):await fetchTelemetryData(params.token,params.deviceId,params.startDate,params.endDate,params.telemetryQuery);chartData=processMultiSeriesChartData(rawData,params.telemetryQuery?.keys||"consumption",params.correctionFactor||1,locale);if(chartData.isEmpty){errorEl.style.display="flex";errorText.textContent=strings.noData;return}if(chartData.globalPeak){const peak=chartData.globalPeak;const date=new Date(peak.timestamp);const dateStr=date.toLocaleDateString(locale,{day:"2-digit",month:"2-digit",year:"numeric"});const timeStr=date.toLocaleTimeString(locale,{hour:"2-digit",minute:"2-digit"});peakEl.textContent=`${strings.maximum}: ${peak.formattedValue} kW ${peak.key?`(${peak.key}) `:""}${strings.at} ${dateStr} ${strings.atTime} ${timeStr}${strings.timeUnit}`;peakEl.style.display="block"}const Chart=window.Chart;Chart.register(window.ChartZoom);chart=new Chart(chartCanvas,{type:"line",data:{datasets:chartData.series.map(series=>({label:series.label,data:series.points,borderColor:series.color,backgroundColor:series.color+"20",fill:false,tension:.4,pointRadius:2,pointHoverRadius:6}))},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:chartData.series.length>1,position:"top"},zoom:{zoom:{wheel:{enabled:true},pinch:{enabled:true},drag:{enabled:true,modifierKey:"ctrl"},mode:"x"},pan:{enabled:true,mode:"x",modifierKey:"ctrl"}}},scales:{x:{type:"linear",position:"bottom",title:{display:true,text:"Tempo"},ticks:{callback:function(value){const date=new Date(value);return date.toLocaleDateString(locale,{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}}},y:{title:{display:true,text:params.yAxisLabel||strings.demand},beginAtZero:true}},interaction:{intersect:false,mode:"index"}}});loadingEl.style.display="none";contentEl.style.display="flex"}catch(error){console.error("Error loading demand data:",error);loadingEl.style.display="none";errorEl.style.display="flex";errorText.textContent=`${strings.error}: ${error instanceof Error?error.message:"Unknown error"}`}}loadData();return{destroy:closeModal}}exports.MyIOChartModal=MyIOChartModal;exports.MyIODraggableCard=MyIODraggableCard;exports.MyIOSelectionStore=MyIOSelectionStore;exports.MyIOSelectionStoreClass=MyIOSelectionStoreClass;exports.addDetectionContext=addDetectionContext;exports.addNamespace=addNamespace;exports.averageByDay=averageByDay;exports.buildWaterReportCSV=buildWaterReportCSV;exports.buildWaterStoresCSV=buildWaterStoresCSV;exports.calcDeltaPercent=calcDeltaPercent;exports.classify=classify;exports.classifyWaterLabel=classifyWaterLabel;exports.classifyWaterLabels=classifyWaterLabels;exports.createDateRangePicker=createDateRangePicker2;exports.createInputDateRangePickerInsideDIV=createInputDateRangePickerInsideDIV;exports.decodePayload=decodePayload;exports.decodePayloadBase64Xor=decodePayloadBase64Xor;exports.detectDeviceType=detectDeviceType;exports.determineInterval=determineInterval;exports.exportToCSV=exportToCSV;exports.exportToCSVAll=exportToCSVAll;exports.findValue=findValue;exports.fmtPerc=fmtPerc;exports.fmtPercLegacy=fmtPerc2;exports.formatAllInSameUnit=formatAllInSameUnit;exports.formatAllInSameWaterUnit=formatAllInSameWaterUnit;exports.formatDateForInput=formatDateForInput;exports.formatDateToYMD=formatDateToYMD;exports.formatDateWithTimezoneOffset=formatDateWithTimezoneOffset;exports.formatEnergy=formatEnergy;exports.formatNumberReadable=formatNumberReadable;exports.formatTankHeadFromCm=formatTankHeadFromCm;exports.formatWaterByGroup=formatWaterByGroup;exports.formatWaterVolumeM3=formatWaterVolumeM3;exports.getAvailableContexts=getAvailableContexts;exports.getDateRangeArray=getDateRangeArray;exports.getSaoPauloISOString=getSaoPauloISOString;exports.getSaoPauloISOStringFixed=getSaoPauloISOStringFixed;exports.getValueByDatakey=getValueByDatakey;exports.getValueByDatakeyLegacy=getValueByDatakeyLegacy;exports.getWaterCategories=getWaterCategories;exports.groupByDay=groupByDay;exports.isWaterCategory=isWaterCategory;exports.normalizeRecipients=normalizeRecipients;exports.numbers=numbers_exports;exports.openDashboardPopup=openDashboardPopup;exports.openDashboardPopupAllReport=openDashboardPopupAllReport;exports.openDashboardPopupEnergy=openDashboardPopupEnergy;exports.openDashboardPopupReport=openDashboardPopupReport;exports.openDashboardPopupSettings=openDashboardPopupSettings;exports.openDemandModal=openDemandModal;exports.parseInputDateToDate=parseInputDateToDate;exports.renderCardCompenteHeadOffice=renderCardCompenteHeadOffice;exports.renderCardComponent=renderCardComponent;exports.renderCardComponentEnhanced=renderCardComponent2;exports.renderCardComponentLegacy=renderCardComponentLegacy;exports.renderCardComponentV2=renderCardComponentV2;exports.strings=strings_exports;exports.timeWindowFromInputYMD=timeWindowFromInputYMD;exports.toCSV=toCSV;exports.toFixedSafe=toFixedSafe});
1
+ (function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?factory(exports):typeof define==="function"&&define.amd?define(["exports"],factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,factory(global.MyIOLibrary={}))})(this,function(exports){"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __esm=(fn,res)=>function __init(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var template_card_exports={};__export(template_card_exports,{renderCardComponent:()=>renderCardComponent});function renderCardComponent({entityObject:entityObject,handleActionDashboard:handleActionDashboard,handleActionReport:handleActionReport,handleActionSettings:handleActionSettings,handleSelect:handleSelect,handInfo:handInfo,handleClickCard:handleClickCard}){const{entityId:entityId,labelOrName:labelOrName,deviceIdentifier:deviceIdentifier,entityType:entityType,deviceType:deviceType,slaveId:slaveId,ingestionId:ingestionId,val:val,centralId:centralId,updatedIdentifiers:updatedIdentifiers={},perc:perc=0,connectionStatus:connectionStatus,centralName:centralName,connectionStatusTime:connectionStatusTime,timaVal:timaVal,valType:valType}=entityObject;const DeviceStatus={CONNECTED:"connected",OFFLINE:"offline",POWER_ON:"power_on",STANDBY:"standby",POWER_OFF:"power_off",WARNING:"warning",DANGER:"danger",MAINTENANCE:"maintenance"};const statusIcons={[DeviceStatus.CONNECTED]:"✅",[DeviceStatus.OFFLINE]:"🔌",[DeviceStatus.POWER_ON]:"⚡",[DeviceStatus.STANDBY]:"⏸️",[DeviceStatus.POWER_OFF]:"⏹️",[DeviceStatus.WARNING]:"⚠️",[DeviceStatus.DANGER]:"🚨",[DeviceStatus.MAINTENANCE]:"🛠️"};const isOfflineOrDanger=connectionStatus===DeviceStatus.OFFLINE||connectionStatus===DeviceStatus.DANGER;const shouldFlashIcon=connectionStatus===DeviceStatus.OFFLINE||connectionStatus===DeviceStatus.WARNING||connectionStatus===DeviceStatus.DANGER||connectionStatus===DeviceStatus.MAINTENANCE;const icon=statusIcons[connectionStatus]||statusIcons[DeviceStatus.POWER_ON];const MyIO=typeof MyIOLibrary!=="undefined"&&MyIOLibrary||typeof window!=="undefined"&&window.MyIOLibrary||{formatEnergy:(v,g)=>`${v} kWh`,formatNumberReadable:n=>Number(n??0).toFixed(1)};let valFormatted=MyIO.formatEnergy(val);if(valType==="ENERGY"){valFormatted=MyIO.formatEnergy(val)}else if(valType==="WATER"){valFormatted=`${val} m³`}else if(valType==="TANK"){valFormatted=`${val} m.c.a`}else{valFormatted=val}const percFormatted=MyIO.formatNumberReadable(perc);if(!document.getElementById("myio-card-styles")){const style=document.createElement("style");style.id="myio-card-styles";style.textContent=` \n.device-card-centered,\n.clickable {\n width: 100%;\n border-radius: 10px;\n padding: 8px 12px;\n background: #fff;\n box-shadow: 0 4px 10px rgba(0, 0, 0, .05);\n /* display: flex; REMOVIDO */\n /* align-items: center; REMOVIDO */\n /* justify-content: center; REMOVIDO */\n cursor: pointer;\n transition: transform .2s;\n /* min-height: 140px; REMOVIDO (movido para .device-card-inner) */\n box-sizing: border-box;\n overflow: hidden;\n}\n\n.device-card-centered:hover,\n.clickable:hover {\n transform: scale(1.05);\n}\n\n.device-title-row {\n width: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-bottom: 4px;\n padding: 0 4px;\n min-height: 22px;\n}\n\n.device-title {\n font-weight: 700;\n font-size: .85rem;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 90%;\n line-height: 1.1;\n}\n\n.device-subtitle {\n font-size: 0.7rem; \n font-weight: 500;\n color: #888; /* Cinza */\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 90%;\n line-height: 1.1;\n margin-top: 2px;\n}\n\n.device-image {\n max-height: 44px;\n width: auto;\n margin: 4px 0;\n display: block;\n}\n\n.device-data-row {\n display: flex;\n justify-content: center;\n align-items: center;\n margin-top: auto;\n margin-bottom: 6px;\n gap: 6px;\n width: 100%;\n}\n\n.consumption-main {\n font-size: .9rem;\n font-weight: 700;\n color: #28a745;\n display: flex;\n align-items: center;\n gap: 6px;\n justify-content: center;\n white-space: nowrap;\n}\n\n.device-title-percent {\n font-size: .75rem;\n color: rgba(0, 0, 0, .45);\n font-weight: 500;\n}\n\n.flash {\n animation: flash 1s infinite;\n color: #ff9800;\n}\n\n@keyframes flash {\n 0% { opacity: 1; }\n 50% { opacity: .2; }\n 100% { opacity: 1; }\n}\n\n.card-actions {\n flex-shrink: 0;\n height: 100%;\n box-shadow: 1px 0 2px rgba(0, 0, 0, .1);\n display: flex;\n flex-direction: column;\n padding: 0 4px;\n justify-content: space-around;\n align-items: center;\n}\n\n.card-action img {\n width: 24px;\n height: 24px;\n transition: transform .2s ease;\n cursor: pointer;\n}\n\n.card-action img:hover {\n transform: scale(1.15);\n}\n\n.device-card-centered.offline {\n border: 2px solid #ff4d4f;\n animation: border-blink 1s infinite;\n}\n\n.device-card-centered.flipped .device-card-inner {\n transform: rotateY(180deg);\n}\n\n@keyframes border-blink {\n 0%, 100% { box-shadow: 0 0 8px rgba(255, 77, 79, 0.9); }\n 50% { box-shadow: 0 0 16px rgba(255, 0, 0, 0.6); }\n}\n\n.device-card-centered.offline .flash-icon {\n color: #ff4d4f !important;\n font-size: 1.2rem;\n} \n.device-card-centered {\n perspective: 1000px;\n}\n\n.device-card-inner {\n position: relative;\n width: 100%;\n height: 100%;\n transform-style: preserve-3d;\n min-height: 140px; /* ATUALIZADO: A altura mínima agora é controlada aqui */\n}\n\n.device-card-front {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: flex-start; /* Agora isso vai funcionar */\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n backface-visibility: hidden;\n gap: 4px;\n}\n\n.device-card-back {\n transform: rotateY(180deg);\n}\n\n.device-card-front .device-info,\n.device-card-back .device-info {\n position: absolute;\n top: 8px;\n right: 12px;\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 4px;\n border-radius: 50%;\n cursor: pointer;\n z-index: 10;\n background: none;\n border: none;\n transition: background 0.2s;\n}\n.device-card-front .device-info:hover,\n.device-card-back .device-info:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n\n.device-card-back {\n display: flex;\n flex-direction: column;\n justify-content: space-around; /* Mantido para preencher o verso */\n align-items: stretch;\n padding: 10px;\n gap: 5px;\n height: 100%;\n width: 100%;\n box-sizing: border-box;\n \n /* Posições para o flip */\n position: absolute;\n top: 0;\n left: 0;\n backface-visibility: hidden;\n transform: rotateY(180deg);\n}\n\n.device-card-back #status-bar {\n position: relative;\n width: 100%;\n padding-top: 10px;\n}\n\n.device-card-back .value-container {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 5px;\n color: #c19efc;\n align-self: center;\n}\n\n.device-card-back #lastconsumptionTime {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n font-size: 11px;\n font-weight: bold;\n color: black;\n width: 100%;\n padding-bottom: 10px;\n}\n\n\n.device-card-centered.flipped .device-card-inner {\n transform: rotateY(180deg);\n}\n\n.flash-icon.flash {\n animation: icon-blink 1s infinite;\n}\n\n@keyframes icon-blink {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.2; transform: scale(1.2); }\n}\n\n.device-card-centered.offline .flash-icon {\n color: #ff4d4f !important;\n}\n\n.device-card-centered.online .flash-icon {\n color: #28a745 !important;\n}\n `;document.head.appendChild(style)}let formattedDateVal;let formattedDate;let Infcolor="#5cb85c";if(connectionStatusTime){const date=new Date(connectionStatusTime);const day=String(date.getDate()).padStart(2,"0");const month=String(date.getMonth()+1).padStart(2,"0");const year=date.getFullYear();const hours=String(date.getHours()).padStart(2,"0");const minutes=String(date.getMinutes()).padStart(2,"0");formattedDate=`Online: (${day}/${month}/${year} - ${hours}:${minutes})`;const datVal=new Date(timaVal);const dayVal=String(datVal.getDate()).padStart(2,"0");const monthVal=String(datVal.getMonth()+1).padStart(2,"0");const yearVal=date.getFullYear();const hoursVal=String(date.getHours()).padStart(2,"0");const minutesVal=String(date.getMinutes()).padStart(2,"0");const now=new Date;const diffMs=now-datVal;const diffMinutes=Math.floor(diffMs/(1e3*60));const diffHours=Math.floor(diffMs/(1e3*60*60));const diffDays=Math.floor(diffMs/(1e3*60*60*24));let diffText="";if(diffMinutes<60){diffText=`${diffMinutes} minuto${diffMinutes!==1?"s":""}`}else if(diffHours<24){diffText=`${diffHours} hora${diffHours!==1?"s":""}`}else{diffText=`${diffDays} dia${diffDays!==1?"s":""} `}formattedDateVal=`${dayVal}/${monthVal}/${yearVal} - ${hoursVal}:${minutesVal} (${diffText})`;if(diffHours>=24){Infcolor="#cc2900"}else if(diffMinutes>=30){Infcolor="#e89105"}}else{Infcolor="#d6dcdd"}function normalizeString(str){if(typeof str!=="string"){str=""}return str.normalize("NFD").replace(/[\u0300-\u036f]/g,"").toUpperCase()}const deviceImages={MOTOR:"https://dashboard.myio-bas.com/api/images/public/8Ezn8qVBJ3jXD0iDfnEAZ0MZhAP1b5Ts","3F_MEDIDOR":"https://dashboard.myio-bas.com/api/images/public/f9Ce4meybsdaAhAkUlAfy5ei3I4kcN4k",RELOGIO:"https://dashboard.myio-bas.com/api/images/public/ljHZostWg0G5AfKiyM8oZixWRIIGRASB",HIDROMETRO:"https://dashboard.myio-bas.com/api/images/public/aMQYFJbGHs9gQbQkMn6XseAlUZHanBR4",ENTRADA:"https://dashboard.myio-bas.com/api/images/public/TQHPFqiejMW6lOSVsb8Pi85WtC0QKOLU",CAIXA_DAGUA:"https://dashboard.myio-bas.com/api/images/public/3t6WVhMQJFsrKA8bSZmrngDsNPkZV7fq"};const defaultImage="https://cdn-icons-png.flaticon.com/512/1178/1178428.png";const nameType=normalizeString(deviceType);const img=deviceImages[nameType]||defaultImage;const html=`\n <div class="device-card-centered clickable ${isOfflineOrDanger?"offline":""}"\n data-entity-id="${entityId}"\n data-entity-label="${labelOrName}"\n data-entity-type="${entityType}"\n data-entity-slaveid="${slaveId}"\n data-entity-ingestionid="${ingestionId}"\n data-entity-consumption="${val}"\n data-entity-centralid="${centralId}"\n data-entity-updated-identifiers='${JSON.stringify(updatedIdentifiers)}'>\n <div class="device-card-inner" style="width:100%; height:100%; transform-style: preserve-3d; transition: transform 0.6s;">\n <div class="device-card-front">\n\n <div class="card-actions" >\n ${typeof handleActionDashboard==="function"?`\n <div class="card-action action-dashboard" data-action="dashboard" title="Dashboard">\n <img src="https://dashboard.myio-bas.com/api/images/public/TAVXE0sTbCZylwGsMF9lIWdllBB3iFtS"/>\n </div>`:``}\n ${typeof handleActionReport==="function"?`\n <div class="card-action action-report" data-action="report" title="Relatório">\n <img src="https://dashboard.myio-bas.com/api/images/public/d9XuQwMYQCG2otvtNSlqUHGavGaSSpz4"/>\n </div>`:``}\n ${typeof handleActionSettings==="function"?`\n <div class="card-action action-settings" data-action="settings" title="Configurações">\n <img src="https://dashboard.myio-bas.com/api/images/public/5n9tze6vED2uwIs5VvJxGzNNZ9eV4yoz"/>\n </div>`:``}\n ${typeof handleSelect==="function"?`\n <input class="card-action action-checker" data-action="checker" title="Selecionar" type="checkbox">`:``}\n </div>\n\n <div style="display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%; flex-grow: 1; min-width: 0; padding: 0 12px;">\n \n <div class="device-title-row" style="flex-direction: column; min-height: 38px;">\n <span class="device-title" title="${labelOrName}">\n ${String(labelOrName??"").length>15?String(labelOrName).slice(0,15)+"…":String(labelOrName??"")}\n </span>\n ${deviceIdentifier?`\n <span class="device-subtitle" title="${deviceIdentifier}">\n ${deviceIdentifier}\n </span>\n `:""}\n </div>\n\n <img class="device-image" src="${img}" />\n <div class="device-data-row">\n <div class="consumption-main">\n \n <span class="flash-icon ${shouldFlashIcon?"flash":""}">\n ${icon}\n </span>\n\n <span class="consumption-value" data-entity-consumption="${val}">${valFormatted}</span>\n <span class="device-title-percent">(${percFormatted}%)</span>\n </div>\n </div>\n </div>\n \n ${handInfo?`\n <button id="infoButtom-front" class="device-info info-button">\n <svg xmlns="http://www.w3.org/2000/svg" height="17px" viewBox="0 -960 960 960" width="17px" fill=${Infcolor}>\n <path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/>\n </svg>\n </button>`:``}\n </div>\n <div class="device-card-back" >\n <div id="status-bar"> \n <div id="status-information">\n <div style="font-size: 0.85rem; font-weight: bold; line-height: 1;"><span>Central: ${centralName}</span></div>\n <div style="display: flex; flex-direction: row; gap: 4px; font-weight: bold; align-items: center;">\n <div style="font-size: 12px; font-weight: bold; line-height: 1;"><span> ${formattedDate}</span></div>\n <div style="font-size: 10px; line-height: 1;"><span></span></div> \n </div>\n </div>\n <button id="infoButtom-back" class="device-info" style="background:none; border:none; cursor:pointer;">\n <svg xmlns="http://www.w3.org/2000/svg" height="17px" viewBox="0 -960 960 960" width="17px" fill=${Infcolor}>\n <path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/>\n </svg>\n </button>\n </div>\n\n <div class="value-container">\n <svg xmlns="http://www.w3.org/2000/svg" height="30px" viewBox="0 -960 960 960" width="30px" fill="#dea404">\n <path d="m456-200 174-340H510v-220L330-420h126v220Zm24 120q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/>\n </svg>\n <div><span>${MyIO.formatEnergy(val/1e3)||"-"}</span></div>\n </div>\n\n <div id="lastconsumptionTime">\n <div style="font-size: 12px; font-weight: bold; color: black; line-height: 1;">Ultima Telemetria:</div>\n <div style="font-size: 11px; font-weight: bold; color: black; line-height: 1;">${formattedDateVal}</div>\n </div>\n </div>\n </div>\n </div> \n </div>\n \n `;const $card=$(html);if(typeof handleActionDashboard==="function"){$card.find(".action-dashboard").on("click",e=>{e.stopPropagation();handleActionDashboard(entityObject)})}if(typeof handleActionReport==="function"){$card.find(".action-report").on("click",e=>{e.stopPropagation();handleActionReport(entityObject)})}if(typeof handleActionSettings==="function"){$card.find(".action-settings").on("click",e=>{e.stopPropagation();handleActionSettings(entityObject)})}if(typeof handleSelect==="function"){$card.find(".action-checker").on("click",e=>{e.stopPropagation();handleSelect(entityObject)})}if(typeof handleClickCard==="function"){$card.find(".action-checker").on("click",e=>{e.stopPropagation();handleClickCard(entityObject)})}$card.on("click",e=>{if(!$(e.target).closest(".card-action").length){if(typeof handleClickCard==="function"){handleClickCard(entityObject)}else if(typeof handleActionDashboard==="function"){handleActionDashboard(entityObject)}}});$card.find("#infoButtom-front").on("click",function(e){e.stopPropagation();$(this).closest(".device-card-centered").addClass("flipped")});$card.find("#infoButtom-back").on("click",function(e){e.stopPropagation();$(this).closest(".device-card-centered").removeClass("flipped")});return $card}var init_template_card=__esm({"src/thingsboard/main-dashboard-shopping/v-4.0.0/card/template-card.js"(){}});function formatEnergy(value,unit){if(value===null||value===void 0||isNaN(value)){return"-"}let adjustedValue=value;let adjustedUnit=unit;if(!adjustedUnit){if(value>=1e6){adjustedValue=value/1e6;adjustedUnit="GWh"}else if(value>=1e3){adjustedValue=value/1e3;adjustedUnit="MWh"}else{adjustedUnit="kWh"}}const formattedValue=adjustedValue.toLocaleString("pt-BR",{minimumFractionDigits:2,maximumFractionDigits:2});return`${formattedValue} ${adjustedUnit}`}function formatAllInSameUnit(values,targetUnit,sourceUnit="kWh"){const unitMultipliers={kWh:1,MWh:1e3,GWh:1e6};const targetMultiplier=unitMultipliers[targetUnit]||1;if(typeof values[0]==="number"){const numberValues=values;const sourceMultiplier=unitMultipliers[sourceUnit]||1;return numberValues.map(value=>{if(value===null||value===void 0||isNaN(value)){return"-"}const convertedValue=value*sourceMultiplier/targetMultiplier;return formatEnergy(convertedValue,targetUnit)})}const objectValues=values;return objectValues.map(item=>{if(item.value===null||item.value===void 0||isNaN(item.value)){return"-"}const sourceMultiplier=unitMultipliers[item.unit]||1;const convertedValue=item.value*sourceMultiplier/targetMultiplier;return formatEnergy(convertedValue,targetUnit)})}function fmtPerc(value){if(value===null||value===void 0||isNaN(value)||!isFinite(value)){return"-"}const percentage=value*100;return percentage.toLocaleString("pt-BR",{minimumFractionDigits:2,maximumFractionDigits:2})+"%"}function formatNumberReadable(value,locale="pt-BR",minimumFractionDigits=2,maximumFractionDigits=2){const n=typeof value==="string"?Number(value.replace(",",".")):Number(value);if(!Number.isFinite(n)){return"-"}const safe=Object.is(n,-0)?0:n;return safe.toLocaleString(locale,{minimumFractionDigits:minimumFractionDigits,maximumFractionDigits:maximumFractionDigits})}function formatWaterVolumeM3(value,locale="pt-BR"){if(value===null||value===void 0||isNaN(value)){return"-"}const formattedValue=value.toLocaleString(locale,{minimumFractionDigits:2,maximumFractionDigits:2});return`${formattedValue} M³`}function formatTankHeadFromCm(valueCm,locale="pt-BR"){if(valueCm===null||valueCm===void 0||isNaN(valueCm)){return"-"}const valueMeters=valueCm/100;const formattedValue=valueMeters.toLocaleString(locale,{minimumFractionDigits:2,maximumFractionDigits:2});return`${formattedValue} m.c.a.`}function calcDeltaPercent(prev,current){if(prev===null||prev===void 0||isNaN(prev)||current===null||current===void 0||isNaN(current)){return{value:0,type:"neutral"}}if(prev===0&&current===0){return{value:0,type:"neutral"}}if(prev===0&&current>0){return{value:100,type:"increase"}}if(prev===0&&current<0){return{value:100,type:"decrease"}}const percentChange=(current-prev)/prev*100;if(percentChange>0){return{value:percentChange,type:"increase"}}else if(percentChange<0){return{value:Math.abs(percentChange),type:"decrease"}}else{return{value:0,type:"neutral"}}}function formatWaterByGroup(value,group){if(value===null||value===void 0||isNaN(value)){return"-"}if(group==="Caixas D'Água"){return formatTankHeadFromCm(value)}if(value>=1e3){return formatWaterVolumeM3(value/1e3)+" x 10³ "}return formatWaterVolumeM3(value)}function formatAllInSameWaterUnit(values){const max=Math.max(...values.filter(v=>!isNaN(v)&&v!==null&&v!==void 0));let divisor=1;let unit="M³";if(max>=1e6){divisor=1e6;unit="M³"}else if(max>=1e3){divisor=1e3;unit="M³"}return{format:val=>{if(val===null||val===void 0||isNaN(val)){return"-"}return(val/divisor).toFixed(2)+" "+unit},unit:unit}}function formatDateToYMD(date){if(!date){return""}const dateObj=new Date(date);if(isNaN(dateObj.getTime())){return""}const year=dateObj.getFullYear();const month=String(dateObj.getMonth()+1).padStart(2,"0");const day=String(dateObj.getDate()).padStart(2,"0");return`${year}-${month}-${day}`}function determineInterval(startDate,endDate){const start=new Date(startDate);const end=new Date(endDate);if(isNaN(start.getTime())||isNaN(end.getTime())){return"day"}const diffMs=end.getTime()-start.getTime();const diffDays=diffMs/(1e3*60*60*24);if(diffDays<=1){return"hour"}else if(diffDays<=7){return"day"}else if(diffDays<=31){return"week"}else if(diffDays<=365){return"month"}else{return"year"}}function getSaoPauloISOString(date,edge="start"){const dateObj=new Date(date);if(isNaN(dateObj.getTime())){return""}const saoPauloOffset=-3;const saoPauloDate=new Date(dateObj.getTime()+saoPauloOffset*60*60*1e3);if(edge==="start"){saoPauloDate.setHours(0,0,0,0)}else{saoPauloDate.setHours(23,59,59,999)}const utcDate=new Date(saoPauloDate.getTime()-saoPauloOffset*60*60*1e3);return utcDate.toISOString()}function getDateRangeArray(startDate,endDate,interval="day"){const start=new Date(startDate);const end=new Date(endDate);const dates=[];if(isNaN(start.getTime())||isNaN(end.getTime())||start>end){return dates}const current=new Date(start);while(current<=end){dates.push(new Date(current));switch(interval){case"day":current.setDate(current.getDate()+1);break;case"week":current.setDate(current.getDate()+7);break;case"month":current.setMonth(current.getMonth()+1);break;case"year":current.setFullYear(current.getFullYear()+1);break;default:current.setDate(current.getDate()+1)}}return dates}function formatDateForInput(date){if(!date||isNaN(date.getTime())){return""}const year=date.getFullYear();const month=String(date.getMonth()+1).padStart(2,"0");const day=String(date.getDate()).padStart(2,"0");return`${year}-${month}-${day}`}function parseInputDateToDate(inputDateStr){if(!inputDateStr){return null}const parts=inputDateStr.split("-");if(parts.length!==3){return null}const year=parseInt(parts[0],10);const month=parseInt(parts[1],10)-1;const day=parseInt(parts[2],10);if(isNaN(year)||isNaN(month)||isNaN(day)){return null}return new Date(year,month,day,0,0,0,0)}function timeWindowFromInputYMD(startYmd,endYmd,tzOffset="-03:00"){if(!startYmd||!endYmd){return{startTs:0,endTs:0}}const startParts=startYmd.split("-");const endParts=endYmd.split("-");if(startParts.length!==3||endParts.length!==3){return{startTs:0,endTs:0}}const startDate=new Date(parseInt(startParts[0],10),parseInt(startParts[1],10)-1,parseInt(startParts[2],10),0,0,0,0);const endDate=new Date(parseInt(endParts[0],10),parseInt(endParts[1],10)-1,parseInt(endParts[2],10),23,59,59,999);return{startTs:startDate.getTime(),endTs:endDate.getTime()}}function formatDateWithTimezoneOffset(date,endOfDay=false,tzOffset="-03:00"){if(!date||isNaN(date.getTime())){return""}const year=date.getFullYear();const month=String(date.getMonth()+1).padStart(2,"0");const day=String(date.getDate()).padStart(2,"0");let hours,minutes,seconds,milliseconds;if(endOfDay){hours="23";minutes="59";seconds="59";milliseconds="999"}else{hours=String(date.getHours()).padStart(2,"0");minutes=String(date.getMinutes()).padStart(2,"0");seconds=String(date.getSeconds()).padStart(2,"0");milliseconds=String(date.getMilliseconds()).padStart(3,"0")}return`${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${tzOffset}`}function getSaoPauloISOStringFixed(dateStr,endOfDay=false){if(!dateStr)return"";if(endOfDay){return`${dateStr}T23:59:59.999-03:00`}else{return`${dateStr}T00:00:00.000-03:00`}}function averageByDay(data){if(!data||data.length===0){return[]}const grouped={};data.forEach(item=>{if(!item||item.value===null||item.value===void 0||isNaN(item.value)){return}const date=new Date(item.ts);if(isNaN(date.getTime())){return}const day=date.toISOString().split("T")[0];if(!grouped[day]){grouped[day]=[]}grouped[day].push(Number(item.value))});const result=Object.entries(grouped).map(([day,values])=>{const sum=values.reduce((acc,val)=>acc+val,0);const average=sum/values.length;return{day:day,average:average}});result.sort((a,b)=>a.day.localeCompare(b.day));return result}function groupByDay(data){if(!data||data.length===0){return{}}const grouped={};data.forEach(item=>{if(!item||item.value===null||item.value===void 0||isNaN(item.value)){return}const date=new Date(item.ts);if(isNaN(date.getTime())){return}const day=date.toISOString().split("T")[0];if(!grouped[day]){grouped[day]=[]}grouped[day].push(Number(item.value))});return grouped}function exportToCSV(data,headers,filename){if(!data||data.length===0){return""}const csvHeaders=headers.join(",");const csvRows=data.map(row=>headers.map(header=>{const value=row[header];if(value===null||value===void 0){return""}const stringValue=String(value);if(stringValue.includes(",")||stringValue.includes('"')||stringValue.includes("\n")){return`"${stringValue.replace(/"/g,'""')}"`}return stringValue}).join(","));const csvContent=[csvHeaders,...csvRows].join("\n");return csvContent}function exportToCSVAll(storesData,headers,filename){if(!storesData||Object.keys(storesData).length===0){return""}const csvRows=[];const csvHeaders=["Store",...headers].join(",");csvRows.push(csvHeaders);Object.entries(storesData).forEach(([storeName,storeData])=>{if(!storeData||storeData.length===0){return}storeData.forEach(row=>{let formattedStoreName=storeName;if(storeName.includes(",")||storeName.includes('"')||storeName.includes("\n")){formattedStoreName=`"${storeName.replace(/"/g,'""')}"`}const csvRow=[formattedStoreName,...headers.map(header=>{const value=row[header];if(value===null||value===void 0){return""}const stringValue=String(value);if(stringValue.includes(",")||stringValue.includes('"')||stringValue.includes("\n")){return`"${stringValue.replace(/"/g,'""')}"`}return stringValue})].join(",");csvRows.push(csvRow)})});return csvRows.join("\n")}function buildWaterReportCSV(rows,meta){if(!rows||rows.length===0){return""}const csvRows=[];let totalConsumption=0;rows.forEach(row=>{const consumptionStr=String(row.totalConsumption).replace(",",".");const consumption=Number(consumptionStr)||0;totalConsumption+=consumption});const finalTotal=meta.total!==void 0?meta.total:totalConsumption;csvRows.push(["DATA EMISSÃO",meta.issueDate]);csvRows.push(["Total",finalTotal.toFixed(2)]);if(meta.name&&meta.identifier){csvRows.push(["Loja:",meta.name,meta.identifier])}csvRows.push(["Data","Dia da Semana","Consumo Médio (m³)","Consumo Mínimo (m³)","Consumo Máximo (m³)","Consumo (m³)"]);rows.forEach(row=>{csvRows.push([row.formattedDate,row.day,String(row.avgConsumption),String(row.minDemand),String(row.maxDemand),String(row.totalConsumption)])});return csvRows.map(row=>row.join(";")).join("\n")}function buildWaterStoresCSV(rows,meta){if(!rows||rows.length===0){return""}const csvRows=[];let totalConsumption=0;rows.forEach(row=>{const consumption=row.consumptionM3!==void 0?row.consumptionM3:row.consumptionKwh||0;totalConsumption+=consumption});const finalTotal=meta.total!==void 0?meta.total:totalConsumption;csvRows.push(["DATA EMISSÃO",meta.issueDate]);csvRows.push(["Total",finalTotal.toFixed(2)]);csvRows.push(["Loja","Identificador","Consumo"]);rows.forEach(row=>{const label=row.entityLabel||row.deviceName||"-";const deviceId=row.deviceId||"-";const consumption=row.consumptionM3!==void 0?row.consumptionM3:row.consumptionKwh||0;const formattedConsumption=consumption!==null&&consumption!==void 0?formatNumberReadable(consumption):"0,00";csvRows.push([label,deviceId,formattedConsumption])});return csvRows.map(row=>row.join(";")).join("\n")}function toCSV(rows,delimiter=";"){if(!rows||rows.length===0){return""}return rows.map(row=>row.map(cell=>{const value=String(cell);if(value.includes(delimiter)||value.includes('"')||value.includes("\n")){return`"${value.replace(/"/g,'""')}"`}return value}).join(delimiter)).join("\n")}function classify(entity,criteria){if(!entity||!criteria){return{category:"unknown",confidence:0}}let category="unknown";let subcategory;let confidence=0;if(entity.type){switch(entity.type.toLowerCase()){case"consumption":category="energy_consumption";confidence=.9;break;case"generation":category="energy_generation";confidence=.9;break;case"storage":category="energy_storage";confidence=.9;break;case"distribution":category="energy_distribution";confidence=.8;break;default:category="energy_other";confidence=.5}}if(entity.powerRating){const power=parseFloat(entity.powerRating);if(!isNaN(power)){if(power<1e3){subcategory="small_scale"}else if(power<1e4){subcategory="medium_scale"}else{subcategory="large_scale"}confidence=Math.min(confidence+.1,1)}}return{category:category,subcategory:subcategory,confidence:confidence}}function classifyWaterLabel(label){if(!label){console.warn('classifyWaterLabel: empty label, defaulting to "Lojas"');return"Lojas"}const normalizedLabel=label.toLowerCase().trim();if(/rel[óo]gio|caixa|superior|inferior|nível_terraço/.test(normalizedLabel)){return"Caixas D'Água"}if(/administra|bomba|chiller|adm/.test(normalizedLabel)){return"Área Comum"}return"Lojas"}function classifyWaterLabels(labels){const counts={"Caixas D'Água":0,Lojas:0,"Área Comum":0,total:0};labels.forEach(label=>{const category=classifyWaterLabel(label);counts[category]++;counts.total++});return counts}function getWaterCategories(){return["Caixas D'Água","Lojas","Área Comum"]}function isWaterCategory(label,category){return classifyWaterLabel(label)===category}function getValueByDatakey(data,datakey){if(!data||!datakey){return void 0}if(Array.isArray(data)){for(const item of data){const value=getValueByDatakey(item,datakey);if(value!==void 0){return value}}return void 0}if(typeof data==="object"&&data!==null){const keys=datakey.split(".");let current=data;for(const key of keys){if(current===null||current===void 0){return void 0}if(key.includes("[")&&key.includes("]")){const arrayKey=key.substring(0,key.indexOf("["));const indexMatch=key.match(/\[(\d+)\]/);if(indexMatch){const index=parseInt(indexMatch[1],10);current=current[arrayKey];if(Array.isArray(current)&&index>=0&&index<current.length){current=current[index]}else{return void 0}}else{return void 0}}else{current=current[key]}}return current}return void 0}function getValueByDatakeyLegacy(dataList,dataSourceNameTarget,dataKeyTarget){if(!Array.isArray(dataList)||!dataSourceNameTarget||!dataKeyTarget){return void 0}for(const item of dataList){if(item&&item.dataSourceName===dataSourceNameTarget&&item.dataKey===dataKeyTarget){return item.value}}return void 0}function findValue(data,keyOrPath,legacyDataKey){if(legacyDataKey!==void 0){return getValueByDatakeyLegacy(data,keyOrPath,legacyDataKey)}return getValueByDatakey(data,keyOrPath)}function normalize(str){if(typeof str!=="string")return"";let normalized=str.toUpperCase().trim();normalized=normalized.replace(/[ÀÁÂÃÄÅ]/g,"A").replace(/[ÈÉÊË]/g,"E").replace(/[ÌÍÎÏ]/g,"I").replace(/[ÒÓÔÕÖ]/g,"O").replace(/[ÙÚÛÜ]/g,"U").replace(/[Ç]/g,"C").replace(/[Ñ]/g,"N");normalized=normalized.replace(/\s+/g," ");return normalized}function matchCaixaDAgua(normalizedStr){if(normalizedStr.includes("SCD"))return true;const caixaVariants=["CAIXA D'AGUA","CAIXA D AGUA","CAIXA_D_AGUA","CAIXA DAGUA"];return caixaVariants.some(variant=>normalizedStr.includes(variant))}var contexts={building:name=>{const normalized=normalize(name);const rules=[{test:s=>s.includes("COMPRESSOR"),type:"COMPRESSOR"},{test:s=>s.includes("VENT"),type:"VENTILADOR"},{test:s=>s.includes("AUTOMATICO"),type:"SELETOR_AUTO_MANUAL"},{test:s=>s.includes("ESRL"),type:"ESCADA_ROLANTE"},{test:s=>s.includes("ESCADA"),type:"ESCADA_ROLANTE"},{test:s=>s.includes("ELEV"),type:"ELEVADOR"},{test:s=>s.includes("MOTR")||s.includes("RECALQUE"),type:"MOTOR"},{test:s=>s.includes("TERMOSTATO"),type:"TERMOSTATO"},{test:s=>s.includes("TERMO")||s.includes("TEMP"),type:"TERMOSTATO"},{test:s=>s.includes("3F"),type:"3F_MEDIDOR"},{test:s=>s.includes("HIDR"),type:"HIDROMETRO"},{test:s=>s.includes("ABRE"),type:"SOLENOIDE"},{test:s=>matchCaixaDAgua(s),type:"CAIXA_D_AGUA"},{test:s=>s.includes("AUTOMACAO")||s.includes("GW_AUTO"),type:"GLOBAL_AUTOMACAO"},{test:s=>s.includes("AC"),type:"CONTROLE REMOTO"}];for(const rule of rules){if(rule.test(normalized)){return rule.type}}return"default"},mall:name=>{const normalized=normalize(name);const rules=[{test:s=>s.includes("CHILLER"),type:"CHILLER"},{test:s=>s.includes("ESCADA"),type:"ESCADA_ROLANTE"},{test:s=>s.includes("LOJA"),type:"LOJA_SENSOR"},{test:s=>s.includes("ILUMINACAO"),type:"ILUMINACAO"}];for(const rule of rules){if(rule.test(normalized)){return rule.type}}return"default"}};var warnedContexts=new Set;function detectDeviceType(name,context="building"){if(typeof name!=="string"){throw new Error("Device name must be a string.")}const detectFunction=contexts[context];if(!detectFunction){if(!warnedContexts.has(context)){console.warn(`[myio-js-library] Context "${context}" not found. Using default fallback.`);warnedContexts.add(context)}return contexts.building(name)}return detectFunction(name)}function getAvailableContexts(){return Object.keys(contexts)}function addDetectionContext(contextName,detectFunction){if(typeof contextName!=="string"){throw new Error("Context name must be a string.")}if(typeof detectFunction!=="function"){throw new Error("Detection function must be a function.")}contexts[contextName]=detectFunction}function addNamespace(payload,namespace=""){if(!payload||typeof payload!=="object"||Array.isArray(payload)){throw new Error("Payload must be an object.")}const keys=Object.keys(payload);const suffix=namespace.trim()?` (${namespace.trim()})`:"";return keys.reduce((acc,key)=>{acc[`${key}${suffix}`]=payload[key];return acc},{})}var numbers_exports={};__export(numbers_exports,{fmtPerc:()=>fmtPerc2,toFixedSafe:()=>toFixedSafe});function fmtPerc2(x,digits=2){if(!Number.isFinite(x))return"—";return(x*100).toFixed(digits)+"%"}function toFixedSafe(x,digits=2){if(!Number.isFinite(x))return"—";return x.toFixed(digits)}var strings_exports={};__export(strings_exports,{normalizeRecipients:()=>normalizeRecipients});function normalizeRecipients(val){if(val===null||val===void 0||val==="")return"";if(Object.prototype.toString.call(val)==="[object Array]"){return val.filter(Boolean).join(",")}let s=String(val).trim();if(/^\s*\[/.test(s)){try{const arr=JSON.parse(s);if(Object.prototype.toString.call(arr)==="[object Array]"){return arr.filter(Boolean).join(",")}}catch{}}s=s.replace(/[;\s]+/g,",");s=s.replace(/,+/g,",").replace(/^,|,$/g,"");return s}function decodePayload(encoded,key){const bytes=base64ToBytesStrict(encoded);if(bytes.length===0)return"";if(key===""||key===void 0||key===null){return(new TextDecoder).decode(bytes)}if(typeof key==="number"&&Number.isFinite(key)){const k=key&255;for(let i=0;i<bytes.length;i++)bytes[i]^=k;return(new TextDecoder).decode(bytes)}const keyStr=String(key);const keyBytes=(new TextEncoder).encode(keyStr);if(keyBytes.length===0){return(new TextDecoder).decode(bytes)}for(let i=0;i<bytes.length;i++){bytes[i]^=keyBytes[i%keyBytes.length]}return(new TextDecoder).decode(bytes)}function decodePayloadBase64Xor(encoded,xorKey=73){const bytes=base64ToBytesStrict(encoded);for(let i=0;i<bytes.length;i++)bytes[i]^=xorKey&255;return(new TextDecoder).decode(bytes)}function base64ToBytesStrict(b64){if(b64===""||b64===void 0||b64===null)return new Uint8Array;const s=String(b64).replace(/\s+/g,"");const re=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;if(!re.test(s))throw new Error("Invalid base64");if(typeof Buffer!=="undefined"&&Buffer.from){return Uint8Array.from(Buffer.from(s,"base64"))}const bin=atob(s);const out=new Uint8Array(bin.length);for(let i=0;i<bin.length;i++)out[i]=bin.charCodeAt(i);return out}init_template_card();var MyIOSelectionStoreClass=class{constructor(){this.selectedIds=new Set;this.entities=new Map;this.eventListeners=new Map;this.analytics=null;this.timeSeriesCache=new Map;this.cacheExpiry=5*60*1e3;this.eventListeners.set("selection:change",[]);this.eventListeners.set("selection:totals",[]);this.eventListeners.set("comparison:open",[]);this.eventListeners.set("comparison:too_many",[])}add(id){if(typeof id!=="string"||!id.trim())return;const wasSelected=this.selectedIds.has(id);this.selectedIds.add(id);if(!wasSelected){this._emitSelectionChange("add",id);this._trackEvent("footer_dock.drop_add",{entityId:id})}}remove(id){if(typeof id!=="string"||!this.selectedIds.has(id))return;this.selectedIds.delete(id);this._emitSelectionChange("remove",id);this._trackEvent("footer_dock.remove_chip",{entityId:id})}toggle(id){if(this.isSelected(id)){this.remove(id)}else{this.add(id)}}clear(){if(this.selectedIds.size===0)return;this.selectedIds.clear();this._emitSelectionChange("clear");this._trackEvent("footer_dock.clear_all",{count:0})}syncFromCheckbox(id,checked){if(typeof id!=="string"||typeof checked!=="boolean")return;if(checked&&!this.isSelected(id)){this.add(id)}else if(!checked&&this.isSelected(id)){this.remove(id)}this._trackEvent("card.checkbox_toggle",{entityId:id,checked:checked})}registerEntity(entity){if(!entity||typeof entity!=="object"||!entity.id){throw new Error("Entity must be an object with an id property")}const normalizedEntity={id:entity.id,name:entity.name||"",icon:entity.icon||"generic",group:entity.group||"",lastValue:Number(entity.lastValue)||0,unit:entity.unit||"",status:entity.status||"unknown"};this.entities.set(entity.id,normalizedEntity)}unregisterEntity(id){if(typeof id!=="string")return;this.entities.delete(id);this.remove(id)}getSelectedIds(){return Array.from(this.selectedIds)}getSelectedEntities(){return this.getSelectedIds().map(id=>this.entities.get(id)).filter(entity=>entity!==void 0)}getTotals(){const selectedEntities=this.getSelectedEntities();const totals={energyKwh:0,waterM3:0,tempC:0,percentage:0,count:selectedEntities.length,unitBreakdown:{}};selectedEntities.forEach(entity=>{const value=entity.lastValue||0;const unit=entity.unit||"";if(!totals.unitBreakdown[unit]){totals.unitBreakdown[unit]=0}totals.unitBreakdown[unit]+=value;switch(unit.toLowerCase()){case"kwh":case"mwh":case"gwh":totals.energyKwh+=this._convertToKwh(value,unit);break;case"m³":case"m3":totals.waterM3+=value;break;case"°c":case"celsius":totals.tempC+=value;break;case"%":case"percent":totals.percentage+=value;break}});return totals}isSelected(id){return this.selectedIds.has(id)}getSelectionCount(){return this.selectedIds.size}getMultiUnitTotalDisplay(){const totals=this.getTotals();const parts=[];if(totals.energyKwh>0){parts.push(`Energy: ${this._formatNumber(totals.energyKwh)} kWh`)}if(totals.waterM3>0){parts.push(`Water: ${this._formatNumber(totals.waterM3)} m³`)}if(totals.tempC>0){parts.push(`Temp: ${this._formatNumber(totals.tempC)} °C`)}if(totals.percentage>0){parts.push(`${this._formatNumber(totals.percentage)}%`)}return parts.join(" | ")||"No selection"}on(event,callback){if(typeof event!=="string"||typeof callback!=="function")return;if(!this.eventListeners.has(event)){this.eventListeners.set(event,[])}this.eventListeners.get(event).push(callback)}off(event,callback){if(!this.eventListeners.has(event))return;const listeners=this.eventListeners.get(event);const index=listeners.indexOf(callback);if(index>-1){listeners.splice(index,1)}}async getTimeSeriesData(entityIds,startDate,endDate){if(!Array.isArray(entityIds)||entityIds.length===0){return{}}const cacheKey=`${entityIds.join(",")}_${startDate.getTime()}_${endDate.getTime()}`;const cached=this.timeSeriesCache.get(cacheKey);if(cached&&Date.now()-cached.timestamp<this.cacheExpiry){return cached.data}const mockData={};entityIds.forEach(id=>{mockData[id]=this._generateMockTimeSeriesData(startDate,endDate)});this.timeSeriesCache.set(cacheKey,{data:mockData,timestamp:Date.now()});return mockData}invalidateCache(reason="manual"){this.timeSeriesCache.clear();this._trackEvent("cache.invalidated",{reason:reason})}setAnalytics(analyticsInstance){if(!analyticsInstance||typeof analyticsInstance.track!=="function"){throw new Error("Analytics instance must have a track method")}this.analytics=analyticsInstance}trackEvent(eventName,payload={}){this._trackEvent(eventName,payload)}openComparison(){const count=this.getSelectionCount();if(count===0){this.announceToScreenReader("No items selected for comparison");return false}if(count>20){this._emit("comparison:too_many",{count:count,maxAllowed:20,selectedIds:this.getSelectedIds()});this._trackEvent("chart_modal.too_many_entities",{count:count});return false}const data={entities:this.getSelectedEntities(),totals:this.getTotals(),count:count};this._emit("comparison:open",data);this._trackEvent("chart_modal.open",{entityCount:count});return true}startDrag(id){if(typeof id!=="string")return;this._trackEvent("drag.start",{entityId:id})}announceToScreenReader(message){if(typeof message!=="string"||typeof document==="undefined")return;let announcer=document.getElementById("myio-sr-announcer");if(!announcer){announcer=document.createElement("div");announcer.id="myio-sr-announcer";announcer.setAttribute("aria-live","polite");announcer.setAttribute("aria-atomic","true");announcer.style.position="absolute";announcer.style.left="-10000px";announcer.style.width="1px";announcer.style.height="1px";announcer.style.overflow="hidden";document.body.appendChild(announcer)}announcer.textContent=message}_emitSelectionChange(action,id=null){const data={action:action,id:id,selectedIds:this.getSelectedIds(),totals:this.getTotals()};this._emit("selection:change",data);this._emit("selection:totals",data.totals);this._trackEvent("footer_dock.total_update",{action:action,count:data.selectedIds.length,totals:data.totals})}_emit(event,data){if(!this.eventListeners.has(event))return;this.eventListeners.get(event).forEach(callback=>{try{callback(data)}catch(error){console.error(`Error in ${event} listener:`,error)}})}_trackEvent(eventName,payload={}){if(!this.analytics)return;try{this.analytics.track(eventName,{timestamp:Date.now(),...payload})}catch(error){console.error("Analytics tracking error:",error)}}_convertToKwh(value,unit){switch(unit.toLowerCase()){case"mwh":return value*1e3;case"gwh":return value*1e6;case"kwh":default:return value}}_formatNumber(value){if(typeof value!=="number"||isNaN(value))return"0";return new Intl.NumberFormat("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2}).format(value)}_generateMockTimeSeriesData(startDate,endDate){const data=[];const current=new Date(startDate);const end=new Date(endDate);while(current<=end){data.push({timestamp:current.getTime(),value:Math.random()*100+50,unit:"kWh"});current.setHours(current.getHours()+1)}return data}};var MyIOSelectionStore=new MyIOSelectionStoreClass;if(typeof globalThis!=="undefined"&&typeof globalThis.window!=="undefined"){globalThis.window.MyIOSelectionStore=MyIOSelectionStore;globalThis.window.MyIOSelectionStoreClass=MyIOSelectionStoreClass}if(typeof module!=="undefined"&&module.exports){module.exports={MyIOSelectionStore:MyIOSelectionStore,MyIOSelectionStoreClass:MyIOSelectionStoreClass}}var MyIODraggableCard=class{constructor(container,entity,options={}){if(!container||!entity||!entity.id){throw new Error("Container and entity with id are required")}this.container=container;this.entity=entity;this.options={showCheckbox:true,draggable:true,className:"",...options};this.cardElement=null;this.checkbox=null;this.isDragging=false;this.touchStartTime=0;this.touchTimer=null;this.destroyed=false;this._init()}destroy(){if(this.destroyed)return;this._removeEventListeners();if(this.cardElement&&this.cardElement.parentNode){this.cardElement.parentNode.removeChild(this.cardElement)}this.destroyed=true}updateEntity(newEntity){if(this.destroyed)return;this.entity={...this.entity,...newEntity};this._updateCardContent()}setSelected(selected){if(this.destroyed)return;if(this.checkbox){this.checkbox.checked=selected}this._updateSelectionState(selected)}_init(){this._createCardElement();this._attachEventListeners();this._updateSelectionState(this._getSelectionStore()?.isSelected(this.entity.id)||false)}_createCardElement(){if(typeof document==="undefined")return;const card=document.createElement("div");card.className=`myio-draggable-card ${this.options.className}`.trim();card.setAttribute("data-entity-id",this.entity.id);card.setAttribute("role","article");card.setAttribute("tabindex","0");if(this.options.draggable){card.draggable=true;card.setAttribute("aria-grabbed","false")}card.innerHTML=this._generateCardHTML();this.cardElement=card;this.checkbox=card.querySelector(".card-checkbox");this.container.appendChild(card)}_generateCardHTML(){const{id:id,name:name,icon:icon,group:group,lastValue:lastValue,unit:unit,status:status}=this.entity;const checkboxHtml=this.options.showCheckbox?`<input type="checkbox" class="card-checkbox" aria-label="Select ${name}">`:"";return`\n <div class="card-header">\n ${checkboxHtml}\n <div class="card-icon card-icon-${icon}">\n ${this._getIconSvg(icon)}\n </div>\n <div class="card-status card-status-${status}"></div>\n </div>\n <div class="card-body">\n <h3 class="card-title">${this._escapeHtml(name)}</h3>\n <p class="card-group">${this._escapeHtml(group)}</p>\n <div class="card-value">\n <span class="value">${this._formatValue(lastValue)}</span>\n <span class="unit">${this._escapeHtml(unit)}</span>\n </div>\n </div>\n <div class="card-footer">\n <span class="card-id">${this._escapeHtml(id)}</span>\n </div>\n `}_attachEventListeners(){if(!this.cardElement)return;this.cardElement.addEventListener("dragstart",this._handleDragStart.bind(this));this.cardElement.addEventListener("dragend",this._handleDragEnd.bind(this));this.cardElement.addEventListener("click",this._handleClick.bind(this));this.cardElement.addEventListener("touchstart",this._handleTouchStart.bind(this),{passive:false});this.cardElement.addEventListener("touchmove",this._handleTouchMove.bind(this),{passive:false});this.cardElement.addEventListener("touchend",this._handleTouchEnd.bind(this));this.cardElement.addEventListener("keydown",this._handleKeyDown.bind(this));if(this.checkbox){this.checkbox.addEventListener("change",this._handleCheckboxChange.bind(this));this.checkbox.addEventListener("click",this._handleCheckboxClick.bind(this))}const store=this._getSelectionStore();if(store){this._selectionChangeHandler=data=>{const isSelected=data.selectedIds.includes(this.entity.id);this._updateSelectionState(isSelected)};store.on("selection:change",this._selectionChangeHandler)}}_removeEventListeners(){if(!this.cardElement)return;const store=this._getSelectionStore();if(store&&this._selectionChangeHandler){store.off("selection:change",this._selectionChangeHandler)}this._selectionChangeHandler=null}_handleDragStart(event){if(!this.options.draggable){event.preventDefault();return}this.isDragging=true;this.cardElement.setAttribute("aria-grabbed","true");this.cardElement.classList.add("dragging");event.dataTransfer.setData("text/myio-id",this.entity.id);event.dataTransfer.setData("text/plain",this.entity.id);event.dataTransfer.effectAllowed="copy";const store=this._getSelectionStore();if(store){store.startDrag(this.entity.id)}this._announceToScreenReader(`Started dragging ${this.entity.name}`)}_handleDragEnd(event){this.isDragging=false;this.cardElement.setAttribute("aria-grabbed","false");this.cardElement.classList.remove("dragging");this._announceToScreenReader(`Finished dragging ${this.entity.name}`)}_handleTouchStart(event){if(!this.options.draggable)return;this.touchStartTime=Date.now();this.touchTimer=setTimeout(()=>{this._startTouchDrag(event)},500)}_handleTouchMove(event){if(this.touchTimer){clearTimeout(this.touchTimer);this.touchTimer=null}if(this.isDragging){event.preventDefault()}}_handleTouchEnd(event){if(this.touchTimer){clearTimeout(this.touchTimer);this.touchTimer=null}if(this.isDragging){this._endTouchDrag(event)}}_startTouchDrag(event){if(!this.options.draggable)return;this.isDragging=true;this.cardElement.classList.add("touch-dragging");if(navigator.vibrate){navigator.vibrate(50)}this._announceToScreenReader(`Touch drag started for ${this.entity.name}`)}_endTouchDrag(event){this.isDragging=false;this.cardElement.classList.remove("touch-dragging");this._announceToScreenReader(`Touch drag ended for ${this.entity.name}`)}_handleClick(event){if(event.target===this.checkbox)return;if(this.isDragging)return;const store=this._getSelectionStore();if(store){store.toggle(this.entity.id)}}_handleKeyDown(event){switch(event.key){case"Enter":case" ":event.preventDefault();if(event.shiftKey){const store=this._getSelectionStore();if(store){store.openComparison()}}else{const store=this._getSelectionStore();if(store){store.toggle(this.entity.id)}}break;case"Delete":case"Backspace":{event.preventDefault();const store=this._getSelectionStore();if(store){store.remove(this.entity.id)}break}}}_handleCheckboxChange(event){event.stopPropagation();const store=this._getSelectionStore();if(store){store.syncFromCheckbox(this.entity.id,event.target.checked)}}_handleCheckboxClick(event){event.stopPropagation()}_updateSelectionState(isSelected){if(this.destroyed)return;if(this.checkbox){this.checkbox.checked=isSelected}this.cardElement.classList.toggle("selected",isSelected);this.cardElement.setAttribute("aria-selected",isSelected.toString());const action=isSelected?"selected":"not selected";this.cardElement.setAttribute("aria-label",`${this.entity.name}, ${this.entity.group}, ${action}`)}_updateCardContent(){if(this.destroyed)return;const titleElement=this.cardElement.querySelector(".card-title");const groupElement=this.cardElement.querySelector(".card-group");const valueElement=this.cardElement.querySelector(".value");const unitElement=this.cardElement.querySelector(".unit");const idElement=this.cardElement.querySelector(".card-id");if(titleElement)titleElement.textContent=this.entity.name||"";if(groupElement)groupElement.textContent=this.entity.group||"";if(valueElement)valueElement.textContent=this._formatValue(this.entity.lastValue);if(unitElement)unitElement.textContent=this.entity.unit||"";if(idElement)idElement.textContent=this.entity.id||"";const iconElement=this.cardElement.querySelector(".card-icon");const statusElement=this.cardElement.querySelector(".card-status");if(iconElement){iconElement.className=`card-icon card-icon-${this.entity.icon||"generic"}`;iconElement.innerHTML=this._getIconSvg(this.entity.icon||"generic")}if(statusElement){statusElement.className=`card-status card-status-${this.entity.status||"unknown"}`}}_getSelectionStore(){if(typeof globalThis!=="undefined"&&globalThis.window?.MyIOSelectionStore){return globalThis.window.MyIOSelectionStore}if(typeof globalThis!=="undefined"&&globalThis.window&&globalThis.window.MyIOSelectionStore){return globalThis.window.MyIOSelectionStore}return null}_formatValue(value){if(value===null||value===void 0||isNaN(value)){return"-"}return new Intl.NumberFormat("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2}).format(Number(value))}_escapeHtml(text){if(typeof text!=="string")return"";if(typeof document==="undefined")return text;const div=document.createElement("div");div.textContent=text;return div.innerHTML}_getIconSvg(iconType){const icons={energy:'<svg viewBox="0 0 24 24"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>',water:'<svg viewBox="0 0 24 24"><path d="M12 2c-5.33 4.55-8 8.48-8 11.8 0 4.98 3.8 8.2 8 8.2s8-3.22 8-8.2c0-3.32-2.67-7.25-8-11.8z"/></svg>',temp:'<svg viewBox="0 0 24 24"><path d="M15 13V5c0-1.66-1.34-3-3-3S9 3.34 9 5v8c-1.21.91-2 2.37-2 4 0 2.76 2.24 5 5 5s5-2.24 5-5c0-1.63-.79-3.09-2-4z"/></svg>',net:'<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/></svg>',alert:'<svg viewBox="0 0 24 24"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',generic:'<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>'};return icons[iconType]||icons.generic}_announceToScreenReader(message){const store=this._getSelectionStore();if(store&&store.announceToScreenReader){store.announceToScreenReader(message)}}};if(typeof globalThis!=="undefined"&&typeof globalThis.window!=="undefined"){globalThis.window.MyIODraggableCard=MyIODraggableCard}if(typeof module!=="undefined"&&module.exports){module.exports={MyIODraggableCard:MyIODraggableCard}}function renderCardComponentV2({entityObject:entityObject,handleActionDashboard:handleActionDashboard,handleActionReport:handleActionReport,handleActionSettings:handleActionSettings,handleSelect:handleSelect,handInfo:handInfo,handleClickCard:handleClickCard,useNewComponents:useNewComponents=true,enableSelection:enableSelection=true,enableDragDrop:enableDragDrop=true}){const{entityId:entityId,labelOrName:labelOrName,deviceIdentifier:deviceIdentifier,entityType:entityType,deviceType:deviceType,slaveId:slaveId,ingestionId:ingestionId,val:val,centralId:centralId,updatedIdentifiers:updatedIdentifiers={},perc:perc=0,deviceStatus:deviceStatus,centralName:centralName,connectionStatusTime:connectionStatusTime,timeVal:timeVal,valType:valType}=entityObject;const MyIOToast=function(){let toastContainer=null;let toastTimeout=null;const TOAST_CSS=`\n #myio-global-toast-container {\n position: fixed;\n top: 25px;\n right: 25px;\n z-index: 99999;\n width: 320px;\n padding: 16px;\n border-radius: 8px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n font-size: 15px;\n color: #fff;\n transform: translateX(120%);\n transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);\n border-left: 5px solid transparent;\n display: flex;\n align-items: center;\n }\n #myio-global-toast-container.show {\n transform: translateX(0);\n }\n #myio-global-toast-container.warning {\n background-color: #ff9800; /* Laranja para alerta */\n border-color: #f57c00;\n }\n #myio-global-toast-container.error {\n background-color: #d32f2f; /* Vermelho para erro */\n border-color: #b71c1c;\n }\n #myio-global-toast-container::before {\n content: '⚠️'; /* Ícone de alerta */\n margin-right: 12px;\n font-size: 20px;\n }\n #myio-global-toast-container.error::before {\n content: '🚫'; /* Ícone de erro */\n }\n `;function createToastElement(){if(document.getElementById("myio-global-toast-container")){toastContainer=document.getElementById("myio-global-toast-container");return}const style=document.createElement("style");style.id="myio-global-toast-styles";style.textContent=TOAST_CSS;document.head.appendChild(style);toastContainer=document.createElement("div");toastContainer.id="myio-global-toast-container";document.body.appendChild(toastContainer)}function show(message,type="warning",duration=3500){if(!toastContainer){createToastElement()}clearTimeout(toastTimeout);toastContainer.textContent=message;toastContainer.className="";toastContainer.classList.add(type);setTimeout(()=>{toastContainer.classList.add("show")},10);toastTimeout=setTimeout(()=>{toastContainer.classList.remove("show")},duration)}if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",createToastElement)}else{createToastElement()}return{show:show}}();if(!useNewComponents){return renderCardComponentLegacy({entityObject:entityObject,handleActionDashboard:handleActionDashboard,handleActionReport:handleActionReport,handleActionSettings:handleActionSettings,handleSelect:handleSelect,handInfo:handInfo,handleClickCard:handleClickCard})}const DeviceStatusType={POWER_ON:"power_on",STANDBY:"standby",POWER_OFF:"power_off",WARNING:"warning",DANGER:"danger",MAINTENANCE:"maintenance",NO_INFO:"no_info"};const connectionStatusType={CONNECTED:"connected",OFFLINE:"offline"};const mapDeviceToConnectionStatus=deviceStatus2=>{if(deviceStatus2===DeviceStatusType.NO_INFO){return connectionStatusType.OFFLINE}return connectionStatusType.CONNECTED};const connectionStatus=mapDeviceToConnectionStatus(deviceStatus);const deviceStatusIcons={[DeviceStatusType.POWER_ON]:"⚡",[DeviceStatusType.STANDBY]:"🔌",[DeviceStatusType.POWER_OFF]:"🔴",[DeviceStatusType.WARNING]:"⚠️",[DeviceStatusType.DANGER]:"🚨",[DeviceStatusType.MAINTENANCE]:"🛠️",[DeviceStatusType.NO_INFO]:"❓️"};const shouldFlashIcon=deviceStatus===DeviceStatusType.OFFLINE||deviceStatus===DeviceStatusType.WARNING||deviceStatus===DeviceStatusType.DANGER||deviceStatus===DeviceStatusType.MAINTENANCE;const icon=deviceStatusIcons[deviceStatus]||deviceStatusIcons[DeviceStatusType.POWER_ON];const mapDeviceStatus=status=>{const statusMap={power_on:"ok",standby:"alert",power_off:"fail",warning:"alert",danger:"fail",maintenance:"alert"};return statusMap[status]||"unknown"};const mapDeviceTypeToIcon=deviceType2=>{const typeMap={MOTOR:"energy","3F_MEDIDOR":"energy",RELOGIO:"energy",HIDROMETRO:"water",ENTRADA:"energy",CAIXA_DAGUA:"water",TANK:"water"};const normalizedType=deviceType2?.toUpperCase()||"";return typeMap[normalizedType]||"generic"};const isEnergyDevice=(valType2,deviceType2)=>{if(valType2==="ENERGY"){return true}const energyDeviceTypes=["MOTOR","3F_MEDIDOR","RELOGIO","ENTRADA"];const normalizedType=deviceType2?.toUpperCase()||"";return energyDeviceTypes.includes(normalizedType)};const formatCardValue=(value,valType2,deviceType2)=>{const numValue=Number(value)||0;if(isEnergyDevice(valType2,deviceType2)){return formatEnergy(numValue)}else{const unit=determineUnit(valType2);const formattedValue=numValue.toLocaleString("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2});return`${formattedValue} ${unit}`}};const determineUnit=(valType2,val2,deviceType2)=>{switch(valType2){case"ENERGY":return"";case"WATER":return"m³";case"TANK":return"m.c.a";default:return""}};const cardEntity={id:entityId,name:labelOrName||"Dispositivo",icon:mapDeviceTypeToIcon(deviceType),group:deviceIdentifier||entityType||"Dispositivo",lastValue:Number(val)||0,unit:determineUnit(valType),status:mapDeviceStatus(deviceStatus)};if(enableSelection&&MyIOSelectionStore){MyIOSelectionStore.registerEntity(cardEntity)}const container=document.createElement("div");container.className="myio-enhanced-card-container";if(!document.getElementById("myio-enhanced-card-styles")){const style=document.createElement("style");style.id="myio-enhanced-card-styles";style.textContent=`\n .myio-enhanced-card-container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .myio-enhanced-card-container .myio-draggable-card {\n width: 100%;\n border-radius: 10px;\n padding: 8px 12px; \n background: #fff;\n box-shadow: 0 4px 10px rgba(0, 0, 0, .05);\n cursor: pointer;\n \n transition: transform .2s;\n box-sizing: border-box;\n overflow: hidden;\n min-height: 140px;\n display: flex;\n flex-direction: row;\n align-items: stretch;\n }\n \n .myio-enhanced-card-container .myio-draggable-card:hover {\n transform: scale(1.05);\n }\n \n .myio-enhanced-card-container .myio-draggable-card.selected {\n border: 2px solid #00e09e;\n box-shadow: 0 4px 12px rgba(0,224,158,0.2);\n background: linear-gradient(135deg, #f0fdf9, #ecfdf5);\n }\n \n .myio-enhanced-card-container .myio-draggable-card.offline {\n border: 2px solid #ff4d4f;\n animation: border-blink 1s infinite;\n }\n \n @keyframes border-blink {\n 0%, 100% { box-shadow: 0 0 8px rgba(255, 77, 79, 0.9); }\n 50% { box-shadow: 0 0 16px rgba(255, 0, 0, 0.6); }\n }\n \n .myio-enhanced-card-container .card-actions {\n flex-shrink: 0;\n height: 100%;\n box-shadow: 1px 0 2px rgba(0, 0, 0, .1);\n display: flex;\n flex-direction: column;\n padding: 0 4px;\n justify-content: space-around;\n align-items: center;\n gap: 8px;\n }\n \n .myio-enhanced-card-container .card-action {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: all 0.2s ease;\n cursor: pointer;\n border: none;\n background: rgba(0, 0, 0, 0.05);\n }\n \n .myio-enhanced-card-container .card-action:hover {\n background: rgba(0, 224, 158, 0.1);\n transform: scale(1.1);\n }\n \n .myio-enhanced-card-container .card-action img {\n width: 20px;\n height: 20px;\n }\n \n .myio-enhanced-card-container .card-checkbox {\n width: 16px;\n height: 16px;\n cursor: pointer;\n }\n \n .myio-enhanced-card-container .card-body {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n padding: 0 12px;\n text-align: center;\n }\n \n .myio-enhanced-card-container .card-title {\n font-weight: 700;\n font-size: 0.85rem;\n margin-bottom: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n }\n \n .myio-enhanced-card-container .card-group {\n font-size: 0.7rem;\n color: #888;\n margin-bottom: 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n }\n \n .myio-enhanced-card-container .card-value {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 0.9rem;\n font-weight: 700;\n color: #28a745;\n }\n \n .myio-enhanced-card-container .card-unit {\n font-size: 0.75rem;\n color: rgba(0, 0, 0, 0.6);\n }\n \n .myio-enhanced-card-container .card-percentage {\n font-size: 0.75rem;\n color: rgba(0, 0, 0, 0.45);\n margin-left: 4px;\n }\n \n .myio-enhanced-card-container .card-icon {\n width: 24px;\n height: 24px;\n margin-bottom: 8px;\n }\n \n .myio-enhanced-card-container .card-icon svg {\n width: 100%;\n height: 100%;\n fill: currentColor;\n }\n \n .myio-enhanced-card-container .card-status-indicator {\n position: absolute;\n top: 8px;\n right: 8px;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n z-index: 10;\n }\n \n .myio-enhanced-card-container .card-status-ok {\n background: #28a745;\n }\n \n .myio-enhanced-card-container .card-status-alert {\n background: #ffc107;\n }\n \n .myio-enhanced-card-container .card-status-fail,\n .myio-enhanced-card-container .card-status-offline {\n background: #dc3545;\n }\n \n .myio-enhanced-card-container .card-status-unknown {\n background: #6c757d;\n }\n \n .myio-enhanced-card-container .info-panel {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(4px);\n display: none;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n padding: 16px;\n border-radius: 10px;\n z-index: 20;\n }\n \n .myio-enhanced-card-container .info-panel.active {\n display: flex;\n }\n \n .myio-enhanced-card-container .info-close {\n position: absolute;\n top: 8px;\n right: 8px;\n background: none;\n border: none;\n font-size: 18px;\n cursor: pointer;\n color: #666;\n }\n \n .myio-enhanced-card-container .info-content {\n text-align: center;\n font-size: 0.8rem;\n line-height: 1.4;\n }\n \n .myio-enhanced-card-container .info-content strong {\n display: block;\n margin-bottom: 8px;\n color: #333;\n }\n `;document.head.appendChild(style)}const getDeviceImageUrl=deviceType2=>{function normalizeString(str){if(typeof str!=="string"){str=""}return str.normalize("NFD").replace(/[\u0300-\u036f]/g,"").toUpperCase()}const deviceImages={MOTOR:"https://dashboard.myio-bas.com/api/images/public/8Ezn8qVBJ3jXD0iDfnEAZ0MZhAP1b5Ts","3F_MEDIDOR":"https://dashboard.myio-bas.com/api/images/public/f9Ce4meybsdaAhAkUlAfy5ei3I4kcN4k",RELOGIO:"https://dashboard.myio-bas.com/api/images/public/ljHZostWg0G5AfKiyM8oZixWRIIGRASB",HIDROMETRO:"https://dashboard.myio-bas.com/api/images/public/aMQYFJbGHs9gQbQkMn6XseAlUZHanBR4",ENTRADA:"https://dashboard.myio-bas.com/api/images/public/TQHPFqiejMW6lOSVsb8Pi85WtC0QKOLU",CAIXA_DAGUA:"https://dashboard.myio-bas.com/api/images/public/3t6WVhMQJFsrKA8bSZmrngDsNPkZV7fq"};const defaultImage="https://cdn-icons-png.flaticon.com/512/1178/1178428.png";const nameType=normalizeString(deviceType2);return deviceImages[nameType]||defaultImage};const deviceImageUrl=getDeviceImageUrl(deviceType);const cardHTML=`\n <div class="device-card-centered clickable ${cardEntity.status==="offline"?"offline":""}" \n data-entity-id="${entityId}"\n draggable="${enableDragDrop}"\n tabindex="0"\n role="article"\n aria-label="${cardEntity.name}, ${cardEntity.group}">\n \n <div class="device-card-inner">\n <div class="device-card-front">\n ${enableSelection&&typeof handleSelect==="function"?`<input type="checkbox" class="card-checkbox action-checker" aria-label="Select ${cardEntity.name}" style="position: absolute; top: 8px; right: 8px; z-index: 10;">`:""}\n \n <div style="display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%; flex-grow: 1; min-width: 0; padding: 0 12px 0 20px; margin-left: 16px;">\n \n <div class="device-title-row" style="flex-direction: column; min-height: 38px; text-align: center; width: 100%;">\n <span class="device-title" title="${cardEntity.name}">\n ${cardEntity.name.length>15?cardEntity.name.slice(0,15)+"…":cardEntity.name}\n </span>\n ${deviceIdentifier?`\n <span class="device-subtitle" title="${deviceIdentifier}">\n ${deviceIdentifier}\n </span>\n `:""}\n </div>\n\n <img class="device-image" src="${deviceImageUrl}" alt="${deviceType}" />\n \n <div class="device-data-row">\n <div class="consumption-main">\n <span class="flash-icon ${shouldFlashIcon?"flash":""}">\n ${icon}\n </span>\n <span class="consumption-value">${formatCardValue(cardEntity.lastValue,valType,deviceType)}</span>\n <span class="device-title-percent">(${perc.toFixed(1)}%)</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class="connection-status-icon" data-conn="${connectionStatus}" data-state="${deviceStatus}" aria-label="${connectionStatus}"></div>\n \n </div>\n `;container.innerHTML=cardHTML;const enhancedCardElement=container.querySelector(".device-card-centered");if(!document.getElementById("myio-enhanced-card-layout-styles")){const layoutStyle=document.createElement("style");layoutStyle.id="myio-enhanced-card-layout-styles";layoutStyle.textContent=`\n /* ===== MYIO Card v2 — Clean Piano Keys & Flat Status ===== */\n\n /* Card shell (kept) */\n .device-card-centered.clickable {\n width: 90% !important;\n max-width: 280px !important;\n border-radius: 14px !important;\n padding: 18px !important;\n background: linear-gradient(145deg, #ffffff 0%, #f8fafc 100%) !important;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04) !important;\n cursor: pointer;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;\n border: 1px solid rgba(226, 232, 240, 0.8) !important;\n position: relative;\n overflow: hidden;\n backdrop-filter: blur(10px);\n min-height: 126px !important;\n margin: 0 auto;\n }\n \n .device-card-centered.clickable::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: linear-gradient(90deg, #00e09e 0%, #00b4d8 50%, #7209b7 100%);\n opacity: 0;\n transition: opacity 0.3s ease;\n }\n \n .device-card-centered.clickable:hover {\n transform: translateY(-4px) scale(1.02) !important;\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.12), 0 8px 16px rgba(0, 0, 0, 0.08) !important;\n border-color: rgba(0, 224, 158, 0.3) !important;\n }\n \n .device-card-centered.clickable:hover::before {\n opacity: 1;\n }\n\n /* Selected / Offline (kept) */\n .device-card-centered.selected {\n border: 2px solid #00e09e !important;\n box-shadow: 0 12px 40px rgba(0, 224, 158, 0.25), 0 4px 12px rgba(0, 224, 158, 0.15) !important;\n background: linear-gradient(145deg, #f0fdf9 0%, #ecfdf5 50%, #f0fdf9 100%) !important;\n transform: translateY(-2px) !important;\n }\n \n .device-card-centered.selected::before {\n opacity: 1;\n background: linear-gradient(90deg, #00e09e 0%, #00d4aa 100%);\n }\n \n .device-card-centered.offline {\n border: 2px solid #ef4444 !important;\n background: linear-gradient(145deg, #fef2f2 0%, #fee2e2 50%, #fef2f2 100%) !important;\n animation: premium-offline-pulse 2s infinite !important;\n }\n \n .device-card-centered.offline::before {\n opacity: 1;\n background: linear-gradient(90deg, #ef4444 0%, #dc2626 100%);\n }\n \n @keyframes premium-offline-pulse {\n 0%, 100% { \n box-shadow: 0 8px 32px rgba(239, 68, 68, 0.15), 0 2px 8px rgba(239, 68, 68, 0.1);\n }\n 50% { \n box-shadow: 0 12px 40px rgba(239, 68, 68, 0.25), 0 4px 12px rgba(239, 68, 68, 0.2);\n }\n }\n\n /* Device image & titles (kept) */\n .device-card-centered .device-image {\n max-height: 47px !important;\n width: auto;\n margin: 10px 0 !important;\n display: block;\n filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.1));\n transition: all 0.3s ease;\n border-radius: 7px;\n }\n \n .device-card-centered:hover .device-image {\n filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.15));\n transform: scale(1.05);\n }\n \n .device-card-centered .device-title-row {\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n justify-content: center !important;\n text-align: center !important;\n width: 100% !important;\n min-height: 38px !important;\n margin-bottom: 8px !important;\n }\n \n .device-card-centered .device-title {\n font-weight: 700 !important;\n font-size: 0.85rem !important;\n color: #1e293b !important;\n margin: 0 0 4px 0 !important;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n letter-spacing: -0.025em;\n display: block !important;\n width: 100% !important;\n text-align: center !important;\n }\n \n .device-card-centered .device-subtitle {\n font-size: 0.67rem !important;\n color: #64748b !important;\n font-weight: 500 !important;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n opacity: 0.8;\n display: block !important;\n width: 100% !important;\n text-align: center !important;\n margin: 0 !important;\n padding: 0 !important;\n }\n\n /* Value pill (kept) */\n .device-card-centered .consumption-main {\n background: linear-gradient(135deg, rgba(0, 224, 158, 0.1) 0%, rgba(0, 180, 216, 0.1) 100%);\n border-radius: 10px;\n padding: 7px 10px;\n margin-top: 7px;\n border: 1px solid rgba(0, 224, 158, 0.2);\n backdrop-filter: blur(10px);\n }\n \n .device-card-centered .consumption-value {\n font-weight: 700 !important;\n font-size: 0.9rem !important;\n color: #059669 !important;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n }\n \n .device-card-centered .device-title-percent {\n font-size: 0.72rem !important;\n color: #6b7280 !important;\n font-weight: 600 !important;\n margin-left: 5px;\n }\n \n .device-card-centered .flash-icon {\n font-size: 1rem !important;\n margin-right: 7px;\n transition: all 0.3s ease;\n }\n \n .device-card-centered:hover .flash-icon {\n transform: scale(1.1);\n }\n \n .device-card-centered .flash-icon.flash {\n animation: premium-flash 1.5s infinite;\n }\n \n @keyframes premium-flash {\n 0%, 100% { \n opacity: 1; \n transform: scale(1);\n filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));\n }\n 50% { \n opacity: 0.3; \n transform: scale(1.15);\n filter: drop-shadow(0 4px 8px rgba(239, 68, 68, 0.3));\n }\n }\n\n /* Checkbox (kept) */\n .device-card-centered .card-checkbox {\n width: 16px !important;\n height: 16px !important;\n cursor: pointer;\n background: rgba(255, 255, 255, 0.9) !important;\n border: 2px solid #e2e8f0 !important;\n border-radius: 5px !important;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n backdrop-filter: blur(10px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n position: relative;\n }\n \n .device-card-centered .card-checkbox:hover {\n border-color: #00e09e !important;\n box-shadow: 0 3px 6px rgba(0, 224, 158, 0.15);\n transform: scale(1.05);\n }\n \n .device-card-centered .card-checkbox:checked {\n background: linear-gradient(135deg, #00e09e 0%, #00d4aa 100%) !important;\n border-color: #00e09e !important;\n box-shadow: 0 3px 10px rgba(0, 224, 158, 0.3);\n }\n \n .device-card-centered .card-checkbox:checked::after {\n content: '✓';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: white;\n font-size: 10px;\n font-weight: bold;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);\n }\n\n /* ——— NEW: Piano-Key Actions (flat by default, full height) ——— */\n .device-card-centered .card-actions {\n position: absolute;\n left: 12px;\n top: 12px;\n bottom: 12px;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 0;\n border: 1px solid rgba(226, 232, 240, 0.9);\n border-radius: 8px;\n background: #fff;\n overflow: visible;\n box-shadow: none !important;\n z-index: 10;\n }\n \n .device-card-centered .card-action {\n width: 36px !important;\n height: 36px !important;\n border: 0;\n border-bottom: 1px solid rgba(226, 232, 240, 0.9);\n background: #fff !important;\n box-shadow: none !important;\n backdrop-filter: none !important;\n transform: translateZ(0);\n transition: transform 0.18s ease, box-shadow 0.18s ease;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0;\n border-radius: 0;\n }\n \n .device-card-centered .card-action:first-child {\n border-top-left-radius: 7px;\n border-top-right-radius: 7px;\n }\n \n .device-card-centered .card-action:last-child {\n border-bottom: 0;\n border-bottom-left-radius: 7px;\n border-bottom-right-radius: 7px;\n }\n \n .device-card-centered .card-action img {\n width: 16px !important;\n height: 16px !important;\n filter: grayscale(0.2) brightness(0.85);\n transition: transform 0.18s ease, filter 0.18s ease;\n }\n\n /* Lift on interaction only */\n .device-card-centered .card-action:hover,\n .device-card-centered .card-action:focus-visible {\n transform: translateY(-2px) scale(1.05);\n box-shadow: 0 6px 14px rgba(16, 24, 40, 0.12), 0 2px 6px rgba(16, 24, 40, 0.08);\n outline: none;\n }\n \n .device-card-centered .card-action:hover img,\n .device-card-centered .card-action:focus-visible img {\n filter: grayscale(0) brightness(1);\n transform: scale(1.08);\n }\n\n /* ——— NEW: Flat Status (CSS dot, never clipped) ——— */\n .device-card-centered .connection-status-icon {\n position: absolute;\n bottom: 18px;\n right: 18px;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: #22c55e;\n border: 1px solid rgba(0, 0, 0, 0.06);\n box-shadow: none !important;\n backdrop-filter: none !important;\n z-index: 5;\n }\n\n /* Map colors by connection or device state */\n .device-card-centered .connection-status-icon[data-conn="offline"] {\n background: #94a3b8;\n }\n .device-card-centered .connection-status-icon[data-state="warning"] {\n background: #f59e0b;\n }\n .device-card-centered .connection-status-icon[data-state="danger"] {\n background: #ef4444;\n }\n .device-card-centered .connection-status-icon[data-state="no_info"] {\n background: #94a3b8;\n }\n .device-card-centered .connection-status-icon[data-state="maintenance"] {\n background: #0ea5e9;\n }\n \n .myio-enhanced-card-container .info-close:hover {\n background: rgba(239, 68, 68, 0.2) !important;\n transform: scale(1.1);\n }\n\n /* Responsive / Dark mode (kept) */\n @media (max-width: 768px) {\n .device-card-centered.clickable {\n padding: 16px !important;\n border-radius: 12px !important;\n }\n \n .device-card-centered .device-image {\n max-height: 44px !important;\n }\n \n .device-card-centered .card-action {\n width: 36px !important;\n height: 36px !important;\n }\n }\n \n @media (prefers-color-scheme: dark) {\n .device-card-centered.clickable {\n background: linear-gradient(145deg, #1e293b 0%, #334155 100%) !important;\n border-color: rgba(71, 85, 105, 0.8) !important;\n color: #f1f5f9 !important;\n }\n \n .device-card-centered .device-title {\n color: #f1f5f9 !important;\n }\n \n .device-card-centered .device-subtitle {\n color: #94a3b8 !important;\n }\n \n .device-card-centered .card-actions {\n border-color: rgba(71, 85, 105, 0.8);\n background: #1e293b;\n }\n \n .device-card-centered .card-action {\n background: #1e293b !important;\n border-bottom: 1px solid rgba(71, 85, 105, 0.8);\n }\n }\n `;document.head.appendChild(layoutStyle)}const actionsContainer=document.createElement("div");actionsContainer.className="card-actions";if(typeof handleActionDashboard==="function"){const dashboardBtn=document.createElement("button");dashboardBtn.className="card-action action-dashboard";dashboardBtn.title="Dashboard";dashboardBtn.innerHTML='<img src="https://dashboard.myio-bas.com/api/images/public/TAVXE0sTbCZylwGsMF9lIWdllBB3iFtS"/>';dashboardBtn.addEventListener("click",e=>{e.stopPropagation();handleActionDashboard(entityObject)});actionsContainer.appendChild(dashboardBtn)}if(typeof handleActionReport==="function"){const reportBtn=document.createElement("button");reportBtn.className="card-action action-report";reportBtn.title="Relatório";reportBtn.innerHTML='<img src="https://dashboard.myio-bas.com/api/images/public/d9XuQwMYQCG2otvtNSlqUHGavGaSSpz4"/>';reportBtn.addEventListener("click",e=>{e.stopPropagation();handleActionReport(entityObject)});actionsContainer.appendChild(reportBtn)}if(typeof handleActionSettings==="function"){const settingsBtn=document.createElement("button");settingsBtn.className="card-action action-settings";settingsBtn.title="Configurações";settingsBtn.innerHTML='<img src="https://dashboard.myio-bas.com/api/images/public/5n9tze6vED2uwIs5VvJxGzNNZ9eV4yoz"/>';settingsBtn.addEventListener("click",e=>{e.stopPropagation();handleActionSettings(entityObject)});actionsContainer.appendChild(settingsBtn)}if(handInfo){const infoPanel=document.createElement("div");infoPanel.className="info-panel";const closeBtn=document.createElement("button");closeBtn.className="info-close";closeBtn.innerHTML="×";closeBtn.addEventListener("click",()=>{infoPanel.classList.remove("active")});const infoContent=document.createElement("div");infoContent.className="info-content";let connectionInfo="";if(connectionStatusTime){const date=new Date(connectionStatusTime);connectionInfo=`<strong>Central:</strong> ${centralName||"N/A"}<br>`;connectionInfo+=`<strong>Última Conexão:</strong> ${date.toLocaleString("pt-BR")}<br>`}if(timeVal){const telemetryDate=new Date(timeVal);const now=new Date;const diffMs=now-telemetryDate;const diffHours=Math.floor(diffMs/(1e3*60*60));connectionInfo+=`<strong>Última Telemetria:</strong> ${telemetryDate.toLocaleString("pt-BR")}`;if(diffHours>0){connectionInfo+=` (${diffHours}h atrás)`}}infoContent.innerHTML=connectionInfo||"<strong>Informações não disponíveis</strong>";infoPanel.appendChild(closeBtn);infoPanel.appendChild(infoContent);container.appendChild(infoPanel);const infoBtn=document.createElement("button");infoBtn.className="card-action action-info";infoBtn.title="Informações";infoBtn.innerHTML="📊";infoBtn.addEventListener("click",e=>{e.stopPropagation();infoPanel.classList.toggle("active")});actionsContainer.appendChild(infoBtn)}if(enhancedCardElement&&actionsContainer.children.length>0){enhancedCardElement.insertBefore(actionsContainer,enhancedCardElement.firstChild)}if(enableSelection&&MyIOSelectionStore){const checkbox=enhancedCardElement.querySelector(".card-checkbox");if(checkbox){checkbox.addEventListener("change",e=>{e.stopPropagation();if(e.target.checked){const currentCount=MyIOSelectionStore.getSelectedEntities().length;const isTryingToAdd=e.target.checked;if(isTryingToAdd&&currentCount>=6){e.preventDefault();e.target.checked=false;MyIOToast.show("Não é possível selecionar mais de 6 itens.","warning");return}MyIOSelectionStore.add(entityId)}else{MyIOSelectionStore.remove(entityId)}})}const handleSelectionChange=data=>{const isSelected=data.selectedIds.includes(entityId);if(checkbox){checkbox.checked=isSelected}enhancedCardElement.classList.toggle("selected",isSelected);if(typeof handleSelect==="function"){handleSelect(entityObject)}};MyIOSelectionStore.on("selection:change",handleSelectionChange);const isInitiallySelected=MyIOSelectionStore.isSelected(entityId);if(checkbox){checkbox.checked=isInitiallySelected}enhancedCardElement.classList.toggle("selected",isInitiallySelected);container._cleanup=()=>{MyIOSelectionStore.off("selection:change",handleSelectionChange)}}if(enableDragDrop){enhancedCardElement.addEventListener("dragstart",e=>{e.dataTransfer.setData("text/myio-id",entityId);e.dataTransfer.setData("application/json",JSON.stringify(entityObject));e.dataTransfer.effectAllowed="copy";if(MyIOSelectionStore){MyIOSelectionStore.startDrag(entityId)}});enhancedCardElement.addEventListener("dragend",()=>{})}if(typeof handleClickCard==="function"){enhancedCardElement.addEventListener("click",e=>{if(!e.target.closest(".card-action")&&!e.target.closest(".card-checkbox")){handleClickCard(entityObject)}})}const jQueryLikeObject={get:index=>index===0?container:void 0,0:container,length:1,find:selector=>{const found=container.querySelector(selector);return{get:index=>index===0?found:void 0,0:found,length:found?1:0,on:(event,handler)=>{if(found)found.addEventListener(event,handler);return this}}},on:(event,handler)=>{container.addEventListener(event,handler);return this},addClass:className=>{container.classList.add(className);return this},removeClass:className=>{container.classList.remove(className);return this},destroy:()=>{if(container._cleanup){container._cleanup()}}};return jQueryLikeObject}function renderCardComponentLegacy(options){const{renderCardComponent:renderCardComponent3}=(init_template_card(),__toCommonJS(template_card_exports));return renderCardComponent3(options)}function renderCardComponent2(options){const useNewComponents=options.useNewComponents!==false&&typeof MyIOSelectionStore!=="undefined"&&typeof MyIODraggableCard!=="undefined";if(useNewComponents){return renderCardComponentV2(options)}else{return renderCardComponentLegacy(options)}}var CSS_STRING=`\n/* CSS Variables for theming */\n:root {\n --myio-card-radius: 16px;\n --myio-card-shadow: 0 2px 8px rgba(10, 31, 68, .06);\n --myio-card-bg: #fff;\n --myio-card-border: #e9eef5;\n\n --myio-chip-ok-bg: #e8f7ff;\n --myio-chip-ok-fg: #007ecc;\n --myio-chip-alert-bg: #fff4e5;\n --myio-chip-alert-fg: #b96b00;\n --myio-chip-failure-bg: #ffeaea;\n --myio-chip-failure-fg: #b71c1c;\n --myio-chip-offline-bg: #f1f5f9;\n --myio-chip-offline-fg: #64748b;\n\n --myio-text-1: #0f172a;\n --myio-text-2: #4b5563;\n --myio-muted: #94a3b8;\n\n --myio-eff-bar-bg: #e6edf5;\n --myio-eff-bar-a: #1e90ff;\n --myio-eff-bar-b: #a3d1ff;\n\n --myio-badge-border: rgba(255, 153, 0, .35);\n --myio-badge-border-failure: rgba(244, 67, 54, .45);\n}\n\n/* Main card container */\n.myio-ho-card {\n background: var(--myio-card-bg);\n border: 1px solid var(--myio-card-border);\n border-radius: var(--myio-card-radius);\n box-shadow: var(--myio-card-shadow);\n padding: 16px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n line-height: 1.4;\n color: var(--myio-text-1);\n position: relative;\n cursor: pointer;\n transition: all 0.2s ease;\n min-width: 280px;\n max-width: 320px;\n}\n\n.myio-ho-card:hover {\n box-shadow: 0 4px 12px rgba(10, 31, 68, .12);\n transform: translateY(-1px);\n}\n\n.myio-ho-card:focus-within {\n outline: 2px solid #007ecc;\n outline-offset: 2px;\n}\n\n/* Selected state with light green background */\n.myio-ho-card.is-selected {\n border: 2px solid #00e09e;\n box-shadow: 0 12px 40px rgba(0, 224, 158, 0.25), 0 4px 12px rgba(0, 224, 158, 0.15);\n background: linear-gradient(145deg, #f0fdf9 0%, #ecfdf5 50%, #f0fdf9 100%);\n transform: translateY(-2px);\n}\n\n.myio-ho-card.is-selected:hover {\n box-shadow: 0 16px 48px rgba(0, 224, 158, 0.3), 0 8px 16px rgba(0, 224, 158, 0.2);\n}\n\n/* Alert and failure states */\n.myio-ho-card.is-alert {\n border-color: var(--myio-badge-border);\n box-shadow: 0 0 0 1px var(--myio-badge-border), var(--myio-card-shadow);\n}\n\n.myio-ho-card.is-failure {\n border-color: var(--myio-badge-border-failure);\n box-shadow: 0 0 0 1px var(--myio-badge-border-failure), var(--myio-card-shadow);\n}\n\n/* Header section */\n.myio-ho-card__header {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 12px;\n}\n\n.myio-ho-card__icon {\n width: 28px;\n height: 28px;\n color: #4b6bfb;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.myio-ho-card.is-alert .myio-ho-card__icon {\n color: var(--myio-chip-alert-fg);\n}\n\n.myio-ho-card.is-failure .myio-ho-card__icon {\n color: var(--myio-chip-failure-fg);\n}\n\n.myio-ho-card__title {\n flex: 1;\n min-width: 0;\n}\n\n.myio-ho-card__name {\n font-weight: 600;\n font-size: 15px;\n color: var(--myio-text-1);\n margin-bottom: 2px;\n word-wrap: break-word;\n line-height: 1.3;\n}\n\n.myio-ho-card__code {\n font-size: 12px;\n color: var(--myio-muted);\n font-weight: 500;\n}\n\n.myio-ho-card__actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.myio-ho-card__kebab {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n border-radius: 4px;\n color: var(--myio-muted);\n transition: all 0.15s ease;\n position: relative;\n}\n\n.myio-ho-card__kebab:hover {\n background: #f1f5f9;\n color: var(--myio-text-2);\n}\n\n.myio-ho-card__kebab:focus {\n outline: 2px solid #007ecc;\n outline-offset: 1px;\n}\n\n.myio-ho-card__menu {\n position: absolute;\n top: 100%;\n right: 0;\n background: white;\n border: 1px solid var(--myio-card-border);\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n min-width: 140px;\n padding: 4px 0;\n margin-top: 4px;\n}\n\n.myio-ho-card__menu[hidden] {\n display: none;\n}\n\n.myio-ho-card__menu button {\n width: 100%;\n background: none;\n border: none;\n padding: 8px 12px;\n text-align: left;\n cursor: pointer;\n font-size: 13px;\n color: var(--myio-text-1);\n transition: background-color 0.15s ease;\n}\n\n.myio-ho-card__menu button:hover {\n background: #f8fafc;\n}\n\n.myio-ho-card__menu button:focus {\n background: #e2e8f0;\n outline: none;\n}\n\n.myio-ho-card__select {\n display: flex;\n align-items: center;\n cursor: pointer;\n}\n\n.myio-ho-card__select[hidden] {\n display: none;\n}\n\n.myio-ho-card__select input[type="checkbox"] {\n width: 16px;\n height: 16px;\n margin: 0;\n cursor: pointer;\n}\n\n/* Status chip */\n.myio-ho-card__status {\n margin-bottom: 16px;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n padding: 4px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 500;\n gap: 4px;\n}\n\n.chip--ok {\n background: var(--myio-chip-ok-bg);\n color: var(--myio-chip-ok-fg);\n}\n\n.chip--alert {\n background: var(--myio-chip-alert-bg);\n color: var(--myio-chip-alert-fg);\n}\n\n.chip--failure {\n background: var(--myio-chip-failure-bg);\n color: var(--myio-chip-failure-fg);\n}\n\n.chip--offline {\n background: var(--myio-chip-offline-bg);\n color: var(--myio-chip-offline-fg);\n}\n\n/* Primary metric */\n.myio-ho-card__primary {\n margin-bottom: 16px;\n padding: 8px 0;\n border-radius: 8px;\n transition: background-color 0.15s ease;\n}\n\n.myio-ho-card__primary:hover {\n background: #f8fafc;\n}\n\n.myio-ho-card__primary:focus {\n outline: 2px solid #007ecc;\n outline-offset: 2px;\n}\n\n.myio-ho-card__value {\n display: flex;\n align-items: baseline;\n gap: 4px;\n flex-wrap: wrap;\n}\n\n.myio-ho-card__value .num {\n font-size: 24px;\n font-weight: 700;\n color: var(--myio-text-1);\n line-height: 1;\n}\n\n.myio-ho-card__value .unit {\n font-size: 16px;\n font-weight: 600;\n color: var(--myio-text-2);\n line-height: 1;\n}\n\n.myio-ho-card__value .suffix {\n font-size: 12px;\n color: var(--myio-muted);\n margin-left: 4px;\n}\n\n/* Efficiency bar */\n.myio-ho-card__eff {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 16px;\n}\n\n.myio-ho-card__eff .label {\n font-size: 12px;\n color: var(--myio-text-2);\n font-weight: 500;\n min-width: 60px;\n}\n\n.myio-ho-card__eff .bar {\n flex: 1;\n height: 6px;\n background: var(--myio-eff-bar-bg);\n border-radius: 3px;\n position: relative;\n overflow: hidden;\n}\n\n.myio-ho-card__eff .bar__fill {\n height: 100%;\n background: linear-gradient(90deg, var(--myio-eff-bar-a) 0%, var(--myio-eff-bar-b) 100%);\n border-radius: 3px;\n transition: width 0.3s ease;\n min-width: 2px;\n}\n\n.myio-ho-card__eff .perc {\n font-size: 12px;\n font-weight: 600;\n color: var(--myio-text-1);\n min-width: 32px;\n text-align: right;\n}\n\n/* Footer metrics */\n.myio-ho-card__footer {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 12px;\n}\n\n.myio-ho-card__footer .metric {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n gap: 4px;\n}\n\n.myio-ho-card__footer .metric .ico {\n width: 16px;\n height: 16px;\n color: var(--myio-muted);\n flex-shrink: 0;\n}\n\n.myio-ho-card__footer .metric .label {\n font-size: 10px;\n color: var(--myio-muted);\n font-weight: 500;\n line-height: 1.2;\n}\n\n.myio-ho-card__footer .metric .val {\n font-size: 12px;\n font-weight: 600;\n color: var(--myio-text-1);\n line-height: 1;\n}\n\n/* Drag and drop states */\n.myio-ho-card[draggable="true"] {\n cursor: grab;\n}\n\n.myio-ho-card[draggable="true"]:active {\n cursor: grabbing;\n}\n\n.myio-ho-card.is-dragging {\n opacity: 0.5;\n transform: rotate(2deg);\n}\n\n/* Responsive adjustments */\n@media (max-width: 320px) {\n .myio-ho-card {\n min-width: 260px;\n padding: 14px;\n }\n \n .myio-ho-card__value .num {\n font-size: 20px;\n }\n \n .myio-ho-card__footer {\n gap: 8px;\n }\n}\n\n/* High contrast mode support */\n@media (prefers-contrast: high) {\n .myio-ho-card {\n border-width: 2px;\n }\n \n .chip {\n border: 1px solid currentColor;\n }\n \n .myio-ho-card__eff .bar {\n border: 1px solid var(--myio-text-2);\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .myio-ho-card,\n .myio-ho-card__primary,\n .myio-ho-card__kebab,\n .myio-ho-card__eff .bar__fill {\n transition: none;\n }\n}\n`;var Icons={gear:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M19.14 12.94c.04-.31.06-.63.06-.94s-.02-.63-.06-.94l2.03-1.58a.5.5 0 0 0 .12-.66l-1.92-3.32a.5.5 0 0 0-.62-.22l-2.39.96a7.36 7.36 0 0 0-1.63-.94l-.36-2.55A.5.5 0 0 0 13.89 1h-3.78a.5.5 0 0 0-.49.41l-.36 2.55c-.58.23-1.12.53-1.63.94l-2.39-.96a.5.5 0 0 0-.62.22L2.7 7.48a.5.5 0 0 0 .12.66l2.03 1.58c-.04.31-.06.63-.06.94s.02.63.06.94L2.82 13.18a.5.5 0 0 0-.12.66l1.92 3.32c.13.23.4.32.62.22l2.39-.96c.5.4 1.05.71 1.63.94l.36 2.55c.05.23.26.41.49.41h3.78c.23 0 .44-.18.49-.41l.36-2.55c.58-.23 1.12-.53 1.63-.94l2.39.96c.22.1.49 0 .62-.22l1.92-3.32a.5.5 0 0 0-.12-.66l-2.03-1.58ZM12 15.5A3.5 3.5 0 1 1 12 8.5a3.5 3.5 0 0 1 0 7Z"/>\n</svg>`,elevator:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M6 3h12a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Zm0 2v14h12V5H6Z"/>\n <path d="M11 17h2v-5h-2v5Zm-2.5-7.5 2-2-2-2v4Zm7 0v-4l-2 2 2 2Z"/>\n</svg>`,escalator:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M3 16a3 3 0 0 1 3-3h3.6l4.4-6H20a2 2 0 1 1 0 4h-3.6l-4.4 6H6a3 3 0 0 1-3-3Z"/>\n <circle cx="8.5" cy="6" r="1.5"/>\n</svg>`,chiller:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"\n stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">\n <path d="M12 2v20M4 7l16 10M4 17L20 7"/>\n <path d="M8 4l4 3 4-3M8 20l4-3 4 3M3 12h18"/>\n</svg>`,pump:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" aria-hidden="true" focusable="false">\n <path fill="currentColor" d="M12 3s-5 5.6-5 9a5 5 0 0 0 10 0c0-3.4-5-9-5-9Zm0 12a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z"/>\n <path fill="currentColor" d="M12 9.3c.9 0 1.7.8 1.7 1.7S12.9 12.7 12 12.7 10.3 12 10.3 11 11.1 9.3 12 9.3Z"/>\n</svg>`,fan:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <circle cx="12" cy="12" r="2.2"/>\n <path d="M12 4c2.5 0 4 1.5 4 3.3 0 1.3-.7 2.4-1.7 3.2-1.3 1-3 .7-3-.9V4Z"/>\n <path d="M20 12c0 2.5-1.5 4-3.3 4-1.3 0-2.4-.7-3.2-1.7-1-1.3-.7-3 .9-3H20Z"/>\n <path d="M12 20c-2.5 0-4-1.5-4-3.3 0-1.3.7-2.4 1.7-3.2 1.3-1 3-.7 3 .9V20Z"/>\n <path d="M4 12c0-2.5 1.5-4 3.3-4 1.3 0 2.4.7 3.2 1.7 1 1.3.7 3-.9 3H4Z"/>\n</svg>`,motor:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="3" y="7" width="14" height="10" rx="3"/>\n <rect x="17" y="10" width="4" height="4" rx="1"/>\n <circle cx="10" cy="12" r="2.5" fill="none" stroke="currentColor" stroke-width="1.6"/>\n</svg>`,thermometer:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <path d="M11 5a3 3 0 0 1 6 0v6.1a5 5 0 1 1-6 0V5Z"/>\n <rect x="13" y="4" width="2" height="9" rx="1"/>\n</svg>`,switch:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="2" y="7" width="20" height="10" rx="5"/>\n <circle cx="9" cy="12" r="3.5" fill="#fff"/>\n</svg>`,energyMeter:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="3" y="4" width="18" height="14" rx="2"/>\n <path d="M6 16h12v2H6z"/>\n <path d="M12 8a5 5 0 0 0-5 5h2a3 3 0 0 1 6 0h2a5 5 0 0 0-5-5Z"/>\n</svg>`,waterTank:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <rect x="5" y="4" width="14" height="16" rx="2"/>\n <path d="M7 12c1.5 1 3 .9 5-.3s3.5-1.3 5 .3v4H7v-4Z" fill="#fff" fill-opacity=".25"/>\n</svg>`,dot:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <circle cx="12" cy="12" r="5"/>\n</svg>`,kebab:`\n<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"\n viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">\n <circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/>\n</svg>`};var ICON_MAP={ESCADA_ROLANTE:Icons.escalator,ELEVADOR:Icons.elevator,ELEVADOR_SERVICO:Icons.elevator,CHILLER:Icons.chiller,PUMP:Icons.pump,COMPRESSOR:Icons.motor,VENTILADOR:Icons.fan,MOTOR:Icons.motor,TERMOSTATO:Icons.thermometer,SELETOR_AUTO_MANUAL:Icons.switch,"3F_MEDIDOR":Icons.energyMeter,CAIXA_D_AGUA:Icons.waterTank,DEFAULT:Icons.gear};var DEFAULT_I18N={in_operation:"Em operação",alert:"Alerta",failure:"Falha",offline:"Offline",efficiency:"Eficiência",temperature:"Temperatura",operation_time:"Tempo de operação",updated:"Atualizado",current_suffix:"Atual",menu_dashboard:"Dashboard",menu_report:"Relatório",menu_settings:"Configurações"};var CSS_TAG="head-office-card-v1";function ensureCss(){if(!document.querySelector(`style[data-myio-css="${CSS_TAG}"]`)){const style=document.createElement("style");style.setAttribute("data-myio-css",CSS_TAG);style.textContent=CSS_STRING;document.head.appendChild(style)}}function normalizeParams(params){if(!params||!params.entityObject){throw new Error("renderCardCompenteHeadOffice: entityObject is required")}const entityObject=params.entityObject;if(!entityObject.entityId){console.warn("renderCardCompenteHeadOffice: entityId is missing, generating temporary ID");entityObject.entityId=`temp-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}return{entityObject:entityObject,i18n:{...DEFAULT_I18N,...params.i18n||{}},enableSelection:Boolean(params.enableSelection),enableDragDrop:Boolean(params.enableDragDrop),useNewComponents:Boolean(params.useNewComponents),callbacks:{handleActionDashboard:params.handleActionDashboard,handleActionReport:params.handleActionReport,handleActionSettings:params.handleActionSettings,handleSelect:params.handleSelect,handInfo:params.handInfo,handleClickCard:params.handleClickCard}}}function getIconSvg(deviceType){return ICON_MAP[deviceType]||ICON_MAP.DEFAULT}function formatPrimaryValue(val,valType){if(val===null||val===void 0||isNaN(val)){return{num:"—",unit:"",suffix:""}}switch(valType){case"power_kw":return{num:val.toFixed(1),unit:"kW",suffix:""};case"flow_m3h":return{num:val.toFixed(1),unit:"m³/h",suffix:""};case"temp_c":return{num:val.toFixed(1),unit:"°C",suffix:""};default:return{num:val.toFixed(1),unit:"",suffix:""}}}function formatTemperature(temp){if(temp===null||temp===void 0||isNaN(temp)){return"—"}return`${temp.toFixed(0)}°C`}function formatOperationHours(hours){if(hours===null||hours===void 0||isNaN(hours)){return"—"}return`${hours.toFixed(3)}h`}function formatRelativeTime(timestamp){if(!timestamp)return"—";const now=Date.now();const diff=now-timestamp;const minutes=Math.floor(diff/(1e3*60));const hours=Math.floor(minutes/60);const days=Math.floor(hours/24);if(days>0)return`${days}d`;if(hours>0)return`${hours}h`;if(minutes>0)return`${minutes}m`;return"agora"}function getStatusInfo(connectionStatus,i18n){switch(connectionStatus){case"RUNNING":case"ONLINE":return{chipClass:"chip--ok",label:i18n.in_operation};case"ALERT":return{chipClass:"chip--alert",label:i18n.alert};case"FAILURE":return{chipClass:"chip--failure",label:i18n.failure};case"OFFLINE":case"PAUSED":default:return{chipClass:"chip--offline",label:i18n.offline}}}function getCardStateClass(connectionStatus){switch(connectionStatus){case"ALERT":return"is-alert";case"FAILURE":return"is-failure";default:return""}}function buildDOM(state){const{entityObject:entityObject,i18n:i18n,enableSelection:enableSelection,enableDragDrop:enableDragDrop}=state;const root=document.createElement("div");root.className="myio-ho-card";root.setAttribute("role","group");root.setAttribute("data-entity-id",entityObject.entityId);if(enableDragDrop){root.setAttribute("draggable","true")}const header=document.createElement("div");header.className="myio-ho-card__header";const iconContainer=document.createElement("div");iconContainer.className="myio-ho-card__icon";iconContainer.innerHTML=getIconSvg(entityObject.deviceType);header.appendChild(iconContainer);const titleSection=document.createElement("div");titleSection.className="myio-ho-card__title";const nameEl=document.createElement("div");nameEl.className="myio-ho-card__name";nameEl.textContent=entityObject.labelOrName||"Unknown Device";titleSection.appendChild(nameEl);if(entityObject.deviceIdentifier){const codeEl=document.createElement("div");codeEl.className="myio-ho-card__code";codeEl.textContent=entityObject.deviceIdentifier;titleSection.appendChild(codeEl)}header.appendChild(titleSection);const actionsSection=document.createElement("div");actionsSection.className="myio-ho-card__actions";const kebabBtn=document.createElement("button");kebabBtn.className="myio-ho-card__kebab";kebabBtn.setAttribute("aria-label","Open actions");kebabBtn.setAttribute("aria-haspopup","menu");kebabBtn.innerHTML=Icons.kebab;actionsSection.appendChild(kebabBtn);const menu=document.createElement("div");menu.className="myio-ho-card__menu";menu.setAttribute("role","menu");menu.setAttribute("hidden","");const dashboardBtn=document.createElement("button");dashboardBtn.setAttribute("role","menuitem");dashboardBtn.setAttribute("data-action","dashboard");dashboardBtn.textContent=i18n.menu_dashboard;menu.appendChild(dashboardBtn);const reportBtn=document.createElement("button");reportBtn.setAttribute("role","menuitem");reportBtn.setAttribute("data-action","report");reportBtn.textContent=i18n.menu_report;menu.appendChild(reportBtn);const settingsBtn=document.createElement("button");settingsBtn.setAttribute("role","menuitem");settingsBtn.setAttribute("data-action","settings");settingsBtn.textContent=i18n.menu_settings;menu.appendChild(settingsBtn);actionsSection.appendChild(menu);if(enableSelection){const selectLabel=document.createElement("label");selectLabel.className="myio-ho-card__select";const checkbox=document.createElement("input");checkbox.type="checkbox";selectLabel.appendChild(checkbox);actionsSection.appendChild(selectLabel)}header.appendChild(actionsSection);root.appendChild(header);const statusSection=document.createElement("div");statusSection.className="myio-ho-card__status";const chip=document.createElement("span");chip.className="chip";statusSection.appendChild(chip);root.appendChild(statusSection);const primarySection=document.createElement("div");primarySection.className="myio-ho-card__primary";primarySection.setAttribute("role","button");primarySection.setAttribute("tabindex","0");const valueContainer=document.createElement("div");valueContainer.className="myio-ho-card__value";const numSpan=document.createElement("span");numSpan.className="num";valueContainer.appendChild(numSpan);const unitSpan=document.createElement("span");unitSpan.className="unit";valueContainer.appendChild(unitSpan);const suffixSpan=document.createElement("span");suffixSpan.className="suffix";suffixSpan.textContent=i18n.current_suffix;valueContainer.appendChild(suffixSpan);primarySection.appendChild(valueContainer);root.appendChild(primarySection);const effSection=document.createElement("div");effSection.className="myio-ho-card__eff";const effLabel=document.createElement("div");effLabel.className="label";effLabel.textContent=i18n.efficiency;effSection.appendChild(effLabel);const barContainer=document.createElement("div");barContainer.className="bar";barContainer.setAttribute("role","progressbar");barContainer.setAttribute("aria-valuemin","0");barContainer.setAttribute("aria-valuemax","100");const barFill=document.createElement("div");barFill.className="bar__fill";barContainer.appendChild(barFill);effSection.appendChild(barContainer);const percSpan=document.createElement("div");percSpan.className="perc";effSection.appendChild(percSpan);root.appendChild(effSection);const footer=document.createElement("div");footer.className="myio-ho-card__footer";const tempMetric=document.createElement("div");tempMetric.className="metric";const tempIcon=document.createElement("i");tempIcon.className="ico ico-temp";tempIcon.innerHTML=Icons.thermometer;tempMetric.appendChild(tempIcon);const tempLabel=document.createElement("div");tempLabel.className="label";tempLabel.textContent=i18n.temperature;tempMetric.appendChild(tempLabel);const tempVal=document.createElement("div");tempVal.className="val";tempMetric.appendChild(tempVal);footer.appendChild(tempMetric);const opTimeMetric=document.createElement("div");opTimeMetric.className="metric";const opTimeIcon=document.createElement("i");opTimeIcon.className="ico ico-clock";opTimeIcon.innerHTML=Icons.dot;opTimeMetric.appendChild(opTimeIcon);const opTimeLabel=document.createElement("div");opTimeLabel.className="label";opTimeLabel.textContent=i18n.operation_time;opTimeMetric.appendChild(opTimeLabel);const opTimeVal=document.createElement("div");opTimeVal.className="val";opTimeMetric.appendChild(opTimeVal);footer.appendChild(opTimeMetric);const updatedMetric=document.createElement("div");updatedMetric.className="metric";const updatedIcon=document.createElement("i");updatedIcon.className="ico ico-sync";updatedIcon.innerHTML=Icons.dot;updatedMetric.appendChild(updatedIcon);const updatedLabel=document.createElement("div");updatedLabel.className="label";updatedLabel.textContent=i18n.updated;updatedMetric.appendChild(updatedLabel);const updatedVal=document.createElement("div");updatedVal.className="val";updatedMetric.appendChild(updatedVal);footer.appendChild(updatedMetric);root.appendChild(footer);return root}function paint(root,state){const{entityObject:entityObject,i18n:i18n}=state;const stateClass=getCardStateClass(entityObject.connectionStatus);root.className=`myio-ho-card ${stateClass}`;const statusInfo=getStatusInfo(entityObject.connectionStatus,i18n);const chip=root.querySelector(".chip");chip.className=`chip ${statusInfo.chipClass}`;chip.textContent=statusInfo.label;const primaryValue=formatPrimaryValue(entityObject.val,entityObject.valType);const numSpan=root.querySelector(".myio-ho-card__value .num");const unitSpan=root.querySelector(".myio-ho-card__value .unit");numSpan.textContent=primaryValue.num;unitSpan.textContent=primaryValue.unit;const perc=entityObject.perc||0;const barFill=root.querySelector(".bar__fill");const percSpan=root.querySelector(".myio-ho-card__eff .perc");const barContainer=root.querySelector(".bar");barFill.style.width=`${Math.max(0,Math.min(100,perc))}%`;percSpan.textContent=`${Math.round(perc)}%`;barContainer.setAttribute("aria-valuenow",Math.round(perc).toString());barContainer.setAttribute("aria-label",`${i18n.efficiency} ${Math.round(perc)}%`);const tempVal=root.querySelector(".myio-ho-card__footer .metric:nth-child(1) .val");tempVal.textContent=formatTemperature(entityObject.temperatureC);const opTimeVal=root.querySelector(".myio-ho-card__footer .metric:nth-child(2) .val");opTimeVal.textContent=formatOperationHours(entityObject.operationHours);const updatedVal=root.querySelector(".myio-ho-card__footer .metric:nth-child(3) .val");updatedVal.textContent=formatRelativeTime(entityObject.timaVal)}function bindEvents(root,state,callbacks){const{entityObject:entityObject}=state;const kebabBtn=root.querySelector(".myio-ho-card__kebab");const menu=root.querySelector(".myio-ho-card__menu");function toggleMenu(){const isHidden=menu.hasAttribute("hidden");if(isHidden){menu.removeAttribute("hidden");kebabBtn.setAttribute("aria-expanded","true")}else{menu.setAttribute("hidden","");kebabBtn.setAttribute("aria-expanded","false")}}function closeMenu(){menu.setAttribute("hidden","");kebabBtn.setAttribute("aria-expanded","false")}kebabBtn.addEventListener("click",e=>{e.stopPropagation();toggleMenu()});document.addEventListener("click",closeMenu);document.addEventListener("keydown",e=>{if(e.key==="Escape"){closeMenu()}});const dashboardBtn=menu.querySelector('[data-action="dashboard"]');const reportBtn=menu.querySelector('[data-action="report"]');const settingsBtn=menu.querySelector('[data-action="settings"]');if(callbacks.handleActionDashboard){dashboardBtn.addEventListener("click",e=>{e.stopPropagation();closeMenu();callbacks.handleActionDashboard(e,entityObject)})}if(callbacks.handleActionReport){reportBtn.addEventListener("click",e=>{e.stopPropagation();closeMenu();callbacks.handleActionReport(e,entityObject)})}if(callbacks.handleActionSettings){settingsBtn.addEventListener("click",e=>{e.stopPropagation();closeMenu();callbacks.handleActionSettings(e,entityObject)})}const checkbox=root.querySelector('.myio-ho-card__select input[type="checkbox"]');if(checkbox&&callbacks.handleSelect){checkbox.addEventListener("change",e=>{e.stopPropagation();const isSelected=checkbox.checked;root.classList.toggle("is-selected",isSelected);callbacks.handleSelect(isSelected,entityObject)})}const primarySection=root.querySelector(".myio-ho-card__primary");if(callbacks.handleClickCard){let handleCardClick=function(e){if(e.target.closest(".myio-ho-card__actions"))return;callbacks.handleClickCard(e,entityObject)};root.addEventListener("click",handleCardClick);primarySection.addEventListener("keydown",e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();callbacks.handleClickCard(e,entityObject)}})}if(state.enableDragDrop){root.addEventListener("dragstart",e=>{root.classList.add("is-dragging");e.dataTransfer.setData("text/plain",entityObject.entityId);const customEvent=new CustomEvent("myio:dragstart",{detail:{entityObject:entityObject},bubbles:true});root.dispatchEvent(customEvent)});root.addEventListener("dragend",()=>{root.classList.remove("is-dragging")});root.addEventListener("drop",e=>{e.preventDefault();const draggedId=e.dataTransfer.getData("text/plain");const customEvent=new CustomEvent("myio:drop",{detail:{draggedId:draggedId,targetEntity:entityObject},bubbles:true});root.dispatchEvent(customEvent)});root.addEventListener("dragover",e=>{e.preventDefault()})}root._cleanup=()=>{document.removeEventListener("click",closeMenu);document.removeEventListener("keydown",closeMenu)}}function unbindEvents(root){if(root._cleanup){root._cleanup();delete root._cleanup}}function renderCardCompenteHeadOffice(containerEl,params){if(!containerEl){throw new Error("renderCardCompenteHeadOffice: containerEl is required")}ensureCss();const state=normalizeParams(params);const root=buildDOM(state);containerEl.appendChild(root);bindEvents(root,state,state.callbacks);paint(root,state);return{update(next){if(next){Object.assign(state.entityObject,next);paint(root,state)}},destroy(){unbindEvents(root);if(root.parentNode){root.parentNode.removeChild(root)}},getRoot(){return root}}}var MyIOChartModalClass=class{constructor(){this.isOpen=false;this.modalElement=null;this.chartInstance=null;this.currentData=null;this.chartConfig={type:"line",timeRange:7,maxEntities:20};this._init()}async open(data){if(!data||!data.entities||data.entities.length===0){console.warn("ChartModal: No data provided for comparison");return}if(data.count>this.chartConfig.maxEntities){this._showTooManyEntitiesWarning(data);return}this.currentData=data;this.isOpen=true;await this._createModal();await this._loadChartJS();await this._renderChart();this._trackEvent("chart_modal.open",{entityCount:data.count,chartType:this.chartConfig.type,timeRange:this.chartConfig.timeRange})}close(){if(!this.isOpen)return;this.isOpen=false;if(this.chartInstance){this.chartInstance.destroy();this.chartInstance=null}if(this.modalElement){this.modalElement.remove();this.modalElement=null}if(typeof document!=="undefined"){document.body.focus()}this._trackEvent("chart_modal.close",{entityCount:this.currentData?.count||0})}exportCsv(){if(!this.currentData)return;const timestamp=(new Date).toISOString().slice(0,19).replace(/:/g,"-");const filename=`comparativo_${timestamp}.csv`;const csvData=this._generateCsvData();this._downloadFile(csvData,filename,"text/csv");this._trackEvent("chart_modal.export",{format:"csv",entityCount:this.currentData.count})}exportPng(){if(!this.chartInstance)return;const timestamp=(new Date).toISOString().slice(0,19).replace(/:/g,"-");const filename=`grafico_comparativo_${timestamp}.png`;const canvas=this.chartInstance.canvas;const url=canvas.toDataURL("image/png");this._downloadFile(url,filename,"image/png",true);this._trackEvent("chart_modal.export",{format:"png",entityCount:this.currentData.count})}exportPdf(){this._showNotImplementedNotice("PDF export");this._trackEvent("chart_modal.export",{format:"pdf",entityCount:this.currentData?.count||0,status:"not_implemented"})}_init(){const store=this._getSelectionStore();if(store){store.on("comparison:open",data=>this.open(data));store.on("comparison:too_many",data=>this._showTooManyEntitiesWarning(data))}}async _createModal(){if(typeof document==="undefined")return;const existing=document.getElementById("myio-chart-modal");if(existing){existing.remove()}const modal=document.createElement("div");modal.id="myio-chart-modal";modal.className="chart-modal-overlay";modal.setAttribute("role","dialog");modal.setAttribute("aria-modal","true");modal.setAttribute("aria-labelledby","chart-modal-title");modal.innerHTML=this._generateModalHTML();document.body.appendChild(modal);this.modalElement=modal;this._attachModalEventListeners();this._trapFocus();this._announceToScreenReader("Chart comparison modal opened")}_generateModalHTML(){const{entities:entities,totals:totals,count:count}=this.currentData;return`\n <div class="chart-modal-container" \n style="\n background: rgba(20, 20, 20, 0.95);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 16px;\n padding: 20px;\n max-width: 900px;\n margin: auto;\n color: #fff;\n font-family: Arial, sans-serif;\n box-shadow: 0 8px 30px rgba(0,0,0,0.5);\n ">\n \n <div class="chart-modal-header" \n style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">\n <h2 id="chart-modal-title" \n style="font-size: 20px; font-weight: bold; margin: 0; color: #fff;">\n Comparativo de Dispositivos (${count} selecionados)\n </h2>\n <button class="chart-modal-close" aria-label="Fechar modal"\n style="background: none; border: none; color: #fff; font-size: 24px; cursor: pointer; padding: 5px; transition: 0.3s;">\n ×\n </button>\n </div>\n \n <div class="chart-modal-controls" \n style="display: flex; gap: 20px; flex-wrap: wrap; margin-bottom: 20px;">\n \n <div class="chart-type-controls" style="flex: 1; min-width: 180px;">\n <label style="display: block; margin-bottom: 6px; color: rgba(255,255,255,0.8); font-size: 14px;">\n Tipo de Gráfico:\n </label>\n <select class="chart-type-select" aria-label="Selecionar tipo de gráfico"\n style="width: 100%; padding: 8px 12px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.08); \n background: rgba(255,255,255,0.08); color: #fff; outline: none; cursor: pointer;">\n <option value="line" ${this.chartConfig.type==="line"?"selected":""}>Linha</option>\n <option value="bar" ${this.chartConfig.type==="bar"?"selected":""}>Barras</option>\n </select>\n </div>\n \n <div class="chart-range-controls" style="flex: 1; min-width: 180px;">\n <label style="display: block; margin-bottom: 6px; color: rgba(255,255,255,0.8); font-size: 14px;">\n Período:\n </label>\n <select class="chart-range-select" aria-label="Selecionar período"\n style="width: 100%; padding: 8px 12px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.08); \n background: rgba(255,255,255,0.08); color: #fff; outline: none; cursor: pointer;">\n <option value="7" ${this.chartConfig.timeRange===7?"selected":""}>7 dias</option>\n <option value="14" ${this.chartConfig.timeRange===14?"selected":""}>14 dias</option>\n <option value="30" ${this.chartConfig.timeRange===30?"selected":""}>30 dias</option>\n </select>\n </div>\n \n <div class="chart-export-controls" style="display: flex; gap: 10px; align-items: end;">\n <button class="export-csv-btn"\n style="padding: 8px 14px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; transition: 0.3s;">\n Exportar CSV\n </button>\n <button class="export-png-btn"\n style="padding: 8px 14px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; transition: 0.3s;">\n Exportar PNG\n </button>\n <button class="export-pdf-btn"\n style="padding: 8px 14px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; transition: 0.3s;">\n Exportar PDF\n </button>\n </div>\n </div>\n \n <div class="chart-modal-body" style="display: flex; flex-direction: column; gap: 20px;">\n <div class="chart-container" \n style="background: rgba(255,255,255,0.05); border-radius: 12px; padding: 15px;">\n <canvas id="comparison-chart" aria-label="Gráfico comparativo de dispositivos"></canvas>\n </div>\n \n <div class="chart-summary" \n style="background: rgba(255,255,255,0.05); border-radius: 12px; padding: 15px;">\n <h3 style="margin: 0 0 12px; font-size: 16px; font-weight: bold;">Resumo da Seleção</h3>\n <div class="summary-grid" \n style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;">\n ${this._generateSummaryHTML(totals)}\n </div>\n </div>\n </div>\n \n <div class="chart-modal-footer" \n style="display: flex; justify-content: flex-end; margin-top: 20px;">\n <button class="chart-modal-close-btn"\n style="padding: 10px 20px; border-radius: 8px; border: none; cursor: pointer; \n background: rgba(255,255,255,0.08); color: #fff; font-weight: bold; transition: 0.3s;">\n Fechar\n </button>\n </div>\n </div>\n `}_generateSummaryHTML(totals){const items=[];if(totals.energyKwh>0){items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Energia Total:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(totals.energyKwh)} kWh</span>\n </div>`)}if(totals.waterM3>0){items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Água Total:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(totals.waterM3)} m³</span>\n </div>`)}if(totals.tempC>0){items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Temperatura Média:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${this._formatNumber(totals.tempC/totals.count)} °C</span>\n </div>`)}items.push(`<div class="summary-item" \n style="background: rgba(255,255,255,0.08); padding: 10px; border-radius: 8px;">\n <span class="summary-label" style="display: block; font-size: 13px; color: rgba(255,255,255,0.7);">Dispositivos:</span>\n <span class="summary-value" style="font-weight: bold; font-size: 14px;">${totals.count}</span>\n </div>`);return items.join("")}_generateSummaryHTML(totals){const items=[];if(totals.energyKwh>0){items.push(`<div class="summary-item">\n <span class="summary-label">Energia Total:</span>\n <span class="summary-value">${this._formatNumber(totals.energyKwh)} kWh</span>\n </div>`)}if(totals.waterM3>0){items.push(`<div class="summary-item">\n <span class="summary-label">Água Total:</span>\n <span class="summary-value">${this._formatNumber(totals.waterM3)} m³</span>\n </div>`)}if(totals.tempC>0){items.push(`<div class="summary-item">\n <span class="summary-label">Temperatura Média:</span>\n <span class="summary-value">${this._formatNumber(totals.tempC/totals.count)} °C</span>\n </div>`)}items.push(`<div class="summary-item">\n <span class="summary-label">Dispositivos:</span>\n <span class="summary-value">${totals.count}</span>\n </div>`);return items.join("")}_attachModalEventListeners(){if(!this.modalElement)return;const closeButtons=this.modalElement.querySelectorAll(".chart-modal-close, .chart-modal-close-btn");closeButtons.forEach(btn=>{btn.addEventListener("click",()=>this.close())});const typeSelect=this.modalElement.querySelector(".chart-type-select");if(typeSelect){typeSelect.addEventListener("change",e=>{this.chartConfig.type=e.target.value;this._renderChart();this._trackEvent("chart_modal.type_change",{newType:e.target.value,entityCount:this.currentData.count})})}const rangeSelect=this.modalElement.querySelector(".chart-range-select");if(rangeSelect){rangeSelect.addEventListener("change",e=>{this.chartConfig.timeRange=parseInt(e.target.value);this._renderChart();this._trackEvent("chart_modal.range_change",{newRange:e.target.value,entityCount:this.currentData.count})})}const csvBtn=this.modalElement.querySelector(".export-csv-btn");const pngBtn=this.modalElement.querySelector(".export-png-btn");const pdfBtn=this.modalElement.querySelector(".export-pdf-btn");if(csvBtn)csvBtn.addEventListener("click",()=>this.exportCsv());if(pngBtn)pngBtn.addEventListener("click",()=>this.exportPng());if(pdfBtn)pdfBtn.addEventListener("click",()=>this.exportPdf());this.modalElement.addEventListener("keydown",e=>{if(e.key==="Escape"){this.close()}});this.modalElement.addEventListener("click",e=>{if(e.target===this.modalElement){this.close()}})}async _loadChartJS(){if(typeof globalThis!=="undefined"&&globalThis.Chart){return}return new Promise((resolve,reject)=>{if(typeof document==="undefined"){resolve();return}const script=document.createElement("script");script.src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js";script.onload=resolve;script.onerror=reject;document.head.appendChild(script)})}async _renderChart(){if(typeof globalThis==="undefined"||!globalThis.Chart){console.error("Chart.js not loaded");return}const canvas=this.modalElement?.querySelector("#comparison-chart");if(!canvas)return;if(this.chartInstance){this.chartInstance.destroy()}const store=this._getSelectionStore();const entityIds=this.currentData.entities.map(e=>e.id);const endDate=new Date;const startDate=new Date;startDate.setDate(startDate.getDate()-this.chartConfig.timeRange);let timeSeriesData={};if(store&&store.getTimeSeriesData){timeSeriesData=await store.getTimeSeriesData(entityIds,startDate,endDate)}const chartData=this._prepareChartData(timeSeriesData);this.chartInstance=new globalThis.Chart(canvas,{type:this.chartConfig.type,data:chartData,options:this._getChartOptions()})}_prepareChartData(timeSeriesData){const datasets=[];const colors=["#FF6384","#36A2EB","#FFCE56","#4BC0C0","#9966FF","#FF9F40","#FF6384","#C9CBCF","#4BC0C0","#FF6384"];this.currentData.entities.forEach((entity,index)=>{const data=timeSeriesData[entity.id]||[];const color=colors[index%colors.length];datasets.push({label:entity.name,data:data.map(point=>({x:point.timestamp,y:point.value})),borderColor:color,backgroundColor:color+"20",fill:this.chartConfig.type==="line"?false:true})});return{datasets:datasets}}_getChartOptions(){return{responsive:true,maintainAspectRatio:false,scales:{x:{type:"time",time:{unit:"day"},title:{display:true,text:"Data"}},y:{title:{display:true,text:"Valor"}}},plugins:{title:{display:true,text:`Comparativo - ${this.chartConfig.timeRange} dias`},legend:{display:true,position:"top"},tooltip:{mode:"index",intersect:false}},interaction:{mode:"nearest",axis:"x",intersect:false}}}_generateCsvData(){const headers=["Data","Dispositivo","Valor","Unidade"];const rows=[headers];this.currentData.entities.forEach(entity=>{const today=new Date;for(let i=0;i<this.chartConfig.timeRange;i++){const date=new Date(today);date.setDate(date.getDate()-i);const value=Math.random()*100+50;rows.push([date.toLocaleDateString("pt-BR"),entity.name,this._formatNumber(value),entity.unit||""])}});return rows.map(row=>row.join(";")).join("\n")}_downloadFile(data,filename,mimeType,isDataUrl=false){if(typeof document==="undefined")return;const link=document.createElement("a");if(isDataUrl){link.href=data}else{const blob=new Blob([data],{type:mimeType});link.href=URL.createObjectURL(blob)}link.download=filename;document.body.appendChild(link);link.click();document.body.removeChild(link);if(!isDataUrl){URL.revokeObjectURL(link.href)}}_showTooManyEntitiesWarning(data){if(typeof document==="undefined")return;const message=`Muitos dispositivos selecionados (${data.count}). Máximo permitido: ${this.chartConfig.maxEntities}.`;if(typeof globalThis!=="undefined"&&globalThis.alert){globalThis.alert(message)}this._announceToScreenReader(message)}_showNotImplementedNotice(feature){const message=`${feature} será implementado em uma versão futura.`;if(typeof globalThis!=="undefined"&&globalThis.alert){globalThis.alert(message)}this._announceToScreenReader(message)}_trapFocus(){if(!this.modalElement||typeof document==="undefined")return;const focusableElements=this.modalElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');const firstElement=focusableElements[0];const lastElement=focusableElements[focusableElements.length-1];if(firstElement){firstElement.focus()}this.modalElement.addEventListener("keydown",e=>{if(e.key==="Tab"&&typeof document!=="undefined"){if(e.shiftKey){if(document.activeElement===firstElement){e.preventDefault();lastElement?.focus()}}else{if(document.activeElement===lastElement){e.preventDefault();firstElement?.focus()}}}})}_getSelectionStore(){if(typeof globalThis!=="undefined"&&globalThis.window?.MyIOSelectionStore){return globalThis.window.MyIOSelectionStore}return null}_trackEvent(eventName,payload={}){const store=this._getSelectionStore();if(store&&store.trackEvent){store.trackEvent(eventName,payload)}}_announceToScreenReader(message){const store=this._getSelectionStore();if(store&&store.announceToScreenReader){store.announceToScreenReader(message)}}_formatNumber(value){if(typeof value!=="number"||isNaN(value))return"0";return new Intl.NumberFormat("pt-BR",{minimumFractionDigits:0,maximumFractionDigits:2}).format(value)}};var MyIOChartModal=new MyIOChartModalClass;if(typeof globalThis!=="undefined"&&typeof globalThis.window!=="undefined"){globalThis.window.MyIOChartModal=MyIOChartModal}if(typeof module!=="undefined"&&module.exports){module.exports={MyIOChartModal:MyIOChartModal}}function openDashboardPopupEnergy(params){console.log("Opening energy modal with params:",params);return{close:()=>{console.log("Closing energy modal")},on:(event,handler)=>{console.log(`Registering ${event} handler for energy modal`)}}}var CSS_TOKENS=`\n:root {\n /* Brand Colors */\n --myio-brand-700: #3e1a7d;\n --myio-brand-600: #2d1458;\n --myio-accent: #2d1458;\n --myio-danger: #d32f2f;\n --myio-success: #388E3C;\n --myio-warning: #f57c00;\n --myio-info: #1976d2;\n \n /* Neutral Colors */\n --myio-bg: #f7f7f7;\n --myio-card: #ffffff;\n --myio-border: #e0e0e0;\n --myio-text: #333333;\n --myio-text-muted: #666666;\n --myio-text-light: #999999;\n \n /* Layout */\n --myio-shadow: 0 2px 6px rgba(0,0,0,0.08);\n --myio-shadow-lg: 0 4px 12px rgba(0,0,0,0.15);\n --myio-radius: 10px;\n --myio-radius-sm: 6px;\n --myio-spacing: 16px;\n --myio-spacing-sm: 8px;\n --myio-spacing-lg: 24px;\n \n /* Typography */\n --myio-font: 'Roboto', Arial, sans-serif;\n --myio-font-size: 14px;\n --myio-font-size-sm: 12px;\n --myio-font-size-lg: 16px;\n --myio-line-height: 1.4;\n \n /* Z-index */\n --myio-z-modal: 9999;\n --myio-z-backdrop: 9998;\n --myio-z-sticky: 100;\n \n /* Animation */\n --myio-transition: 0.2s ease;\n --myio-transition-slow: 0.3s ease;\n}\n\n/* Dark theme tokens */\n[data-theme="dark"] {\n --myio-bg: #1a1a1a;\n --myio-card: #2d2d2d;\n --myio-border: #404040;\n --myio-text: #ffffff;\n --myio-text-muted: #cccccc;\n --myio-text-light: #999999;\n --myio-shadow: 0 2px 6px rgba(0,0,0,0.3);\n --myio-shadow-lg: 0 4px 12px rgba(0,0,0,0.4);\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n :root {\n --myio-transition: 0s;\n --myio-transition-slow: 0s;\n }\n}\n`;var MODAL_STYLES=`\n.myio-modal-scope {\n font-family: var(--myio-font);\n font-size: var(--myio-font-size);\n line-height: var(--myio-line-height);\n color: var(--myio-text);\n box-sizing: border-box;\n}\n\n.myio-modal-scope *,\n.myio-modal-scope *::before,\n.myio-modal-scope *::after {\n box-sizing: inherit;\n}\n\n.myio-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(2px);\n z-index: var(--myio-z-backdrop);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--myio-spacing);\n}\n\n.myio-modal {\n background: var(--myio-card);\n border-radius: var(--myio-radius);\n box-shadow: var(--myio-shadow-lg);\n max-width: 90vw;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transform: scale(0.95);\n opacity: 0;\n transition: transform var(--myio-transition), opacity var(--myio-transition);\n}\n\n.myio-modal.myio-modal-open {\n transform: scale(1);\n opacity: 1;\n}\n\n.myio-modal-header {\n padding: var(--myio-spacing);\n border-bottom: none;\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--myio-brand-700);\n color: white;\n border-radius: var(--myio-radius) var(--myio-radius) 0 0;\n}\n\n.myio-modal-title {\n font-size: var(--myio-font-size-lg);\n font-weight: 600;\n margin: 0;\n color: white;\n}\n\n.myio-modal-close {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--myio-radius-sm);\n color: rgba(255, 255, 255, 0.8);\n transition: background-color var(--myio-transition);\n}\n\n.myio-modal-close:hover {\n background: rgba(255, 255, 255, 0.1);\n color: white;\n}\n\n.myio-modal-close:focus-visible {\n outline: 2px solid rgba(255, 255, 255, 0.5);\n outline-offset: 2px;\n}\n\n.myio-modal-body {\n flex: 1;\n overflow: auto;\n padding: var(--myio-spacing);\n}\n\n.myio-modal-footer {\n padding: var(--myio-spacing);\n border-top: 1px solid var(--myio-border);\n display: flex;\n gap: var(--myio-spacing-sm);\n justify-content: flex-end;\n}\n\n/* Button styles */\n.myio-btn {\n padding: 8px 16px;\n border: none;\n border-radius: var(--myio-radius-sm);\n font-family: inherit;\n font-size: var(--myio-font-size);\n cursor: pointer;\n transition: background-color var(--myio-transition);\n display: inline-flex;\n align-items: center;\n gap: var(--myio-spacing-sm);\n}\n\n.myio-btn-primary {\n background: var(--myio-brand-700);\n color: white;\n}\n\n.myio-btn-primary:hover {\n background: var(--myio-brand-600);\n}\n\n.myio-btn-secondary {\n background: var(--myio-bg);\n color: var(--myio-text);\n border: 1px solid var(--myio-border);\n}\n\n.myio-btn-secondary:hover {\n background: var(--myio-border);\n}\n\n.myio-btn:focus-visible {\n outline: 2px solid var(--myio-brand-700);\n outline-offset: 2px;\n}\n\n.myio-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Form styles */\n.myio-form-group {\n margin-bottom: var(--myio-spacing);\n}\n\n.myio-label {\n display: block;\n margin-bottom: var(--myio-spacing-sm);\n font-weight: 500;\n color: var(--myio-text);\n}\n\n.myio-input {\n width: 100%;\n padding: var(--myio-spacing-sm);\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius-sm);\n font-family: inherit;\n font-size: var(--myio-font-size);\n transition: border-color var(--myio-transition);\n}\n\n.myio-input:focus {\n outline: none;\n border-color: var(--myio-brand-700);\n}\n\n/* Table styles */\n.myio-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--myio-font-size);\n}\n\n.myio-table th,\n.myio-table td {\n padding: var(--myio-spacing-sm) var(--myio-spacing);\n text-align: left;\n border-bottom: 1px solid var(--myio-border);\n}\n\n.myio-table th:first-child,\n.myio-table td:first-child {\n padding-left: var(--myio-spacing-lg);\n}\n\n.myio-table th:last-child,\n.myio-table td:last-child {\n padding-right: var(--myio-spacing-lg);\n}\n\n.myio-table th {\n background: var(--myio-brand-700);\n color: white;\n font-weight: 600;\n position: sticky;\n top: 0;\n z-index: var(--myio-z-sticky);\n}\n\n.myio-table tbody tr:nth-child(even) {\n background: var(--myio-bg);\n}\n\n.myio-table tbody tr:hover {\n background: var(--myio-border);\n}\n\n/* Loading spinner */\n.myio-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid var(--myio-border);\n border-top: 2px solid var(--myio-brand-700);\n border-radius: 50%;\n animation: myio-spin 1s linear infinite;\n}\n\n@keyframes myio-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n/* Utility classes */\n.myio-text-center { text-align: center; }\n.myio-text-right { text-align: right; }\n.myio-text-muted { color: var(--myio-text-muted); }\n.myio-text-success { color: var(--myio-success); }\n.myio-text-danger { color: var(--myio-danger); }\n.myio-mb-0 { margin-bottom: 0; }\n.myio-mt-0 { margin-top: 0; }\n.myio-p-0 { padding: 0; }\n`;var DATERANGEPICKER_STYLES=`\n/* MyIO Premium DateRangePicker Styling */\n.myio-modal-scope .daterangepicker {\n font-family: var(--myio-font);\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius);\n box-shadow: var(--myio-shadow-lg);\n background: var(--myio-card);\n z-index: var(--myio-z-popover, 10000);\n}\n\n.myio-modal-scope .daterangepicker .calendar-table {\n background: var(--myio-card);\n border: none;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table th,\n.myio-modal-scope .daterangepicker .calendar-table td {\n border: none;\n padding: 8px;\n text-align: center;\n font-size: 13px;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table th {\n background: var(--myio-bg);\n color: var(--myio-text);\n font-weight: 600;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.available:hover {\n background: var(--myio-bg);\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.in-range {\n background: rgba(74, 20, 140, 0.1);\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.start-date,\n.myio-modal-scope .daterangepicker .calendar-table td.end-date {\n background: var(--myio-brand-700);\n color: white;\n border-radius: 4px;\n}\n\n.myio-modal-scope .daterangepicker .calendar-table td.active {\n background: var(--myio-brand-700);\n color: white;\n border-radius: 4px;\n}\n\n/* Premium button styling for Aplicar/Cancelar */\n.myio-modal-scope .daterangepicker .drp-buttons {\n border-top: 1px solid var(--myio-border);\n padding: 12px 16px;\n background: var(--myio-bg);\n text-align: right;\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .btn {\n margin-left: 8px;\n padding: 8px 16px;\n border-radius: var(--myio-radius-sm);\n font-family: var(--myio-font);\n font-size: 14px;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all var(--myio-transition);\n min-width: 80px;\n}\n\n/* Aplicar button - MyIO Primary */\n.myio-modal-scope .daterangepicker .drp-buttons .applyBtn {\n background: linear-gradient(135deg, var(--myio-brand-700) 0%, var(--myio-accent) 100%);\n color: white;\n box-shadow: 0 2px 4px rgba(74, 20, 140, 0.2);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .applyBtn:hover {\n background: linear-gradient(135deg, var(--myio-brand-600) 0%, var(--myio-brand-700) 100%);\n box-shadow: 0 4px 8px rgba(74, 20, 140, 0.3);\n transform: translateY(-1px);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .applyBtn:active {\n transform: translateY(0);\n box-shadow: 0 2px 4px rgba(74, 20, 140, 0.2);\n}\n\n/* Cancelar button - MyIO Secondary */\n.myio-modal-scope .daterangepicker .drp-buttons .cancelBtn {\n background: var(--myio-card);\n color: var(--myio-text);\n border: 1px solid var(--myio-border);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .cancelBtn:hover {\n background: var(--myio-bg);\n border-color: var(--myio-brand-700);\n color: var(--myio-brand-700);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n transform: translateY(-1px);\n}\n\n.myio-modal-scope .daterangepicker .drp-buttons .cancelBtn:active {\n transform: translateY(0);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n/* Ranges (preset buttons) styling */\n.myio-modal-scope .daterangepicker .ranges {\n background: var(--myio-bg);\n border-right: 1px solid var(--myio-border);\n}\n\n.myio-modal-scope .daterangepicker .ranges li {\n padding: 10px 16px;\n margin: 2px 8px;\n border-radius: var(--myio-radius-sm);\n cursor: pointer;\n transition: all var(--myio-transition);\n font-size: 13px;\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .ranges li:hover {\n background: rgba(74, 20, 140, 0.1);\n color: var(--myio-brand-700);\n}\n\n.myio-modal-scope .daterangepicker .ranges li.active {\n background: var(--myio-brand-700);\n color: white;\n font-weight: 500;\n}\n\n/* Time picker styling */\n.myio-modal-scope .daterangepicker .calendar-time {\n border-top: 1px solid var(--myio-border);\n background: var(--myio-bg);\n padding: 8px;\n}\n\n.myio-modal-scope .daterangepicker .calendar-time select {\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius-sm);\n padding: 4px 8px;\n font-family: var(--myio-font);\n background: var(--myio-card);\n color: var(--myio-text);\n}\n\n.myio-modal-scope .daterangepicker .calendar-time select:focus {\n outline: none;\n border-color: var(--myio-brand-700);\n box-shadow: 0 0 0 2px rgba(74, 20, 140, 0.2);\n}\n\n/* Header styling */\n.myio-modal-scope .daterangepicker .drp-calendar {\n background: var(--myio-card);\n}\n\n.myio-modal-scope .daterangepicker .month {\n color: var(--myio-brand-700);\n font-weight: 600;\n font-size: 14px;\n}\n\n.myio-modal-scope .daterangepicker .prev,\n.myio-modal-scope .daterangepicker .next {\n color: var(--myio-brand-700);\n border: 1px solid var(--myio-border);\n border-radius: var(--myio-radius-sm);\n background: var(--myio-card);\n transition: all var(--myio-transition);\n}\n\n.myio-modal-scope .daterangepicker .prev:hover,\n.myio-modal-scope .daterangepicker .next:hover {\n background: var(--myio-brand-700);\n color: white;\n border-color: var(--myio-brand-700);\n}\n`;var ModalPremiumShell=class{constructor(options){this.options=options;this.originalActiveElement=document.activeElement;this.originalBodyOverflow=document.body.style.overflow;this.injectStyles();this.createElements();this.setupEventListeners();this.setupFocusTrap();this.lockBodyScroll();this.setInertBackground()}backdrop;modal;header;body;footer;closeButton;styleElement;focusTrap;originalBodyOverflow;originalActiveElement;closeHandlers=[];injectStyles(){this.styleElement=document.createElement("style");this.styleElement.textContent=CSS_TOKENS+MODAL_STYLES;document.head.appendChild(this.styleElement)}createElements(){this.backdrop=document.createElement("div");this.backdrop.className="myio-modal-backdrop myio-modal-scope";this.backdrop.setAttribute("role","dialog");this.backdrop.setAttribute("aria-modal","true");this.backdrop.setAttribute("aria-labelledby","myio-modal-title");if(this.options.theme==="dark"){this.backdrop.setAttribute("data-theme","dark")}this.modal=document.createElement("div");this.modal.className="myio-modal";if(this.options.width){const width=typeof this.options.width==="number"?`${this.options.width}px`:this.options.width;this.modal.style.width=width}if(this.options.height){const height=typeof this.options.height==="number"?`${this.options.height}px`:this.options.height;this.modal.style.height=height}this.header=document.createElement("div");this.header.className="myio-modal-header";const title=document.createElement("h2");title.id="myio-modal-title";title.className="myio-modal-title";title.textContent=this.options.title;this.closeButton=document.createElement("button");this.closeButton.className="myio-modal-close";this.closeButton.innerHTML="×";this.closeButton.setAttribute("aria-label","Fechar modal");this.closeButton.type="button";this.header.appendChild(title);this.header.appendChild(this.closeButton);this.body=document.createElement("div");this.body.className="myio-modal-body";this.footer=document.createElement("div");this.footer.className="myio-modal-footer";this.footer.style.display="none";this.modal.appendChild(this.header);this.modal.appendChild(this.body);this.modal.appendChild(this.footer);this.backdrop.appendChild(this.modal)}setupEventListeners(){this.closeButton.addEventListener("click",()=>this.close());if(this.options.closeOnBackdrop!==false){this.backdrop.addEventListener("click",e=>{if(e.target===this.backdrop){this.close()}})}if(this.options.closeOnEscape!==false){document.addEventListener("keydown",this.handleKeyDown)}}handleKeyDown=e=>{if(e.key==="Escape"){this.close()}};setupFocusTrap(){this.focusTrap=new FocusTrap(this.modal)}lockBodyScroll(){document.body.style.overflow="hidden"}unlockBodyScroll(){document.body.style.overflow=this.originalBodyOverflow}setInertBackground(){const topLevelElements=Array.from(document.body.children);topLevelElements.forEach(element=>{if(element!==this.backdrop&&element.tagName!=="SCRIPT"&&element.tagName!=="STYLE"){element.inert=true}})}removeInertBackground(){const topLevelElements=Array.from(document.body.children);topLevelElements.forEach(element=>{element.inert=false})}show(){document.body.appendChild(this.backdrop);requestAnimationFrame(()=>{this.modal.classList.add("myio-modal-open");this.focusTrap.activate()});return{element:this.body,close:()=>this.close(),setContent:content=>this.setContent(content),setFooter:footer=>this.setFooter(footer),on:(event,handler)=>this.on(event,handler)}}setContent(content){if(typeof content==="string"){this.body.innerHTML=content}else{this.body.innerHTML="";this.body.appendChild(content)}}setFooter(footer){if(typeof footer==="string"){this.footer.innerHTML=footer}else{this.footer.innerHTML="";this.footer.appendChild(footer)}this.footer.style.display="flex"}on(event,handler){if(event==="close"){this.closeHandlers.push(handler)}}close(){this.modal.classList.remove("myio-modal-open");setTimeout(()=>{this.cleanup();this.closeHandlers.forEach(handler=>handler())},200)}cleanup(){document.removeEventListener("keydown",this.handleKeyDown);if(this.originalActiveElement&&"focus"in this.originalActiveElement){this.originalActiveElement.focus()}this.focusTrap.deactivate();this.unlockBodyScroll();this.removeInertBackground();if(this.backdrop.parentNode){this.backdrop.parentNode.removeChild(this.backdrop)}if(this.styleElement.parentNode){this.styleElement.parentNode.removeChild(this.styleElement)}}};var FocusTrap=class{constructor(container){this.container=container}focusableElements=[];firstFocusable=null;lastFocusable=null;activate(){this.updateFocusableElements();this.container.addEventListener("keydown",this.handleTabKey);if(this.firstFocusable){this.firstFocusable.focus()}}deactivate(){this.container.removeEventListener("keydown",this.handleTabKey)}updateFocusableElements(){const focusableSelectors=["button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","a[href]",'[tabindex]:not([tabindex="-1"])'].join(", ");this.focusableElements=Array.from(this.container.querySelectorAll(focusableSelectors));this.firstFocusable=this.focusableElements[0]||null;this.lastFocusable=this.focusableElements[this.focusableElements.length-1]||null}handleTabKey=e=>{if(e.key!=="Tab")return;if(e.shiftKey){if(document.activeElement===this.firstFocusable){e.preventDefault();this.lastFocusable?.focus()}}else{if(document.activeElement===this.lastFocusable){e.preventDefault();this.firstFocusable?.focus()}}}};function createModal(options){const shell=new ModalPremiumShell(options);return shell.show()}var rangeDaysInclusive=(start,end)=>{const out=[];let cur=new Date(start);const last=new Date(end);while(cur<=last){out.push(cur.toISOString().slice(0,10));cur.setDate(cur.getDate()+1)}return out};var toCsv=(rows,locale="pt-BR",sep=";")=>{const fmt=new Intl.NumberFormat(locale,{minimumFractionDigits:2,maximumFractionDigits:2});const esc=v=>(typeof v==="number"?fmt.format(v):String(v)).replace(/"/g,'""');return rows.map(r=>r.map(c=>`"${esc(c)}"`).join(sep)).join("\r\n")};var fmtPt=n=>new Intl.NumberFormat("pt-BR",{minimumFractionDigits:2,maximumFractionDigits:2}).format(n);var AuthClient=class{constructor(cfg){this.cfg=cfg}token;async getBearer(){const now=Date.now()/1e3;if(this.token&&this.token.exp-now>60)return this.token.value;this.token={value:"",exp:now+300};return this.token.value}clearCache(){this.token=void 0}};var CDN_RESOURCES=[{id:"jquery-3.7.1",src:"https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js",integrity:"sha384-1H217gwSVyLSIfaLxHbE7dRb3v4mYCKbpQvzx0cegeju1MVsGrX5xXxAvs/HgeFs",crossorigin:"anonymous"},{id:"moment-2.29.4",src:"https://cdn.jsdelivr.net/npm/moment@2.29.4/min/moment.min.js",integrity:"sha384-2xoILS8hBHw+Atyv/qJLEdk8dFdW1hbGjfeQ3G0GU3pGNPlqck0chRqjMTZ5blGf",crossorigin:"anonymous"},{id:"daterangepicker-3.1.0",src:"https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js",integrity:"sha384-IbJFThFkdkMvvxP0U8wOffxBHPYEJE65UtA/l25/jJQUt/hft6OdAuKLxGjtOVnL",crossorigin:"anonymous"}];var CSS_RESOURCE={href:"https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.css",integrity:"sha384-zLkQsiLfAQqGeIJeKLC+rcCR1YoYaQFLCL7cLDUoKE1ajKJzySpjzWGfYS2vjSG+"};var FALLBACK_PATHS=["/assets/vendor/jquery.min.js","/assets/vendor/moment.min.js","/assets/vendor/daterangepicker.min.js"];var PT_BR_LOCALE={format:"DD/MM/YY HH:mm",separator:" até ",applyLabel:"Aplicar",cancelLabel:"Cancelar",fromLabel:"De",toLabel:"Até",customRangeLabel:"Personalizado",daysOfWeek:["Do","Se","Te","Qa","Qi","Se","Sa"],monthNames:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],firstDay:1};var CDNLoader=class{static jQueryInstance=null;static loadingPromise=null;static loaded=false;static async ensureLoaded(){if(this.loaded&&this.jQueryInstance){return this.jQueryInstance}if(this.loadingPromise){return this.loadingPromise}this.loadingPromise=this.loadResources();return this.loadingPromise}static async loadResources(){if(window.jQuery&&window.moment&&window.jQuery.fn.daterangepicker){this.jQueryInstance=window.jQuery.noConflict(true);this.loaded=true;return this.jQueryInstance}try{await this.loadFromCDN();console.log("DateRangePicker: CDN loaded successfully")}catch(cdnError){console.warn("DateRangePicker: CDN failed, trying local assets:",cdnError);try{await this.loadFromLocal();console.log("DateRangePicker: Local assets loaded successfully")}catch(localError){console.warn("DateRangePicker: Local assets failed, using native inputs:",localError);throw new Error("DateRangePicker unavailable - using native inputs")}}this.jQueryInstance=window.jQuery?.noConflict(true);this.loaded=true;if(!this.jQueryInstance){throw new Error("jQuery not available after loading")}return this.jQueryInstance}static async loadFromCDN(){await this.loadCSS(CSS_RESOURCE.href,CSS_RESOURCE.integrity);for(const resource of CDN_RESOURCES){await this.loadScript(resource.src,resource.integrity)}}static async loadFromLocal(){for(const path of FALLBACK_PATHS){await this.loadScript(path)}}static loadScript(src,integrity){return new Promise((resolve,reject)=>{if(document.querySelector(`script[src="${src}"]`)){resolve();return}const script=document.createElement("script");script.src=src;script.async=false;if(integrity){script.integrity=integrity;script.crossOrigin="anonymous"}script.onload=()=>resolve();script.onerror=()=>reject(new Error(`Failed to load script: ${src}`));document.head.appendChild(script)})}static loadCSS(href,integrity){return new Promise((resolve,reject)=>{if(document.querySelector(`link[href="${href}"]`)){resolve();return}const link=document.createElement("link");link.rel="stylesheet";link.href=href;if(integrity){link.integrity=integrity;link.crossOrigin="anonymous"}link.onload=()=>resolve();link.onerror=()=>reject(new Error(`Failed to load CSS: ${href}`));document.head.appendChild(link)})}};function injectPremiumStyling(){const styleId="myio-daterangepicker-styles";if(document.getElementById(styleId)){return}const style=document.createElement("style");style.id=styleId;style.textContent=DATERANGEPICKER_STYLES;document.head.appendChild(style)}async function attach(input,opts={}){try{const $2=await CDNLoader.ensureLoaded();return createDateRangePicker($2,input,opts)}catch(error){console.error("DateRangePicker: Failed to load dependencies. Native date inputs are forbidden in this project.",error);throw new Error("DateRangePicker dependencies unavailable. Please ensure jQuery, moment.js, and daterangepicker are accessible.")}}function createDateRangePicker($2,input,opts){const $input=$2(input);const maxRangeDays=opts.maxRangeDays??31;injectPremiumStyling();input.readOnly=true;input.setAttribute("aria-label","Período de datas");const helpText=document.createElement("div");helpText.className="myio-text-muted";helpText.style.fontSize="12px";helpText.style.marginTop="4px";helpText.style.display="flex";helpText.style.alignItems="center";input.parentNode?.appendChild(helpText);const moment=window.moment;const startDate=opts.presetStart?moment(opts.presetStart).startOf("day"):moment().startOf("month");const endDate=opts.presetEnd?moment(opts.presetEnd).endOf("day"):moment().endOf("day");$input.daterangepicker({parentEl:opts.parentEl||document.body,timePicker:true,timePicker24Hour:true,timePickerIncrement:1,autoApply:true,autoUpdateInput:true,linkedCalendars:true,showCustomRangeLabel:true,maxSpan:{days:maxRangeDays},maxDate:moment().endOf("day"),startDate:startDate,endDate:endDate,opens:"right",drops:"down",locale:PT_BR_LOCALE,applyButtonClasses:"btn btn-primary",cancelClass:"btn btn-muted",ranges:{Hoje:[moment().startOf("day"),moment().endOf("day")],"Últimos 7 dias":[moment().subtract(6,"days").startOf("day"),moment().endOf("day")],"Últimos 30 dias":[moment().subtract(29,"days").startOf("day"),moment().endOf("day")],"Mês Anterior":[moment().subtract(1,"month").startOf("month"),moment().subtract(1,"month").endOf("month")]}});updateInputDisplay();$input.on("apply.daterangepicker.myio",()=>{updateInputDisplay();if(opts.onApply){const result=getDates();opts.onApply(result)}});$input.on("cancel.daterangepicker.myio",()=>{$input.val("");if(opts.onApply){opts.onApply({startISO:"",endISO:"",startLabel:"",endLabel:""})}});function updateInputDisplay(){const picker=$input.data("daterangepicker");if(picker){const formatted=`${picker.startDate.format(PT_BR_LOCALE.format)}${PT_BR_LOCALE.separator}${picker.endDate.format(PT_BR_LOCALE.format)}`;$input.val(formatted)}}function getDates(){const picker=$input.data("daterangepicker");const startISO=picker.startDate.format("YYYY-MM-DD[T]HH:mm:ssZ");const endISO=picker.endDate.format("YYYY-MM-DD[T]HH:mm:ssZ");const startLabel=picker.startDate.format(PT_BR_LOCALE.format);const endLabel=picker.endDate.format(PT_BR_LOCALE.format);return{startISO:startISO,endISO:endISO,startLabel:startLabel,endLabel:endLabel}}function setDates(startISO,endISO){const picker=$input.data("daterangepicker");picker.setStartDate(moment(startISO));picker.setEndDate(moment(endISO));updateInputDisplay()}function destroy(){const picker=$input.data("daterangepicker");$input.off(".daterangepicker.myio");picker?.remove?.();$input.removeData("daterangepicker");helpText?.remove()}return{getDates:getDates,setDates:setDates,destroy:destroy}}var DateRangePickerJQ={attach:attach};var createDefaultEnergyFetcher=params=>async({baseUrl:baseUrl,ingestionId:ingestionId,startISO:startISO,endISO:endISO})=>{const url=`${baseUrl}/api/v1/telemetry/devices/${ingestionId}/energy?startTime=${encodeURIComponent(startISO)}&endTime=${encodeURIComponent(endISO)}&granularity=1d&page=1&pageSize=1000&deep=0`;const token=params.api.ingestionToken;if(!token){throw new Error("ingestionToken is required for Data API calls to data.apps.myio-bas.com")}const response=await fetch(url,{headers:{Authorization:`Bearer ${token}`,"Content-Type":"application/json"}});if(!response.ok){throw new Error(`HTTP ${response.status}: ${response.statusText}`)}return response.json()};var DeviceReportModal=class{constructor(params){this.params=params;this.authClient=new AuthClient({clientId:params.api.clientId,clientSecret:params.api.clientSecret,base:params.api.dataApiBaseUrl});this.energyFetcher=params.fetcher||createDefaultEnergyFetcher(params)}modal;authClient;energyFetcher;data=[];isLoading=false;eventHandlers={};dateRangePicker=null;sortState={key:null,direction:"asc"};show(){this.modal=createModal({title:`Relatório - ${this.params.identifier||"SEM IDENTIFICADOR"} - ${this.params.label||"SEM ETIQUETA"}`,width:"80vw",height:"90vh",theme:this.params.ui?.theme||"light"});this.renderContent();this.modal.on("close",()=>{if(this.dateRangePicker){this.dateRangePicker.destroy();this.dateRangePicker=null}this.authClient.clearCache();this.emit("close")});return{close:()=>this.modal.close(),on:(event,handler)=>this.on(event,handler)}}renderContent(){const content=document.createElement("div");content.innerHTML=`\n <div class="myio-modal-scope">\n <div style="margin-bottom: 16px;">\n <div style="display: flex; gap: 16px; align-items: end; margin-bottom: 16px;">\n <div class="myio-form-group" style="margin-bottom: 0;">\n <label class="myio-label" for="date-range">Período</label>\n <input type="text" id="date-range" class="myio-input" readonly placeholder="Selecione o período" style="width: 300px;">\n </div>\n <button id="load-btn" class="myio-btn myio-btn-primary">\n <span class="myio-spinner" id="load-spinner" style="display: none;"></span>\n Carregar\n </button>\n <button id="export-btn" class="myio-btn myio-btn-secondary" disabled>\n Exportar CSV\n </button>\n </div>\n </div>\n \n <div id="error-container" style="display: none; background: #ffebee; color: #c62828; padding: 12px; border-radius: 6px; margin-bottom: 16px;">\n </div>\n \n <div id="table-container">\n <div style="text-align: center; padding: 40px; color: var(--myio-text-muted);">\n Selecione um período e clique em "Carregar" para visualizar os dados.\n </div>\n </div>\n </div>\n `;this.modal.setContent(content);this.setupEventListeners()}async setupEventListeners(){const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const dateRangeInput=document.getElementById("date-range");loadBtn?.addEventListener("click",()=>this.loadData());exportBtn?.addEventListener("click",()=>this.exportCSV());try{this.dateRangePicker=await attach(dateRangeInput,{presetStart:this.getDefaultStartDate(),presetEnd:this.getDefaultEndDate(),maxRangeDays:31,parentEl:this.modal.element,onApply:({startISO:startISO,endISO:endISO})=>{this.hideError();console.log("Date range selected:",{startISO:startISO,endISO:endISO})}})}catch(error){console.warn("DateRangePicker initialization failed, using fallback:",error)}}async loadData(){if(this.isLoading)return;const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const spinner=document.getElementById("load-spinner");if(!this.dateRangePicker){this.showError("Seletor de data não inicializado");return}this.isLoading=true;loadBtn.disabled=true;exportBtn.disabled=true;spinner.style.display="inline-block";try{const{startISO:startISO,endISO:endISO}=this.dateRangePicker.getDates();if(!startISO||!endISO){this.showError("Selecione um período válido");return}const startDate=startISO.split("T")[0];const endDate=endISO.split("T")[0];const dateRange=rangeDaysInclusive(startDate,endDate);const apiResponse=await this.energyFetcher({baseUrl:this.params.api.dataApiBaseUrl||"https://api.data.apps.myio-bas.com",ingestionId:this.params.ingestionId,startISO:startISO,endISO:endISO});this.data=this.processApiResponse(apiResponse,dateRange);this.renderTable();exportBtn.disabled=false;this.emit("loaded",{date:{start:startDate,end:endDate},count:this.data.length,total:this.calculateTotal()})}catch(error){this.showError("Erro ao carregar dados: "+error.message);console.error("Error loading data:",error);this.emit("error",{message:error.message,context:"loadData"})}finally{this.isLoading=false;loadBtn.disabled=false;spinner.style.display="none"}}processApiResponse(apiResponse,dateRange){const dataArray=Array.isArray(apiResponse)?apiResponse:apiResponse.data||[];if(!Array.isArray(dataArray)||dataArray.length===0){console.warn("[DeviceReportModal] API returned empty or invalid response, zero-filling date range");return dateRange.map(date=>({date:date,consumption:0}))}const deviceData=dataArray[0];const consumption=deviceData.consumption||[];const dailyMap={};consumption.forEach(item=>{if(item.timestamp&&item.value!=null){const date=item.timestamp.slice(0,10);const value=Number(item.value);if(!dailyMap[date])dailyMap[date]=0;dailyMap[date]+=value}});return dateRange.map(date=>({date:date,consumption:dailyMap[date]||0}))}generateMockData(dateRange){return dateRange.map(date=>({date:date,consumption:Math.random()*50+10}))}renderTable(){const container=document.getElementById("table-container");if(!container)return;const total=this.calculateTotal();const getSortIndicator=columnKey=>{if(this.sortState.key===columnKey){return this.sortState.direction==="asc"?"↑":"↓"}return"↕"};container.innerHTML=`\n <div style="margin-bottom: 16px; padding: 12px; background: var(--myio-bg); border-radius: 6px;">\n <strong>Total: ${fmtPt(total)} kWh</strong>\n </div>\n \n <div style="max-height: 400px; overflow-y: auto; border: 1px solid var(--myio-border); border-radius: 6px;">\n <table class="myio-table">\n <thead>\n <tr>\n <th style="cursor: pointer;" data-sort="date">\n Data\n <span style="margin-left: 4px; opacity: ${this.sortState.key==="date"?"1":"0.5"};">${getSortIndicator("date")}</span>\n </th>\n <th style="cursor: pointer; text-align: right;" data-sort="consumption">\n Consumo (kWh)\n <span style="margin-left: 4px; opacity: ${this.sortState.key==="consumption"?"1":"0.5"};">${getSortIndicator("consumption")}</span>\n </th>\n </tr>\n </thead>\n <tbody>\n ${this.data.map(row=>`\n <tr>\n <td>${this.formatDate(row.date)}</td>\n <td style="text-align: right;">${fmtPt(row.consumption)}</td>\n </tr>\n `).join("")}\n </tbody>\n </table>\n </div>\n `;this.setupTableSorting()}setupTableSorting(){const headers=document.querySelectorAll("[data-sort]");headers.forEach(header=>{header.addEventListener("click",()=>{const sortKey=header.getAttribute("data-sort");this.sortData(sortKey);this.renderTable()})})}sortData(key){if(this.sortState.key===key){this.sortState.direction=this.sortState.direction==="asc"?"desc":"asc"}else{this.sortState.key=key;this.sortState.direction="asc"}this.data.sort((a,b)=>{let comparison=0;if(key==="date"){comparison=new Date(a.date).getTime()-new Date(b.date).getTime()}else{comparison=a.consumption-b.consumption}return this.sortState.direction==="desc"?-comparison:comparison})}calculateTotal(){return this.data.reduce((sum,row)=>sum+row.consumption,0)}formatDate(dateStr){const date=new Date(dateStr+"T00:00:00");return date.toLocaleDateString("pt-BR")}exportCSV(){const total=this.calculateTotal();const now=new Date;const timestamp=now.toLocaleDateString("pt-BR")+" - "+now.toLocaleTimeString("pt-BR",{hour:"2-digit",minute:"2-digit"});const csvData=[["Dispositivo/Loja",this.params.identifier||"N/A",this.params.label||""],["DATA EMISSÃO",timestamp,""],["Total",fmtPt(total),""],["Data","Consumo",""],...this.data.map(row=>[this.formatDate(row.date),fmtPt(row.consumption)])];const csvContent=toCsv(csvData);this.downloadCSV(csvContent,`relatorio-${this.params.identifier||"dispositivo"}-${(new Date).toISOString().split("T")[0]}.csv`)}downloadCSV(content,filename){const BOM="\ufeff";const csvWithBOM=BOM+content;const blob=new Blob([csvWithBOM],{type:"text/csv;charset=utf-8;"});const link=document.createElement("a");const url=URL.createObjectURL(blob);link.setAttribute("href",url);link.setAttribute("download",filename);link.style.visibility="hidden";document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(url)}getDefaultStartDate(){const date=new Date;date.setDate(1);return date.toISOString().split("T")[0]}getDefaultEndDate(){return(new Date).toISOString().split("T")[0]}showError(message){const container=document.getElementById("error-container");if(container){container.textContent=message;container.style.display="block"}}hideError(){const container=document.getElementById("error-container");if(container){container.style.display="none"}}on(event,handler){if(!this.eventHandlers[event]){this.eventHandlers[event]=[]}this.eventHandlers[event].push(handler)}emit(event,payload){if(this.eventHandlers[event]){this.eventHandlers[event].forEach(handler=>handler())}}};function openDashboardPopupReport(params){const modal=new DeviceReportModal(params);return modal.show()}var defaultI18n={selectAll:"Selecionar todas",clear:"Limpar",searchPlaceholder:"Buscar lojas...",sortingTitle:"Ordenação",consumptionDesc:"Consumo ↓ (padrão)",consumptionAsc:"Consumo ↑",aToZ:"A → Z",zToA:"Z → A",tieNote:"Caso o consumo seja o mesmo é considerada a ordem alfabética.",apply:"Aplicar",reset:"Resetar",totalLabel:"Lojas",selectedLabel:"Selecionadas",closeLabel:"Fechar"};var FilterOrderingModal=class{state;props;i18n;dom=null;searchTimeout=null;itemsById;initialState;openerEl=null;constructor(props){this.props=props;this.i18n={...defaultI18n,...props.i18n};this.itemsById=new Map(props.items.map(item=>[item.id,item]));const initialSelected=new Set(props.initialSelected||[]);const initialSort=props.initialSort||"CONSUMPTION_DESC";this.state={allIds:props.items.map(item=>item.id),selected:new Set(initialSelected),query:"",sort:initialSort};this.initialState={selected:new Set(initialSelected),sort:initialSort}}open(){if(!this.dom){this.createDOM()}this.openerEl=document.activeElement instanceof HTMLElement?document.activeElement:null;this.updateCounters();this.renderList();this.dom.overlay.setAttribute("aria-hidden","false");this.dom.root.setAttribute("aria-hidden","false");this.lockBodyScroll();this.dom.root.addEventListener("keydown",this.trapFocus);setTimeout(()=>{const search=this.dom.searchInput||this.dom.root.querySelector("button, input");if(search)search.focus()},200);this.emit("myio:filter:open",{})}close(){if(this.dom){this.dom.overlay.setAttribute("aria-hidden","true");this.dom.root.setAttribute("aria-hidden","true");if(this.openerEl&&document.contains(this.openerEl)){this.openerEl.focus()}this.openerEl=null;this.unlockBodyScroll();this.dom.root.removeEventListener("keydown",this.trapFocus)}this.emit("myio:filter:close",{});this.props.onClose?.()}lockBodyScroll(){const hasScrollbar=document.documentElement.scrollHeight>document.documentElement.clientHeight;if(hasScrollbar){const scrollBarW=window.innerWidth-document.documentElement.clientWidth;document.documentElement.style.paddingRight=`${scrollBarW}px`}document.body.classList.add("body--myio-modal-open")}unlockBodyScroll(){document.body.classList.remove("body--myio-modal-open");document.documentElement.style.paddingRight=""}getState(){return{selected:Array.from(this.state.selected),sort:this.state.sort}}setSelection(ids){this.state.selected=new Set(ids);this.updateCounters();this.renderList()}setSort(sort){this.state.sort=sort;this.renderList();if(this.dom){this.dom.sortRadios.forEach(radio=>{radio.checked=radio.value===sort})}}destroy(){if(this.dom){this.close();this.dom.overlay.remove();this.dom.root.remove();this.dom=null}}trapFocus=e=>{if(e.isComposing)return;if(!this.dom||e.key!=="Tab"||this.dom.root.getAttribute("aria-hidden")==="true")return;const focusable=[...this.dom.root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')].filter(el=>{const htmlEl=el;return!htmlEl.hasAttribute("disabled")&&htmlEl.tabIndex!==-1&&htmlEl.offsetParent!==null});if(!focusable.length)return;const first=focusable[0];const last=focusable[focusable.length-1];if(e.shiftKey&&document.activeElement===first){last.focus();e.preventDefault()}else if(!e.shiftKey&&document.activeElement===last){first.focus();e.preventDefault()}};createDOM(){const existing=document.querySelector(".myio-modal-root");if(existing){existing.remove()}const overlay=document.createElement("div");overlay.className="myio-modal-overlay";overlay.setAttribute("aria-hidden","true");const root=document.createElement("div");root.className="myio-modal-root myio-modal-portal";root.setAttribute("aria-hidden","true");root.setAttribute("role","dialog");root.setAttribute("aria-modal","true");root.setAttribute("aria-labelledby","myioFilterTitle");const card=document.createElement("div");card.className="myio-modal-card";card.setAttribute("role","document");root.appendChild(card);card.addEventListener("click",e=>e.stopPropagation());card.innerHTML=`\n <header class="myio-header">\n <h2 id="myioFilterTitle">${this.props.title||"Filtros & Ordenação"}</h2>\n <div class="myio-counters" aria-live="polite">\n <span class="counter">\n <strong class="value" data-total>0</strong> <span>${this.i18n.totalLabel}</span>\n </span>\n <span class="sep">•</span>\n <span class="counter">\n <strong class="value" data-selected>0</strong> <span>${this.i18n.selectedLabel}</span>\n </span>\n </div>\n <button class="icon-btn close" aria-label="${this.i18n.closeLabel}" data-close>×</button>\n </header>\n\n <section class="myio-toolbar">\n <div class="actions">\n <button class="btn ghost" data-select-all>${this.i18n.selectAll}</button>\n <button class="btn ghost" data-clear>${this.i18n.clear}</button>\n </div>\n <div class="search">\n <div class="search-input-wrapper">\n <span class="search-icon">🔍</span>\n <input type="text" placeholder="${this.i18n.searchPlaceholder}" aria-label="Buscar" data-search />\n <button class="icon-btn clear-search" aria-label="Limpar busca" data-clear-search hidden>✕</button>\n </div>\n </div>\n </section>\n\n <section class="myio-list" role="listbox" aria-multiselectable="true" data-virtualized>\n \x3c!-- Items will be rendered here --\x3e\n </section>\n\n <section class="myio-sorting">\n <h3>${this.i18n.sortingTitle}</h3>\n <div class="radio-group">\n <label><input type="radio" name="sort" value="CONSUMPTION_DESC" checked /> ${this.i18n.consumptionDesc}</label>\n <label><input type="radio" name="sort" value="CONSUMPTION_ASC" /> ${this.i18n.consumptionAsc}</label>\n <label><input type="radio" name="sort" value="ALPHA_ASC" /> ${this.i18n.aToZ}</label>\n <label><input type="radio" name="sort" value="ALPHA_DESC" /> ${this.i18n.zToA}</label>\n </div>\n <p class="hint">${this.i18n.tieNote}</p>\n </section>\n\n <footer class="myio-footer">\n <button class="btn secondary" data-reset>${this.i18n.reset}</button>\n <button class="btn primary" data-apply>${this.i18n.apply}</button>\n </footer>\n `;this.addStyles();document.body.appendChild(overlay);document.body.appendChild(root);const totalCounter=card.querySelector("[data-total]");const selectedCounter=card.querySelector("[data-selected]");const searchInput=card.querySelector("[data-search]");const listContainer=card.querySelector(".myio-list");const sortRadios=card.querySelectorAll('input[name="sort"]');const clearSearchBtn=card.querySelector("[data-clear-search]");this.dom={overlay:overlay,root:root,card:card,totalCounter:totalCounter,selectedCounter:selectedCounter,searchInput:searchInput,listContainer:listContainer,sortRadios:sortRadios,clearSearchBtn:clearSearchBtn};this.attachEventListeners()}addStyles(){if(document.getElementById("myio-filter-styles"))return;const style=document.createElement("style");style.id="myio-filter-styles";style.textContent=`\n /* === Overlay / Scrim ==================================================== */\n .myio-modal-overlay {\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n background: rgba(0, 0, 0, 0.50); /* 50% dim */\n backdrop-filter: saturate(100%) blur(2px);\n z-index: 10000; /* above app UI */\n opacity: 0;\n pointer-events: none;\n transition: opacity 160ms ease-out;\n margin: 0 !important; /* Reset any inherited margins */\n width: auto !important; /* Reset any inherited width */\n height: auto !important; /* Reset any inherited height */\n touch-action: none; /* iOS overscroll prevention */\n }\n .myio-modal-overlay[aria-hidden="false"] {\n opacity: 1;\n pointer-events: auto;\n }\n\n /* === Card container ====================================================== */\n .myio-modal-root {\n position: fixed !important; /* Force fixed positioning relative to viewport */\n top: 0 !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n z-index: 10001; /* above overlay */\n opacity: 0;\n pointer-events: none;\n transition: opacity 160ms ease-out;\n padding: 20px; /* Add padding for better mobile positioning */\n margin: 0 !important; /* Reset any inherited margins */\n width: auto !important; /* Reset any inherited width */\n height: auto !important; /* Reset any inherited height */\n touch-action: none; /* iOS overscroll prevention */\n }\n .myio-modal-root[aria-hidden="false"] {\n opacity: 1;\n pointer-events: auto;\n }\n\n /* === Card ================================================================ */\n .myio-modal-card {\n width: min(960px, 94vw);\n max-height: calc(100vh - 40px); /* Account for padding */\n overflow: auto;\n background: #fff;\n border-radius: 16px;\n box-shadow: 0 24px 64px rgba(0,0,0,.28);\n transform: translateY(-12px) scale(0.98);\n transition: transform 160ms ease-out;\n }\n .myio-modal-root[aria-hidden="false"] .myio-modal-card {\n transform: translateY(0) scale(1);\n }\n\n /* Reduced motion support */\n @media (prefers-reduced-motion: reduce) {\n .myio-modal-overlay,\n .myio-modal-root,\n .myio-modal-card {\n transition: none !important;\n transform: none !important;\n }\n .myio-modal-root[aria-hidden="false"] .myio-modal-card {\n transform: none !important;\n }\n }\n\n /* Header stays purple (MYIO palette) and sticky */\n .myio-modal-card header.myio-header {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: 16px 20px;\n background: var(--myio-purple-600, #4A148C);\n color: #fff;\n border-radius: 16px 16px 0 0;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .myio-modal-card footer.myio-footer {\n position: sticky;\n bottom: 0;\n background: #fff;\n border-top: 1px solid var(--myio-border, #E5E7EB);\n padding: 12px 20px;\n border-radius: 0 0 16px 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n\n /* Prevent accidental stacking-context issues inside transformed parents */\n .myio-modal-portal {\n position: relative;\n z-index: 10000;\n }\n\n /* Optional: body lock when open */\n .body--myio-modal-open {\n overflow: hidden;\n overscroll-behavior: contain;\n }\n\n .myio-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 20px;\n color: #fff;\n background: #4A148C;\n position: sticky;\n top: 0;\n z-index: 1;\n border-radius: 16px 16px 0 0;\n }\n\n .myio-header h2 {\n font-size: 18px;\n font-weight: 700;\n margin: 0;\n flex: 1;\n }\n\n .myio-counters {\n display: flex;\n align-items: center;\n gap: 8px;\n opacity: 0.95;\n }\n\n .myio-header .close {\n background: transparent;\n color: #fff;\n font-size: 20px;\n border: none;\n cursor: pointer;\n padding: 4px 8px;\n border-radius: 4px;\n }\n\n .myio-header .close:hover {\n background: rgba(255,255,255,0.1);\n }\n\n .myio-toolbar {\n display: flex;\n gap: 12px;\n align-items: center;\n padding: 12px 20px;\n flex-wrap: wrap;\n border-bottom: 1px solid #E5E7EB;\n }\n\n .myio-toolbar .actions {\n display: flex;\n gap: 8px;\n }\n\n .myio-toolbar .search {\n margin-left: auto;\n flex: 1 1 320px;\n max-width: 400px;\n }\n\n .search-input-wrapper {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-icon {\n position: absolute;\n left: 12px;\n z-index: 1;\n opacity: 0.5;\n }\n\n .myio-toolbar .search input {\n width: 100%;\n height: 40px;\n padding: 0 40px;\n border-radius: 12px;\n border: 1px solid #E5E7EB;\n font-size: 14px;\n }\n\n .clear-search {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 4px;\n opacity: 0.5;\n }\n\n .clear-search:hover {\n opacity: 1;\n }\n\n .myio-list {\n display: grid;\n grid-template-columns: repeat(2, minmax(0,1fr));\n gap: 12px;\n padding: 16px 20px;\n max-height: 300px;\n overflow-y: auto;\n }\n\n @media (max-width: 768px) {\n .myio-list {\n grid-template-columns: 1fr;\n }\n }\n\n .chip {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 44px;\n border-radius: 12px;\n border: 2px solid #4A148C;\n background: #fff;\n padding: 0 14px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s ease;\n }\n\n .chip:hover {\n background: #EDE7F3;\n }\n\n .chip.selected {\n background: #EDE7F3;\n border-color: #4A148C;\n }\n\n .chip .checkbox {\n width: 22px;\n height: 22px;\n border-radius: 6px;\n border: 2px solid #4A148C;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n font-weight: bold;\n color: #4A148C;\n }\n\n .chip.selected .checkbox {\n background: #4A148C;\n color: white;\n }\n\n .myio-sorting {\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n }\n\n .myio-sorting h3 {\n margin: 0 0 12px 0;\n font-size: 16px;\n font-weight: 600;\n color: #1F2937;\n }\n\n .radio-group {\n display: flex;\n flex-wrap: wrap;\n gap: 16px;\n margin-bottom: 8px;\n }\n\n .myio-sorting label {\n display: flex;\n gap: 8px;\n align-items: center;\n cursor: pointer;\n font-size: 14px;\n }\n\n .myio-sorting input[type="radio"] {\n margin: 0;\n }\n\n .hint {\n font-size: 12px;\n color: #6B7280;\n margin: 8px 0 0 0;\n font-style: italic;\n }\n\n .myio-footer {\n position: sticky;\n bottom: 0;\n background: #fff;\n border-top: 1px solid #E5E7EB;\n padding: 12px 20px;\n border-radius: 0 0 16px 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n\n .btn {\n border: none;\n border-radius: 8px;\n padding: 10px 16px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .btn.primary {\n background: #4A148C;\n color: #fff;\n }\n\n .btn.primary:hover {\n background: #3A0E5C;\n }\n\n .btn.secondary {\n background: #fff;\n border: 1px solid #D1D5DB;\n color: #374151;\n }\n\n .btn.secondary:hover {\n background: #F9FAFB;\n }\n\n .btn.ghost {\n background: transparent;\n border: 1px solid #D1D5DB;\n color: #374151;\n padding: 8px 12px;\n font-size: 13px;\n }\n\n .btn.ghost:hover {\n background: #F3F4F6;\n }\n\n .empty-state {\n text-align: center;\n padding: 40px 20px;\n color: #6B7280;\n }\n `;document.head.appendChild(style)}attachEventListeners(){if(!this.dom)return;const{overlay:overlay,root:root,searchInput:searchInput,clearSearchBtn:clearSearchBtn,sortRadios:sortRadios}=this.dom;overlay.addEventListener("click",()=>this.close());root.querySelector("[data-close]")?.addEventListener("click",()=>this.close());root.addEventListener("keydown",e=>{if(e.key==="Escape"){this.close()}});searchInput.addEventListener("input",e=>{const query=e.target.value;this.debounceSearch(query);if(query){clearSearchBtn.hidden=false}else{clearSearchBtn.hidden=true}});clearSearchBtn.addEventListener("click",()=>{searchInput.value="";clearSearchBtn.hidden=true;this.updateQuery("")});root.querySelector("[data-select-all]")?.addEventListener("click",()=>{this.selectAllVisible()});root.querySelector("[data-clear]")?.addEventListener("click",()=>{this.clearSelection()});sortRadios.forEach(radio=>{radio.addEventListener("change",()=>{if(radio.checked){this.setSort(radio.value)}})});root.querySelector("[data-apply]")?.addEventListener("click",()=>{this.apply()});root.querySelector("[data-reset]")?.addEventListener("click",()=>{this.reset()})}debounceSearch(query){if(this.searchTimeout){clearTimeout(this.searchTimeout)}this.searchTimeout=window.setTimeout(()=>{this.updateQuery(query)},200)}updateQuery(query){this.state.query=query;this.renderList()}selectAllVisible(){const visibleIds=this.getVisibleItems();visibleIds.forEach(id=>this.state.selected.add(id));this.updateCounters();this.renderList();this.emit("myio:filter:select_all",{scope:this.state.query?"visible":"all"})}clearSelection(){const visibleIds=this.getVisibleItems();const queryActive=this.state.query.length>0;if(queryActive){visibleIds.forEach(id=>this.state.selected.delete(id))}else{this.state.selected.clear()}this.updateCounters();this.renderList();this.emit("myio:filter:clear",{scope:queryActive?"visible":"all"})}apply(){const startTime=performance.now();this.props.onApply({selected:Array.from(this.state.selected),sort:this.state.sort});this.emit("myio:filter:apply",{selectedCount:this.state.selected.size,sort:this.state.sort,queryLength:this.state.query.length,durationMs:performance.now()-startTime});if(this.props.autoCloseOnApply!==false){this.close()}}reset(){this.state.selected=new Set(this.initialState.selected);this.state.sort=this.initialState.sort;this.state.query="";if(this.dom){this.dom.searchInput.value="";this.dom.clearSearchBtn.hidden=true;this.dom.sortRadios.forEach(radio=>{radio.checked=radio.value===this.state.sort})}this.updateCounters();this.renderList()}getVisibleItems(){const sorted=this.sortItems([...this.itemsById.values()],this.state.sort);if(!this.state.query){return sorted.map(x=>x.id)}const query=this.normalize(this.state.query);return sorted.filter(x=>this.normalize(x.label).includes(query)).map(x=>x.id)}normalize(s){return s.normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase().trim()}sortItems(list,mode){const byLabelAsc=(a,b)=>a.label.localeCompare(b.label,void 0,{sensitivity:"base"})||(a.id>b.id?1:-1);const byLabelDesc=(a,b)=>-byLabelAsc(a,b);const num=x=>x==null?Number.NEGATIVE_INFINITY:x;switch(mode){case"CONSUMPTION_DESC":return[...list].sort((a,b)=>num(b.consumption)-num(a.consumption)||byLabelAsc(a,b));case"CONSUMPTION_ASC":return[...list].sort((a,b)=>num(a.consumption)-num(b.consumption)||byLabelAsc(a,b));case"ALPHA_ASC":return[...list].sort(byLabelAsc);case"ALPHA_DESC":return[...list].sort(byLabelDesc);default:return[...list]}}updateCounters(){if(!this.dom)return;this.dom.totalCounter.textContent=this.state.allIds.length.toString();this.dom.selectedCounter.textContent=this.state.selected.size.toString()}renderList(){if(!this.dom)return;const visibleIds=this.getVisibleItems();if(visibleIds.length===0){this.dom.listContainer.innerHTML=`\n <div class="empty-state">\n ${this.state.query?"Nenhuma loja encontrada com o filtro aplicado.":"Nenhuma loja disponível."}\n </div>\n `;return}this.dom.listContainer.innerHTML=visibleIds.map(id=>this.renderChip(id)).join("");this.dom.listContainer.querySelectorAll(".chip").forEach(chip=>{chip.addEventListener("click",()=>{const id=chip.getAttribute("data-id");this.toggleItem(id)})})}renderChip(id){const item=this.itemsById.get(id);const isSelected=this.state.selected.has(id);return`\n <button role="option" aria-selected="${isSelected}"\n class="chip ${isSelected?"selected":""}"\n data-id="${id}">\n <span class="checkbox" aria-hidden="true">${isSelected?"✓":""}</span>\n <span class="label" title="${item.label}">${item.label}</span>\n </button>\n `}toggleItem(id){if(this.state.selected.has(id)){this.state.selected.delete(id)}else{this.state.selected.add(id)}this.updateCounters();this.renderList()}emit(eventType,detail){if(this.dom){const event=new CustomEvent(eventType,{detail:detail});this.dom.card.dispatchEvent(event)}}};function attachFilterOrderingModal(props){const modal=new FilterOrderingModal(props);return{open:()=>modal.open(),close:()=>modal.close(),getState:()=>modal.getState(),setSelection:ids=>modal.setSelection(ids),setSort:sort=>modal.setSort(sort),destroy:()=>modal.destroy()}}var AllReportModal=class{constructor(params){this.params=params;this.authClient=new AuthClient({clientId:params.api.clientId,clientSecret:params.api.clientSecret,base:params.api.dataApiBaseUrl});this.debugEnabled=params.debug===1;this.debugLog("🚀 AllReportModal initialized",{customerId:params.customerId,itemsListLength:params.itemsList?.length||0,itemsList:params.itemsList,debugEnabled:this.debugEnabled,debugParam:params.debug,apiConfig:{hasIngestionToken:!!params.api.ingestionToken,dataApiBaseUrl:params.api.dataApiBaseUrl}})}modal;authClient;data=[];isLoading=false;eventHandlers={};dateRangePicker=null;currentPage=1;itemsPerPage=10;sortField="consumption";sortDirection="desc";searchFilter="";filterModal=null;selectedStoreIds=new Set;currentSortMode="CONSUMPTION_DESC";debugEnabled;debugLog(message,data){console.log(`[AllReportModal DEBUG] ${message}`,data||"")}normalizeId(v){return(v||"").toString().normalize("NFKC").toUpperCase().replace(/\s+/g,"").replace(/[^A-Z0-9]/g,"")}resolveStoreIdentifierFromApi(item){if(item?.assetName){return item.assetName}const name=item?.name||"";if(!name)return null;const tokens=name.trim().split(/\s+/);const last=tokens[tokens.length-1]||"";if(/[A-Za-z0-9]{3,}/.test(last)){return last}const maybe=tokens.find(t=>/[A-Za-z0-9]{3,}/.test(t));return maybe||null}pickConsumption(item){const fields=["total_value","totalValue","consumption","value","total","energy","kwh"];for(const f of fields){if(item?.[f]!==void 0&&item?.[f]!==null){const n=typeof item[f]==="string"?parseFloat(item[f].replace(",",".")):Number(item[f]);if(!Number.isNaN(n))return n}}return 0}show(){this.debugLog("🎭 Modal show() called - creating modal UI");this.modal=createModal({title:`Relatório Geral - Todas as Lojas${this.debugEnabled?" [DEBUG MODE]":""}`,width:"85vw",height:"90vh",theme:this.params.ui?.theme||"light"});this.renderContent();this.modal.on("close",()=>{this.debugLog("🚪 Modal closing - cleaning up resources");if(this.dateRangePicker){this.dateRangePicker.destroy();this.dateRangePicker=null}if(this.filterModal){this.filterModal.destroy();this.filterModal=null}this.authClient.clearCache();this.emit("close")});this.debugLog("✅ Modal created and ready to use");return{close:()=>this.modal.close(),on:(event,handler)=>this.on(event,handler)}}renderContent(){const content=document.createElement("div");content.innerHTML=`\n <div class="myio-modal-scope">\n <div style="margin-bottom: 16px;">\n <div style="display: flex; gap: 16px; align-items: end; margin-bottom: 16px; flex-wrap: wrap;">\n <div class="myio-form-group" style="margin-bottom: 0;">\n <label class="myio-label" for="date-range">Período</label>\n <input type="text" id="date-range" class="myio-input" readonly placeholder="Selecione o período" style="width: 300px;">\n </div>\n <button id="load-btn" class="myio-btn myio-btn-primary">\n <span class="myio-spinner" id="load-spinner" style="display: none;"></span>\n Carregar\n </button>\n <button id="export-btn" class="myio-btn myio-btn-secondary" disabled>\n Exportar CSV\n </button>\n <button id="filter-btn" class="myio-btn myio-btn-secondary" style="background: var(--myio-brand-700); color: white;">\n 🔍 Filtros & Ordenação\n </button>\n <div class="myio-form-group" style="margin-bottom: 0; margin-left: auto;">\n <label class="myio-label" for="search-input">Busca rápida</label>\n <input type="text" id="search-input" class="myio-input" placeholder="Digite para filtrar..." style="width: 200px;">\n </div>\n </div>\n </div>\n\n <div id="error-container" style="display: none; background: #ffebee; color: #c62828; padding: 12px; border-radius: 6px; margin-bottom: 16px;">\n </div>\n\n <div id="summary-container" style="display: none; margin-bottom: 16px;">\n </div>\n\n <div id="table-container">\n <div style="text-align: center; padding: 40px; color: var(--myio-text-muted);">\n Selecione um período e clique em "Carregar" para visualizar os dados de todas as lojas.\n </div>\n </div>\n\n <div id="pagination-container" style="display: none; margin-top: 16px; text-align: center;">\n </div>\n </div>\n `;this.modal.setContent(content);this.setupEventListeners()}async setupEventListeners(){const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const filterBtn=document.getElementById("filter-btn");const dateRangeInput=document.getElementById("date-range");const searchInput=document.getElementById("search-input");loadBtn?.addEventListener("click",()=>this.loadData());exportBtn?.addEventListener("click",()=>this.exportCSV());filterBtn?.addEventListener("click",()=>this.openFilterModal());if(searchInput){searchInput.addEventListener("input",e=>{this.searchFilter=e.target.value.toLowerCase();this.currentPage=1;this.renderTable();this.renderPagination()});searchInput.addEventListener("keyup",e=>{this.searchFilter=e.target.value.toLowerCase();this.currentPage=1;this.renderTable();this.renderPagination()})}try{this.dateRangePicker=await attach(dateRangeInput,{presetStart:this.getDefaultStartDate(),presetEnd:this.getDefaultEndDate(),maxRangeDays:31,parentEl:this.modal.element,onApply:({startISO:startISO,endISO:endISO})=>{this.hideError();console.log("Date range selected:",{startISO:startISO,endISO:endISO})}})}catch(error){console.warn("DateRangePicker initialization failed, using fallback:",error)}}async loadData(){if(this.isLoading)return;this.debugLog("📊 Starting loadData process");const loadBtn=document.getElementById("load-btn");const exportBtn=document.getElementById("export-btn");const spinner=document.getElementById("load-spinner");if(!this.dateRangePicker){this.showError("Seletor de data não inicializado");return}this.isLoading=true;loadBtn.disabled=true;exportBtn.disabled=true;spinner.style.display="inline-block";try{const{startISO:startISO,endISO:endISO}=this.dateRangePicker.getDates();this.debugLog("📅 Date range selected",{startISO:startISO,endISO:endISO});if(!startISO||!endISO){this.showError("Selecione um período válido");return}const startDate=startISO.split("T")[0];const endDate=endISO.split("T")[0];this.debugLog("🌐 Fetching customer totals from API...");const customerTotalsData=await this.fetchCustomerTotals(startISO,endISO);this.debugLog("✅ API response received",customerTotalsData);this.debugLog("🔄 Processing API response...");this.data=this.mapCustomerTotalsResponse(customerTotalsData);this.debugLog("✅ Data mapping completed",{mappedDataLength:this.data.length,mappedData:this.data,totalConsumption:this.calculateTotalConsumption()});this.selectedStoreIds=new Set(this.data.map(store=>this.generateStoreId(store.name)));this.debugLog("🎯 Store IDs initialized",{selectedStoreIdsSize:this.selectedStoreIds.size,selectedStoreIds:Array.from(this.selectedStoreIds)});this.currentPage=1;this.debugLog("🎨 Rendering UI components...");this.renderSummary();this.renderTable();this.renderPagination();exportBtn.disabled=false;this.debugLog("🎉 Load process completed successfully");this.emit("loaded",{date:{start:startDate,end:endDate},stores:this.data.length,totalConsumption:this.calculateTotalConsumption()})}catch(error){this.debugLog("❌ Error in loadData",error);this.showError("Erro ao carregar dados: "+error.message);console.error("Error loading data:",error);this.emit("error",{message:error.message,context:"loadData"})}finally{this.isLoading=false;loadBtn.disabled=false;spinner.style.display="none"}}getFilteredData(){let filtered=this.data;if(this.selectedStoreIds.size>0){filtered=this.data.filter(store=>{const storeId=this.generateStoreId(store.name);return this.selectedStoreIds.has(storeId)})}if(this.searchFilter){filtered=filtered.filter(store=>{const name=(store.name||"").toString().toLowerCase();const identifier=(store.identifier||"").toString().toLowerCase();return name.includes(this.searchFilter)||identifier.includes(this.searchFilter)})}return filtered.sort((a,b)=>{const aVal=a[this.sortField];const bVal=b[this.sortField];if(typeof aVal==="string"&&typeof bVal==="string"){return this.sortDirection==="asc"?aVal.localeCompare(bVal):bVal.localeCompare(aVal)}else{return this.sortDirection==="asc"?aVal-bVal:bVal-aVal}})}getPaginatedData(){const filtered=this.getFilteredData();const startIndex=(this.currentPage-1)*this.itemsPerPage;return filtered.slice(startIndex,startIndex+this.itemsPerPage)}renderSummary(){const container=document.getElementById("summary-container");if(!container)return;const totalConsumption=this.calculateTotalConsumption();const storeCount=Math.max(1,this.data.length);container.innerHTML=`\n <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; padding: 16px; background: var(--myio-bg); border-radius: 6px;">\n <div style="text-align: center;">\n <div style="font-size: 24px; font-weight: bold; color: var(--myio-primary);">${storeCount}</div>\n <div style="color: var(--myio-text-muted);">Lojas</div>\n </div>\n <div style="text-align: center;">\n <div style="font-size: 24px; font-weight: bold; color: var(--myio-primary);">${fmtPt(totalConsumption)}</div>\n <div style="color: var(--myio-text-muted);">Total kWh</div>\n </div>\n <div style="text-align: center;">\n <div style="font-size: 24px; font-weight: bold; color: var(--myio-primary);">${fmtPt(totalConsumption/storeCount)}</div>\n <div style="color: var(--myio-text-muted);">Média por Loja</div>\n </div>\n </div>\n `;container.style.display="block"}renderTable(){const container=document.getElementById("table-container");if(!container)return;const paginatedData=this.getPaginatedData();this.getFilteredData();if(paginatedData.length===0){container.innerHTML=`\n <div style="text-align: center; padding: 40px; color: var(--myio-text-muted);">\n ${this.searchFilter?"Nenhuma loja encontrada com o filtro aplicado.":"Nenhum dado encontrado."}\n </div>\n `;return}container.innerHTML=`\n <div style="max-height: 500px; overflow-y: auto; border: 1px solid var(--myio-border); border-radius: 6px;">\n <style>\n @media (max-width: 768px) {\n .myio-table-mobile {\n display: block !important;\n }\n .myio-table-mobile thead,\n .myio-table-mobile tbody,\n .myio-table-mobile th,\n .myio-table-mobile td,\n .myio-table-mobile tr {\n display: block !important;\n }\n .myio-table-mobile thead tr {\n position: absolute !important;\n top: -9999px !important;\n left: -9999px !important;\n }\n .myio-table-mobile tbody tr {\n border: 1px solid var(--myio-border) !important;\n border-radius: 8px !important;\n margin-bottom: 16px !important;\n padding: 16px !important;\n background: white !important;\n }\n .myio-table-mobile tbody td {\n border: none !important;\n padding: 8px 0 !important;\n position: relative !important;\n }\n .myio-table-mobile tbody td:before {\n content: attr(data-label) ": " !important;\n font-weight: bold !important;\n display: inline-block !important;\n width: 120px !important;\n color: var(--myio-text-muted) !important;\n }\n }\n </style>\n <table class="myio-table myio-table-mobile" style="table-layout: fixed; width: 100%;">\n <thead style="position: sticky; top: 0; background: var(--myio-bg); z-index: 1;">\n <tr>\n <th style="cursor: pointer; width: 25%;" data-sort="identifier">\n Identifier\n <span style="margin-left: 4px; opacity: ${this.getSortOpacity("identifier")};">${this.getSortIcon("identifier")}</span>\n </th>\n <th style="cursor: pointer; width: 45%;" data-sort="name">\n Name\n <span style="margin-left: 4px; opacity: ${this.getSortOpacity("name")};">${this.getSortIcon("name")}</span>\n </th>\n <th style="cursor: pointer; text-align: right; width: 30%;" data-sort="consumption">\n Consumption (kWh)\n <span style="margin-left: 4px; opacity: ${this.getSortOpacity("consumption")};">${this.getSortIcon("consumption")}</span>\n </th>\n </tr>\n </thead>\n <tbody>\n ${paginatedData.map(row=>`\n <tr>\n <td data-label="Identifier" style="font-family: monospace; font-weight: bold; text-transform: uppercase;">${row.identifier}</td>\n <td data-label="Name"><strong>${row.name}</strong></td>\n <td data-label="Consumption (kWh)" style="text-align: right; font-weight: bold;">${row.consumption.toFixed(2)}</td>\n </tr>\n `).join("")}\n </tbody>\n </table>\n </div>\n `;this.setupTableSorting()}getSortIcon(field){if(this.sortField!==field)return"↕";return this.sortDirection==="asc"?"↑":"↓"}getSortOpacity(field){return this.sortField===field?"1":"0.5"}setupTableSorting(){const headers=document.querySelectorAll("[data-sort]");headers.forEach(header=>{header.addEventListener("click",()=>{const sortKey=header.getAttribute("data-sort");if(this.sortField===sortKey){this.sortDirection=this.sortDirection==="asc"?"desc":"asc"}else{this.sortField=sortKey;this.sortDirection=sortKey==="identifier"||sortKey==="name"?"asc":"desc"}this.currentPage=1;this.renderTable();this.renderPagination()})})}renderPagination(){const container=document.getElementById("pagination-container");if(!container)return;const filteredData=this.getFilteredData();const totalPages=Math.ceil(filteredData.length/this.itemsPerPage);if(totalPages<=1){container.style.display="none";return}const startItem=(this.currentPage-1)*this.itemsPerPage+1;const endItem=Math.min(this.currentPage*this.itemsPerPage,filteredData.length);container.innerHTML=`\n <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">\n <div style="color: var(--myio-text-muted);">\n Mostrando ${startItem}-${endItem} de ${filteredData.length} lojas\n </div>\n <div style="display: flex; gap: 8px; align-items: center;">\n <button id="prev-page" class="myio-btn myio-btn-outline" ${this.currentPage===1?"disabled":""}>\n Anterior\n </button>\n <span style="padding: 0 12px; font-weight: bold;">\n ${this.currentPage} / ${totalPages}\n </span>\n <button id="next-page" class="myio-btn myio-btn-outline" ${this.currentPage===totalPages?"disabled":""}>\n Próximo\n </button>\n </div>\n </div>\n `;document.getElementById("prev-page")?.addEventListener("click",()=>{if(this.currentPage>1){this.currentPage--;this.renderTable();this.renderPagination()}});document.getElementById("next-page")?.addEventListener("click",()=>{if(this.currentPage<totalPages){this.currentPage++;this.renderTable();this.renderPagination()}});container.style.display="block"}calculateTotalConsumption(){return this.data.reduce((sum,row)=>sum+row.consumption,0)}openFilterModal(){if(!this.filterModal){this.filterModal=attachFilterOrderingModal({title:"Filtros & Ordenação - Lojas",items:this.convertToStoreItems(),initialSelected:Array.from(this.selectedStoreIds),initialSort:this.currentSortMode,onApply:({selected:selected,sort:sort})=>{this.applyFiltersAndSort(selected,sort)},onClose:()=>{}})}else{this.filterModal.setSelection(Array.from(this.selectedStoreIds));this.filterModal.setSort(this.currentSortMode)}this.filterModal.open()}convertToStoreItems(){return this.data.map(store=>({id:this.generateStoreId(store.name),identifier:store.identifier,label:store.name,consumption:store.consumption}))}generateStoreId(storeName){return storeName.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"")}applyFiltersAndSort(selectedIds,sortMode){this.selectedStoreIds=new Set(selectedIds);this.currentSortMode=sortMode;switch(sortMode){case"CONSUMPTION_DESC":this.sortField="consumption";this.sortDirection="desc";break;case"CONSUMPTION_ASC":this.sortField="consumption";this.sortDirection="asc";break;case"ALPHA_ASC":this.sortField="name";this.sortDirection="asc";break;case"ALPHA_DESC":this.sortField="name";this.sortDirection="desc";break}this.currentPage=1;this.renderSummary();this.renderTable();this.renderPagination();const filterBtn=document.getElementById("filter-btn");if(filterBtn&&selectedIds.length>0&&selectedIds.length<this.data.length){filterBtn.innerHTML=`🔍 Filtros & Ordenação (${selectedIds.length})`;filterBtn.style.background="var(--myio-brand-600)"}else{filterBtn.innerHTML="🔍 Filtros & Ordenação";filterBtn.style.background="var(--myio-brand-700)"}}exportCSV(){const totalConsumption=this.calculateTotalConsumption();const now=new Date;const timestamp=now.toLocaleDateString("pt-BR")+" - "+now.toLocaleTimeString("pt-BR",{hour:"2-digit",minute:"2-digit"});const sortedData=[...this.data].sort((a,b)=>b.consumption-a.consumption);const csvData=[["RELATÓRIO GERAL - TODAS AS LOJAS","","",""],["DATA EMISSÃO",timestamp,"",""],["RESUMO","","",""],["Total de Lojas",this.data.length.toString(),"",""],["Consumo Total",totalConsumption.toFixed(2),"kWh",""],["Consumo Médio por Loja",(totalConsumption/this.data.length).toFixed(2),"kWh",""],["","","",""],["DETALHAMENTO POR LOJA","","",""],["Identifier","Name","Consumption (kWh)",""],...sortedData.map(row=>[row.identifier,row.name,row.consumption.toFixed(2),""])];const csvContent=toCsv(csvData);this.downloadCSV(csvContent,`relatorio-geral-lojas-${(new Date).toISOString().split("T")[0]}.csv`)}async fetchCustomerTotals(startISO,endISO){if(this.params.fetcher){const token2=this.params.api.ingestionToken||await this.authClient.getBearer();return await this.params.fetcher({baseUrl:this.params.api.dataApiBaseUrl||"https://api.data.apps.myio-bas.com",token:token2,customerId:this.params.customerId,startISO:startISO,endISO:endISO})}const token=this.params.api.ingestionToken;if(!token){throw new Error("ingestionToken is required for Data API calls to data.apps.myio-bas.com")}const baseUrl=this.params.api.dataApiBaseUrl||"https://api.data.apps.myio-bas.com";const startTime=encodeURIComponent(startISO);const endTime=encodeURIComponent(endISO);const url=`${baseUrl}/api/v1/telemetry/customers/${this.params.customerId}/energy/devices/totals?startTime=${startTime}&endTime=${endTime}`;console.log("[AllReportModal] Fetching customer totals:",{url:url,customerId:this.params.customerId});const response=await fetch(url,{method:"GET",headers:{Authorization:`Bearer ${token}`,"Content-Type":"application/json"}});if(!response.ok){throw new Error(`Erro na API: ${response.status} ${response.statusText}`)}const data=await response.json();console.log("[AllReportModal] Customer totals response:",data);return data}mapCustomerTotalsResponse(apiResponse){this.debugLog("🔍 Starting mapCustomerTotalsResponse",{apiResponse:apiResponse});const apiArray=Array.isArray(apiResponse?.data)?apiResponse.data:Array.isArray(apiResponse)?apiResponse:[];console.log("[AllReportModal] NEW MAPPING - API array length:",apiArray.length);console.log("[AllReportModal] NEW MAPPING - ItemsList length:",this.params.itemsList.length);this.debugLog("📋 API data array extracted",{isDataProperty:!!apiResponse?.data,isDirectArray:Array.isArray(apiResponse),apiArrayLength:apiArray.length,firstFewItems:apiArray.slice(0,3)});if(!apiArray.length){this.debugLog("⚠️ Empty API array, returning empty result");console.warn("[AllReportModal] Empty/invalid API response:",apiResponse);return[]}const sumByApiId=new Map;let apiItemsWithoutId=0;let totalApiConsumption=0;this.debugLog("🔨 Building ID index from API data...");for(const[index,item]of apiArray.entries()){const consumption=this.pickConsumption(item);totalApiConsumption+=consumption;if(index<3){console.log(`[AllReportModal] NEW MAPPING - API item ${index}:`,{id:item?.id,name:item?.name,assetName:item?.assetName,total_value:item?.total_value,extractedConsumption:consumption})}this.debugLog(`📊 Processing API item ${index}`,{item:item,extractedConsumption:consumption,hasId:!!item?.id});if(item?.id){const id=String(item.id);const previousSum=sumByApiId.get(id)||0;sumByApiId.set(id,previousSum+consumption);this.debugLog(`✅ Added to ID index: ${id} = ${previousSum} + ${consumption} = ${previousSum+consumption}`)}else{apiItemsWithoutId++;this.debugLog(`❌ API item without ID:`,item)}}console.log("[AllReportModal] NEW MAPPING - Total API consumption:",totalApiConsumption);console.log("[AllReportModal] NEW MAPPING - Unique API IDs:",sumByApiId.size);this.debugLog("📊 ID index built",{sumByApiIdSize:sumByApiId.size,sumByApiIdEntries:Array.from(sumByApiId.entries()),apiItemsWithoutId:apiItemsWithoutId});let matchedById=0,matchedBySubstring=0;let totalMappedConsumption=0;this.debugLog("🎯 Starting itemsList mapping...");const rows=this.params.itemsList.map((listItem,index)=>{this.debugLog(`🔍 Processing listItem ${index}`,listItem);let consumption=sumByApiId.get(listItem.id)??0;this.debugLog(`🎯 Primary ID match for ${listItem.id}: ${consumption}`);if(index<3){console.log(`[AllReportModal] NEW MAPPING - ItemsList item ${index}:`,{id:listItem.id,identifier:listItem.identifier,label:listItem.label,idMatchConsumption:consumption})}if(consumption>0){matchedById++;this.debugLog(`✅ Matched by ID: ${listItem.id} -> ${consumption}`)}else{this.debugLog(`🔄 No ID match, trying substring fallback for identifier: ${listItem.identifier}`);for(const[apiIndex,apiItem]of apiArray.entries()){const assetName=apiItem?.assetName||"";const name=apiItem?.name||"";const assetNameMatch=assetName.includes(listItem.identifier);const nameMatch=name.includes(listItem.identifier);if(assetNameMatch||nameMatch){const itemConsumption=this.pickConsumption(apiItem);consumption+=itemConsumption;if(index<3){console.log(`[AllReportModal] NEW MAPPING - Substring match for ${listItem.identifier}:`,{apiItemName:name,apiItemAssetName:assetName,itemConsumption:itemConsumption,totalConsumption:consumption})}this.debugLog(`✅ Substring match found in API item ${apiIndex}`,{listItemIdentifier:listItem.identifier,apiItemAssetName:assetName,apiItemName:name,assetNameMatch:assetNameMatch,nameMatch:nameMatch,itemConsumption:itemConsumption,totalConsumption:consumption})}}if(consumption>0){matchedBySubstring++;this.debugLog(`✅ Matched by substring: ${listItem.identifier} -> ${consumption}`)}else{this.debugLog(`❌ No match found for: ${listItem.identifier}`)}}const result={identifier:listItem.identifier,name:listItem.label,consumption:Math.round(consumption*100)/100};totalMappedConsumption+=result.consumption;this.debugLog(`📝 Final row for ${listItem.identifier}:`,result);return result});const stats={apiItems:apiArray.length,uniqueApiIds:sumByApiId.size,itemsInList:this.params.itemsList.length,matchedById:matchedById,matchedBySubstring:matchedBySubstring,unmatched:this.params.itemsList.length-matchedById-matchedBySubstring,apiItemsWithoutId:apiItemsWithoutId,totalApiConsumption:totalApiConsumption,totalMappedConsumption:totalMappedConsumption};console.log("[AllReportModal] NEW MAPPING - Final stats:",stats);this.debugLog("📊 Final mapping stats:",stats);console.log("[AllReportModal] Mapping stats:",stats);return rows}parseConsumptionValue(item){const possibleFields=["total_value","totalValue","consumption","value","total","energy","kwh"];for(const field of possibleFields){if(item[field]!==void 0&&item[field]!==null){const value=typeof item[field]==="string"?parseFloat(item[field].replace(",",".")):Number(item[field]);if(!isNaN(value)){return Math.round(value*100)/100}}}console.warn("[AllReportModal] No valid consumption value found in item:",item);return 0}downloadCSV(content,filename){const BOM="\ufeff";const csvWithBOM=BOM+content;const blob=new Blob([csvWithBOM],{type:"text/csv;charset=utf-8;"});const link=document.createElement("a");const url=URL.createObjectURL(blob);link.setAttribute("href",url);link.setAttribute("download",filename);link.style.visibility="hidden";document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(url)}getDefaultStartDate(){const date=new Date;date.setDate(1);return date.toISOString().split("T")[0]}getDefaultEndDate(){return(new Date).toISOString().split("T")[0]}showError(message){const container=document.getElementById("error-container");if(container){container.textContent=message;container.style.display="block"}}hideError(){const container=document.getElementById("error-container");if(container){container.style.display="none"}}on(event,handler){if(!this.eventHandlers[event]){this.eventHandlers[event]=[]}this.eventHandlers[event].push(handler)}emit(event,payload){if(this.eventHandlers[event]){this.eventHandlers[event].forEach(handler=>handler())}}};function openDashboardPopupAllReport(params){const modal=new AllReportModal(params);return modal.show()}function openDashboardPopup(params){console.log("Opening settings modal with params:",params);return{close:()=>{console.log("Closing settings modal")},on:(event,handler)=>{console.log(`Registering ${event} handler for settings modal`)}}}var SettingsModalView=class{container;modal;form;config;focusTrapElements=[];originalActiveElement=null;constructor(config){this.config=config;this.createModal()}render(initialData){this.originalActiveElement=document.activeElement;document.body.appendChild(this.container);this.populateForm(initialData);this.attachEventListeners();this.setupAccessibility();this.setupFocusTrap();this.applyTheme()}close(){this.teardownFocusTrap();if(this.originalActiveElement&&"focus"in this.originalActiveElement){this.originalActiveElement.focus()}if(this.container.parentNode){this.container.parentNode.removeChild(this.container)}}showError(message){const errorEl=this.modal.querySelector(".error-message");if(errorEl){errorEl.textContent=message;errorEl.style.display="block";errorEl.setAttribute("role","alert");errorEl.setAttribute("aria-live","polite")}}hideError(){const errorEl=this.modal.querySelector(".error-message");if(errorEl){errorEl.style.display="none";errorEl.removeAttribute("role");errorEl.removeAttribute("aria-live")}}showLoadingState(isLoading){const saveBtn=this.modal.querySelector(".btn-save");const cancelBtn=this.modal.querySelector(".btn-cancel");const formInputs=this.modal.querySelectorAll("input, select, textarea");if(saveBtn){saveBtn.disabled=isLoading;saveBtn.textContent=isLoading?"Salvando...":"Salvar"}if(cancelBtn){cancelBtn.disabled=isLoading}formInputs.forEach(input=>{input.disabled=isLoading})}getFormData(){const formData=new FormData(this.form);const data={};for(const[key,value]of formData.entries()){if(typeof value==="string"){if(["maxDailyKwh","maxNightKwh","maxBusinessKwh"].includes(key)){const num=parseFloat(value);if(!isNaN(num)&&num>=0){data[key]=num}}else if(value.trim()){data[key]=value.trim()}}}return data}createModal(){this.container=document.createElement("div");this.container.className="myio-settings-modal-overlay";this.container.innerHTML=this.getModalHTML();this.modal=this.container.querySelector(".myio-settings-modal");this.form=this.modal.querySelector("form")}getModalHTML(){const width=typeof this.config.width==="number"?`${this.config.width}px`:this.config.width;return`\n <div class="myio-settings-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="modal-title">\n <div class="myio-settings-modal" style="width: ${width}">\n <div class="modal-header">\n <h3 id="modal-title">Configurações</h3>\n <button type="button" class="close-btn" aria-label="Fechar">&times;</button>\n </div>\n <div class="modal-body">\n <div class="error-message" style="display: none;" role="alert" aria-live="polite"></div>\n <form novalidate>\n ${this.getFormHTML()}\n </form>\n </div>\n <div class="modal-footer">\n <button type="button" class="btn-cancel">Fechar</button>\n <button type="button" class="btn-save btn-primary">Salvar</button>\n </div>\n </div>\n </div>\n ${this.getModalCSS()}\n `}getFormHTML(){return`\n <div class="form-columns">\n \x3c!-- Left Column: Outback --\x3e\n <div class="form-column">\n <div class="form-card">\n <h4 class="section-title">${this.config.deviceLabel||"Outback"}</h4>\n \n <div class="form-group">\n <label for="label">Etiqueta</label>\n <input type="text" id="label" name="label" required maxlength="255">\n </div>\n \n <div class="form-group">\n <label for="floor">Andar</label>\n <input type="text" id="floor" name="floor" maxlength="50">\n </div>\n \n <div class="form-group">\n <label for="identifier">Número da Loja</label>\n <input type="text" id="identifier" name="identifier" maxlength="20" readonly>\n </div>\n </div>\n </div>\n\n \x3c!-- Right Column: Energy Alarms --\x3e\n <div class="form-column">\n <div class="form-card">\n <h4 class="section-title">Alarmes Energia - ${this.config.deviceLabel||"Outback"}</h4>\n \n <div class="form-group">\n <label for="maxDailyKwh">Consumo Máximo Diário (kWh)</label>\n <input type="number" id="maxDailyKwh" name="maxDailyKwh" min="0" step="0.1">\n </div>\n \n <div class="form-group">\n <label for="maxNightKwh">Consumo Máximo na Madrugada (0h–06h)</label>\n <input type="number" id="maxNightKwh" name="maxNightKwh" min="0" step="0.1">\n </div>\n \n <div class="form-group">\n <label for="maxBusinessKwh">Consumo Máximo Horário Comercial (09h–22h)</label>\n <input type="number" id="maxBusinessKwh" name="maxBusinessKwh" min="0" step="0.1">\n </div>\n </div>\n </div>\n </div>\n `}getModalCSS(){return`\n <style>\n .myio-settings-modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n \n .myio-settings-modal {\n background: white;\n border-radius: 8px;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);\n max-width: 95vw;\n max-height: 90vh;\n width: 1000px;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n \n .modal-header {\n background: #3e1a7d;\n color: white;\n padding: 20px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n \n .modal-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: white;\n }\n \n .close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: white;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n }\n \n .close-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n }\n \n .modal-body {\n padding: 24px;\n overflow-y: auto;\n flex: 1;\n background: #f8f9fa;\n }\n \n .error-message {\n background: #fee;\n border: 1px solid #fcc;\n color: #c33;\n padding: 12px;\n border-radius: 4px;\n margin-bottom: 16px;\n font-size: 14px;\n }\n \n .form-columns {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 20px;\n }\n \n .form-column {\n display: flex;\n flex-direction: column;\n }\n \n .form-card {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n padding: 20px;\n height: fit-content;\n }\n \n .section-title {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #3e1a7d;\n }\n \n .form-group {\n display: flex;\n flex-direction: column;\n margin-bottom: 16px;\n }\n \n .form-group:last-child {\n margin-bottom: 0;\n }\n \n .form-group label {\n font-weight: 500;\n margin-bottom: 6px;\n color: #333;\n font-size: 14px;\n }\n \n .form-group input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n transition: border-color 0.2s, box-shadow 0.2s;\n box-sizing: border-box;\n }\n \n .form-group input:focus {\n outline: none;\n border-color: #3e1a7d;\n box-shadow: 0 0 0 2px rgba(62, 26, 125, 0.25);\n }\n \n .form-group input:invalid {\n border-color: #dc3545;\n }\n \n .form-group input[readonly] {\n background-color: #f8f9fa;\n color: #6c757d;\n cursor: not-allowed;\n }\n \n .modal-footer {\n padding: 16px 24px;\n border-top: 1px solid #e0e0e0;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: white;\n }\n \n .modal-footer button {\n padding: 10px 20px;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n }\n \n .btn-cancel {\n background: #6c757d;\n color: white;\n }\n \n .btn-cancel:hover:not(:disabled) {\n background: #545b62;\n }\n \n .btn-primary {\n background: #3e1a7d;\n color: white;\n }\n \n .btn-primary:hover:not(:disabled) {\n background: #2d1458;\n }\n \n .modal-footer button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n \n /* Responsive design */\n @media (max-width: 1700px) {\n .myio-settings-modal {\n width: 95vw !important;\n }\n }\n \n @media (max-width: 1024px) {\n .myio-settings-modal {\n width: 90vw !important;\n }\n \n .form-columns {\n gap: 16px;\n }\n \n .form-card {\n padding: 16px;\n }\n }\n \n @media (max-width: 768px) {\n .myio-settings-modal {\n width: 95vw !important;\n margin: 10px;\n }\n \n .form-columns {\n grid-template-columns: 1fr;\n gap: 16px;\n }\n \n .modal-header, .modal-body, .modal-footer {\n padding-left: 16px;\n padding-right: 16px;\n }\n \n .form-card {\n padding: 16px;\n }\n }\n \n /* Scrollbar styling for modal body */\n .modal-body::-webkit-scrollbar {\n width: 6px;\n }\n \n .modal-body::-webkit-scrollbar-track {\n background: #f1f1f1;\n border-radius: 3px;\n }\n \n .modal-body::-webkit-scrollbar-thumb {\n background: #c1c1c1;\n border-radius: 3px;\n }\n \n .modal-body::-webkit-scrollbar-thumb:hover {\n background: #a8a8a8;\n }\n </style>\n `}populateForm(data){for(const[key,value]of Object.entries(data)){const input=this.form.querySelector(`[name="${key}"]`);if(input&&value!==void 0&&value!==null){input.value=String(value)}}}setupAccessibility(){const firstInput=this.modal.querySelector("input");if(firstInput){setTimeout(()=>firstInput.focus(),100)}this.modal.setAttribute("aria-labelledby","modal-title")}setupFocusTrap(){this.focusTrapElements=Array.from(this.modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'));this.modal.addEventListener("keydown",this.handleKeyDown.bind(this))}teardownFocusTrap(){this.modal.removeEventListener("keydown",this.handleKeyDown.bind(this))}handleKeyDown(event){if(event.key==="Escape"&&this.config.closeOnBackdrop!==false){event.preventDefault();this.config.onClose();return}if(event.key==="Tab"){const firstElement=this.focusTrapElements[0];const lastElement=this.focusTrapElements[this.focusTrapElements.length-1];if(event.shiftKey){if(document.activeElement===firstElement){event.preventDefault();lastElement.focus()}}else{if(document.activeElement===lastElement){event.preventDefault();firstElement.focus()}}}}attachEventListeners(){this.form.addEventListener("submit",event=>{event.preventDefault();this.hideError();const formData=this.getFormData();this.config.onSave(formData)});const closeBtn=this.modal.querySelector(".close-btn");if(closeBtn){closeBtn.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.config.onClose()})}const cancelBtn=this.modal.querySelector(".btn-cancel");if(cancelBtn){cancelBtn.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.config.onClose()})}const saveBtn=this.modal.querySelector(".btn-save");if(saveBtn){saveBtn.addEventListener("click",event=>{event.preventDefault();event.stopPropagation();this.hideError();const formData=this.getFormData();this.config.onSave(formData)})}this.container.addEventListener("click",event=>{const target=event.target;if(target.classList.contains("myio-settings-modal-overlay")&&this.config.closeOnBackdrop!==false){this.config.onClose()}});this.form.addEventListener("input",this.handleInputValidation.bind(this))}handleInputValidation(event){const input=event.target;input.classList.remove("is-invalid");if(input.name==="guid"&&input.value){const guidPattern=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!guidPattern.test(input.value)){input.classList.add("is-invalid");input.setCustomValidity("Invalid GUID format")}else{input.setCustomValidity("")}}if(input.type==="number"&&input.value){const num=parseFloat(input.value);if(isNaN(num)||num<0){input.classList.add("is-invalid");input.setCustomValidity("Must be a positive number")}else{input.setCustomValidity("")}}}applyTheme(){if(this.config.themeTokens){const style=document.createElement("style");let css="";for(const[property,value]of Object.entries(this.config.themeTokens)){css+=`--myio-${property}: ${value};\n`}style.textContent=`.myio-settings-modal { ${css} }`;this.container.appendChild(style)}}getI18nText(key,defaultText){return this.config.i18n?.t(key,defaultText)||defaultText}};var DefaultSettingsPersister=class{jwtToken;tbBaseUrl;constructor(jwtToken,apiConfig){this.jwtToken=jwtToken;this.tbBaseUrl=apiConfig?.tbBaseUrl||window.location.origin}async saveEntityLabel(deviceId,label){try{const getRes=await fetch(`${this.tbBaseUrl}/api/device/${deviceId}`,{headers:{"X-Authorization":`Bearer ${this.jwtToken}`}});if(!getRes.ok){throw this.createHttpError(getRes.status,await getRes.text().catch(()=>""))}const device=await getRes.json();const postRes=await fetch(`${this.tbBaseUrl}/api/device`,{method:"POST",headers:{"X-Authorization":`Bearer ${this.jwtToken}`,"Content-Type":"application/json"},body:JSON.stringify({...device,label:this.sanitizeLabel(label)})});if(!postRes.ok){throw this.createHttpError(postRes.status,await postRes.text().catch(()=>""))}return{ok:true}}catch(error){console.error("[SettingsPersister] Entity label save failed:",error);return{ok:false,error:this.mapError(error)}}}async saveServerScopeAttributes(deviceId,attributes){try{const namespacedAttrs=this.addNamespaceAndVersion(attributes);const res=await fetch(`${this.tbBaseUrl}/api/plugins/telemetry/DEVICE/${deviceId}/attributes/SERVER_SCOPE`,{method:"POST",headers:{"X-Authorization":`Bearer ${this.jwtToken}`,"Content-Type":"application/json"},body:JSON.stringify(namespacedAttrs)});if(!res.ok){throw this.createHttpError(res.status,await res.text().catch(()=>""))}return{ok:true,updatedKeys:Object.keys(namespacedAttrs)}}catch(error){console.error("[SettingsPersister] Attributes save failed:",error);return{ok:false,error:this.mapError(error)}}}addNamespaceAndVersion(attributes){const namespaced={"myio.settings.energy.__version":1};for(const[key,value]of Object.entries(attributes)){if(key!=="label"){namespaced[`myio.settings.energy.${key}`]=value}}return namespaced}sanitizeLabel(label){return label.trim().slice(0,255).replace(/[\x00-\x1F\x7F]/g,"")}createHttpError(status,body){const error=new Error(`HTTP ${status}: ${body}`);error.status=status;error.body=body;return error}mapError(error){const status=error.status;if(status===400){return{code:"VALIDATION_ERROR",message:"Invalid input data",userAction:"FIX_INPUT",cause:error}}if(status===401){return{code:"TOKEN_EXPIRED",message:"Authentication token has expired",userAction:"RE_AUTH",cause:error}}if(status===403){return{code:"AUTH_ERROR",message:"Insufficient permissions",userAction:"RE_AUTH",cause:error}}if(status===404){return{code:"NETWORK_ERROR",message:"Device not found",userAction:"CONTACT_ADMIN",cause:error}}if(status===409){return{code:"VALIDATION_ERROR",message:"Concurrent modification detected",userAction:"RETRY",cause:error}}if(status>=500){return{code:"NETWORK_ERROR",message:"Server error occurred",userAction:"RETRY",cause:error}}return{code:"UNKNOWN_ERROR",message:error.message||"Unknown error occurred",userAction:"CONTACT_ADMIN",cause:error}}};var DefaultSettingsFetcher=class{jwtToken;tbBaseUrl;constructor(jwtToken,apiConfig){this.jwtToken=jwtToken;this.tbBaseUrl=apiConfig?.tbBaseUrl||window.location.origin}async fetchCurrentSettings(deviceId,jwtToken,scope="SERVER_SCOPE"){try{const[entityResult,attributesResult]=await Promise.allSettled([this.fetchDeviceEntity(deviceId),this.fetchDeviceAttributes(deviceId,scope)]);const result={};if(entityResult.status==="fulfilled"){result.entity=entityResult.value}else{console.warn("[SettingsFetcher] Failed to fetch device entity:",entityResult.reason)}if(attributesResult.status==="fulfilled"){result.attributes=attributesResult.value}else{console.warn("[SettingsFetcher] Failed to fetch device attributes:",attributesResult.reason)}return result}catch(error){console.error("[SettingsFetcher] Failed to fetch current settings:",error);return{}}}async fetchDeviceEntity(deviceId){const response=await fetch(`${this.tbBaseUrl}/api/device/${deviceId}`,{headers:{"X-Authorization":`Bearer ${this.jwtToken}`}});if(!response.ok){throw new Error(`Failed to fetch device entity: ${response.status} ${response.statusText}`)}const device=await response.json();return{label:device.label||device.name||""}}async fetchDeviceAttributes(deviceId,scope){const response=await fetch(`${this.tbBaseUrl}/api/plugins/telemetry/DEVICE/${deviceId}/values/attributes/${scope}`,{headers:{"X-Authorization":`Bearer ${this.jwtToken}`}});if(!response.ok){throw new Error(`Failed to fetch device attributes: ${response.status} ${response.statusText}`)}const attributesArray=await response.json();const attributes={};const settingsNamespace="myio.settings.energy.";for(const attr of attributesArray){if(attr.key&&attr.value!==void 0&&attr.value!==null&&attr.value!==""){if(attr.key.startsWith(settingsNamespace)){const key=attr.key.replace(settingsNamespace,"");if(key!=="__version"){attributes[key]=attr.value}}else if(attr.key==="floor"){attributes.floor=attr.value}else if(attr.key==="identifier"){attributes.identifier=attr.value}}}return attributes}static mergeWithSeed(fetchedData,seedData){const merged={};if(seedData){Object.assign(merged,seedData)}if(fetchedData.entity?.label){merged.label=fetchedData.entity.label}if(fetchedData.attributes){Object.assign(merged,fetchedData.attributes)}return merged}static sanitizeFetchedData(data){const sanitized={};const stringFields=["label","floor","identifier"];for(const field of stringFields){if(data[field]&&typeof data[field]==="string"){sanitized[field]=data[field].trim()}}const numericFields=["maxDailyKwh","maxNightKwh","maxBusinessKwh"];for(const field of numericFields){if(data[field]!==void 0&&data[field]!==null){const num=Number(data[field]);if(!isNaN(num)&&num>=0){sanitized[field]=num}}}return sanitized}};var SettingsController=class{view;persister;fetcher;params;constructor(params){this.params=params;this.validateParams();this.persister=params.persister||new DefaultSettingsPersister(params.jwtToken,params.api);this.fetcher=params.fetcher||new DefaultSettingsFetcher(params.jwtToken,params.api);this.view=new SettingsModalView({title:params.ui?.title||`Settings - ${params.label||params.deviceId}`,width:params.ui?.width||600,theme:"light",closeOnBackdrop:params.ui?.closeOnBackdrop!==false,themeTokens:params.ui?.themeTokens,i18n:params.ui?.i18n,deviceLabel:params.label,onSave:this.handleSave.bind(this),onClose:this.handleClose.bind(this)})}async show(){console.info("[SettingsModal] Opening modal",{deviceId:this.params.deviceId,ingestionId:this.params.ingestionId});this.emitEvent("modal_opened");let initialData=this.params.seed||{};if(!this.params.seed){try{const fetchedData=await this.fetcher.fetchCurrentSettings(this.params.deviceId,this.params.jwtToken,this.params.scope||"SERVER_SCOPE");initialData=DefaultSettingsFetcher.mergeWithSeed(fetchedData,this.params.seed);initialData=DefaultSettingsFetcher.sanitizeFetchedData(initialData)}catch(error){console.warn("[SettingsModal] Failed to fetch current settings:",error);if(this.params.onError){this.params.onError({code:"NETWORK_ERROR",message:"Failed to load current settings",cause:error})}}}this.view.render(initialData)}validateParams(){if(!this.params.jwtToken){throw new Error("jwtToken is required for settings persistence")}if(!this.params.deviceId){throw new Error("deviceId is required")}if(!this.params.ingestionId){console.warn("[SettingsModal] ingestionId not provided - using deviceId for display")}}async handleSave(formData){console.info("[SettingsModal] Save initiated",{deviceId:this.params.deviceId,formData:formData});this.emitEvent("save_started",{formData:formData});this.view.showLoadingState(true);try{const result=await this.saveSettings(formData);if(result.ok){console.info("[SettingsModal] Settings saved successfully",result);this.emitEvent("save_completed",{result:result});if(this.params.onSaved){this.params.onSaved(result)}setTimeout(()=>{this.view.close()},500)}else{console.error("[SettingsModal] Save failed:",result);this.emitEvent("save_failed",{result:result});const errorMessage=this.getErrorMessage(result);this.view.showError(errorMessage);if(this.params.onError){this.params.onError({code:"VALIDATION_ERROR",message:errorMessage,cause:result})}}}catch(error){console.error("[SettingsModal] Save error:",error);this.emitEvent("save_failed",{error:error.message});const errorMessage="Network error occurred while saving settings";this.view.showError(errorMessage);if(this.params.onError){this.params.onError({code:"NETWORK_ERROR",message:errorMessage,cause:error})}}finally{this.view.showLoadingState(false)}}async saveSettings(formData){const result={ok:true,timestamp:(new Date).toISOString()};if(formData.label){try{const labelResult=await this.persister.saveEntityLabel(this.params.deviceId,formData.label);result.entity={ok:labelResult.ok,updated:labelResult.ok?["label"]:void 0,error:labelResult.error?{code:labelResult.error.code,message:labelResult.error.message,cause:labelResult.error.cause}:void 0};if(!labelResult.ok){result.ok=false}}catch(error){result.entity={ok:false,error:{code:"UNKNOWN_ERROR",message:error.message||"Failed to save device label",cause:error}};result.ok=false}}const attributes=this.extractAttributes(formData);if(Object.keys(attributes).length>0){try{const attributesResult=await this.persister.saveServerScopeAttributes(this.params.deviceId,attributes);result.serverScope={ok:attributesResult.ok,updatedKeys:attributesResult.updatedKeys,error:attributesResult.error?{code:attributesResult.error.code,message:attributesResult.error.message,cause:attributesResult.error.cause}:void 0};if(!attributesResult.ok){result.ok=false}}catch(error){result.serverScope={ok:false,error:{code:"UNKNOWN_ERROR",message:error.message||"Failed to save device attributes",cause:error}};result.ok=false}}return result}extractAttributes(formData){const attributes={};for(const[key,value]of Object.entries(formData)){if(key!=="label"&&value!==void 0&&value!==null&&value!==""){attributes[key]=value}}return attributes}getErrorMessage(result){const errors=[];if(result.entity?.error){errors.push(`Device label: ${result.entity.error.message}`)}if(result.serverScope?.error){errors.push(`Settings: ${result.serverScope.error.message}`)}return errors.length>0?errors.join("; "):"Failed to save settings"}handleClose(){console.info("[SettingsModal] Modal closed");this.emitEvent("modal_closed");if(this.params.onClose){this.params.onClose()}}emitEvent(type,data){if(this.params.onEvent){const event={type:type,deviceId:this.params.deviceId,timestamp:(new Date).toISOString(),data:data};try{this.params.onEvent(event)}catch(error){console.warn("[SettingsModal] Event handler error:",error)}}}validateFormData(formData){const errors=[];if(formData.guid){const guidPattern=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!guidPattern.test(formData.guid)){errors.push("GUID must be in valid UUID format")}}const numericFields=["maxDailyKwh","maxNightKwh","maxBusinessKwh"];for(const field of numericFields){if(formData[field]!==void 0){const num=Number(formData[field]);if(isNaN(num)||num<0){errors.push(`${field} must be a positive number`)}}}if(formData.label&&formData.label.length>255){errors.push("Device label must be 255 characters or less")}if(formData.floor&&formData.floor.length>50){errors.push("Floor must be 50 characters or less")}if(formData.storeNumber&&formData.storeNumber.length>20){errors.push("Store number must be 20 characters or less")}return{valid:errors.length===0,errors:errors}}closeModal(){this.view.close()}getCurrentFormData(){return this.view.getFormData()}};async function openDashboardPopupSettings(params){if(!params.jwtToken){throw new Error("jwtToken is required for settings persistence")}if(!params.deviceId){throw new Error("deviceId is required")}console.info("[openDashboardPopupSettings] Initializing settings modal",{deviceId:params.deviceId,ingestionId:params.ingestionId,hasJwtToken:!!params.jwtToken,hasSeedData:!!params.seed,apiConfig:params.api?Object.keys(params.api):void 0});const controller=new SettingsController(params);try{await controller.show()}catch(error){console.error("[openDashboardPopupSettings] Error:",error);if(params.onError){params.onError({code:"UNKNOWN_ERROR",message:error.message||"Unknown error occurred while opening settings modal",cause:error})}throw error}}async function createDateRangePicker2(input,options={}){const defaultOptions={maxRangeDays:31,...options};return await DateRangePickerJQ.attach(input,defaultOptions)}var PREMIUM_STYLES=`\n .myio-daterange-wrapper {\n font-family: 'Roboto', Arial, sans-serif;\n background: #f9f9f9;\n padding: 20px;\n border-radius: 8px;\n margin-bottom: 20px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n transition: all 0.2s ease;\n }\n \n .myio-daterange-wrapper:hover {\n box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n }\n \n .myio-daterange-label {\n display: block;\n margin-bottom: 8px;\n font-weight: 500;\n color: #333;\n font-size: 14px;\n line-height: 1.4;\n }\n \n .myio-daterange-input {\n width: 100%;\n max-width: 300px;\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n background: white;\n font-size: 14px;\n color: #333;\n cursor: pointer;\n transition: all 0.2s ease;\n font-family: inherit;\n line-height: 1.4;\n }\n \n .myio-daterange-input:hover {\n border-color: #4A148C;\n box-shadow: 0 0 0 2px rgba(74, 20, 140, 0.1);\n }\n \n .myio-daterange-input:focus {\n outline: none;\n border-color: #4A148C;\n box-shadow: 0 0 0 3px rgba(74, 20, 140, 0.2);\n }\n \n .myio-daterange-input::placeholder {\n color: #999;\n opacity: 1;\n }\n \n .myio-daterange-helper {\n font-size: 12px;\n color: #666;\n margin-top: 4px;\n line-height: 1.3;\n transition: color 0.2s ease;\n }\n \n .myio-daterange-helper.success {\n color: #28a745;\n font-weight: 500;\n }\n \n .myio-daterange-helper.error {\n color: #dc3545;\n font-weight: 500;\n }\n \n /* Responsive design */\n @media (max-width: 768px) {\n .myio-daterange-wrapper {\n padding: 16px;\n margin-bottom: 16px;\n }\n \n .myio-daterange-input {\n max-width: 100%;\n font-size: 16px; /* Prevents zoom on iOS */\n }\n }\n \n /* High contrast mode support */\n @media (prefers-contrast: high) {\n .myio-daterange-wrapper {\n border: 2px solid #000;\n }\n \n .myio-daterange-input {\n border: 2px solid #000;\n }\n }\n \n /* Reduced motion support */\n @media (prefers-reduced-motion: reduce) {\n .myio-daterange-wrapper,\n .myio-daterange-input,\n .myio-daterange-helper {\n transition: none;\n }\n }\n`;function injectPremiumStyles(){const styleId="myio-daterange-premium-styles";if(document.getElementById(styleId)){return}const styleEl=document.createElement("style");styleEl.id=styleId;styleEl.textContent=PREMIUM_STYLES;document.head.appendChild(styleEl);console.log("[MyIO] Premium date range styles injected")}function validateId(id,context){if(!id||typeof id!=="string"){throw new Error(`[createInputDateRangePickerInsideDIV] ${context} must be a non-empty string`)}if(!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(id)){throw new Error(`[createInputDateRangePickerInsideDIV] ${context} '${id}' is not a valid HTML ID`)}}async function createInputDateRangePickerInsideDIV(params){const{containerId:containerId,inputId:inputId,label:label="Período de Datas",placeholder:placeholder="Clique para selecionar período",pickerOptions:pickerOptions={},classNames:classNames={},injectStyles:injectStyles=true,showHelper:showHelper=true}=params;validateId(containerId,"containerId");validateId(inputId,"inputId");const container=document.getElementById(containerId);if(!container){throw new Error(`[createInputDateRangePickerInsideDIV] Container '#${containerId}' not found`)}if(injectStyles){injectPremiumStyles()}let inputEl=document.getElementById(inputId);if(inputEl&&inputEl.tagName.toLowerCase()!=="input"){throw new Error(`[createInputDateRangePickerInsideDIV] Element '#${inputId}' exists but is not an input element`)}const wrapper=document.createElement("div");wrapper.className=classNames.wrapper||"myio-daterange-wrapper";wrapper.setAttribute("data-myio-component","daterange-input");wrapper.setAttribute("data-version","1.0.0");let labelEl=null;if(label){labelEl=document.createElement("label");labelEl.className=classNames.label||"myio-daterange-label";labelEl.textContent=label;labelEl.setAttribute("for",inputId);wrapper.appendChild(labelEl)}if(!inputEl){inputEl=document.createElement("input");inputEl.type="text";inputEl.id=inputId;inputEl.name=inputId}inputEl.className=classNames.input||"myio-daterange-input";inputEl.readOnly=true;inputEl.placeholder=placeholder;inputEl.autocomplete="off";inputEl.setAttribute("aria-label",label||"Date range selector");if(showHelper){inputEl.setAttribute("aria-describedby",`${inputId}-helper`)}let helperEl=null;if(showHelper){helperEl=document.createElement("div");helperEl.id=`${inputId}-helper`;helperEl.className=classNames.helper||"myio-daterange-helper";helperEl.setAttribute("aria-live","polite");helperEl.style.display="flex";helperEl.style.alignItems="center"}wrapper.appendChild(inputEl);if(helperEl){wrapper.appendChild(helperEl)}const existingWrapper=container.querySelector('[data-myio-component="daterange-input"]');if(existingWrapper){console.warn(`[createInputDateRangePickerInsideDIV] Replacing existing daterange input in container '#${containerId}'`);existingWrapper.remove()}container.appendChild(wrapper);const enhancedOptions={maxRangeDays:31,onApply:result=>{if(helperEl){const startDate=new Date(result.startISO);const endDate=new Date(result.endISO);const days=Math.ceil((endDate.getTime()-startDate.getTime())/(1e3*60*60*24))+1;helperEl.textContent=`Período selecionado: ${days} dia${days!==1?"s":""}`;helperEl.className=(classNames.helper||"myio-daterange-helper")+" success";setTimeout(()=>{if(helperEl){helperEl.className=classNames.helper||"myio-daterange-helper"}},3e3)}if(pickerOptions.onApply){pickerOptions.onApply(result)}},...pickerOptions};let picker;try{picker=await createDateRangePicker2(inputEl,enhancedOptions);console.log(`[createInputDateRangePickerInsideDIV] Successfully initialized for input '#${inputId}'`)}catch(error){wrapper.remove();throw new Error(`[createInputDateRangePickerInsideDIV] Failed to initialize date picker: ${error.message}`)}const controller={input:inputEl,container:container,wrapper:wrapper,picker:picker,getDisplayValue:()=>inputEl.value,getDates:()=>picker.getDates(),setDates:(startISO,endISO)=>{try{picker.setDates(startISO,endISO)}catch(error){console.error(`[createInputDateRangePickerInsideDIV] Error setting dates:`,error);throw error}},setHelperText:(text,type="default")=>{if(helperEl){helperEl.textContent=text;const baseClass=classNames.helper||"myio-daterange-helper";helperEl.className=type==="default"?baseClass:`${baseClass} ${type}`}},destroy:()=>{try{picker.destroy();console.log(`[createInputDateRangePickerInsideDIV] Date picker destroyed for input '#${inputId}'`)}catch(error){console.warn(`[createInputDateRangePickerInsideDIV] Error destroying picker:`,error)}try{wrapper.remove();console.log(`[createInputDateRangePickerInsideDIV] Wrapper removed for input '#${inputId}'`)}catch(error){console.warn(`[createInputDateRangePickerInsideDIV] Error removing wrapper:`,error)}}};return controller}var DEFAULT_STYLES={primaryColor:"#4A148C",accentColor:"#EDE7F3",dangerColor:"#f44336",infoColor:"#2196F3",textPrimary:"#212121",textSecondary:"#757575",backgroundColor:"#ffffff",overlayColor:"rgba(0, 0, 0, 0.5)",borderRadius:"8px",buttonRadius:"6px",pillRadius:"20px",zIndex:1e4,spacingXs:"4px",spacingSm:"8px",spacingMd:"16px",spacingLg:"24px",spacingXl:"32px",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',fontSizeXs:"12px",fontSizeSm:"14px",fontSizeMd:"16px",fontSizeLg:"18px",fontSizeXl:"20px",fontWeight:"400",fontWeightBold:"600"};var CHART_JS_CDN="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js";var ZOOM_PLUGIN_CDN="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom@2.0.1/dist/chartjs-plugin-zoom.min.js";var JSPDF_VERSION="2.5.1";var JSPDF_CDN=`https://cdnjs.cloudflare.com/ajax/libs/jspdf/${JSPDF_VERSION}/jspdf.umd.min.js`;var chartJsLoaded=false;var zoomPluginLoaded=false;var jsPdfLoaded=false;var _jspdfPromise=null;var cssInjected=false;var STRINGS={"pt-BR":{title:"Demanda",period:"Período",maximum:"Máxima",at:"no dia",atTime:"ás",timeUnit:"hs",exportPdf:"Exportar PDF",fullscreen:"Tela cheia",close:"Fechar",resetZoom:"Reset Zoom",loading:"Carregando dados...",noData:"Sem pontos de demanda no período selecionado",error:"Erro ao carregar dados",zoomHelp:"Scroll: zoom | Drag: selecionar | Ctrl+Drag: mover",demand:"Demanda (kW)",reportTitle:"Relatório de Demanda",reportFooter:"MyIO Energy Management System"},"en-US":{title:"Demand",period:"Period",maximum:"Maximum",at:"on",atTime:"at",timeUnit:"",exportPdf:"Export PDF",fullscreen:"Fullscreen",close:"Close",resetZoom:"Reset Zoom",loading:"Loading data...",noData:"No demand points in the selected period",error:"Error loading data",zoomHelp:"Scroll: zoom | Drag: select | Ctrl+Drag: pan",demand:"Demand (kW)",reportTitle:"Demand Report",reportFooter:"MyIO Energy Management System"}};async function loadScript(url,checkGlobal){return new Promise((resolve,reject)=>{if(window[checkGlobal]){resolve();return}const existingScript=document.querySelector(`script[src="${url}"]`);if(existingScript){existingScript.addEventListener("load",()=>{if(window[checkGlobal]){resolve()}else{reject(new Error(`Library ${checkGlobal} not available after loading ${url}`))}});existingScript.addEventListener("error",()=>reject(new Error(`Failed to load ${url}`)));return}const script=document.createElement("script");script.src=url;script.onload=()=>{if(window[checkGlobal]){resolve()}else{reject(new Error(`Library ${checkGlobal} not available after loading ${url}`))}};script.onerror=()=>reject(new Error(`Failed to load ${url}`));document.head.appendChild(script)})}async function loadExternalLibraries(){try{if(!chartJsLoaded){await loadScript(CHART_JS_CDN,"Chart");chartJsLoaded=true}if(!zoomPluginLoaded){await loadScript(ZOOM_PLUGIN_CDN,"ChartZoom");zoomPluginLoaded=true}if(!jsPdfLoaded){await ensureJsPDF();jsPdfLoaded=true}}catch(error){throw new Error(`Failed to load external libraries: ${error}`)}}function ensureJsPDF(){if(window.jspdf?.jsPDF){console.info("jsPDF already loaded.");return Promise.resolve()}if(_jspdfPromise){console.info("jsPDF loading already in progress.");return _jspdfPromise}_jspdfPromise=new Promise((resolve,reject)=>{const existing=document.querySelector('script[data-lib="jspdf"]');if(existing){existing.addEventListener("load",()=>{if(window.jspdf?.jsPDF){console.info("jsPDF loaded via existing script.");resolve()}else{reject(new Error("jsPDF loaded but window.jspdf.jsPDF missing"))}});existing.addEventListener("error",()=>reject(new Error("Failed to load jsPDF via existing script")));return}const s=document.createElement("script");s.src=JSPDF_CDN;s.async=true;s.defer=true;s.dataset.lib="jspdf";s.onload=()=>{if(window.jspdf?.jsPDF){console.info("jsPDF loaded successfully.");resolve()}else{reject(new Error("jsPDF loaded but window.jspdf.jsPDF missing"))}};s.onerror=()=>reject(new Error("Failed to load jsPDF from CDN"));document.head.appendChild(s)}).finally(()=>{_jspdfPromise=null});return _jspdfPromise}function getJsPDFCtor(){if(window.jspdf?.jsPDF)return window.jspdf.jsPDF;if(window.jsPDF?.jsPDF)return window.jsPDF.jsPDF;if(window.jsPDF)return window.jsPDF;throw new Error("jsPDF constructor not found on window")}function savePdfSafe(doc,filename){try{doc.save(filename)}catch(e){console.warn("doc.save() failed, attempting Blob URL fallback:",e);const blob=doc.output("blob");const url=URL.createObjectURL(blob);window.open(url,"_blank")||alert("Pop-up blocked. Allow pop-ups to download the PDF.");setTimeout(()=>URL.revokeObjectURL(url),3e4)}}function addCanvasToPdf(doc,canvas,x=10,y=20,maxWmm=190){const img=canvas.toDataURL("image/png",1);const pageWmm=doc.internal.pageSize.getWidth();const mmW=Math.min(maxWmm,pageWmm-x*2);const mmH=canvas.height/canvas.width*mmW;doc.addImage(img,"PNG",x,y,mmW,mmH,void 0,"FAST");return y+mmH}function ensureRoom(doc,nextY,minRoom=40){const h=doc.internal.pageSize.getHeight();if(nextY+minRoom>h){doc.addPage();return 20}return nextY}function injectCSS(styles){if(cssInjected)return;const css=`\n .myio-demand-modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: ${styles.overlayColor};\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${styles.zIndex};\n font-family: ${styles.fontFamily};\n font-size: ${styles.fontSizeMd};\n color: ${styles.textPrimary};\n }\n\n .myio-demand-modal-card {\n background: ${styles.backgroundColor};\n border-radius: ${styles.borderRadius};\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 90vw;\n max-height: 90vh;\n width: 800px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .myio-demand-modal-card.fullscreen {\n width: 100vw;\n height: 100vh;\n max-width: 100vw;\n max-height: 100vh;\n border-radius: 0;\n }\n\n .myio-demand-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: ${styles.spacingMd};\n background: #4A148C;\n color: white;\n }\n\n .myio-demand-modal-title-section {\n display: flex;\n align-items: center;\n gap: ${styles.spacingSm};\n }\n\n .myio-demand-modal-icon {\n font-size: ${styles.fontSizeLg};\n }\n\n .myio-demand-modal-title {\n margin: 0;\n font-size: ${styles.fontSizeLg};\n font-weight: ${styles.fontWeightBold};\n }\n\n .myio-demand-modal-actions {\n display: flex;\n gap: ${styles.spacingSm};\n }\n\n .myio-demand-modal-btn {\n background: rgba(255, 255, 255, 0.2);\n border: 1px solid rgba(255, 255, 255, 0.3);\n color: white;\n padding: ${styles.spacingSm} ${styles.spacingMd};\n border-radius: ${styles.buttonRadius};\n cursor: pointer;\n font-size: ${styles.fontSizeSm};\n font-family: inherit;\n transition: background-color 0.2s;\n }\n\n .myio-demand-modal-btn:hover {\n background: rgba(255, 255, 255, 0.3);\n }\n\n .myio-demand-modal-btn:focus {\n outline: 2px solid white;\n outline-offset: 2px;\n }\n\n .myio-demand-modal-btn-close {\n font-size: ${styles.fontSizeLg};\n padding: ${styles.spacingSm};\n min-width: 32px;\n background: ${styles.dangerColor} !important;\n }\n\n .myio-demand-modal-btn-close:hover {\n background: #d32f2f !important;\n }\n\n .myio-demand-modal-period {\n padding: ${styles.spacingMd} ${styles.spacingLg};\n background: #f5f5f5;\n font-size: ${styles.fontSizeSm};\n color: ${styles.textSecondary};\n border-bottom: 1px solid #e0e0e0;\n }\n\n .myio-demand-modal-peak {\n margin: ${styles.spacingMd} ${styles.spacingLg} 0;\n padding: ${styles.spacingSm} ${styles.spacingMd};\n background: ${styles.accentColor};\n color: #333;\n border-radius: ${styles.pillRadius};\n font-size: ${styles.fontSizeSm};\n font-weight: ${styles.fontWeightBold};\n display: inline-block;\n width: fit-content;\n }\n\n .myio-demand-modal-content {\n flex: 1;\n padding: ${styles.spacingLg};\n display: flex;\n flex-direction: column;\n min-height: 400px;\n }\n\n .myio-demand-modal-chart-container {\n flex: 1;\n position: relative;\n min-height: 300px;\n }\n\n .myio-demand-modal-chart {\n width: 100% !important;\n height: 100% !important;\n }\n\n .myio-demand-modal-zoom-controls {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: ${styles.spacingMd};\n padding-top: ${styles.spacingMd};\n border-top: 1px solid #e0e0e0;\n }\n\n .myio-demand-modal-btn-reset {\n background: ${styles.infoColor};\n border: none;\n color: white;\n padding: ${styles.spacingSm} ${styles.spacingMd};\n border-radius: ${styles.buttonRadius};\n cursor: pointer;\n font-size: ${styles.fontSizeSm};\n font-family: inherit;\n }\n\n .myio-demand-modal-btn-reset:hover {\n background: #1976D2;\n }\n\n .myio-demand-modal-zoom-help {\n font-size: ${styles.fontSizeXs};\n color: ${styles.textSecondary};\n }\n\n .myio-demand-modal-loading,\n .myio-demand-modal-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: ${styles.spacingXl};\n text-align: center;\n }\n\n .myio-demand-modal-spinner {\n font-size: 2rem;\n animation: spin 1s linear infinite;\n margin-bottom: ${styles.spacingMd};\n }\n\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n .myio-demand-modal-loading-text {\n color: ${styles.textSecondary};\n }\n\n .myio-demand-modal-error-icon {\n font-size: 2rem;\n color: ${styles.dangerColor};\n margin-bottom: ${styles.spacingMd};\n }\n\n .myio-demand-modal-error-text {\n color: ${styles.dangerColor};\n }\n\n /* Responsive design */\n @media (max-width: 768px) {\n .myio-demand-modal-card {\n width: 95vw;\n height: 90vh;\n max-height: 90vh;\n }\n\n .myio-demand-modal-header {\n padding: ${styles.spacingMd};\n }\n\n .myio-demand-modal-title {\n font-size: ${styles.fontSizeMd};\n }\n\n .myio-demand-modal-actions {\n gap: ${styles.spacingXs};\n }\n\n .myio-demand-modal-btn {\n padding: ${styles.spacingXs} ${styles.spacingSm};\n font-size: ${styles.fontSizeXs};\n }\n\n .myio-demand-modal-content {\n padding: ${styles.spacingMd};\n }\n }\n `;const style=document.createElement("style");style.textContent=css;document.head.appendChild(style);cssInjected=true}function formatDate(date,locale){return date.toLocaleDateString(locale,{day:"2-digit",month:"2-digit",year:"numeric"})}function formatDateTime(date,locale){return date.toLocaleDateString(locale,{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"})}async function fetchTelemetryData(token,deviceId,startDate,endDate,queryParams){const startTs=new Date(startDate).getTime();const endTs=new Date(endDate).getTime();const keys=queryParams?.keys||"consumption";const limit=queryParams?.limit||5e4;const intervalType=queryParams?.intervalType||"MILLISECONDS";const interval=queryParams?.interval||54e6;const agg=queryParams?.agg||"SUM";const orderBy=queryParams?.orderBy||"ASC";const url=`/api/plugins/telemetry/DEVICE/${deviceId}/values/timeseries?keys=${keys}&startTs=${startTs}&endTs=${endTs}&limit=${limit}&intervalType=${intervalType}&interval=${interval}&agg=${agg}&orderBy=${orderBy}`;const response=await fetch(url,{headers:{"X-Authorization":`Bearer ${token}`,"Content-Type":"application/json"}});if(!response.ok){throw new Error(`HTTP ${response.status}: ${response.statusText}`)}const data=await response.json();return data}function processMultiSeriesChartData(rawData,keys,correctionFactor,locale){const seriesKeys=keys.split(",").map(k=>k.trim());const seriesData=[];let globalPeak=null;let isEmpty=true;const colors=["#4A148C","#2196F3","#4CAF50","#FF9800","#F44336","#9C27B0","#795548","#607D8B"];seriesKeys.forEach((key,index)=>{const rawSeries=rawData[key]||[];if(rawSeries.length===0){seriesData.push({key:key,label:key,points:[],peak:null,color:colors[index%colors.length]});return}isEmpty=false;const sortedData=rawSeries.sort((a,b)=>a.ts-b.ts);const points=[];let previousValue=0;let previousTs=0;for(let i=0;i<sortedData.length;i++){const current=sortedData[i];const currentValue=parseFloat(current.value);const currentTs=current.ts;if(i>0){const deltaWh=currentValue-previousValue;const deltaHours=(currentTs-previousTs)/(1e3*60*60);if(deltaWh>0&&deltaHours>0){const demandKw=deltaWh/1e3/deltaHours*correctionFactor;points.push({x:currentTs,y:demandKw})}}previousValue=currentValue;previousTs=currentTs}let seriesPeak=null;if(points.length>0){const maxPoint=points.reduce((max,point)=>point.y>max.y?point:max);seriesPeak={value:maxPoint.y,timestamp:maxPoint.x,formattedValue:maxPoint.y.toFixed(2),formattedTime:formatDateTime(new Date(maxPoint.x),locale),key:key};if(!globalPeak||seriesPeak.value>globalPeak.value){globalPeak=seriesPeak}}seriesData.push({key:key,label:key,points:points,peak:seriesPeak,color:colors[index%colors.length]})});return{series:seriesData,globalPeak:globalPeak,isEmpty:isEmpty}}function createFocusTrap(container){const focusableElements=container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');const firstElement=focusableElements[0];const lastElement=focusableElements[focusableElements.length-1];function handleTabKey(e){if(e.key!=="Tab")return;if(e.shiftKey){if(document.activeElement===firstElement){lastElement.focus();e.preventDefault()}}else{if(document.activeElement===lastElement){firstElement.focus();e.preventDefault()}}}container.addEventListener("keydown",handleTabKey);firstElement?.focus();return()=>{container.removeEventListener("keydown",handleTabKey)}}async function openDemandModal(params){if(!params.token||!params.deviceId||!params.startDate||!params.endDate){throw new Error("Missing required parameters: token, deviceId, startDate, endDate")}const styles={...DEFAULT_STYLES,...params.styles};const locale=params.locale||"pt-BR";const strings=STRINGS[locale]||STRINGS["pt-BR"];await loadExternalLibraries();injectCSS(styles);const container=typeof params.container==="string"?document.querySelector(params.container):params.container||document.body;if(!container){throw new Error("Container element not found")}const overlay=document.createElement("div");overlay.className="myio-demand-modal-overlay";overlay.setAttribute("role","dialog");overlay.setAttribute("aria-modal","true");overlay.setAttribute("aria-labelledby","modal-title");const label=params.label||"Dispositivo";const startDateFormatted=formatDate(new Date(params.startDate),locale);const endDateFormatted=formatDate(new Date(params.endDate),locale);overlay.innerHTML=`\n <div class="myio-demand-modal-card">\n <div class="myio-demand-modal-header">\n <div class="myio-demand-modal-title-section">\n <span class="myio-demand-modal-icon">⚡</span>\n <h2 id="modal-title" class="myio-demand-modal-title">${strings.title} – ${label}</h2>\n </div>\n <div class="myio-demand-modal-actions">\n <button class="myio-demand-modal-btn myio-demand-modal-btn-pdf" type="button">\n ${strings.exportPdf}\n </button>\n <button class="myio-demand-modal-btn myio-demand-modal-btn-fullscreen" type="button" aria-label="${strings.fullscreen}">\n ⛶\n </button>\n <button class="myio-demand-modal-btn myio-demand-modal-btn-close" type="button" aria-label="${strings.close}">\n ×\n </button>\n </div>\n </div>\n \n <div class="myio-demand-modal-period">\n ${strings.period}: ${startDateFormatted} → ${endDateFormatted}\n </div>\n \n <div class="myio-demand-modal-peak" style="display: none;"></div>\n \n <div class="myio-demand-modal-content">\n <div class="myio-demand-modal-chart-container">\n <canvas class="myio-demand-modal-chart"></canvas>\n </div>\n \n <div class="myio-demand-modal-zoom-controls">\n <button class="myio-demand-modal-btn-reset" type="button">\n ${strings.resetZoom}\n </button>\n <div class="myio-demand-modal-zoom-help">\n <small>${strings.zoomHelp}</small>\n </div>\n </div>\n </div>\n \n <div class="myio-demand-modal-loading">\n <div class="myio-demand-modal-spinner">⧗</div>\n <div class="myio-demand-modal-loading-text">${strings.loading}</div>\n </div>\n \n <div class="myio-demand-modal-error" style="display: none;">\n <div class="myio-demand-modal-error-icon">⚠</div>\n <div class="myio-demand-modal-error-text"></div>\n </div>\n </div>\n `;container.appendChild(overlay);const card=overlay.querySelector(".myio-demand-modal-card");const closeBtn=overlay.querySelector(".myio-demand-modal-btn-close");const fullscreenBtn=overlay.querySelector(".myio-demand-modal-btn-fullscreen");const pdfBtn=overlay.querySelector(".myio-demand-modal-btn-pdf");const resetBtn=overlay.querySelector(".myio-demand-modal-btn-reset");const chartCanvas=overlay.querySelector(".myio-demand-modal-chart");const loadingEl=overlay.querySelector(".myio-demand-modal-loading");const errorEl=overlay.querySelector(".myio-demand-modal-error");const errorText=overlay.querySelector(".myio-demand-modal-error-text");const peakEl=overlay.querySelector(".myio-demand-modal-peak");const contentEl=overlay.querySelector(".myio-demand-modal-content");let chart=null;let chartData=null;let isFullscreen=false;const originalOverflow=document.body.style.overflow;document.body.style.overflow="hidden";const releaseFocusTrap=createFocusTrap(overlay);function closeModal(){if(chart){chart.destroy()}overlay.remove();document.body.style.overflow=originalOverflow;releaseFocusTrap();params.onClose?.()}function toggleFullscreen(){isFullscreen=!isFullscreen;card.classList.toggle("fullscreen",isFullscreen);if(chart){setTimeout(()=>chart.resize(),100)}}function resetZoom(){if(chart){chart.resetZoom()}}async function exportPdf(){if(!chartData||!chart){alert("Nenhum dado disponível para exportar");return}const btn=pdfBtn;const originalHtml=btn.innerHTML;btn.disabled=true;btn.innerHTML="<span>⏳</span> Gerando PDF...";try{await ensureJsPDF();await(document.fonts?.ready?.catch(e=>console.warn("Font loading interrupted or failed:",e)));const JsPDF=getJsPDFCtor();const doc=new JsPDF("p","mm","a4");doc.setFontSize(20);doc.setTextColor(74,20,140);doc.text(strings.reportTitle,20,20);doc.setFontSize(14);doc.setTextColor(0,0,0);const label2=params.label||"Dispositivo";doc.text(`${strings.title} - ${label2}`,20,35);const startDate=formatDate(new Date(params.startDate),params.locale||"pt-BR");const endDate=formatDate(new Date(params.endDate),params.locale||"pt-BR");doc.text(`${strings.period}: ${startDate} - ${endDate}`,20,45);let currentY=55;if(chartData.globalPeak){const peak=chartData.globalPeak;doc.setFontSize(12);doc.setTextColor(255,152,0);doc.text(`${strings.maximum}: ${peak.formattedValue} kW ${peak.key?`(${peak.key}) `:""}${strings.at} ${peak.formattedTime}`,20,currentY);currentY+=10}currentY=ensureRoom(doc,currentY,120);currentY=addCanvasToPdf(doc,chartCanvas,20,currentY);currentY+=10;if(chartData.series.length>0&&chartData.series[0].points.length>0){currentY=ensureRoom(doc,currentY,60);doc.setFontSize(12);doc.setTextColor(0,0,0);doc.text("Amostra de Dados:",20,currentY);currentY+=10;const samplePoints=chartData.series[0].points.slice(0,10);doc.setFontSize(10);doc.text("Data/Hora",20,currentY);doc.text(params.yAxisLabel||strings.demand,100,currentY);currentY+=7;samplePoints.forEach(point=>{currentY=ensureRoom(doc,currentY,10);const dateStr=formatDateTime(new Date(point.x),params.locale||"pt-BR");doc.text(dateStr,20,currentY);doc.text(point.y.toFixed(2),100,currentY);currentY+=7})}currentY=ensureRoom(doc,currentY,20);doc.setFontSize(8);doc.setTextColor(128,128,128);doc.text(`${strings.reportFooter}`,20,doc.internal.pageSize.getHeight()-15);doc.text(`Gerado em: ${(new Date).toLocaleString(params.locale||"pt-BR")}`,20,doc.internal.pageSize.getHeight()-10);const fileName=params.pdf?.fileName||`demanda_${label2.replace(/\s+/g,"_")}_${(new Date).toISOString().slice(0,10)}.pdf`;savePdfSafe(doc,fileName)}catch(error){console.error("[PDF Export] Error:",error);alert("Erro ao gerar PDF. Por favor, tente novamente. Verifique o console para mais detalhes.")}finally{btn.disabled=false;btn.innerHTML=originalHtml}}closeBtn.addEventListener("click",closeModal);fullscreenBtn.addEventListener("click",toggleFullscreen);resetBtn.addEventListener("click",resetZoom);pdfBtn.addEventListener("click",exportPdf);overlay.addEventListener("click",e=>{if(e.target===overlay){closeModal()}});overlay.addEventListener("keydown",e=>{if(e.key==="Escape"){closeModal()}});async function loadData(){try{loadingEl.style.display="flex";contentEl.style.display="none";errorEl.style.display="none";const startDateObj=new Date(params.startDate);const endDateObj=new Date(params.endDate);const diffTime=Math.abs(endDateObj.getTime()-startDateObj.getTime());const diffDays=Math.ceil(diffTime/(1e3*60*60*24));if(diffDays>30){loadingEl.style.display="none";errorEl.style.display="flex";errorText.textContent="O Limite de busca é de 30 dias de intervalo.";return}const rawData=params.fetcher?await params.fetcher({token:params.token,deviceId:params.deviceId,startDate:params.startDate,endDate:params.endDate,telemetryQuery:params.telemetryQuery}):await fetchTelemetryData(params.token,params.deviceId,params.startDate,params.endDate,params.telemetryQuery);chartData=processMultiSeriesChartData(rawData,params.telemetryQuery?.keys||"consumption",params.correctionFactor||1,locale);if(chartData.isEmpty){errorEl.style.display="flex";errorText.textContent=strings.noData;return}if(chartData.globalPeak){const peak=chartData.globalPeak;const date=new Date(peak.timestamp);const dateStr=date.toLocaleDateString(locale,{day:"2-digit",month:"2-digit",year:"numeric"});const timeStr=date.toLocaleTimeString(locale,{hour:"2-digit",minute:"2-digit"});peakEl.textContent=`${strings.maximum}: ${peak.formattedValue} kW ${peak.key?`(${peak.key}) `:""}${strings.at} ${dateStr} ${strings.atTime} ${timeStr}${strings.timeUnit}`;peakEl.style.display="block"}const Chart=window.Chart;Chart.register(window.ChartZoom);chart=new Chart(chartCanvas,{type:"line",data:{datasets:chartData.series.map(series=>({label:series.label,data:series.points,borderColor:series.color,backgroundColor:series.color+"20",fill:false,tension:.4,pointRadius:2,pointHoverRadius:6}))},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:chartData.series.length>1,position:"top"},zoom:{zoom:{wheel:{enabled:true},pinch:{enabled:true},drag:{enabled:true,modifierKey:"ctrl"},mode:"x"},pan:{enabled:true,mode:"x",modifierKey:"ctrl"}}},scales:{x:{type:"linear",position:"bottom",title:{display:true,text:"Tempo"},ticks:{callback:function(value){const date=new Date(value);return date.toLocaleDateString(locale,{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}}},y:{title:{display:true,text:params.yAxisLabel||strings.demand},beginAtZero:true}},interaction:{intersect:false,mode:"index"}}});loadingEl.style.display="none";contentEl.style.display="flex"}catch(error){console.error("Error loading demand data:",error);loadingEl.style.display="none";errorEl.style.display="flex";errorText.textContent=`${strings.error}: ${error instanceof Error?error.message:"Unknown error"}`}}loadData();return{destroy:closeModal}}exports.MyIOChartModal=MyIOChartModal;exports.MyIODraggableCard=MyIODraggableCard;exports.MyIOSelectionStore=MyIOSelectionStore;exports.MyIOSelectionStoreClass=MyIOSelectionStoreClass;exports.addDetectionContext=addDetectionContext;exports.addNamespace=addNamespace;exports.averageByDay=averageByDay;exports.buildWaterReportCSV=buildWaterReportCSV;exports.buildWaterStoresCSV=buildWaterStoresCSV;exports.calcDeltaPercent=calcDeltaPercent;exports.classify=classify;exports.classifyWaterLabel=classifyWaterLabel;exports.classifyWaterLabels=classifyWaterLabels;exports.createDateRangePicker=createDateRangePicker2;exports.createInputDateRangePickerInsideDIV=createInputDateRangePickerInsideDIV;exports.decodePayload=decodePayload;exports.decodePayloadBase64Xor=decodePayloadBase64Xor;exports.detectDeviceType=detectDeviceType;exports.determineInterval=determineInterval;exports.exportToCSV=exportToCSV;exports.exportToCSVAll=exportToCSVAll;exports.findValue=findValue;exports.fmtPerc=fmtPerc;exports.fmtPercLegacy=fmtPerc2;exports.formatAllInSameUnit=formatAllInSameUnit;exports.formatAllInSameWaterUnit=formatAllInSameWaterUnit;exports.formatDateForInput=formatDateForInput;exports.formatDateToYMD=formatDateToYMD;exports.formatDateWithTimezoneOffset=formatDateWithTimezoneOffset;exports.formatEnergy=formatEnergy;exports.formatNumberReadable=formatNumberReadable;exports.formatTankHeadFromCm=formatTankHeadFromCm;exports.formatWaterByGroup=formatWaterByGroup;exports.formatWaterVolumeM3=formatWaterVolumeM3;exports.getAvailableContexts=getAvailableContexts;exports.getDateRangeArray=getDateRangeArray;exports.getSaoPauloISOString=getSaoPauloISOString;exports.getSaoPauloISOStringFixed=getSaoPauloISOStringFixed;exports.getValueByDatakey=getValueByDatakey;exports.getValueByDatakeyLegacy=getValueByDatakeyLegacy;exports.getWaterCategories=getWaterCategories;exports.groupByDay=groupByDay;exports.isWaterCategory=isWaterCategory;exports.normalizeRecipients=normalizeRecipients;exports.numbers=numbers_exports;exports.openDashboardPopup=openDashboardPopup;exports.openDashboardPopupAllReport=openDashboardPopupAllReport;exports.openDashboardPopupEnergy=openDashboardPopupEnergy;exports.openDashboardPopupReport=openDashboardPopupReport;exports.openDashboardPopupSettings=openDashboardPopupSettings;exports.openDemandModal=openDemandModal;exports.parseInputDateToDate=parseInputDateToDate;exports.renderCardCompenteHeadOffice=renderCardCompenteHeadOffice;exports.renderCardComponent=renderCardComponent;exports.renderCardComponentEnhanced=renderCardComponent2;exports.renderCardComponentLegacy=renderCardComponentLegacy;exports.renderCardComponentV2=renderCardComponentV2;exports.strings=strings_exports;exports.timeWindowFromInputYMD=timeWindowFromInputYMD;exports.toCSV=toCSV;exports.toFixedSafe=toFixedSafe});