`;for(const e of c){const n=l.get(e);if(!n)continue;const i=pn(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,un(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const p=e.querySelector(".toggle-pill");if(p){p.classList.toggle("toggle-on",c),p.classList.toggle("toggle-off",!c);const e=p.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const u=e.querySelector(".list-status-badge");u&&(u.textContent=c?"ON":"OFF",u.classList.toggle("list-status-on",c),u.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=jt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,un(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},p=new Set,u=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&p.add(s);const o=n.name_by_user??n.name??i.device_name??"";u.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(p),perPanelStats:u}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends Pe{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=qe(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
+ `,m([Me()],Xe.prototype,"_errors",void 0),Xe=m([Ee("span-error-banner")],Xe);const it=g.power;function st(e){return it.unit(e)}function ot(e){return(e<0?"-":"")+it.format(e)}function rt(e){return(Math.abs(e)/1e3).toFixed(1)}function at(e){return Math.ceil(e/2)}function lt(e){return e%2==0?1:0}function ct(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return at(t)===at(n)?"row-span":lt(t)===lt(n)?"col-span":"row-span"}function dt(e){const t=e.chart_metric??s;return g[t]??g[s]}function ht(e,t){const n=function(e){return dt(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class pt{constructor(){this._status=null,this._lastFetch=0,this._inflight=null,this._generation=0,this._errorStore=null,this._retry=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e,this._retry=e?new We(e):null}async fetch(e,t){const i=Date.now();if(this._inflight&&this._inflight.gen===this._generation)return this._inflight.promise;if(this._status&&i-this._lastFetch<3e4)return this._status;const s=this._generation,o=(async()=>{try{const i={};t&&(i.config_entry_id=t);const o={type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0},r=this._retry?await this._retry.callWS(e,o,{errorId:"fetch:monitoring",errorMessage:n("error.monitoring_failed")}):await e.callWS(o),l=r?.response??null;return s===this._generation&&(this._status=l,this._lastFetch=Date.now()),l}catch(e){return console.warn("SPAN Panel: monitoring status fetch failed",e),s===this._generation&&(this._status=null),this._retry||this._errorStore?.add({key:"fetch:monitoring",level:"warning",message:n("error.monitoring_failed"),persistent:!1}),null}finally{this._inflight?.gen===s&&(this._inflight=null)}})();return this._inflight={gen:s,promise:o},o}invalidate(){this._lastFetch=0,this._generation++}get status(){return this._status}clear(){this._status=null,this._lastFetch=0,this._generation++}}class ut{constructor(){this._caches=new Map,this._errorStore=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e;for(const t of this._caches.values())t.errorStore=e}async fetchOne(e,t){let n=this._caches.get(t);return n||(n=new pt,n.errorStore=this._errorStore,this._caches.set(t,n)),n.fetch(e,t)}invalidate(){for(const e of this._caches.values())e.invalidate()}clear(){this._caches.clear()}}function gt(e,t){return e?.circuits?e.circuits[t]??null:null}function _t(e){return!!e&&void 0!==e.continuous_threshold_pct}function ft(e,t,n,i){const s=[];return n||s.push("circuit-off"),i&&s.push("circuit-producer"),function(e){return!!e&&null!=e.over_threshold_since}(t)&&s.push("circuit-alert"),_t(t)&&s.push("circuit-custom-monitoring"),s.join(" ")}function vt(e,t,i,s,o,r,a,d,h,p=!1){const u=t.entities?.power,g=u?r.states[u]:null,_=g&&parseFloat(g.state)||0,m=t.device_type===c||_<0,b=t.entities?.switch,y=b?r.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===l,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",$=Oe(t.name||n("grid.unknown")),C=dt(a);let P;if("current"===C.entityRole){const e=t.entities?.current,n=e?r.states[e]:null,i=n&&parseFloat(n.state)||0;P=`${C.format(i)}A`}else P=`${ot(_)}${st(_)}`;const k=h||"unknown";let E="";if("unknown"!==k){const e=f[k]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"},t=Oe(e.label()),n=Oe(e.icon),i=Oe(e.color);if(e.icon2){E=`\n \n \n `}else if(e.textLabel){E=`\n \n ${Oe(e.textLabel)}\n `}else E=``}const z=d&&_t(d)?v:"#555",A=``;let N="",M=d?.utilization_pct??null;if(null==M&&t.breaker_rating_a){const e=t.entities?.current,n=e?r.states[e]:null,i=n?Math.abs(parseFloat(n.state)||0):0;M=Math.round(i/t.breaker_rating_a*1e3)/10}if(null!=M){N=`=80?"utilization-warning":"utilization-normal"}">${Math.round(M)}%`}return`\n
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=pn(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,un(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const p=e.querySelector(".toggle-pill");if(p){p.classList.toggle("toggle-on",c),p.classList.toggle("toggle-off",!c);const e=p.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const u=e.querySelector(".list-status-badge");u&&(u.textContent=c?"ON":"OFF",u.classList.toggle("list-status-on",c),u.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=jt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,un(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},p=new Set,u=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&p.add(s);const o=n.name_by_user??n.name??i.device_name??"";u.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(p),perPanelStats:u}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends Pe{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=qe(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._recoverTimer=null,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._recoverIfNeeded()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._recoverTimer&&(clearTimeout(this._recoverTimer),this._recoverTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
`:"");"activity"===h?this._listCtrl.renderActivityView(e,this.hass,a,g,_,o):this._listCtrl.renderAreaView(e,this.hass,a,g,_,o),this._updateFavoritesPanelStats(e,g),this._listDashCtrl.setupResizeObserver(e,e),this._listDashCtrl.startIntervals(e,()=>{this._updateFavoritesPanelStats(e,g)})}catch(n){if(t())return;const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=n.message,e.appendChild(i)}}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}const o=new Map;for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const r=document.createElement("h2");r.style.margin="8px 0 12px",r.style.fontSize="1em",r.textContent=t?.name_by_user??t?.name??e,n.appendChild(r);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const l=new sn;l.errorStore=this._errorStore,o.set(e,l);try{await l.render(a,this.hass,e)}catch(t){console.warn("SPAN Panel: favorites monitoring render failed",e,t);const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message??String(t),a.appendChild(n)}}this._favoritesMonitoringTabs=o}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};wn._shellStyles=C`
:host {
color: var(--primary-text-color);
}
diff --git a/src/panel/span-panel.ts b/src/panel/span-panel.ts
index 6d08916..c4b10ff 100644
--- a/src/panel/span-panel.ts
+++ b/src/panel/span-panel.ts
@@ -100,6 +100,12 @@ export class SpanPanelElement extends LitElement {
* column count, horizon edits) the user made inside the sidebar.
*/
private _pendingTabRender = false;
+ /**
+ * Pending retry timer for ``_recoverIfNeeded``. Cleared on disconnect
+ * so a delayed retry cannot fire against a detached element after HA
+ * has torn down the panel.
+ */
+ private _recoverTimer: ReturnType | null = null;
private static _shellStyles = css`
:host {
@@ -230,7 +236,7 @@ export class SpanPanelElement extends LitElement {
this._onVisibilityChange = (): void => {
if (document.visibilityState !== "visible" || !this._discovered || !this.hass) return;
- this._scheduleTabRender();
+ this._recoverIfNeeded();
};
document.addEventListener("visibilitychange", this._onVisibilityChange);
@@ -267,6 +273,10 @@ export class SpanPanelElement extends LitElement {
clearTimeout(this._persistFavoritesViewStateTimer);
this._persistFavoritesViewStateTimer = null;
}
+ if (this._recoverTimer) {
+ clearTimeout(this._recoverTimer);
+ this._recoverTimer = null;
+ }
this._errorStore.dispose();
super.disconnectedCallback();
}
@@ -871,6 +881,58 @@ export class SpanPanelElement extends LitElement {
*/
private readonly _beginRender = makeRenderToken();
+ /**
+ * Visibility-restore recovery. When the browser tab is backgrounded
+ * and HA's WebSocket drops/reconnects, a tab re-render kicked off on
+ * ``visibilitychange`` can silently bail out mid-flight — a WS call
+ * resolving empty, a supersession race, or a cache returning null
+ * without throwing — and the Favorites view in particular is left
+ * with a blank ``#tab-content`` because it clears the container
+ * before awaiting its async build steps.
+ *
+ * Wrap ``_scheduleTabRender`` in a try/catch **and** verify the
+ * container produced content afterwards; if either fails, retry
+ * with backoff so the render can catch a freshly-reconnected WS.
+ * Mirrors the pre-LitElement ``_recoverIfNeeded`` helper removed
+ * during the c4154d2 refactor.
+ */
+ private async _recoverIfNeeded(attempt = 0): Promise {
+ if (!this._discovered || !this.hass) return;
+ const MAX_ATTEMPTS = 3;
+ const BACKOFF_BASE_MS = 2000;
+
+ const scheduleRetry = (): void => {
+ if (attempt >= MAX_ATTEMPTS) return;
+ if (this._recoverTimer) clearTimeout(this._recoverTimer);
+ this._recoverTimer = setTimeout(
+ () => {
+ this._recoverTimer = null;
+ this._recoverIfNeeded(attempt + 1);
+ },
+ BACKOFF_BASE_MS * (attempt + 1)
+ );
+ };
+
+ try {
+ await this._scheduleTabRender();
+ } catch {
+ scheduleRetry();
+ return;
+ }
+
+ // A render that completed without throwing but left the tab
+ // container empty is the symptom we are recovering from. Every
+ // successful render path produces at least one child node — the
+ // empty-favorites state appends a ``
`` with ``list.no_results``,
+ // the error paths append a ``
`` with the error message, and the
+ // normal dashboard/activity/area/monitoring renders produce their
+ // respective headers/grids. Zero children means a silent bailout.
+ const container = this._root.getElementById("tab-content");
+ if (container && container.childNodes.length === 0) {
+ scheduleRetry();
+ }
+ }
+
/**
* Coalesce tab-render requests. If a render is in-flight, remember
* that another was requested and run exactly one follow-up once the
From 74ddb32fd445b608d0856d10e71903b089642c7f Mon Sep 17 00:00:00 2001
From: cayossarian <23534755+cayossarian@users.noreply.github.com>
Date: Sun, 19 Apr 2026 12:25:12 -0700
Subject: [PATCH 2/6] fix(list): close gap between relay toggle and power value
The .list-row flex gap of 10px was applied between every pair of row
children, including the ON/OFF badge (or toggle-pill) and the power
reading. On narrow displays that gap came out of the flex:1 circuit
name, truncating the label earlier than necessary.
Negative margin-left on .list-power-value cancels the preceding gap
without touching the gap before the gear or after the power value,
so the row layout stays intact and the freed space is absorbed by
.list-circuit-name.
---
dist/span-panel-card.js | 2 +-
dist/span-panel.js | 2 +-
src/card/card-styles.ts | 6 ++++++
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js
index 39b2709..6586f14 100644
--- a/dist/span-panel-card.js
+++ b/dist/span-panel-card.js
@@ -133,4 +133,4 @@ const ze=e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=pn(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,un(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const p=e.querySelector(".toggle-pill");if(p){p.classList.toggle("toggle-on",c),p.classList.toggle("toggle-off",!c);const e=p.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const u=e.querySelector(".list-status-badge");u&&(u.textContent=c?"ON":"OFF",u.classList.toggle("list-status-on",c),u.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=jt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,un(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},p=new Set,u=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&p.add(s);const o=n.name_by_user??n.name??i.device_name??"";u.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(p),perPanelStats:u}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends Pe{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=qe(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._recoverTimer=null,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._recoverIfNeeded()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._recoverTimer&&(clearTimeout(this._recoverTimer),this._recoverTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
+ `,m([Me()],Xe.prototype,"_errors",void 0),Xe=m([Ee("span-error-banner")],Xe);const it=g.power;function st(e){return it.unit(e)}function ot(e){return(e<0?"-":"")+it.format(e)}function rt(e){return(Math.abs(e)/1e3).toFixed(1)}function at(e){return Math.ceil(e/2)}function lt(e){return e%2==0?1:0}function ct(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return at(t)===at(n)?"row-span":lt(t)===lt(n)?"col-span":"row-span"}function dt(e){const t=e.chart_metric??s;return g[t]??g[s]}function ht(e,t){const n=function(e){return dt(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class pt{constructor(){this._status=null,this._lastFetch=0,this._inflight=null,this._generation=0,this._errorStore=null,this._retry=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e,this._retry=e?new We(e):null}async fetch(e,t){const i=Date.now();if(this._inflight&&this._inflight.gen===this._generation)return this._inflight.promise;if(this._status&&i-this._lastFetch<3e4)return this._status;const s=this._generation,o=(async()=>{try{const i={};t&&(i.config_entry_id=t);const o={type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0},r=this._retry?await this._retry.callWS(e,o,{errorId:"fetch:monitoring",errorMessage:n("error.monitoring_failed")}):await e.callWS(o),l=r?.response??null;return s===this._generation&&(this._status=l,this._lastFetch=Date.now()),l}catch(e){return console.warn("SPAN Panel: monitoring status fetch failed",e),s===this._generation&&(this._status=null),this._retry||this._errorStore?.add({key:"fetch:monitoring",level:"warning",message:n("error.monitoring_failed"),persistent:!1}),null}finally{this._inflight?.gen===s&&(this._inflight=null)}})();return this._inflight={gen:s,promise:o},o}invalidate(){this._lastFetch=0,this._generation++}get status(){return this._status}clear(){this._status=null,this._lastFetch=0,this._generation++}}class ut{constructor(){this._caches=new Map,this._errorStore=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e;for(const t of this._caches.values())t.errorStore=e}async fetchOne(e,t){let n=this._caches.get(t);return n||(n=new pt,n.errorStore=this._errorStore,this._caches.set(t,n)),n.fetch(e,t)}invalidate(){for(const e of this._caches.values())e.invalidate()}clear(){this._caches.clear()}}function gt(e,t){return e?.circuits?e.circuits[t]??null:null}function _t(e){return!!e&&void 0!==e.continuous_threshold_pct}function ft(e,t,n,i){const s=[];return n||s.push("circuit-off"),i&&s.push("circuit-producer"),function(e){return!!e&&null!=e.over_threshold_since}(t)&&s.push("circuit-alert"),_t(t)&&s.push("circuit-custom-monitoring"),s.join(" ")}function vt(e,t,i,s,o,r,a,d,h,p=!1){const u=t.entities?.power,g=u?r.states[u]:null,_=g&&parseFloat(g.state)||0,m=t.device_type===c||_<0,b=t.entities?.switch,y=b?r.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===l,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",$=Oe(t.name||n("grid.unknown")),C=dt(a);let P;if("current"===C.entityRole){const e=t.entities?.current,n=e?r.states[e]:null,i=n&&parseFloat(n.state)||0;P=`${C.format(i)}A`}else P=`${ot(_)}${st(_)}`;const k=h||"unknown";let E="";if("unknown"!==k){const e=f[k]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"},t=Oe(e.label()),n=Oe(e.icon),i=Oe(e.color);if(e.icon2){E=`\n \n \n `}else if(e.textLabel){E=`\n \n ${Oe(e.textLabel)}\n `}else E=``}const z=d&&_t(d)?v:"#555",A=``;let N="",M=d?.utilization_pct??null;if(null==M&&t.breaker_rating_a){const e=t.entities?.current,n=e?r.states[e]:null,i=n?Math.abs(parseFloat(n.state)||0):0;M=Math.round(i/t.breaker_rating_a*1e3)/10}if(null!=M){N=`=80?"utilization-warning":"utilization-normal"}">${Math.round(M)}%`}return`\n
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=pn(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,un(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const p=e.querySelector(".toggle-pill");if(p){p.classList.toggle("toggle-on",c),p.classList.toggle("toggle-off",!c);const e=p.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const u=e.querySelector(".list-status-badge");u&&(u.textContent=c?"ON":"OFF",u.classList.toggle("list-status-on",c),u.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=jt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,un(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},p=new Set,u=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&p.add(s);const o=n.name_by_user??n.name??i.device_name??"";u.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(p),perPanelStats:u}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends Pe{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=qe(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._recoverTimer=null,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._recoverIfNeeded()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._recoverTimer&&(clearTimeout(this._recoverTimer),this._recoverTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
Span Panel
diff --git a/src/card/card-styles.ts b/src/card/card-styles.ts
index fe97ac4..f650910 100644
--- a/src/card/card-styles.ts
+++ b/src/card/card-styles.ts
@@ -638,6 +638,12 @@ export const CARD_STYLES: string = `
min-width: 70px;
text-align: right;
flex-shrink: 0;
+ /* Cancel the .list-row flex gap against the preceding relay
+ control (toggle-pill or list-status-badge). The 10px separator
+ between the ON/OFF badge and the reading robs horizontal space
+ from .list-circuit-name on narrow rows — close it up so the
+ ellipsis threshold pushes out. */
+ margin-left: -10px;
}
.list-expand-toggle {
From d540ec9113e198b9e0ff01c874e778209b9c396d Mon Sep 17 00:00:00 2001
From: cayossarian <23534755+cayossarian@users.noreply.github.com>
Date: Sun, 19 Apr 2026 12:32:52 -0700
Subject: [PATCH 3/6] fix(list): drop 70px min-width on power-value so short
readings hug the relay
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The previous margin-left:-10px only closed the 10px flex gap, but the
visible space came from .list-power-value's 70px min-width and
text-align:right — short values like '1.3A' sat right-aligned in a 70px
cell, leaving a 40+ px blank column that robbed horizontal space from
.list-circuit-name on narrow rows. Let the value size to its content so
the freed width flows back into the flex:1 name column.
---
dist/span-panel-card.js | 2 +-
dist/span-panel.js | 10 +++++-----
src/card/card-styles.ts | 14 ++++++--------
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js
index 6586f14..ead0eb4 100644
--- a/dist/span-panel-card.js
+++ b/dist/span-panel-card.js
@@ -133,4 +133,4 @@ const ze=e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=pn(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,un(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const p=e.querySelector(".toggle-pill");if(p){p.classList.toggle("toggle-on",c),p.classList.toggle("toggle-off",!c);const e=p.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const u=e.querySelector(".list-status-badge");u&&(u.textContent=c?"ON":"OFF",u.classList.toggle("list-status-on",c),u.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=jt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,un(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},p=new Set,u=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&p.add(s);const o=n.name_by_user??n.name??i.device_name??"";u.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(p),perPanelStats:u}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends Pe{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=qe(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._recoverTimer=null,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._recoverIfNeeded()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._recoverTimer&&(clearTimeout(this._recoverTimer),this._recoverTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
+ `,m([Me()],Xe.prototype,"_errors",void 0),Xe=m([Ee("span-error-banner")],Xe);const it=g.power;function st(e){return it.unit(e)}function ot(e){return(e<0?"-":"")+it.format(e)}function rt(e){return(Math.abs(e)/1e3).toFixed(1)}function at(e){return Math.ceil(e/2)}function lt(e){return e%2==0?1:0}function ct(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return at(t)===at(n)?"row-span":lt(t)===lt(n)?"col-span":"row-span"}function dt(e){const t=e.chart_metric??s;return g[t]??g[s]}function ht(e,t){const n=function(e){return dt(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class pt{constructor(){this._status=null,this._lastFetch=0,this._inflight=null,this._generation=0,this._errorStore=null,this._retry=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e,this._retry=e?new We(e):null}async fetch(e,t){const i=Date.now();if(this._inflight&&this._inflight.gen===this._generation)return this._inflight.promise;if(this._status&&i-this._lastFetch<3e4)return this._status;const s=this._generation,o=(async()=>{try{const i={};t&&(i.config_entry_id=t);const o={type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0},r=this._retry?await this._retry.callWS(e,o,{errorId:"fetch:monitoring",errorMessage:n("error.monitoring_failed")}):await e.callWS(o),l=r?.response??null;return s===this._generation&&(this._status=l,this._lastFetch=Date.now()),l}catch(e){return console.warn("SPAN Panel: monitoring status fetch failed",e),s===this._generation&&(this._status=null),this._retry||this._errorStore?.add({key:"fetch:monitoring",level:"warning",message:n("error.monitoring_failed"),persistent:!1}),null}finally{this._inflight?.gen===s&&(this._inflight=null)}})();return this._inflight={gen:s,promise:o},o}invalidate(){this._lastFetch=0,this._generation++}get status(){return this._status}clear(){this._status=null,this._lastFetch=0,this._generation++}}class ut{constructor(){this._caches=new Map,this._errorStore=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e;for(const t of this._caches.values())t.errorStore=e}async fetchOne(e,t){let n=this._caches.get(t);return n||(n=new pt,n.errorStore=this._errorStore,this._caches.set(t,n)),n.fetch(e,t)}invalidate(){for(const e of this._caches.values())e.invalidate()}clear(){this._caches.clear()}}function gt(e,t){return e?.circuits?e.circuits[t]??null:null}function _t(e){return!!e&&void 0!==e.continuous_threshold_pct}function ft(e,t,n,i){const s=[];return n||s.push("circuit-off"),i&&s.push("circuit-producer"),function(e){return!!e&&null!=e.over_threshold_since}(t)&&s.push("circuit-alert"),_t(t)&&s.push("circuit-custom-monitoring"),s.join(" ")}function vt(e,t,i,s,o,r,a,d,h,p=!1){const u=t.entities?.power,g=u?r.states[u]:null,_=g&&parseFloat(g.state)||0,m=t.device_type===c||_<0,b=t.entities?.switch,y=b?r.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===l,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",$=Oe(t.name||n("grid.unknown")),C=dt(a);let k;if("current"===C.entityRole){const e=t.entities?.current,n=e?r.states[e]:null,i=n&&parseFloat(n.state)||0;k=`${C.format(i)}A`}else k=`${ot(_)}${st(_)}`;const P=h||"unknown";let E="";if("unknown"!==P){const e=f[P]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"},t=Oe(e.label()),n=Oe(e.icon),i=Oe(e.color);if(e.icon2){E=`\n \n \n `}else if(e.textLabel){E=`\n \n ${Oe(e.textLabel)}\n `}else E=``}const z=d&&_t(d)?v:"#555",A=``;let N="",M=d?.utilization_pct??null;if(null==M&&t.breaker_rating_a){const e=t.entities?.current,n=e?r.states[e]:null,i=n?Math.abs(parseFloat(n.state)||0):0;M=Math.round(i/t.breaker_rating_a*1e3)/10}if(null!=M){N=`=80?"utilization-warning":"utilization-normal"}">${Math.round(M)}%`}return`\n
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=pn(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,un(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const p=e.querySelector(".toggle-pill");if(p){p.classList.toggle("toggle-on",c),p.classList.toggle("toggle-off",!c);const e=p.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const u=e.querySelector(".list-status-badge");u&&(u.textContent=c?"ON":"OFF",u.classList.toggle("list-status-on",c),u.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=jt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,un(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},p=new Set,u=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&p.add(s);const o=n.name_by_user??n.name??i.device_name??"";u.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(p),perPanelStats:u}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends ke{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=qe(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._recoverTimer=null,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._recoverIfNeeded()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._recoverTimer&&(clearTimeout(this._recoverTimer),this._recoverTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
Span Panel
diff --git a/src/card/card-styles.ts b/src/card/card-styles.ts
index f650910..90911b9 100644
--- a/src/card/card-styles.ts
+++ b/src/card/card-styles.ts
@@ -635,15 +635,13 @@ export const CARD_STYLES: string = `
.list-power-value {
font-size: 0.9em;
font-weight: 600;
- min-width: 70px;
- text-align: right;
flex-shrink: 0;
- /* Cancel the .list-row flex gap against the preceding relay
- control (toggle-pill or list-status-badge). The 10px separator
- between the ON/OFF badge and the reading robs horizontal space
- from .list-circuit-name on narrow rows — close it up so the
- ellipsis threshold pushes out. */
- margin-left: -10px;
+ /* No min-width / text-align:right: the old 70px right-aligned
+ cell left a visible blank column for short readings (e.g.
+ "1.3A" in a 70px slot), which robbed horizontal space from
+ .list-circuit-name on narrow rows. Let the value hug the
+ preceding relay control and size to its content so the freed
+ width flows back into the flex:1 name column. */
}
.list-expand-toggle {
From 30f10124b815df76c7d4a70f9fc94a0aec1e4f96 Mon Sep 17 00:00:00 2001
From: cayossarian <23534755+cayossarian@users.noreply.github.com>
Date: Sun, 19 Apr 2026 13:01:04 -0700
Subject: [PATCH 4/6] feat(list,grid): fold to name-on-row-1 layout on narrow
widths
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Both list rows and By Panel breaker cells were truncating circuit
names hard at phone-width displays. At narrow widths we now collapse
to a two-row layout where the name occupies the full first row
(paired with the expand chevron on list rows) and the
badges/controls/reading/gear drop to a second row with the relay
snug against the power/current value.
List rows use a viewport media query at 520px (the row always spans
the full list-view width at that point). Breaker cells use a
container query on .panel-grid so the fold triggers on the cell's
own width (each cell is half the grid), not the viewport — grid
widths below ~760px put cells under ~340px, which is where the name
starts to ellipsize. display:contents on the cell's nested wrappers
lets the outer grid place leaf elements directly via grid-area.
---
dist/span-panel-card.js | 12 ++---
dist/span-panel.js | 14 ++---
src/card/card-styles.ts | 113 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 126 insertions(+), 13 deletions(-)
diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js
index ead0eb4..58bc5c4 100644
--- a/dist/span-panel-card.js
+++ b/dist/span-panel-card.js
@@ -1,4 +1,4 @@
-let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","error.panel_offline":"SPAN Panel unreachable","error.panel_reconnected":"SPAN Panel reconnected","error.panel_offline_named":"{name} unreachable","error.panel_reconnected_named":"{name} reconnected","error.discovery_failed":"Unable to connect to SPAN Panel","error.relay_failed":"Unable to toggle relay","error.shedding_failed":"Unable to update shedding priority","error.threshold_failed":"Unable to save threshold","error.graph_horizon_failed":"Unable to update graph time horizon","error.favorites_fetch_failed":"Unable to load favorites","error.favorites_toggle_failed":"Unable to update favorite","error.history_failed":"Unable to load historical data","error.monitoring_failed":"Unable to load monitoring status","error.graph_settings_failed":"Unable to load graph settings","error.areas_failed":"Area assignments may be out of sync","error.retry":"Retry","card.connecting":"Connecting to SPAN Panel...","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.favorites_subtitle":"Favorites","sidepanel.global_default":"Global Default","sidepanel.list_view_columns":"List View Columns","sidepanel.columns":"Columns","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","panel.favorites":"Favorites","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","error.panel_offline":"SPAN Panel inaccesible","error.panel_reconnected":"SPAN Panel reconectado","error.panel_offline_named":"{name} inaccesible","error.panel_reconnected_named":"{name} reconectado","error.discovery_failed":"No se puede conectar al SPAN Panel","error.relay_failed":"No se pudo cambiar el relé","error.shedding_failed":"No se pudo actualizar la prioridad de desconexión","error.threshold_failed":"No se pudo guardar el umbral","error.graph_horizon_failed":"No se pudo actualizar el horizonte temporal del gráfico","error.favorites_fetch_failed":"No se pudieron cargar los favoritos","error.favorites_toggle_failed":"No se pudo actualizar el favorito","error.history_failed":"No se pudieron cargar los datos históricos","error.monitoring_failed":"No se pudo cargar el estado de monitoreo","error.graph_settings_failed":"No se pudo cargar la configuración del gráfico","error.areas_failed":"Las asignaciones de áreas pueden estar desincronizadas","error.retry":"Reintentar","card.connecting":"Conectando al SPAN Panel...","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.favorites_subtitle":"Favoritos","sidepanel.global_default":"Predeterminado Global","sidepanel.list_view_columns":"Columnas de la lista","sidepanel.columns":"Columnas","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","panel.favorites":"Favoritos","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","error.panel_offline":"SPAN Panel inaccessible","error.panel_reconnected":"SPAN Panel reconnecté","error.panel_offline_named":"{name} inaccessible","error.panel_reconnected_named":"{name} reconnecté","error.discovery_failed":"Impossible de se connecter au SPAN Panel","error.relay_failed":"Impossible de basculer le relais","error.shedding_failed":"Impossible de mettre à jour la priorité de délestage","error.threshold_failed":"Impossible d'enregistrer le seuil","error.graph_horizon_failed":"Impossible de mettre à jour l'horizon temporel du graphique","error.favorites_fetch_failed":"Impossible de charger les favoris","error.favorites_toggle_failed":"Impossible de mettre à jour le favori","error.history_failed":"Impossible de charger les données historiques","error.monitoring_failed":"Impossible de charger l'état de surveillance","error.graph_settings_failed":"Impossible de charger les paramètres du graphique","error.areas_failed":"Les affectations de zones peuvent être désynchronisées","error.retry":"Réessayer","card.connecting":"Connexion au SPAN Panel...","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.favorites_subtitle":"Favoris","sidepanel.global_default":"Défaut Global","sidepanel.list_view_columns":"Colonnes de la liste","sidepanel.columns":"Colonnes","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","panel.favorites":"Favoris","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","error.panel_offline":"SPANパネルに接続できません","error.panel_reconnected":"SPANパネルが再接続されました","error.panel_offline_named":"{name}に接続できません","error.panel_reconnected_named":"{name}が再接続されました","error.discovery_failed":"SPANパネルへの接続に失敗しました","error.relay_failed":"リレーの切り替えに失敗しました","error.shedding_failed":"シェディング優先度の更新に失敗しました","error.threshold_failed":"しきい値の保存に失敗しました","error.graph_horizon_failed":"グラフの時間範囲の更新に失敗しました","error.favorites_fetch_failed":"お気に入りの読み込みに失敗しました","error.favorites_toggle_failed":"お気に入りの更新に失敗しました","error.history_failed":"履歴データの読み込みに失敗しました","error.monitoring_failed":"監視ステータスの読み込みに失敗しました","error.graph_settings_failed":"グラフ設定の読み込みに失敗しました","error.areas_failed":"エリア割り当てが同期されていない可能性があります","error.retry":"再試行","card.connecting":"SPANパネルに接続中...","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.favorites_subtitle":"お気に入り","sidepanel.global_default":"グローバルデフォルト","sidepanel.list_view_columns":"リスト表示の列数","sidepanel.columns":"列","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","panel.favorites":"お気に入り","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","error.panel_offline":"SPAN Panel inacessível","error.panel_reconnected":"SPAN Panel reconectado","error.panel_offline_named":"{name} inacessível","error.panel_reconnected_named":"{name} reconectado","error.discovery_failed":"Não foi possível conectar ao SPAN Panel","error.relay_failed":"Não foi possível alternar o relé","error.shedding_failed":"Não foi possível atualizar a prioridade de desligamento","error.threshold_failed":"Não foi possível salvar o limite","error.graph_horizon_failed":"Não foi possível atualizar o horizonte temporal do gráfico","error.favorites_fetch_failed":"Não foi possível carregar os favoritos","error.favorites_toggle_failed":"Não foi possível atualizar o favorito","error.history_failed":"Não foi possível carregar os dados históricos","error.monitoring_failed":"Não foi possível carregar o status de monitoramento","error.graph_settings_failed":"Não foi possível carregar as configurações do gráfico","error.areas_failed":"As atribuições de áreas podem estar fora de sincronização","error.retry":"Tentar novamente","card.connecting":"Conectando ao SPAN Panel...","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.favorites_subtitle":"Favoritos","sidepanel.global_default":"Padrão Global","sidepanel.list_view_columns":"Colunas da Lista","sidepanel.columns":"Colunas","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","panel.favorites":"Favoritos","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function n(n){e=n&&t[n]?n:"en"}function i(n){return t[e]?.[n]??t.en?.[n]??n}function s(n,i){return(t[e]?.[n]??t.en?.[n]??n).replace(/\{(\w+)\}/g,(e,t)=>Object.prototype.hasOwnProperty.call(i,t)?i[t]:`{${t}}`)}const o="power",r="5m",a={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},l="span_panel",c="CLOSED",d="pv",h="bess",p="evse",u="sub_",g=500,_={power:{entityRole:"power",label:()=>i("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>i("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},f={soc:{entityRole:"soc",label:()=>i("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>i("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:_.power},m={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>i("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>i("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>i("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>i("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>i("shedding.unknown")}},v="#ff9800";function b(e,t,n,i){var s,o=arguments.length,r=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var a=e.length-1;a>=0;a--)(s=e[a])&&(r=(o<3?s(r):o>3?s(t,n,r):s(t,n))||r);return o>3&&r&&Object.defineProperty(t,n,r),r}"function"==typeof SuppressedError&&SuppressedError;
+let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","error.panel_offline":"SPAN Panel unreachable","error.panel_reconnected":"SPAN Panel reconnected","error.panel_offline_named":"{name} unreachable","error.panel_reconnected_named":"{name} reconnected","error.discovery_failed":"Unable to connect to SPAN Panel","error.relay_failed":"Unable to toggle relay","error.shedding_failed":"Unable to update shedding priority","error.threshold_failed":"Unable to save threshold","error.graph_horizon_failed":"Unable to update graph time horizon","error.favorites_fetch_failed":"Unable to load favorites","error.favorites_toggle_failed":"Unable to update favorite","error.history_failed":"Unable to load historical data","error.monitoring_failed":"Unable to load monitoring status","error.graph_settings_failed":"Unable to load graph settings","error.areas_failed":"Area assignments may be out of sync","error.retry":"Retry","card.connecting":"Connecting to SPAN Panel...","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.favorites_subtitle":"Favorites","sidepanel.global_default":"Global Default","sidepanel.list_view_columns":"List View Columns","sidepanel.columns":"Columns","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","panel.favorites":"Favorites","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","error.panel_offline":"SPAN Panel inaccesible","error.panel_reconnected":"SPAN Panel reconectado","error.panel_offline_named":"{name} inaccesible","error.panel_reconnected_named":"{name} reconectado","error.discovery_failed":"No se puede conectar al SPAN Panel","error.relay_failed":"No se pudo cambiar el relé","error.shedding_failed":"No se pudo actualizar la prioridad de desconexión","error.threshold_failed":"No se pudo guardar el umbral","error.graph_horizon_failed":"No se pudo actualizar el horizonte temporal del gráfico","error.favorites_fetch_failed":"No se pudieron cargar los favoritos","error.favorites_toggle_failed":"No se pudo actualizar el favorito","error.history_failed":"No se pudieron cargar los datos históricos","error.monitoring_failed":"No se pudo cargar el estado de monitoreo","error.graph_settings_failed":"No se pudo cargar la configuración del gráfico","error.areas_failed":"Las asignaciones de áreas pueden estar desincronizadas","error.retry":"Reintentar","card.connecting":"Conectando al SPAN Panel...","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.favorites_subtitle":"Favoritos","sidepanel.global_default":"Predeterminado Global","sidepanel.list_view_columns":"Columnas de la lista","sidepanel.columns":"Columnas","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","panel.favorites":"Favoritos","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","error.panel_offline":"SPAN Panel inaccessible","error.panel_reconnected":"SPAN Panel reconnecté","error.panel_offline_named":"{name} inaccessible","error.panel_reconnected_named":"{name} reconnecté","error.discovery_failed":"Impossible de se connecter au SPAN Panel","error.relay_failed":"Impossible de basculer le relais","error.shedding_failed":"Impossible de mettre à jour la priorité de délestage","error.threshold_failed":"Impossible d'enregistrer le seuil","error.graph_horizon_failed":"Impossible de mettre à jour l'horizon temporel du graphique","error.favorites_fetch_failed":"Impossible de charger les favoris","error.favorites_toggle_failed":"Impossible de mettre à jour le favori","error.history_failed":"Impossible de charger les données historiques","error.monitoring_failed":"Impossible de charger l'état de surveillance","error.graph_settings_failed":"Impossible de charger les paramètres du graphique","error.areas_failed":"Les affectations de zones peuvent être désynchronisées","error.retry":"Réessayer","card.connecting":"Connexion au SPAN Panel...","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.favorites_subtitle":"Favoris","sidepanel.global_default":"Défaut Global","sidepanel.list_view_columns":"Colonnes de la liste","sidepanel.columns":"Colonnes","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","panel.favorites":"Favoris","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","error.panel_offline":"SPANパネルに接続できません","error.panel_reconnected":"SPANパネルが再接続されました","error.panel_offline_named":"{name}に接続できません","error.panel_reconnected_named":"{name}が再接続されました","error.discovery_failed":"SPANパネルへの接続に失敗しました","error.relay_failed":"リレーの切り替えに失敗しました","error.shedding_failed":"シェディング優先度の更新に失敗しました","error.threshold_failed":"しきい値の保存に失敗しました","error.graph_horizon_failed":"グラフの時間範囲の更新に失敗しました","error.favorites_fetch_failed":"お気に入りの読み込みに失敗しました","error.favorites_toggle_failed":"お気に入りの更新に失敗しました","error.history_failed":"履歴データの読み込みに失敗しました","error.monitoring_failed":"監視ステータスの読み込みに失敗しました","error.graph_settings_failed":"グラフ設定の読み込みに失敗しました","error.areas_failed":"エリア割り当てが同期されていない可能性があります","error.retry":"再試行","card.connecting":"SPANパネルに接続中...","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.favorites_subtitle":"お気に入り","sidepanel.global_default":"グローバルデフォルト","sidepanel.list_view_columns":"リスト表示の列数","sidepanel.columns":"列","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","panel.favorites":"お気に入り","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","error.panel_offline":"SPAN Panel inacessível","error.panel_reconnected":"SPAN Panel reconectado","error.panel_offline_named":"{name} inacessível","error.panel_reconnected_named":"{name} reconectado","error.discovery_failed":"Não foi possível conectar ao SPAN Panel","error.relay_failed":"Não foi possível alternar o relé","error.shedding_failed":"Não foi possível atualizar a prioridade de desligamento","error.threshold_failed":"Não foi possível salvar o limite","error.graph_horizon_failed":"Não foi possível atualizar o horizonte temporal do gráfico","error.favorites_fetch_failed":"Não foi possível carregar os favoritos","error.favorites_toggle_failed":"Não foi possível atualizar o favorito","error.history_failed":"Não foi possível carregar os dados históricos","error.monitoring_failed":"Não foi possível carregar o status de monitoramento","error.graph_settings_failed":"Não foi possível carregar as configurações do gráfico","error.areas_failed":"As atribuições de áreas podem estar fora de sincronização","error.retry":"Tentar novamente","card.connecting":"Conectando ao SPAN Panel...","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.favorites_subtitle":"Favoritos","sidepanel.global_default":"Padrão Global","sidepanel.list_view_columns":"Colunas da Lista","sidepanel.columns":"Colunas","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","panel.favorites":"Favoritos","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function n(n){e=n&&t[n]?n:"en"}function i(n){return t[e]?.[n]??t.en?.[n]??n}function s(n,i){return(t[e]?.[n]??t.en?.[n]??n).replace(/\{(\w+)\}/g,(e,t)=>Object.prototype.hasOwnProperty.call(i,t)?i[t]:`{${t}}`)}const o="power",r="5m",a={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},l="span_panel",c="CLOSED",d="pv",h="bess",p="evse",u="sub_",g=500,f={power:{entityRole:"power",label:()=>i("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>i("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},_={soc:{entityRole:"soc",label:()=>i("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>i("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:f.power},m={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>i("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>i("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>i("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>i("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>i("shedding.unknown")}},v="#ff9800";function b(e,t,n,i){var s,o=arguments.length,r=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var a=e.length-1;a>=0;a--)(s=e[a])&&(r=(o<3?s(r):o>3?s(t,n,r):s(t,n))||r);return o>3&&r&&Object.defineProperty(t,n,r),r}"function"==typeof SuppressedError&&SuppressedError;
/**
* @license
* Copyright 2019 Google LLC
@@ -15,7 +15,7 @@ const y=globalThis,w=y.ShadowRoot&&(void 0===y.ShadyCSS||y.ShadyCSS.nativeShadow
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
-const U=globalThis,q=e=>e,W=U.trustedTypes,B=W?W.createPolicy("lit-html",{createHTML:e=>e}):void 0,G="$lit$",V=`lit$${Math.random().toFixed(9).slice(2)}$`,Q="?"+V,K=`<${Q}>`,J=document,X=()=>J.createComment(""),Z=e=>null===e||"object"!=typeof e&&"function"!=typeof e,Y=Array.isArray,ee="[ \t\n\f\r]",te=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,ne=/-->/g,ie=/>/g,se=RegExp(`>|${ee}(?:([^\\s"'>=/]+)(${ee}*=${ee}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),oe=/'/g,re=/"/g,ae=/^(?:script|style|textarea|title)$/i,le=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ce=Symbol.for("lit-noChange"),de=Symbol.for("lit-nothing"),he=new WeakMap,pe=J.createTreeWalker(J,129);function ue(e,t){if(!Y(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==B?B.createHTML(t):t}const ge=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"")),i]};class _e{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const r=e.length-1,a=this.parts,[l,c]=ge(e,t);if(this.el=_e.createElement(l,n),pe.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=pe.nextNode())&&a.length0){i.textContent=W?W.emptyScript:"";for(let n=0;nY(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==de&&Z(this._$AH)?this._$AA.nextSibling.data=e:this.T(J.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=_e.createElement(ue(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new me(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=he.get(e.strings);return void 0===t&&he.set(e.strings,t=new _e(e)),t}k(e){Y(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new ve(this.O(X()),this.O(X()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=de}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=fe(this,e,t,0),o=!Z(e)||e!==this._$AH&&e!==ce,o&&(this._$AH=e);else{const i=e;let r,a;for(e=s[0],r=0;re,W=q.trustedTypes,B=W?W.createPolicy("lit-html",{createHTML:e=>e}):void 0,G="$lit$",V=`lit$${Math.random().toFixed(9).slice(2)}$`,Q="?"+V,K=`<${Q}>`,J=document,X=()=>J.createComment(""),Z=e=>null===e||"object"!=typeof e&&"function"!=typeof e,Y=Array.isArray,ee="[ \t\n\f\r]",te=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,ne=/-->/g,ie=/>/g,se=RegExp(`>|${ee}(?:([^\\s"'>=/]+)(${ee}*=${ee}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),oe=/'/g,re=/"/g,ae=/^(?:script|style|textarea|title)$/i,le=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ce=Symbol.for("lit-noChange"),de=Symbol.for("lit-nothing"),he=new WeakMap,pe=J.createTreeWalker(J,129);function ue(e,t){if(!Y(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==B?B.createHTML(t):t}const ge=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"")),i]};class fe{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const r=e.length-1,a=this.parts,[l,c]=ge(e,t);if(this.el=fe.createElement(l,n),pe.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=pe.nextNode())&&a.length0){i.textContent=W?W.emptyScript:"";for(let n=0;nY(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==de&&Z(this._$AH)?this._$AA.nextSibling.data=e:this.T(J.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=fe.createElement(ue(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new me(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=he.get(e.strings);return void 0===t&&he.set(e.strings,t=new fe(e)),t}k(e){Y(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new ve(this.O(X()),this.O(X()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=de}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=_e(this,e,t,0),o=!Z(e)||e!==this._$AH&&e!==ce,o&&(this._$AH=e);else{const i=e;let r,a;for(e=s[0],r=0;r(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
- */function Me(e){return Ne({...e,state:!0,attribute:!1})}const Le={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ie(e){return String(e).replace(/[&<>"']/g,e=>Le[e]??e)}const De="span_panel_list_columns";function Te(){try{const e=localStorage.getItem(De);if(!e)return 1;const t=parseInt(e,10);return 1===t||2===t||3===t?t:1}catch{return 1}}function He(e){try{localStorage.setItem(De,String(e))}catch{}}function Oe(e,t,n={}){const s=Ie(e.device_name||i("header.default_name")),o=Ie(e.serial||""),r=Ie(e.firmware||""),a="current"===(t.chart_metric||"power"),l=!1!==n.showSwitches;return`\n
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=Ot(n,t,s);d+=It(e);for(const[e,n]of i){const i=Ze(o,Ft(n)),r=Tt(n,t),a=this._expandedUuids.has(e);d+=`
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=Ot(n,t,s);d+=It(e);for(const[e,n]of i){const i=Ze(o,Ft(n)),r=Tt(n,t),a=this._expandedUuids.has(e);d+=`
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=pn(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,un(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const p=e.querySelector(".toggle-pill");if(p){p.classList.toggle("toggle-on",c),p.classList.toggle("toggle-off",!c);const e=p.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const u=e.querySelector(".list-status-badge");u&&(u.textContent=c?"ON":"OFF",u.classList.toggle("list-status-on",c),u.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=jt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,un(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},p=new Set,u=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&p.add(s);const o=n.name_by_user??n.name??i.device_name??"";u.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(p),perPanelStats:u}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends ke{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=qe(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._recoverTimer=null,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._recoverIfNeeded()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._recoverTimer&&(clearTimeout(this._recoverTimer),this._recoverTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
+ `,m([Me()],Xe.prototype,"_errors",void 0),Xe=m([Ee("span-error-banner")],Xe);const it=g.power;function st(e){return it.unit(e)}function ot(e){return(e<0?"-":"")+it.format(e)}function rt(e){return(Math.abs(e)/1e3).toFixed(1)}function at(e){return Math.ceil(e/2)}function lt(e){return e%2==0?1:0}function ct(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return at(t)===at(n)?"row-span":lt(t)===lt(n)?"col-span":"row-span"}function dt(e){const t=e.chart_metric??s;return g[t]??g[s]}function ht(e,t){const n=function(e){return dt(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class ut{constructor(){this._status=null,this._lastFetch=0,this._inflight=null,this._generation=0,this._errorStore=null,this._retry=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e,this._retry=e?new We(e):null}async fetch(e,t){const i=Date.now();if(this._inflight&&this._inflight.gen===this._generation)return this._inflight.promise;if(this._status&&i-this._lastFetch<3e4)return this._status;const s=this._generation,o=(async()=>{try{const i={};t&&(i.config_entry_id=t);const o={type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0},r=this._retry?await this._retry.callWS(e,o,{errorId:"fetch:monitoring",errorMessage:n("error.monitoring_failed")}):await e.callWS(o),l=r?.response??null;return s===this._generation&&(this._status=l,this._lastFetch=Date.now()),l}catch(e){return console.warn("SPAN Panel: monitoring status fetch failed",e),s===this._generation&&(this._status=null),this._retry||this._errorStore?.add({key:"fetch:monitoring",level:"warning",message:n("error.monitoring_failed"),persistent:!1}),null}finally{this._inflight?.gen===s&&(this._inflight=null)}})();return this._inflight={gen:s,promise:o},o}invalidate(){this._lastFetch=0,this._generation++}get status(){return this._status}clear(){this._status=null,this._lastFetch=0,this._generation++}}class pt{constructor(){this._caches=new Map,this._errorStore=null}get errorStore(){return this._errorStore}set errorStore(e){this._errorStore=e;for(const t of this._caches.values())t.errorStore=e}async fetchOne(e,t){let n=this._caches.get(t);return n||(n=new ut,n.errorStore=this._errorStore,this._caches.set(t,n)),n.fetch(e,t)}invalidate(){for(const e of this._caches.values())e.invalidate()}clear(){this._caches.clear()}}function gt(e,t){return e?.circuits?e.circuits[t]??null:null}function _t(e){return!!e&&void 0!==e.continuous_threshold_pct}function ft(e,t,n,i){const s=[];return n||s.push("circuit-off"),i&&s.push("circuit-producer"),function(e){return!!e&&null!=e.over_threshold_since}(t)&&s.push("circuit-alert"),_t(t)&&s.push("circuit-custom-monitoring"),s.join(" ")}function vt(e,t,i,s,o,r,a,d,h,u=!1){const p=t.entities?.power,g=p?r.states[p]:null,_=g&&parseFloat(g.state)||0,m=t.device_type===c||_<0,b=t.entities?.switch,y=b?r.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===l,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",$=Oe(t.name||n("grid.unknown")),C=dt(a);let k;if("current"===C.entityRole){const e=t.entities?.current,n=e?r.states[e]:null,i=n&&parseFloat(n.state)||0;k=`${C.format(i)}A`}else k=`${ot(_)}${st(_)}`;const P=h||"unknown";let E="";if("unknown"!==P){const e=f[P]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"},t=Oe(e.label()),n=Oe(e.icon),i=Oe(e.color);if(e.icon2){E=`\n \n \n `}else if(e.textLabel){E=`\n \n ${Oe(e.textLabel)}\n `}else E=``}const z=d&&_t(d)?v:"#555",A=``;let N="",M=d?.utilization_pct??null;if(null==M&&t.breaker_rating_a){const e=t.entities?.current,n=e?r.states[e]:null,i=n?Math.abs(parseFloat(n.state)||0):0;M=Math.round(i/t.breaker_rating_a*1e3)/10}if(null!=M){N=`=80?"utilization-warning":"utilization-normal"}">${Math.round(M)}%`}return`\n
`;for(const e of c){const n=l.get(e);if(!n)continue;const i=un(n,t,s);d+=ln(e);for(const[e,n]of i){const i=gt(o,pn(n)),r=dn(n,t),a=this._expandedUuids.has(e);d+=`
`,d+=rn(e,n,t,s,i,r,a),a&&(d+=an(e,n,t,0,i)),d+="
"}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t,h.errorStore=this._ctrl.errorStore),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,s){const o=dt(s),r="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const l=i.circuits[a];if(!l)continue;const{isOn:c,value:d}=cn(l,t,s),h=e.querySelector(".list-power-value");if(h)if(c)if(r)h.innerHTML=`${o.format(d)}A`;else{const e=l.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;h.innerHTML=`${ot(i)}${st(i)}`}else h.innerHTML="";const u=e.querySelector(".toggle-pill");if(u){u.classList.toggle("toggle-on",c),u.classList.toggle("toggle-off",!c);const e=u.querySelector(".toggle-label");e&&(e.textContent=n(c?"grid.on":"grid.off"))}const p=e.querySelector(".list-status-badge");p&&(p.textContent=c?"ON":"OFF",p.classList.toggle("list-status-on",c),p.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n];for(const s of[...e.children])if(s.classList.contains("area-header"))n={anchor:s,units:[]},i.push(n);else if(s.classList.contains("list-cell")){const e=s.dataset.cellUuid,i=e?t.circuits[e]:void 0;e&&i&&n.units.push({cell:s,uuid:e,circuit:i})}return i}(s,n)){if(e.units.length<2)continue;const n=[...e.units].sort((e,n)=>hn(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.cell):s.prepend(e.cell),o=e.cell}}(e,t,i,s)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler);const t=e.querySelector(".slide-confirm");t&&(this._ctrl.bindSlideConfirm(t,e),e.classList.add("switches-disabled"))}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-cell[data-cell-uuid]");for(const e of n){const t=e.querySelector(".list-circuit-name"),n=(t?.textContent?.toLowerCase()??"").includes(this._searchQuery);e.style.display=n?"":"none"}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-cell")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=qt(e),n=this._container.querySelector(`.list-cell[data-cell-uuid="${t}"]`);if(!n)return;const i=n.querySelector(`.list-row[data-row-uuid="${t}"]`),s=n.querySelector(`.list-expand-toggle[data-expand-uuid="${t}"]`);if(i){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const o=n.querySelector(`.list-expanded-content[data-expanded-uuid="${t}"]`);o&&o.remove(),s&&s.classList.remove("expanded"),i.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const t=this._topology.circuits[e];if(!t)return;const n=gt(this._monitoringStatus,pn(t)),o=an(e,t,this._hass,this._config,n);i.insertAdjacentHTML("afterend",o),s&&s.classList.add("expanded"),i.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function _n(e,t){return`${e}|${t}`}class fn{async build(e,t,n,i){const s=new Map;for(const e of n)s.set(e.id,e);const o=i?new We(i):null,r=[];for(const[n,i]of Object.entries(t)){if(!((i?.circuits?.length??0)>0||(i?.sub_devices?.length??0)>0))continue;const t=s.get(n);t&&r.push((async()=>{try{const i=await Ye(e,n,o);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const a=(await Promise.all(r)).filter(e=>null!==e.topology),l=a.length>1,c={},d={},h={},u=new Set,p=[];for(const{panelDeviceId:e,panel:n,topology:i}of a){if(!i)continue;const s=n.config_entries?.[0]??null;s&&u.add(s);const o=n.name_by_user??n.name??i.device_name??"";p.push({panelDeviceId:e,panelName:o,topology:i});const r=t[e],a=r?.circuits??[],g=r?.sub_devices??[];for(const t of a){const n=i.circuits?.[t];if(!n)continue;const r=_n(e,t),a=l&&o?`${o} · ${n.name}`:n.name;c[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=_n(e,t),a=l&&o&&n.name?`${o} · ${n.name}`:n.name??t;d[r]={...n,name:a},h[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:c,sub_devices:d,panel_entities:{},device_name:"",_favoriteRefs:h},entryIds:Array.from(u),perPanelStats:p}}}const vn="span_panel_favorites_view_state";function mn(e){try{localStorage.setItem(vn,JSON.stringify(e))}catch{}}var bn;const yn="favorites";let wn=bn=class extends ke{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._listColumns=je(),this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._favoritesPanelStats=[],this._dashboardTab=new Jt,this._monitoringTab=new sn,this._listDashCtrl=new Qt,this._listCtrl=new gn(this._listDashCtrl),this._favCache=new Be,this._favCtrl=new fn,this._favoritesMonitoringTabs=new Map,this._errorStore=new Le,this._watchedPanelId=null,this._discovering=!1,this._refreshSeq=0,this._areaUnsub=null,this._areaSubscribing=!1,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null,this._pendingTabRender=!1,this._recoverTimer=null,this._persistFavoritesViewStateTimer=null,this._tabRenderScheduler=function(e){let t=null,n=!1;return async function i(){if(t)return n=!0,void await t.catch(()=>{});const s=(async()=>{try{await e()}finally{t=null,n&&(n=!1,await i())}})();t=s,await s}}(async()=>this._renderTab()),this._beginRender=function(){let e=0;return()=>{e+=1;const t=e;return()=>e!==t}}()}get _root(){const e=this.shadowRoot;if(!e)throw new Error("span-panel: shadow root is not available");return e}connectedCallback(){super.connectedCallback(),this._dashboardTab.errorStore=this._errorStore,this._listDashCtrl.errorStore=this._errorStore,this._favCache.errorStore=this._errorStore,this._monitoringTab.errorStore=this._errorStore,this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._recoverIfNeeded()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ge,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaSubscribing=!1,this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ge,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),this._persistFavoritesViewStateTimer&&(clearTimeout(this._persistFavoritesViewStateTimer),this._persistFavoritesViewStateTimer=null),this._recoverTimer&&(clearTimeout(this._recoverTimer),this._recoverTimer=null),this._errorStore.dispose(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._errorStore.updateHass(this.hass),this._discovered?this._root.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric")||e.has("_listColumns"))){if(this._isFavoritesView&&"dashboard"===this._activeTab)return void(this._activeTab="activity");this._scheduleTabRender()}if(e.has("_selectedPanelId")&&(this._selectedPanelId!==yn&&this._selectedPanelId?(this._updatePanelStatusWatch(),this._listDashCtrl.setFavoritesPerPanelInfo(null)):(this._errorStore.clearPanelStatusWatch(),this._watchedPanelId=null)),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this._root.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass,n.errorStore=this._errorStore)}}}setConfig(e){}render(){var i,s,o;if(i=this.hass?.language,e=i&&t[i]?i:"en",!this.hass)return le`
`:"");"activity"===h?this._listCtrl.renderActivityView(e,this.hass,a,g,_,o):this._listCtrl.renderAreaView(e,this.hass,a,g,_,o),this._updateFavoritesPanelStats(e,g),this._listDashCtrl.setupResizeObserver(e,e),this._listDashCtrl.startIntervals(e,()=>{this._updateFavoritesPanelStats(e,g)})}catch(n){if(t())return;const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=n.message,e.appendChild(i)}}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}const o=new Map;for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const r=document.createElement("h2");r.style.margin="8px 0 12px",r.style.fontSize="1em",r.textContent=t?.name_by_user??t?.name??e,n.appendChild(r);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const l=new sn;l.errorStore=this._errorStore,o.set(e,l);try{await l.render(a,this.hass,e)}catch(t){console.warn("SPAN Panel: favorites monitoring render failed",e,t);const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message??String(t),a.appendChild(n)}}this._favoritesMonitoringTabs=o}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};wn._shellStyles=C`
:host {
color: var(--primary-text-color);
}
diff --git a/src/card/card-styles.ts b/src/card/card-styles.ts
index 90911b9..69fb079 100644
--- a/src/card/card-styles.ts
+++ b/src/card/card-styles.ts
@@ -249,6 +249,12 @@ export const CARD_STYLES: string = `
grid-template-columns: 28px 1fr 1fr 28px;
gap: 8px;
align-items: stretch;
+ /* Mark the grid as a size-query container so individual cells can
+ fold to a name-on-row-1 layout based on the grid's rendered
+ width (see .circuit-slot @container rule below). Viewport-based
+ media queries would mis-fire here because cells are half-width
+ of the grid, not half-width of the viewport. */
+ container-type: inline-size;
}
.tab-label {
@@ -325,6 +331,65 @@ export const CARD_STYLES: string = `
.circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
+ /* Narrow-cell fold for By Panel breaker cells. At full width the
+ cell packs breaker + utilization + name on the left of .circuit-header
+ and power + toggle on the right, with .circuit-status (shedding +
+ gear) below. Each cell is half the .panel-grid width, so truncation
+ kicks in once the grid is narrower than ~760px (cell ~340px) —
+ well before any viewport-based media query would fire. Query the
+ grid's own width via a container query and, once crossed, collapse
+ the nested flex containers into a single grid so the name gets the
+ whole first row and all readings/controls/gear drop to a second row.
+ 'display: contents' on the wrappers removes them from the layout
+ tree so the leaf elements can be placed by the outer grid. */
+ @container (max-width: 760px) {
+ .circuit-slot {
+ display: grid;
+ grid-template-columns: auto auto auto 1fr auto auto auto;
+ grid-template-areas:
+ "name name name name name name name"
+ "badge util shed . status power gear"
+ "chart chart chart chart chart chart chart";
+ row-gap: 6px;
+ column-gap: 8px;
+ }
+ .circuit-slot > .circuit-header,
+ .circuit-slot > .circuit-status,
+ .circuit-header > .circuit-info,
+ .circuit-header > .circuit-controls {
+ display: contents;
+ }
+ .circuit-slot .circuit-name {
+ grid-area: name;
+ justify-self: start;
+ }
+ .circuit-slot .breaker-badge {
+ grid-area: badge;
+ }
+ .circuit-slot .utilization {
+ grid-area: util;
+ }
+ .circuit-slot .shedding-icon,
+ .circuit-slot .shedding-composite {
+ grid-area: shed;
+ }
+ .circuit-slot .toggle-pill {
+ grid-area: status;
+ justify-self: end;
+ }
+ .circuit-slot .power-value {
+ grid-area: power;
+ justify-self: end;
+ }
+ .circuit-slot .gear-icon.circuit-gear {
+ grid-area: gear;
+ justify-self: end;
+ }
+ .circuit-slot > .chart-container {
+ grid-area: chart;
+ }
+ }
+
.power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }
.power-value strong { font-weight: 700; font-size: 1.1em; }
.power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }
@@ -673,6 +738,54 @@ export const CARD_STYLES: string = `
color: var(--primary-text-color);
}
+ /* Narrow-viewport fold: the flat flex row truncates the circuit
+ name heavily once breaker + utilization + shedding + toggle +
+ power + gear + chevron are all competing for width. Switch to a
+ two-row grid so the name gets the full width (paired only with
+ the expand chevron), and the badges/controls/reading/gear drop
+ to a secondary row underneath. Named areas keep the CSS readable
+ despite the flat HTML child order. */
+ @media (max-width: 520px) {
+ .list-row {
+ display: grid;
+ grid-template-columns: auto auto auto 1fr auto auto auto;
+ grid-template-areas:
+ "name name name name name name chevron"
+ "badge util shed . status power gear";
+ row-gap: 6px;
+ column-gap: 8px;
+ }
+ .list-row > .list-circuit-name {
+ grid-area: name;
+ justify-self: start;
+ }
+ .list-row > .list-expand-toggle {
+ grid-area: chevron;
+ }
+ .list-row > .breaker-badge {
+ grid-area: badge;
+ }
+ .list-row > .utilization {
+ grid-area: util;
+ }
+ .list-row > .shedding-icon,
+ .list-row > .shedding-composite {
+ grid-area: shed;
+ }
+ .list-row > .toggle-pill,
+ .list-row > .list-status-badge {
+ grid-area: status;
+ }
+ .list-row > .list-power-value {
+ grid-area: power;
+ justify-self: end;
+ }
+ .list-row > .gear-icon.circuit-gear {
+ grid-area: gear;
+ justify-self: end;
+ }
+ }
+
/* ── Expanded circuit content ──────────────────────────── */
.list-expanded-content {
From 5058abb87e6f3bd6b58e24e2ac2b481287bb8419 Mon Sep 17 00:00:00 2001
From: cayossarian <23534755+cayossarian@users.noreply.github.com>
Date: Sun, 19 Apr 2026 13:04:36 -0700
Subject: [PATCH 5/6] docs(changelog): add 0.9.5 entry for Favorites visibility
recovery and narrow-width fold
---
CHANGELOG.md | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d2e112e..609fab4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,31 @@
# Changelog
+## 0.9.5
+
+### Fixed
+
+- **Favorites view blanks after `visibilitychange` restore** — Restored a `_recoverIfNeeded` helper on the panel's visibilitychange handler. It wraps
+ `_scheduleTabRender` in try/catch **and** verifies `#tab-content` received content; on thrown error or zero child nodes, retries with 2s/4s/6s backoff up to
+ three attempts. The Favorites render path clears its container before awaiting several async build steps (`FavoritesController.build`,
+ `fetchAndBuildHorizonMaps`, `fetchMergedMonitoringStatus`), and when HA's WebSocket drops mid-render one of those resolved empty or null without throwing,
+ leaving the container blank with no console error. The retry catches the silent bailout. Dashboard (By Panel) avoided the symptom because its simpler render
+ produces an error message on failure instead of bailing quietly. The helper matches the pre-LitElement behaviour removed during the `c4154d2` refactor.
+- **List row `.list-power-value` min-width shrank the name column for no benefit** — Dropped the 70px `min-width` and `text-align: right` on
+ `.list-power-value`. Short readings (`1.3A`) were right-aligned inside a 70px cell, leaving a ~40px empty column between the relay control and the reading
+ that robbed width from the `flex:1 .list-circuit-name`. The value now sizes to content and hugs the preceding relay pill; the freed column flows back into the
+ name.
+
+### Changed
+
+- **Narrow-viewport list rows fold to a two-row grid** — New `@media (max-width: 520px)` rule switches `.list-row` from flex to grid with `grid-template-areas`
+ so the circuit name occupies the whole first row (paired with the expand chevron) and `breaker-badge`, `utilization`, shedding icon, status control, power
+ value, and gear drop to a second row. A `1fr` gap column between the status and power slots keeps the relay pill snug against the reading.
+- **By Panel breaker cells fold based on grid width, not viewport** — Made `.panel-grid` a size-query container (`container-type: inline-size`) and added an
+ `@container (max-width: 760px)` rule on `.circuit-slot`. Each cell is half the grid's width, so truncation kicks in well before any viewport media query would
+ trigger. The fold uses `display: contents` on `.circuit-header`, `.circuit-info`, `.circuit-controls`, and `.circuit-status` so the leaf elements can be
+ placed directly via `grid-area` on the outer grid — name spans the full first row, the second row mirrors the list-row layout (badge, util, shed, status,
+ power, gear), and `.chart-container` stays as a full-width third row.
+
## 0.9.4
### Added
From 21cbc2a5326d326d2833643141974d4b561257ff Mon Sep 17 00:00:00 2001
From: cayossarian <23534755+cayossarian@users.noreply.github.com>
Date: Sun, 19 Apr 2026 13:20:28 -0700
Subject: [PATCH 6/6] fix(panel): clarify recovery retry constant and changelog
wording
Copilot flagged that MAX_ATTEMPTS=3 with initial attempt=0 yields four
total renders, not three. Rename the constant to MAX_RETRIES and
update the changelog to describe the behaviour as 'initial render
plus up to three retries at 2s/4s/6s backoff' so the code, doc, and
actual count all agree.
---
CHANGELOG.md | 11 ++++++-----
src/panel/span-panel.ts | 8 ++++++--
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 609fab4..c548f91 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,11 +5,12 @@
### Fixed
- **Favorites view blanks after `visibilitychange` restore** — Restored a `_recoverIfNeeded` helper on the panel's visibilitychange handler. It wraps
- `_scheduleTabRender` in try/catch **and** verifies `#tab-content` received content; on thrown error or zero child nodes, retries with 2s/4s/6s backoff up to
- three attempts. The Favorites render path clears its container before awaiting several async build steps (`FavoritesController.build`,
- `fetchAndBuildHorizonMaps`, `fetchMergedMonitoringStatus`), and when HA's WebSocket drops mid-render one of those resolved empty or null without throwing,
- leaving the container blank with no console error. The retry catches the silent bailout. Dashboard (By Panel) avoided the symptom because its simpler render
- produces an error message on failure instead of bailing quietly. The helper matches the pre-LitElement behaviour removed during the `c4154d2` refactor.
+ `_scheduleTabRender` in try/catch **and** verifies `#tab-content` received content; on thrown error or zero child nodes, it makes the initial render and then
+ retries up to three times with 2s / 4s / 6s backoff (four total renders in the worst case). The Favorites render path clears its container before awaiting
+ several async build steps (`FavoritesController.build`, `fetchAndBuildHorizonMaps`, `fetchMergedMonitoringStatus`), and when HA's WebSocket drops mid-render
+ one of those resolved empty or null without throwing, leaving the container blank with no console error. The retry catches the silent bailout. Dashboard (By
+ Panel) avoided the symptom because its simpler render produces an error message on failure instead of bailing quietly. The helper matches the pre-LitElement
+ behaviour removed during the `c4154d2` refactor.
- **List row `.list-power-value` min-width shrank the name column for no benefit** — Dropped the 70px `min-width` and `text-align: right` on
`.list-power-value`. Short readings (`1.3A`) were right-aligned inside a 70px cell, leaving a ~40px empty column between the relay control and the reading
that robbed width from the `flex:1 .list-circuit-name`. The value now sizes to content and hugs the preceding relay pill; the freed column flows back into the
diff --git a/src/panel/span-panel.ts b/src/panel/span-panel.ts
index c4b10ff..daa3443 100644
--- a/src/panel/span-panel.ts
+++ b/src/panel/span-panel.ts
@@ -898,11 +898,15 @@ export class SpanPanelElement extends LitElement {
*/
private async _recoverIfNeeded(attempt = 0): Promise {
if (!this._discovered || !this.hass) return;
- const MAX_ATTEMPTS = 3;
+ // Retries scheduled after the initial render attempt (``attempt = 0``).
+ // With ``MAX_RETRIES = 3`` the behaviour is: one initial run plus up to
+ // three follow-ups at 2s / 4s / 6s backoff — four total renders in the
+ // worst case. Matches the pre-LitElement helper.
+ const MAX_RETRIES = 3;
const BACKOFF_BASE_MS = 2000;
const scheduleRetry = (): void => {
- if (attempt >= MAX_ATTEMPTS) return;
+ if (attempt >= MAX_RETRIES) return;
if (this._recoverTimer) clearTimeout(this._recoverTimer);
this._recoverTimer = setTimeout(
() => {