myio-js-library 0.1.545 → 0.1.547

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -470,6 +470,9 @@ __export(src_exports, {
470
470
  createModalHeader: () => createModalHeader,
471
471
  createMoneyVarianceColumn: () => createMoneyVarianceColumn,
472
472
  createMyIOTheme: () => createMyIOTheme,
473
+ createMyioGcdrLoginSubmit: () => createMyioGcdrLoginSubmit,
474
+ createMyioGcdrLoginView: () => createMyioGcdrLoginView,
475
+ createMyioGcdrShell: () => createMyioGcdrShell,
473
476
  createNewTicketWizard: () => createNewTicketWizard,
474
477
  createOnOffDeviceModal: () => createOnOffDeviceModal,
475
478
  createOnOffTimelineChart: () => createOnOffTimelineChart,
@@ -710,6 +713,7 @@ __export(src_exports, {
710
713
  isInRange: () => isInRange,
711
714
  isLeapYear: () => isLeapYear,
712
715
  isMoneyColumnConfident: () => isMoneyColumnConfident,
716
+ isMyioGcdrLoginModalOpen: () => isMyioGcdrLoginModalOpen,
713
717
  isOnOffDeviceProfile: () => isOnOffDeviceProfile,
714
718
  isSolenoidDevice: () => isSolenoidDevice,
715
719
  isStoreDevice: () => isStoreDevice,
@@ -771,6 +775,7 @@ __export(src_exports, {
771
775
  openMeasurementSetupModal: () => openMeasurementSetupModal,
772
776
  openMessageDialog: () => openMessageDialog,
773
777
  openMetasGuide: () => openMetasGuide,
778
+ openMyioGcdrLoginModal: () => openMyioGcdrLoginModal,
774
779
  openOnOffDeviceModal: () => openOnOffDeviceModal,
775
780
  openOnboardModal: () => openOnboardModal,
776
781
  openOperationalComparisonModal: () => openOperationalComparisonModal,
@@ -894,7 +899,7 @@ module.exports = __toCommonJS(src_exports);
894
899
  // package.json
895
900
  var package_default = {
896
901
  name: "myio-js-library",
897
- version: "0.1.545",
902
+ version: "0.1.547",
898
903
  description: "A clean, standalone JS SDK for MYIO projects",
899
904
  license: "MIT",
900
905
  repository: "github:gh-myio/myio-js-library",
@@ -5423,22 +5428,22 @@ function generateExportHTML(modalId, exportFormats) {
5423
5428
  if (exportFormats.length === 0) return "";
5424
5429
  if (exportFormats.length === 1) {
5425
5430
  const format = exportFormats[0];
5426
- const icon = EXPORT_FORMAT_ICONS[format] || "\u{1F4E5}";
5431
+ const icon2 = EXPORT_FORMAT_ICONS[format] || "\u{1F4E5}";
5427
5432
  return `<button
5428
5433
  id="${modalId}-export"
5429
5434
  class="myio-modal-header__btn"
5430
5435
  title="Exportar ${EXPORT_FORMAT_LABELS[format]}"
5431
- >${icon}</button>`;
5436
+ >${icon2}</button>`;
5432
5437
  }
5433
5438
  const dropdownOptions = exportFormats.map((format) => {
5434
- const icon = EXPORT_FORMAT_ICONS[format] || "\u{1F4C4}";
5439
+ const icon2 = EXPORT_FORMAT_ICONS[format] || "\u{1F4C4}";
5435
5440
  const label = EXPORT_FORMAT_LABELS[format] || format.toUpperCase();
5436
5441
  return `<button
5437
5442
  id="${modalId}-export-${format}"
5438
5443
  class="myio-export-option"
5439
5444
  data-format="${format}"
5440
5445
  title="Exportar ${label}"
5441
- >${icon} ${label}</button>`;
5446
+ >${icon2} ${label}</button>`;
5442
5447
  }).join("");
5443
5448
  return `
5444
5449
  <div style="position: relative; display: inline-block;">
@@ -5493,7 +5498,7 @@ var ModalHeader = {
5493
5498
  generateHTML(options) {
5494
5499
  injectCSS();
5495
5500
  const {
5496
- icon,
5501
+ icon: icon2,
5497
5502
  title,
5498
5503
  modalId,
5499
5504
  theme = "dark",
@@ -5535,7 +5540,7 @@ var ModalHeader = {
5535
5540
  data-drag-handle
5536
5541
  >
5537
5542
  <div class="myio-modal-header__left">
5538
- <span class="myio-modal-header__icon">${icon}</span>
5543
+ <span class="myio-modal-header__icon">${icon2}</span>
5539
5544
  <h2 class="myio-modal-header__title">${title}</h2>
5540
5545
  </div>
5541
5546
  <div class="myio-modal-header__actions">
@@ -5553,7 +5558,7 @@ var ModalHeader = {
5553
5558
  */
5554
5559
  generateInlineHTML(options) {
5555
5560
  const {
5556
- icon,
5561
+ icon: icon2,
5557
5562
  title,
5558
5563
  modalId,
5559
5564
  theme = "dark",
@@ -5598,7 +5603,7 @@ var ModalHeader = {
5598
5603
  return `
5599
5604
  <div id="${modalId}-header" style="${headerStyle}" data-drag-handle>
5600
5605
  <div style="display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;">
5601
- <span style="font-size: 18px;">${icon}</span>
5606
+ <span style="font-size: 18px;">${icon2}</span>
5602
5607
  <h2 style="margin: 0; font-size: 16px; font-weight: 600; color: ${textColor}; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
5603
5608
  ${title}
5604
5609
  </h2>
@@ -6370,10 +6375,10 @@ var state = {
6370
6375
  pinnedCounter: 0,
6371
6376
  isPinned: false
6372
6377
  };
6373
- function generateHeaderHTML(icon, title) {
6378
+ function generateHeaderHTML(icon2, title) {
6374
6379
  return `
6375
6380
  <div class="myio-info-tooltip__header" data-drag-handle>
6376
- <span class="myio-info-tooltip__icon">${icon}</span>
6381
+ <span class="myio-info-tooltip__icon">${icon2}</span>
6377
6382
  <span class="myio-info-tooltip__title">${title}</span>
6378
6383
  <div class="myio-info-tooltip__header-actions">
6379
6384
  <button class="myio-info-tooltip__header-btn" data-action="pin" title="Fixar na tela">
@@ -7002,7 +7007,7 @@ function openDeviceProfileModal(params) {
7002
7007
  });
7003
7008
  const body = handle.element;
7004
7009
  handle.on("close", () => {
7005
- cardHandles.forEach((h2) => h2.destroy());
7010
+ cardHandles.forEach((h3) => h3.destroy());
7006
7011
  cardHandles = [];
7007
7012
  onClose?.();
7008
7013
  });
@@ -7044,7 +7049,7 @@ function openDeviceProfileModal(params) {
7044
7049
  </div>`;
7045
7050
  }
7046
7051
  function mountCards() {
7047
- cardHandles.forEach((h2) => h2.destroy());
7052
+ cardHandles.forEach((h3) => h3.destroy());
7048
7053
  cardHandles = [];
7049
7054
  cardIds = [];
7050
7055
  const d = dom();
@@ -7074,10 +7079,10 @@ function openDeviceProfileModal(params) {
7074
7079
  cardIds.push(id);
7075
7080
  };
7076
7081
  const sep = (text2) => {
7077
- const h2 = document.createElement("h3");
7078
- h2.className = "mdp-sep-title";
7079
- h2.textContent = text2;
7080
- editor.appendChild(h2);
7082
+ const h3 = document.createElement("h3");
7083
+ h3.className = "mdp-sep-title";
7084
+ h3.textContent = text2;
7085
+ editor.appendChild(h3);
7081
7086
  };
7082
7087
  sep("Colunas (grupos)");
7083
7088
  addCard(
@@ -7466,7 +7471,7 @@ function openDeviceProfileModal(params) {
7466
7471
  function setAllCollapsed(collapsed) {
7467
7472
  if (collapsed) cardIds.forEach((id) => collapsedIds.add(id));
7468
7473
  else collapsedIds.clear();
7469
- cardHandles.forEach((h2) => h2.setCollapsed(collapsed));
7474
+ cardHandles.forEach((h3) => h3.setCollapsed(collapsed));
7470
7475
  }
7471
7476
  function refreshPreview() {
7472
7477
  const hasCats = !!dom()?.categories;
@@ -16110,13 +16115,13 @@ var MyIODraggableCard = class {
16110
16115
  this.container.appendChild(card);
16111
16116
  }
16112
16117
  _generateCardHTML() {
16113
- const { id, name, icon, group, lastValue, unit, status } = this.entity;
16118
+ const { id, name, icon: icon2, group, lastValue, unit, status } = this.entity;
16114
16119
  const checkboxHtml = this.options.showCheckbox ? `<input type="checkbox" class="card-checkbox" aria-label="Select ${name}">` : "";
16115
16120
  return `
16116
16121
  <div class="card-header">
16117
16122
  ${checkboxHtml}
16118
- <div class="card-icon card-icon-${icon}">
16119
- ${this._getIconSvg(icon)}
16123
+ <div class="card-icon card-icon-${icon2}">
16124
+ ${this._getIconSvg(icon2)}
16120
16125
  </div>
16121
16126
  <div class="card-status card-status-${status}"></div>
16122
16127
  </div>
@@ -18740,7 +18745,7 @@ function renderCardComponentV5({
18740
18745
  const connectionStatus = mapDeviceToConnectionStatus(deviceStatus);
18741
18746
  const isOffline = isDeviceOffline(deviceStatus);
18742
18747
  const shouldFlashIcon2 = shouldFlashIcon(deviceStatus);
18743
- const icon = getDeviceStatusIcon(deviceStatus, deviceType);
18748
+ const icon2 = getDeviceStatusIcon(deviceStatus, deviceType);
18744
18749
  const connectionIcon = getConnectionStatusIcon(connectionStatus);
18745
18750
  const debugDeviceName = "3F SCMAL3L4304ABC";
18746
18751
  const labelStr = String(labelOrName || "");
@@ -19169,7 +19174,7 @@ function renderCardComponentV5({
19169
19174
  <div class="device-data-row">
19170
19175
  <div class="consumption-main">
19171
19176
  <span class="flash-icon ${shouldFlashIcon2 ? "flash" : ""}">
19172
- ${icon}
19177
+ ${icon2}
19173
19178
  </span>
19174
19179
  <span class="consumption-value">${formatCardValue(cardEntity.lastValue, deviceType)}</span>
19175
19180
  </div>
@@ -20579,7 +20584,7 @@ function renderCardComponentV6({
20579
20584
  const connectionStatus = mapDeviceToConnectionStatus(deviceStatus);
20580
20585
  const isOffline = isDeviceOffline(deviceStatus);
20581
20586
  const shouldFlashIcon2 = shouldFlashIcon(deviceStatus);
20582
- const icon = getDeviceStatusIcon(deviceStatus, effectiveDeviceType);
20587
+ const icon2 = getDeviceStatusIcon(deviceStatus, effectiveDeviceType);
20583
20588
  const connectionIcon = getConnectionStatusIcon(connectionStatus);
20584
20589
  const mapDeviceTypeToIcon = (deviceType2) => {
20585
20590
  const category = getDeviceCategory(deviceType2);
@@ -20961,7 +20966,7 @@ function renderCardComponentV6({
20961
20966
  <div class="device-data-row">
20962
20967
  <div class="consumption-main">
20963
20968
  <span class="flash-icon ${shouldFlashIcon2 ? "flash" : ""}">
20964
- ${icon}
20969
+ ${icon2}
20965
20970
  </span>
20966
20971
  <span class="consumption-value">${formatCardValue(cardEntity.lastValue, deviceType, deviceProfile)}</span>
20967
20972
  </div>
@@ -22510,12 +22515,12 @@ function renderCardAmbienteV6({
22510
22515
  statusText = isOn2 ? "ON" : "OFF";
22511
22516
  stateClass = isOn2 ? "on" : "off";
22512
22517
  }
22513
- const icon = isLamp ? "\u{1F4A1}" : "\u{1F518}";
22518
+ const icon2 = isLamp ? "\u{1F4A1}" : "\u{1F518}";
22514
22519
  const deviceEl = document.createElement("div");
22515
22520
  deviceEl.className = `myio-ambiente-card__switch-device ${stateClass} ${isLamp ? "lamp" : "remote"}`;
22516
22521
  deviceEl.title = device.label || device.name || (isLamp ? "L\xE2mpada" : "Controle");
22517
22522
  deviceEl.innerHTML = `
22518
- <span class="myio-ambiente-card__switch-device-icon">${icon}</span>
22523
+ <span class="myio-ambiente-card__switch-device-icon">${icon2}</span>
22519
22524
  <span class="myio-ambiente-card__switch-device-value">${statusText}</span>
22520
22525
  `;
22521
22526
  scrollContainer.appendChild(deviceEl);
@@ -22936,10 +22941,10 @@ var HeaderPanelComponent = class {
22936
22941
  el2.style.display = quantity >= 0 ? "" : "none";
22937
22942
  }
22938
22943
  }
22939
- setIcon(icon) {
22940
- this.options.icon = icon;
22944
+ setIcon(icon2) {
22945
+ this.options.icon = icon2;
22941
22946
  const el2 = this.root.querySelector(".myio-hp__icon");
22942
- if (el2) el2.innerHTML = icon;
22947
+ if (el2) el2.innerHTML = icon2;
22943
22948
  }
22944
22949
  setSubtitle(subtitle) {
22945
22950
  this.options.subtitle = subtitle;
@@ -22998,7 +23003,7 @@ var HeaderPanelComponent = class {
22998
23003
  render() {
22999
23004
  const {
23000
23005
  title,
23001
- icon,
23006
+ icon: icon2,
23002
23007
  quantity,
23003
23008
  style,
23004
23009
  showSearch,
@@ -23015,10 +23020,10 @@ var HeaderPanelComponent = class {
23015
23020
  }
23016
23021
  const left = document.createElement("div");
23017
23022
  left.className = "myio-hp__left";
23018
- if (icon) {
23023
+ if (icon2) {
23019
23024
  const iconEl = document.createElement("span");
23020
23025
  iconEl.className = "myio-hp__icon";
23021
- iconEl.innerHTML = icon;
23026
+ iconEl.innerHTML = icon2;
23022
23027
  if (style?.iconColor) iconEl.style.color = style.iconColor;
23023
23028
  left.appendChild(iconEl);
23024
23029
  }
@@ -23497,10 +23502,10 @@ var EntityListPanel = class {
23497
23502
  }
23498
23503
  }
23499
23504
  /** Update icon */
23500
- setIcon(icon) {
23501
- this.options.icon = icon;
23505
+ setIcon(icon2) {
23506
+ this.options.icon = icon2;
23502
23507
  if (this.headerComponent) {
23503
- this.headerComponent.setIcon(icon);
23508
+ this.headerComponent.setIcon(icon2);
23504
23509
  }
23505
23510
  }
23506
23511
  /** Update background watermark image */
@@ -23550,7 +23555,7 @@ var EntityListPanel = class {
23550
23555
  const {
23551
23556
  title,
23552
23557
  subtitle,
23553
- icon,
23558
+ icon: icon2,
23554
23559
  quantity,
23555
23560
  backgroundImage,
23556
23561
  searchPlaceholder,
@@ -23569,7 +23574,7 @@ var EntityListPanel = class {
23569
23574
  this.headerComponent = new HeaderPanelComponent({
23570
23575
  title,
23571
23576
  subtitle,
23572
- icon,
23577
+ icon: icon2,
23573
23578
  quantity,
23574
23579
  style: titleStyle,
23575
23580
  showBottomBorder: false,
@@ -24050,10 +24055,10 @@ var CardGridPanel = class {
24050
24055
  }
24051
24056
  }
24052
24057
  /** Update icon */
24053
- setIcon(icon) {
24054
- this.options.icon = icon;
24058
+ setIcon(icon2) {
24059
+ this.options.icon = icon2;
24055
24060
  if (this.headerComponent) {
24056
- this.headerComponent.setIcon(icon);
24061
+ this.headerComponent.setIcon(icon2);
24057
24062
  }
24058
24063
  }
24059
24064
  /** Set maximize state without triggering callback (for external reset) */
@@ -24109,7 +24114,7 @@ var CardGridPanel = class {
24109
24114
  render() {
24110
24115
  const {
24111
24116
  title,
24112
- icon,
24117
+ icon: icon2,
24113
24118
  quantity,
24114
24119
  gridMinCardWidth,
24115
24120
  titleStyle,
@@ -24124,7 +24129,7 @@ var CardGridPanel = class {
24124
24129
  this.root.innerHTML = "";
24125
24130
  this.headerComponent = new HeaderPanelComponent({
24126
24131
  title,
24127
- icon,
24132
+ icon: icon2,
24128
24133
  quantity,
24129
24134
  style: titleStyle,
24130
24135
  showBottomBorder: true,
@@ -28263,20 +28268,20 @@ async function openRealTimeTelemetryModal(params) {
28263
28268
  }
28264
28269
  const todayStr = (/* @__PURE__ */ new Date()).toLocaleDateString(locale, { day: "2-digit", month: "2-digit", year: "numeric" });
28265
28270
  const dateHtml = `<span style="margin-left:8px;font-size:13px;font-weight:400;opacity:0.55;">(${todayStr})</span>`;
28266
- const icon = (glyph, title) => `<span title="${title}" style="margin-left:8px;cursor:default;font-size:16px;vertical-align:middle;">${glyph}</span>`;
28271
+ const icon2 = (glyph, title) => `<span title="${title}" style="margin-left:8px;cursor:default;font-size:16px;vertical-align:middle;">${glyph}</span>`;
28267
28272
  let iconHtml;
28268
28273
  if (!hasTelemetryToday()) {
28269
- iconHtml = icon("\u274C", "Sem telemetrias de hoje para este dispositivo");
28274
+ iconHtml = icon2("\u274C", "Sem telemetrias de hoje para este dispositivo");
28270
28275
  } else if (centralStatus === "offline") {
28271
- iconHtml = icon("\u{1F534}", `Central offline (${STATUS_MAX_RETRIES} falhas seguidas)`);
28276
+ iconHtml = icon2("\u{1F534}", `Central offline (${STATUS_MAX_RETRIES} falhas seguidas)`);
28272
28277
  } else if (deviceStatus === "offline") {
28273
- iconHtml = icon("\u{1F534}", `Dispositivo offline (${STATUS_MAX_RETRIES} verifica\xE7\xF5es seguidas sem telemetria recente)`);
28278
+ iconHtml = icon2("\u{1F534}", `Dispositivo offline (${STATUS_MAX_RETRIES} verifica\xE7\xF5es seguidas sem telemetria recente)`);
28274
28279
  } else if (centralStatus === "warning") {
28275
- iconHtml = icon("\u26A0\uFE0F", `Aten\xE7\xE3o: central sem resposta (tentativa ${centralFailStreak}/${STATUS_MAX_RETRIES})`);
28280
+ iconHtml = icon2("\u26A0\uFE0F", `Aten\xE7\xE3o: central sem resposta (tentativa ${centralFailStreak}/${STATUS_MAX_RETRIES})`);
28276
28281
  } else if (deviceStatus === "warning") {
28277
- iconHtml = icon("\u26A0\uFE0F", `Aten\xE7\xE3o: ${deviceStaleLabel()} (verifica\xE7\xE3o ${deviceStaleStreak}/${STATUS_MAX_RETRIES})`);
28282
+ iconHtml = icon2("\u26A0\uFE0F", `Aten\xE7\xE3o: ${deviceStaleLabel()} (verifica\xE7\xE3o ${deviceStaleStreak}/${STATUS_MAX_RETRIES})`);
28278
28283
  } else {
28279
- iconHtml = icon("\u2705", "H\xE1 telemetrias de hoje e o dispositivo est\xE1 respondendo");
28284
+ iconHtml = icon2("\u2705", "H\xE1 telemetrias de hoje e o dispositivo est\xE1 respondendo");
28280
28285
  }
28281
28286
  chartTitleEl.innerHTML = `Telemetria em Tempo Real de hoje${dateHtml}${iconHtml}`;
28282
28287
  }
@@ -28647,7 +28652,7 @@ async function openRealTimeTelemetryModal(params) {
28647
28652
  }
28648
28653
  injectCardTooltipStyles();
28649
28654
  const ok = checkDeviceHistory.filter((r) => r.status === "ok").length;
28650
- const fail = checkDeviceHistory.filter((r) => r.status === "offline").length;
28655
+ const fail2 = checkDeviceHistory.filter((r) => r.status === "offline").length;
28651
28656
  const total = checkDeviceHistory.length;
28652
28657
  const firstTs = checkDeviceHistory[0]?.ts;
28653
28658
  const uptimeLabel = firstTs ? (() => {
@@ -28666,10 +28671,10 @@ async function openRealTimeTelemetryModal(params) {
28666
28671
  minute: "2-digit",
28667
28672
  second: "2-digit"
28668
28673
  });
28669
- const icon = r.status === "ok" ? "\u2705" : "\u274C";
28670
- return `<div class="rtt-tt-history-row">${icon} ${dt}</div>`;
28674
+ const icon2 = r.status === "ok" ? "\u2705" : "\u274C";
28675
+ return `<div class="rtt-tt-history-row">${icon2} ${dt}</div>`;
28671
28676
  }).join("");
28672
- const failBlock = fail > 0 ? `<div style="margin-top:8px;padding:6px 8px;background:#fff5f5;border-radius:6px;font-size:11px;color:#e74c3c;">\u26A0\uFE0F ${fail} falha${fail > 1 ? "s" : ""} registrada${fail > 1 ? "s" : ""}</div>` : "";
28677
+ const failBlock = fail2 > 0 ? `<div style="margin-top:8px;padding:6px 8px;background:#fff5f5;border-radius:6px;font-size:11px;color:#e74c3c;">\u26A0\uFE0F ${fail2} falha${fail2 > 1 ? "s" : ""} registrada${fail2 > 1 ? "s" : ""}</div>` : "";
28673
28678
  const tooltip = document.createElement("div");
28674
28679
  tooltip.id = "rtt-status-tooltip";
28675
28680
  if (currentTheme === "dark") tooltip.dataset["theme"] = "dark";
@@ -28689,7 +28694,7 @@ async function openRealTimeTelemetryModal(params) {
28689
28694
  ${centralId ? `<div style="font-family:ui-monospace,monospace;background:#f1f5f9;border-radius:5px;padding:3px 8px;font-size:11px;color:#475569;">\u{1F511} Central ID: <b>${centralId}</b></div>` : ""}
28690
28695
  <div style="font-size:12px;">\u{1F4E1} <b>${ok}</b> chamadas com sucesso${total > 0 ? ` de ${total}` : ""}</div>
28691
28696
  <div style="font-size:12px;">\u23F1\uFE0F Monitorando h\xE1: <b>${uptimeLabel}</b></div>
28692
- ${fail > 0 ? `<div style="font-size:12px;color:#e74c3c;">\u274C <b>${fail}</b> falha${fail > 1 ? "s" : ""}</div>` : ""}
28697
+ ${fail2 > 0 ? `<div style="font-size:12px;color:#e74c3c;">\u274C <b>${fail2}</b> falha${fail2 > 1 ? "s" : ""}</div>` : ""}
28693
28698
  </div>
28694
28699
  ${failBlock}
28695
28700
  </div>
@@ -28739,9 +28744,9 @@ async function openRealTimeTelemetryModal(params) {
28739
28744
  minute: "2-digit",
28740
28745
  second: "2-digit"
28741
28746
  }) : "--";
28742
- function row(icon, label, value) {
28747
+ function row(icon2, label, value) {
28743
28748
  return `<div style="display:flex;flex-direction:column;gap:1px;padding:5px 0;border-bottom:1px solid #f3f4f6;">
28744
- <span style="font-size:10px;color:#9ca3af;font-weight:500;">${icon} ${label}</span>
28749
+ <span style="font-size:10px;color:#9ca3af;font-weight:500;">${icon2} ${label}</span>
28745
28750
  <span style="font-family:monospace;font-size:12px;color:#1f2937;font-weight:600;word-break:break-all;">${value || "\u2014"}</span>
28746
28751
  </div>`;
28747
28752
  }
@@ -29189,11 +29194,11 @@ async function openRealTimeTelemetryModal(params) {
29189
29194
  function showCoverageNotice(text2, resume) {
29190
29195
  if (!coverageNoticeEl) return;
29191
29196
  coverageNoticeEl.textContent = "";
29192
- const icon = document.createElement("span");
29193
- icon.textContent = "\u26A0\uFE0F ";
29197
+ const icon2 = document.createElement("span");
29198
+ icon2.textContent = "\u26A0\uFE0F ";
29194
29199
  const msg = document.createElement("span");
29195
29200
  msg.textContent = text2;
29196
- coverageNoticeEl.append(icon, msg);
29201
+ coverageNoticeEl.append(icon2, msg);
29197
29202
  coverageResume = resume ? { startISO: resume.startISO, endISO: resume.endISO } : null;
29198
29203
  if (resume) {
29199
29204
  const link = document.createElement("a");
@@ -29738,8 +29743,8 @@ async function openRealTimeTelemetryModal(params) {
29738
29743
  if (!chart) return;
29739
29744
  chart.options.responsive = false;
29740
29745
  const w = chartContainer.clientWidth - 40;
29741
- const h2 = chartContainer.clientHeight - 60;
29742
- chart.resize(Math.max(w, 200), Math.max(h2, 120));
29746
+ const h3 = chartContainer.clientHeight - 60;
29747
+ chart.resize(Math.max(w, 200), Math.max(h3, 120));
29743
29748
  })
29744
29749
  );
29745
29750
  }
@@ -29885,8 +29890,8 @@ async function openRealTimeTelemetryModal(params) {
29885
29890
  URL.revokeObjectURL(url);
29886
29891
  }
29887
29892
  function ensureRoom2(doc, nextY, minRoom = 12) {
29888
- const h2 = doc.internal.pageSize.getHeight();
29889
- if (nextY + minRoom > h2 - 15) {
29893
+ const h3 = doc.internal.pageSize.getHeight();
29894
+ if (nextY + minRoom > h3 - 15) {
29890
29895
  doc.addPage();
29891
29896
  return 20;
29892
29897
  }
@@ -29985,8 +29990,8 @@ async function openRealTimeTelemetryModal(params) {
29985
29990
  if (isExpanded) {
29986
29991
  chart.options.responsive = false;
29987
29992
  const w = chartContainer.clientWidth - 40;
29988
- const h2 = chartContainer.clientHeight - 60;
29989
- chart.resize(Math.max(w, 200), Math.max(h2, 120));
29993
+ const h3 = chartContainer.clientHeight - 60;
29994
+ chart.resize(Math.max(w, 200), Math.max(h3, 120));
29990
29995
  } else {
29991
29996
  chart.options.responsive = true;
29992
29997
  chartCanvas.style.height = "";
@@ -30774,10 +30779,10 @@ var BASControlPanel = class {
30774
30779
  }
30775
30780
  return items.join("");
30776
30781
  }
30777
- renderTelemetryItem(label, value, unit, icon) {
30782
+ renderTelemetryItem(label, value, unit, icon2) {
30778
30783
  return `
30779
30784
  <div class="myio-bas-telemetry-item">
30780
- <span class="myio-bas-telemetry-icon">${icon}</span>
30785
+ <span class="myio-bas-telemetry-icon">${icon2}</span>
30781
30786
  <div class="myio-bas-telemetry-content">
30782
30787
  <span class="myio-bas-telemetry-label">${label}</span>
30783
30788
  <span class="myio-bas-telemetry-value">${value} <span class="myio-bas-telemetry-unit">${unit}</span></span>
@@ -34143,20 +34148,20 @@ function mixHex(a, b, ratio) {
34143
34148
  };
34144
34149
  return `#${mix(0)}${mix(2)}${mix(4)}`;
34145
34150
  }
34146
- function hslToHex(h2, s, l) {
34151
+ function hslToHex(h3, s, l) {
34147
34152
  const sat = s / 100;
34148
34153
  const lig = l / 100;
34149
- const k = (n) => (n + h2 / 30) % 12;
34154
+ const k = (n) => (n + h3 / 30) % 12;
34150
34155
  const a = sat * Math.min(lig, 1 - lig);
34151
34156
  const f = (n) => lig - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
34152
34157
  const to = (v) => Math.round(v * 255).toString(16).padStart(2, "0");
34153
34158
  return `#${to(f(0))}${to(f(8))}${to(f(4))}`;
34154
34159
  }
34155
34160
  function hashColor(label, dark) {
34156
- let h2 = 5381;
34157
- for (let i = 0; i < label.length; i++) h2 = (h2 << 5) + h2 + label.charCodeAt(i) | 0;
34158
- const hue = Math.abs(h2) % 360;
34159
- const sat = 55 + Math.abs(h2 >> 8) % 25;
34161
+ let h3 = 5381;
34162
+ for (let i = 0; i < label.length; i++) h3 = (h3 << 5) + h3 + label.charCodeAt(i) | 0;
34163
+ const hue = Math.abs(h3) % 360;
34164
+ const sat = 55 + Math.abs(h3 >> 8) % 25;
34160
34165
  return hslToHex(hue, sat, dark ? 58 : 44);
34161
34166
  }
34162
34167
  function paletteColor(base, index, dark) {
@@ -34365,11 +34370,11 @@ function createParticipationChart(container, params) {
34365
34370
  ].join(" ");
34366
34371
  }
34367
34372
  function buildPieSvg2(entries, total) {
34368
- const svg = document.createElementNS(SVG_NS, "svg");
34373
+ const svg2 = document.createElementNS(SVG_NS, "svg");
34369
34374
  const SIZE = 300;
34370
- svg.setAttribute("viewBox", `0 0 ${SIZE} ${SIZE}`);
34371
- svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
34372
- svg.setAttribute("role", "img");
34375
+ svg2.setAttribute("viewBox", `0 0 ${SIZE} ${SIZE}`);
34376
+ svg2.setAttribute("preserveAspectRatio", "xMidYMid meet");
34377
+ svg2.setAttribute("role", "img");
34373
34378
  const cx = SIZE / 2;
34374
34379
  const cy = SIZE / 2;
34375
34380
  const ro = 128;
@@ -34401,7 +34406,7 @@ function createParticipationChart(container, params) {
34401
34406
  path.addEventListener("mouseleave", () => {
34402
34407
  path.style.transform = "";
34403
34408
  });
34404
- svg.appendChild(path);
34409
+ svg2.appendChild(path);
34405
34410
  attachItemTooltip(path, item, pct);
34406
34411
  if (pct >= 8) {
34407
34412
  const rl = (ro + ri) / 2;
@@ -34418,10 +34423,10 @@ function createParticipationChart(container, params) {
34418
34423
  text2.setAttribute("font-family", "'Nunito', system-ui, sans-serif");
34419
34424
  text2.setAttribute("pointer-events", "none");
34420
34425
  text2.textContent = fmtPct(pct);
34421
- svg.appendChild(text2);
34426
+ svg2.appendChild(text2);
34422
34427
  }
34423
34428
  });
34424
- return svg;
34429
+ return svg2;
34425
34430
  }
34426
34431
  function buildBarsSvg(entries, total) {
34427
34432
  const sorted = [...entries].sort((a, b) => b.item.value - a.item.value);
@@ -34433,10 +34438,10 @@ function createParticipationChart(container, params) {
34433
34438
  const maxValue = sorted.reduce((m, e) => Math.max(m, e.item.value), 0);
34434
34439
  const textColor = resolvedText();
34435
34440
  const mutedColor = resolvedMuted();
34436
- const svg = document.createElementNS(SVG_NS, "svg");
34437
- svg.setAttribute("viewBox", `0 0 ${W} ${H}`);
34438
- svg.setAttribute("preserveAspectRatio", "xMidYMin meet");
34439
- svg.setAttribute("role", "img");
34441
+ const svg2 = document.createElementNS(SVG_NS, "svg");
34442
+ svg2.setAttribute("viewBox", `0 0 ${W} ${H}`);
34443
+ svg2.setAttribute("preserveAspectRatio", "xMidYMin meet");
34444
+ svg2.setAttribute("role", "img");
34440
34445
  sorted.forEach(({ item, color }, row) => {
34441
34446
  const pct = total > 0 ? item.value / total * 100 : 0;
34442
34447
  const y = row * ROW_H + 4;
@@ -34450,7 +34455,7 @@ function createParticipationChart(container, params) {
34450
34455
  label.setAttribute("font-family", "'Nunito', system-ui, sans-serif");
34451
34456
  const raw = item.label || "";
34452
34457
  label.textContent = raw.length > 18 ? `${raw.slice(0, 17)}\u2026` : raw;
34453
- svg.appendChild(label);
34458
+ svg2.appendChild(label);
34454
34459
  const rect = document.createElementNS(SVG_NS, "rect");
34455
34460
  rect.setAttribute("x", String(LABEL_W));
34456
34461
  rect.setAttribute("y", String(y + 3));
@@ -34460,7 +34465,7 @@ function createParticipationChart(container, params) {
34460
34465
  rect.setAttribute("fill", color);
34461
34466
  rect.setAttribute("class", `${PARTICIPATION_CHART_CSS_PREFIX}__bar-rect`);
34462
34467
  rect.setAttribute("data-key", keyOf(item));
34463
- svg.appendChild(rect);
34468
+ svg2.appendChild(rect);
34464
34469
  attachItemTooltip(rect, item, pct);
34465
34470
  const value = document.createElementNS(SVG_NS, "text");
34466
34471
  value.setAttribute("x", String(LABEL_W + barW + 6));
@@ -34470,9 +34475,9 @@ function createParticipationChart(container, params) {
34470
34475
  value.setAttribute("font-size", "10.5");
34471
34476
  value.setAttribute("font-family", "'Nunito', system-ui, sans-serif");
34472
34477
  value.textContent = `${settings.formatValue(item.value)}${settings.unit ? ` ${settings.unit}` : ""} \xB7 ${fmtPct(pct)}`;
34473
- svg.appendChild(value);
34478
+ svg2.appendChild(value);
34474
34479
  });
34475
- return svg;
34480
+ return svg2;
34476
34481
  }
34477
34482
  function buildLegend2(total) {
34478
34483
  const legend = document.createElement("div");
@@ -34538,15 +34543,15 @@ function createParticipationChart(container, params) {
34538
34543
  root.appendChild(body);
34539
34544
  }
34540
34545
  async function svgToPng(scale = 2) {
34541
- const svg = root.querySelector("svg");
34542
- if (!svg) {
34546
+ const svg2 = root.querySelector("svg");
34547
+ if (!svg2) {
34543
34548
  console.warn("[ParticipationChart] Nada para exportar \u2014 gr\xE1fico vazio.");
34544
34549
  return null;
34545
34550
  }
34546
- const vb = svg.viewBox.baseVal;
34551
+ const vb = svg2.viewBox.baseVal;
34547
34552
  const width = vb && vb.width ? vb.width : 300;
34548
34553
  const height = vb && vb.height ? vb.height : 300;
34549
- const clone = svg.cloneNode(true);
34554
+ const clone = svg2.cloneNode(true);
34550
34555
  clone.setAttribute("xmlns", SVG_NS);
34551
34556
  clone.setAttribute("width", String(width));
34552
34557
  clone.setAttribute("height", String(height));
@@ -34882,14 +34887,14 @@ function createExportButton(kind, container, params = {}) {
34882
34887
  const label = settings.label ?? defaultLabel;
34883
34888
  const locked = !!settings.locked;
34884
34889
  const disabled = locked || !!settings.disabled;
34885
- const icon = locked ? LOCK_ICON : settings.icon ?? defaultIcon;
34890
+ const icon2 = locked ? LOCK_ICON : settings.icon ?? defaultIcon;
34886
34891
  btn.className = `${EXPORT_BUTTON_CSS_PREFIX}${locked ? ` ${EXPORT_BUTTON_CSS_PREFIX}--locked` : ""}`;
34887
34892
  btn.disabled = disabled;
34888
34893
  btn.style.borderColor = colors2.border;
34889
34894
  btn.style.color = colors2.text;
34890
34895
  btn.style.background = colors2.bg;
34891
34896
  btn.setAttribute("aria-label", label);
34892
- btn.innerHTML = `${icon ? `<span class="${EXPORT_BUTTON_CSS_PREFIX}__icon">${icon}</span>` : ""}${label}`;
34897
+ btn.innerHTML = `${icon2 ? `<span class="${EXPORT_BUTTON_CSS_PREFIX}__icon">${icon2}</span>` : ""}${label}`;
34893
34898
  tooltipCleanup?.();
34894
34899
  tooltipCleanup = null;
34895
34900
  const tt = settings.tooltip;
@@ -40813,11 +40818,11 @@ var PowerLimitsModalView = class {
40813
40818
  const statusKey = status === "standby" ? "standBy" : status;
40814
40819
  const config2 = STATUS_CONFIG[statusKey];
40815
40820
  const formValues = this.formData[status];
40816
- const icon = domainIcons[statusKey];
40821
+ const icon2 = domainIcons[statusKey];
40817
40822
  return `
40818
40823
  <div class="myio-power-limits-card-item myio-status-${status}" style="--status-color: ${config2.color}; --status-bg: ${config2.bgColor};">
40819
40824
  <div class="myio-card-header">
40820
- <span class="myio-status-icon">${icon}</span>
40825
+ <span class="myio-status-icon">${icon2}</span>
40821
40826
  <span class="myio-status-indicator"></span>
40822
40827
  <span class="myio-status-label">${config2.label}</span>
40823
40828
  </div>
@@ -48317,7 +48322,7 @@ var AnnotationsTab = class {
48317
48322
  const isReject = type === "rejected";
48318
48323
  const isComment = type === "comment";
48319
48324
  let title;
48320
- let icon;
48325
+ let icon2;
48321
48326
  let headerClass;
48322
48327
  let btnClass;
48323
48328
  let labelText;
@@ -48327,7 +48332,7 @@ var AnnotationsTab = class {
48327
48332
  let isRequired;
48328
48333
  if (isApprove) {
48329
48334
  title = "Aprovar Anota\xE7\xE3o";
48330
- icon = "\u2713";
48335
+ icon2 = "\u2713";
48331
48336
  headerClass = "response-modal__header--approve";
48332
48337
  btnClass = "response-modal__btn--approve";
48333
48338
  labelText = "Observa\xE7\xE3o (opcional)";
@@ -48337,7 +48342,7 @@ var AnnotationsTab = class {
48337
48342
  isRequired = false;
48338
48343
  } else if (isReject) {
48339
48344
  title = "Rejeitar Anota\xE7\xE3o";
48340
- icon = "\u2717";
48345
+ icon2 = "\u2717";
48341
48346
  headerClass = "response-modal__header--reject";
48342
48347
  btnClass = "response-modal__btn--reject";
48343
48348
  labelText = "Justificativa";
@@ -48347,7 +48352,7 @@ var AnnotationsTab = class {
48347
48352
  isRequired = true;
48348
48353
  } else if (isComment) {
48349
48354
  title = "Adicionar Coment\xE1rio";
48350
- icon = "\u{1F4AC}";
48355
+ icon2 = "\u{1F4AC}";
48351
48356
  headerClass = "response-modal__header--comment";
48352
48357
  btnClass = "response-modal__btn--comment";
48353
48358
  labelText = "Coment\xE1rio";
@@ -48357,7 +48362,7 @@ var AnnotationsTab = class {
48357
48362
  isRequired = true;
48358
48363
  } else {
48359
48364
  title = "Arquivar Anota\xE7\xE3o";
48360
- icon = "\u2B07\uFE0F";
48365
+ icon2 = "\u2B07\uFE0F";
48361
48366
  headerClass = "response-modal__header--archive";
48362
48367
  btnClass = "response-modal__btn--archive-modal";
48363
48368
  labelText = "Justificativa";
@@ -48371,7 +48376,7 @@ var AnnotationsTab = class {
48371
48376
  overlay.innerHTML = `
48372
48377
  <div class="response-modal">
48373
48378
  <div class="response-modal__header ${headerClass}">
48374
- <span class="response-modal__icon">${icon}</span>
48379
+ <span class="response-modal__icon">${icon2}</span>
48375
48380
  <span class="response-modal__title">${title}</span>
48376
48381
  </div>
48377
48382
  <div class="response-modal__body">
@@ -50627,9 +50632,9 @@ var AnnotationsTab = class {
50627
50632
  ` : ""}
50628
50633
  <div class="annotation-detail__history">
50629
50634
  <div class="annotation-detail__history-title">Hist\xF3rico (${annotation.history.length + (annotation.responses?.length || 0)} eventos)</div>
50630
- ${annotation.history.map((h2) => `
50635
+ ${annotation.history.map((h3) => `
50631
50636
  <div class="annotation-detail__history-item">
50632
- <strong>${h2.action}</strong> por ${h2.userName} em ${this.formatDate(h2.timestamp)}
50637
+ <strong>${h3.action}</strong> por ${h3.userName} em ${this.formatDate(h3.timestamp)}
50633
50638
  </div>
50634
50639
  `).join("")}
50635
50640
  ${(annotation.responses || []).map((r) => `
@@ -51850,9 +51855,9 @@ function seededRand(seed) {
51850
51855
  };
51851
51856
  }
51852
51857
  function hashStr(s) {
51853
- let h2 = 0;
51854
- for (let i = 0; i < s.length; i++) h2 = Math.imul(31, h2) + s.charCodeAt(i) | 0;
51855
- return Math.abs(h2);
51858
+ let h3 = 0;
51859
+ for (let i = 0; i < s.length; i++) h3 = Math.imul(31, h3) + s.charCodeAt(i) | 0;
51860
+ return Math.abs(h3);
51856
51861
  }
51857
51862
  function generateBuckets(alarm, devices, period = "mes") {
51858
51863
  const count = alarm.occurrenceCount || 1;
@@ -51937,11 +51942,11 @@ function generateDowDistribution(alarm) {
51937
51942
  function generateHodDistribution(alarm) {
51938
51943
  const count = alarm.occurrenceCount || 1;
51939
51944
  const rand = seededRand(hashStr(alarm.id + "hod"));
51940
- const weights = Array.from({ length: 24 }, (_, h2) => {
51941
- if (h2 < 6) return 0.05 + rand() * 0.05;
51942
- if (h2 < 10) return 0.3 + rand() * 0.3;
51943
- if (h2 <= 19) return 0.7 + rand() * 0.6;
51944
- if (h2 <= 22) return 0.3 + rand() * 0.3;
51945
+ const weights = Array.from({ length: 24 }, (_, h3) => {
51946
+ if (h3 < 6) return 0.05 + rand() * 0.05;
51947
+ if (h3 < 10) return 0.3 + rand() * 0.3;
51948
+ if (h3 <= 19) return 0.7 + rand() * 0.6;
51949
+ if (h3 <= 22) return 0.3 + rand() * 0.3;
51945
51950
  return 0.05 + rand() * 0.05;
51946
51951
  });
51947
51952
  const wSum = weights.reduce((a, b) => a + b, 0);
@@ -52074,7 +52079,7 @@ function createHodChart(canvas, vals) {
52074
52079
  return new Chart2(canvas, {
52075
52080
  type: "bar",
52076
52081
  data: {
52077
- labels: Array.from({ length: 24 }, (_, h2) => `${h2}h`),
52082
+ labels: Array.from({ length: 24 }, (_, h3) => `${h3}h`),
52078
52083
  datasets: [{
52079
52084
  label: "Ocorr\xEAncias",
52080
52085
  data: vals,
@@ -60562,12 +60567,12 @@ var TicketsTab = class {
60562
60567
  const container = this.config.container;
60563
60568
  const toggle = container.querySelector("#ct-new-ticket-toggle");
60564
60569
  const body = container.querySelector("#ct-new-ticket-body");
60565
- const icon = container.querySelector("#ct-collapse-icon");
60570
+ const icon2 = container.querySelector("#ct-collapse-icon");
60566
60571
  if (toggle && body) {
60567
60572
  toggle.addEventListener("click", () => {
60568
60573
  const isOpen = body.style.display !== "none";
60569
60574
  body.style.display = isOpen ? "none" : "block";
60570
- if (icon) icon.textContent = isOpen ? "\u25BC" : "\u25B2";
60575
+ if (icon2) icon2.textContent = isOpen ? "\u25BC" : "\u25B2";
60571
60576
  });
60572
60577
  }
60573
60578
  if (this.config.requesterEmail) {
@@ -60779,13 +60784,13 @@ ${description}` : description;
60779
60784
  return;
60780
60785
  }
60781
60786
  area.innerHTML = this._selectedFiles.map((f, i) => {
60782
- const icon = this._getFileIcon(f);
60787
+ const icon2 = this._getFileIcon(f);
60783
60788
  const isImage = f.type.startsWith("image/");
60784
60789
  const tooltip = `${f.name}
60785
60790
  ${this._formatFileSize(f.size)} \xB7 ${f.type || "arquivo"}`;
60786
60791
  return `
60787
60792
  <div class="ct-file-chip" data-index="${i}" title="${this.esc(tooltip)}">
60788
- ${isImage ? `<img class="ct-file-thumb" src="${URL.createObjectURL(f)}" alt="${this.esc(f.name)}">` : `<span class="ct-file-icon">${icon}</span>`}
60793
+ ${isImage ? `<img class="ct-file-thumb" src="${URL.createObjectURL(f)}" alt="${this.esc(f.name)}">` : `<span class="ct-file-icon">${icon2}</span>`}
60789
60794
  <span class="ct-file-name">${this.esc(f.name.length > 18 ? f.name.slice(0, 16) + "\u2026" : f.name)}</span>
60790
60795
  <span class="ct-file-size">${this._formatFileSize(f.size)}</span>
60791
60796
  <button type="button" class="ct-file-remove" data-index="${i}" title="Remover">\u2715</button>
@@ -62448,11 +62453,11 @@ var SettingsModalView = class _SettingsModalView {
62448
62453
  formatUptime(seconds) {
62449
62454
  if (seconds == null || Number.isNaN(seconds)) return "\u2014";
62450
62455
  const d = Math.floor(seconds / 86400);
62451
- const h2 = Math.floor(seconds % 86400 / 3600);
62456
+ const h3 = Math.floor(seconds % 86400 / 3600);
62452
62457
  const m = Math.floor(seconds % 3600 / 60);
62453
62458
  const parts = [];
62454
62459
  if (d > 0) parts.push(`${d}d`);
62455
- if (h2 > 0 || d > 0) parts.push(`${h2}h`);
62460
+ if (h3 > 0 || d > 0) parts.push(`${h3}h`);
62456
62461
  parts.push(`${m}min`);
62457
62462
  return parts.join(" ");
62458
62463
  }
@@ -65551,11 +65556,11 @@ function formatIsoRelativeSimple(iso) {
65551
65556
  function formatUptime(seconds) {
65552
65557
  if (seconds == null || Number.isNaN(seconds)) return "\u2014";
65553
65558
  const d = Math.floor(seconds / 86400);
65554
- const h2 = Math.floor(seconds % 86400 / 3600);
65559
+ const h3 = Math.floor(seconds % 86400 / 3600);
65555
65560
  const m = Math.floor(seconds % 3600 / 60);
65556
65561
  const parts = [];
65557
65562
  if (d > 0) parts.push(`${d}d`);
65558
- if (h2 > 0 || d > 0) parts.push(`${h2}h`);
65563
+ if (h3 > 0 || d > 0) parts.push(`${h3}h`);
65559
65564
  parts.push(`${m}min`);
65560
65565
  return parts.join(" ");
65561
65566
  }
@@ -68610,7 +68615,7 @@ var WelcomeModalView = class _WelcomeModalView {
68610
68615
  const meta = card.metaCounts || {};
68611
68616
  const details = card.metaDetails || {};
68612
68617
  const loadingBody = '<div style="opacity:.7;padding:6px 0">Carregando\u2026</div>';
68613
- const header = (icon, label, count) => `<div style="font-weight:800;font-size:13px;margin-bottom:8px">${icon} ${label}${count === null || count === void 0 ? "" : ` (${count})`} \u2014 ${esc8(card.title)}</div>`;
68618
+ const header = (icon2, label, count) => `<div style="font-weight:800;font-size:13px;margin-bottom:8px">${icon2} ${label}${count === null || count === void 0 ? "" : ` (${count})`} \u2014 ${esc8(card.title)}</div>`;
68614
68619
  const row = (titleHtml, subHtml) => `<div style="padding:6px 0;border-top:1px solid #334155">
68615
68620
  <div style="font-weight:600">${titleHtml}</div>
68616
68621
  ${subHtml ? `<div style="opacity:.7">${subHtml}</div>` : ""}
@@ -69295,15 +69300,15 @@ var WelcomeModalView = class _WelcomeModalView {
69295
69300
  if (svgIcon) {
69296
69301
  ctaBtn.appendChild(svgIcon);
69297
69302
  } else {
69298
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
69299
- svg.setAttribute("viewBox", "0 0 24 24");
69300
- svg.setAttribute("fill", "none");
69301
- svg.setAttribute("stroke", "currentColor");
69302
- svg.setAttribute("stroke-width", "2");
69303
- svg.setAttribute("stroke-linecap", "round");
69304
- svg.setAttribute("stroke-linejoin", "round");
69305
- svg.innerHTML = '<line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" />';
69306
- ctaBtn.appendChild(svg);
69303
+ const svg2 = document.createElementNS("http://www.w3.org/2000/svg", "svg");
69304
+ svg2.setAttribute("viewBox", "0 0 24 24");
69305
+ svg2.setAttribute("fill", "none");
69306
+ svg2.setAttribute("stroke", "currentColor");
69307
+ svg2.setAttribute("stroke-width", "2");
69308
+ svg2.setAttribute("stroke-linecap", "round");
69309
+ svg2.setAttribute("stroke-linejoin", "round");
69310
+ svg2.innerHTML = '<line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" />';
69311
+ ctaBtn.appendChild(svg2);
69307
69312
  }
69308
69313
  }
69309
69314
  }
@@ -71164,10 +71169,10 @@ function createHeaderComponent(params) {
71164
71169
  const categoriesHtml = categories.map((c) => {
71165
71170
  const name = String(c?.name ?? c?.label ?? "Categoria");
71166
71171
  const deviceCount = Number(c?.deviceCount ?? c?.count ?? 0);
71167
- const icon = String(c?.icon ?? "");
71172
+ const icon2 = String(c?.icon ?? "");
71168
71173
  return `
71169
71174
  <div class="myio-info-tooltip__row" style="padding: 6px 0; gap: 8px;">
71170
- <span class="myio-info-tooltip__label">${icon ? `${icon} ` : ""}${name}</span>
71175
+ <span class="myio-info-tooltip__label">${icon2 ? `${icon2} ` : ""}${name}</span>
71171
71176
  <span class="myio-info-tooltip__value myio-info-tooltip__value--highlight">${deviceCount}</span>
71172
71177
  </div>
71173
71178
  `;
@@ -72465,11 +72470,11 @@ function createOverlay() {
72465
72470
  overlay.style.setProperty("--fc-primary-hover", colors.primaryHover);
72466
72471
  return overlay;
72467
72472
  }
72468
- function createAlertBox(icon, title, message, buttonLabel) {
72473
+ function createAlertBox(icon2, title, message, buttonLabel) {
72469
72474
  const box = document.createElement("div");
72470
72475
  box.className = "myio-footer-alert-box";
72471
72476
  box.innerHTML = `
72472
- <div class="myio-footer-alert-icon">${icon}</div>
72477
+ <div class="myio-footer-alert-icon">${icon2}</div>
72473
72478
  <h2 class="myio-footer-alert-title">${title}</h2>
72474
72479
  <p class="myio-footer-alert-message">${message}</p>
72475
72480
  <button class="myio-footer-alert-button" type="button">${buttonLabel}</button>
@@ -75889,8 +75894,8 @@ function addCanvasToPdf(doc, canvas, x = 10, y = 20, maxWmm = 190) {
75889
75894
  return y + mmH;
75890
75895
  }
75891
75896
  function ensureRoom(doc, nextY, minRoom = 40) {
75892
- const h2 = doc.internal.pageSize.getHeight();
75893
- if (nextY + minRoom > h2) {
75897
+ const h3 = doc.internal.pageSize.getHeight();
75898
+ if (nextY + minRoom > h3) {
75894
75899
  doc.addPage();
75895
75900
  return 20;
75896
75901
  }
@@ -77647,9 +77652,9 @@ function openGoalsPanel(params) {
77647
77652
  };
77648
77653
  const onWriteFailure = (res) => {
77649
77654
  state6.saving = false;
77650
- const conflict = readVersionConflict(res);
77651
- if (conflict !== null) {
77652
- state6.conflictVersion = conflict;
77655
+ const conflict2 = readVersionConflict(res);
77656
+ if (conflict2 !== null) {
77657
+ state6.conflictVersion = conflict2;
77653
77658
  state6.conflict = true;
77654
77659
  state6.pendingReapply = dirtySnapshot;
77655
77660
  reload();
@@ -77715,9 +77720,9 @@ function openGoalsPanel(params) {
77715
77720
  reload();
77716
77721
  return;
77717
77722
  }
77718
- const conflict = readVersionConflict(res);
77719
- if (conflict !== null) {
77720
- state6.conflictVersion = conflict;
77723
+ const conflict2 = readVersionConflict(res);
77724
+ if (conflict2 !== null) {
77725
+ state6.conflictVersion = conflict2;
77721
77726
  state6.conflict = true;
77722
77727
  reload();
77723
77728
  } else {
@@ -77739,9 +77744,9 @@ function openGoalsPanel(params) {
77739
77744
  reload();
77740
77745
  return;
77741
77746
  }
77742
- const conflict = readVersionConflict(res);
77743
- if (conflict !== null) {
77744
- state6.conflictVersion = conflict;
77747
+ const conflict2 = readVersionConflict(res);
77748
+ if (conflict2 !== null) {
77749
+ state6.conflictVersion = conflict2;
77745
77750
  state6.conflict = true;
77746
77751
  reload();
77747
77752
  } else {
@@ -77767,7 +77772,7 @@ function openGoalsPanel(params) {
77767
77772
  const value = sampleHourValue();
77768
77773
  const day = `${state6.year}-03-15`;
77769
77774
  const lines = ["bucket,value"];
77770
- for (let h2 = 0; h2 < 24; h2++) lines.push(`${day}T${pad2(h2)},${value}`);
77775
+ for (let h3 = 0; h3 < 24; h3++) lines.push(`${day}T${pad2(h3)},${value}`);
77771
77776
  return lines.join("\n");
77772
77777
  }
77773
77778
  function downloadCsv(csv, suffix) {
@@ -77821,8 +77826,8 @@ function openGoalsPanel(params) {
77821
77826
  state6.importApplied = res.data;
77822
77827
  reload();
77823
77828
  } else {
77824
- const conflict = readVersionConflict(res);
77825
- if (conflict !== null) state6.conflictVersion = conflict;
77829
+ const conflict2 = readVersionConflict(res);
77830
+ if (conflict2 !== null) state6.conflictVersion = conflict2;
77826
77831
  else state6.saveError = res.error && res.error.message || "Failed to apply import";
77827
77832
  }
77828
77833
  renderImportBody();
@@ -78034,19 +78039,19 @@ function openGoalsPanel(params) {
78034
78039
  if (!yearOptions.includes(state6.year)) yearOptions.unshift(state6.year);
78035
78040
  const actions = state6.editing ? `
78036
78041
  <button class="myio-goals-btn myio-goals-btn-outline" data-action="open-import" ${state6.loading || state6.error ? "disabled" : ""}>
78037
- ${icon("upload")} ${i18n2.importBtn}
78042
+ ${icon2("upload")} ${i18n2.importBtn}
78038
78043
  </button>
78039
78044
  <button class="myio-goals-btn myio-goals-btn-outline" data-action="view-summary" ${state6.loading ? "disabled" : ""}>
78040
- ${icon("eye")} ${i18n2.viewSummary}
78045
+ ${icon2("eye")} ${i18n2.viewSummary}
78041
78046
  </button>
78042
78047
  <button class="myio-goals-btn myio-goals-btn-primary" data-action="save" ${state6.loading || state6.error || state6.saving ? "disabled" : ""}>
78043
- ${icon("save")} ${state6.saving ? i18n2.saving : i18n2.save}
78048
+ ${icon2("save")} ${state6.saving ? i18n2.saving : i18n2.save}
78044
78049
  </button>` : `
78045
78050
  <button class="myio-goals-btn myio-goals-btn-outline" data-action="download-hourly" ${state6.loading ? "disabled" : ""}>
78046
- ${icon("download")} ${i18n2.downloadHourlyExample}
78051
+ ${icon2("download")} ${i18n2.downloadHourlyExample}
78047
78052
  </button>
78048
78053
  <button class="myio-goals-btn myio-goals-btn-primary" data-action="enable-edit" ${state6.loading || state6.error ? "disabled" : ""}>
78049
- ${icon("pencil")} ${i18n2.enableEditing}
78054
+ ${icon2("pencil")} ${i18n2.enableEditing}
78050
78055
  </button>`;
78051
78056
  return `
78052
78057
  <div class="myio-goals-toolbar">
@@ -78064,9 +78069,9 @@ function openGoalsPanel(params) {
78064
78069
  </select>
78065
78070
  </label>
78066
78071
  <div class="myio-goals-chips">
78067
- <span class="myio-goals-chip myio-goals-chip-accent">${icon("target")} ${i18n2.domains[state6.domain]} \xB7 ${i18n2.aggregation[cfg.aggregationMethod]}</span>
78072
+ <span class="myio-goals-chip myio-goals-chip-accent">${icon2("target")} ${i18n2.domains[state6.domain]} \xB7 ${i18n2.aggregation[cfg.aggregationMethod]}</span>
78068
78073
  <span class="myio-goals-chip myio-goals-chip-mono">${unitLabel2()}</span>
78069
- <span class="myio-goals-chip myio-goals-chip-violet">${icon("history")} ${i18n2.currentVersion.replace("{n}", version2)}</span>
78074
+ <span class="myio-goals-chip myio-goals-chip-violet">${icon2("history")} ${i18n2.currentVersion.replace("{n}", version2)}</span>
78070
78075
  ${renderMarginChip()}
78071
78076
  ${renderDeviceGranularityChip()}
78072
78077
  ${renderCoverageChip()}
@@ -78133,7 +78138,7 @@ function openGoalsPanel(params) {
78133
78138
  ${state6.saving ? "disabled" : ""} />
78134
78139
  <span class="myio-goals-margin-pct">%</span>
78135
78140
  <button class="myio-goals-btn myio-goals-btn-outline myio-goals-btn-sm" data-action="save-margin" ${state6.saving ? "disabled" : ""}>
78136
- ${icon("save")} ${i18n2.margin.save}
78141
+ ${icon2("save")} ${i18n2.margin.save}
78137
78142
  </button>
78138
78143
  ${pct != null ? `<button class="myio-goals-btn myio-goals-btn-outline myio-goals-btn-sm" data-action="clear-margin" ${state6.saving ? "disabled" : ""}>${i18n2.margin.clear}</button>` : ""}
78139
78144
  <span class="myio-goals-margin-hint">${i18n2.margin.hint}</span>
@@ -78142,24 +78147,24 @@ function openGoalsPanel(params) {
78142
78147
  function renderMessages() {
78143
78148
  let html = "";
78144
78149
  if (state6.conflict) {
78145
- html += `<div class="myio-goals-alert myio-goals-alert-amber">${icon("alert")} ${i18n2.versionConflict}</div>`;
78150
+ html += `<div class="myio-goals-alert myio-goals-alert-amber">${icon2("alert")} ${i18n2.versionConflict}</div>`;
78146
78151
  }
78147
78152
  if (state6.saveError && !state6.conflict) {
78148
- html += `<div class="myio-goals-alert myio-goals-alert-red">${icon("alert")} ${esc4(state6.saveError)}</div>`;
78153
+ html += `<div class="myio-goals-alert myio-goals-alert-red">${icon2("alert")} ${esc4(state6.saveError)}</div>`;
78149
78154
  }
78150
78155
  if (state6.saved && !state6.saveError) {
78151
- html += `<div class="myio-goals-alert myio-goals-alert-green">${icon("check")} ${i18n2.saveSuccess}</div>`;
78156
+ html += `<div class="myio-goals-alert myio-goals-alert-green">${icon2("check")} ${i18n2.saveSuccess}</div>`;
78152
78157
  }
78153
78158
  return html;
78154
78159
  }
78155
78160
  function renderMain() {
78156
78161
  if (state6.loading) {
78157
- return `<div class="myio-goals-center">${icon("spinner")} <span>${i18n2.loading}</span></div>`;
78162
+ return `<div class="myio-goals-center">${icon2("spinner")} <span>${i18n2.loading}</span></div>`;
78158
78163
  }
78159
78164
  if (state6.error) {
78160
78165
  return `
78161
78166
  <div class="myio-goals-center myio-goals-center-col">
78162
- ${icon("alert-lg")}
78167
+ ${icon2("alert-lg")}
78163
78168
  <p>${esc4(state6.error)}</p>
78164
78169
  <button class="myio-goals-btn myio-goals-btn-outline" data-action="retry">${i18n2.retry}</button>
78165
78170
  </div>`;
@@ -78172,20 +78177,20 @@ function openGoalsPanel(params) {
78172
78177
  if (!s.hasData) {
78173
78178
  return `
78174
78179
  <div class="myio-goals-center myio-goals-center-col">
78175
- ${icon("target-lg")}
78180
+ ${icon2("target-lg")}
78176
78181
  <p>${i18n2.noData.replace("{year}", state6.year)}</p>
78177
- <button class="myio-goals-btn myio-goals-btn-primary" data-action="enable-edit">${icon("pencil")} ${i18n2.enableEditing}</button>
78182
+ <button class="myio-goals-btn myio-goals-btn-primary" data-action="enable-edit">${icon2("pencil")} ${i18n2.enableEditing}</button>
78178
78183
  </div>`;
78179
78184
  }
78180
78185
  const avg = isAverage();
78181
- const glyph = avg ? `<span class="myio-goals-glyph">x\u0304</span>` : icon("sigma");
78186
+ const glyph = avg ? `<span class="myio-goals-glyph">x\u0304</span>` : icon2("sigma");
78182
78187
  const kpis = [
78183
- { ic: icon("calendar"), label: i18n2.summary.year, value: String(state6.year) },
78188
+ { ic: icon2("calendar"), label: i18n2.summary.year, value: String(state6.year) },
78184
78189
  { ic: glyph, label: avg ? i18n2.summary.yearAverage : i18n2.summary.yearTotal, value: fmt2(s.yearValue) },
78185
- { ic: icon("calendar-range"), label: i18n2.summary.monthsWithGoal, value: `${s.monthsWithGoal} / 12` },
78186
- { ic: icon("calendar-days"), label: i18n2.summary.daysWithGoal, value: String(s.daysWithGoal) },
78187
- { ic: icon("trend"), label: i18n2.summary.avgPerMonth, value: fmt2(s.avgPerMonth) },
78188
- { ic: icon("trend"), label: i18n2.summary.avgPerDay, value: fmt2(s.avgPerDay) }
78190
+ { ic: icon2("calendar-range"), label: i18n2.summary.monthsWithGoal, value: `${s.monthsWithGoal} / 12` },
78191
+ { ic: icon2("calendar-days"), label: i18n2.summary.daysWithGoal, value: String(s.daysWithGoal) },
78192
+ { ic: icon2("trend"), label: i18n2.summary.avgPerMonth, value: fmt2(s.avgPerMonth) },
78193
+ { ic: icon2("trend"), label: i18n2.summary.avgPerDay, value: fmt2(s.avgPerDay) }
78189
78194
  ];
78190
78195
  const marginPct = currentMarginPct();
78191
78196
  const adjAnnual = state6.goals && state6.goals.tree && state6.goals.tree.annual ? state6.goals.tree.annual.adjustedValue : null;
@@ -78198,7 +78203,7 @@ function openGoalsPanel(params) {
78198
78203
  }
78199
78204
  const topCol = (title, items, labeler) => `
78200
78205
  <div class="myio-goals-topcard">
78201
- <h4>${icon("trend")} ${title}</h4>
78206
+ <h4>${icon2("trend")} ${title}</h4>
78202
78207
  ${items.length === 0 ? `<p class="myio-goals-muted">\u2014</p>` : `<ol>${items.map(
78203
78208
  (e, i) => `
78204
78209
  <li>
@@ -78237,9 +78242,9 @@ function openGoalsPanel(params) {
78237
78242
  const version2 = state6.goals ? state6.goals.version : 0;
78238
78243
  const crumb = `
78239
78244
  <nav class="myio-goals-crumb">
78240
- <button data-action="crumb-months" class="${state6.level === "month" ? "active" : ""}">${icon("home")} ${i18n2.breadcrumbYear.replace("{year}", state6.year)}</button>
78241
- ${state6.selectedMonth ? `${icon("chevron")}<button data-action="crumb-days" class="${state6.level === "day" ? "active" : ""}">${i18n2.months[state6.selectedMonth]}</button>` : ""}
78242
- ${state6.selectedMonth && state6.selectedDay && state6.level === "hour" ? `${icon("chevron")}<span class="active">${i18n2.breadcrumbDay.replace("{day}", Number(state6.selectedDay))}</span>` : ""}
78245
+ <button data-action="crumb-months" class="${state6.level === "month" ? "active" : ""}">${icon2("home")} ${i18n2.breadcrumbYear.replace("{year}", state6.year)}</button>
78246
+ ${state6.selectedMonth ? `${icon2("chevron")}<button data-action="crumb-days" class="${state6.level === "day" ? "active" : ""}">${i18n2.months[state6.selectedMonth]}</button>` : ""}
78247
+ ${state6.selectedMonth && state6.selectedDay && state6.level === "hour" ? `${icon2("chevron")}<span class="active">${i18n2.breadcrumbDay.replace("{day}", Number(state6.selectedDay))}</span>` : ""}
78243
78248
  </nav>`;
78244
78249
  const emptyHint = state6.level === "month" && monthlyFilledCount() === 0 && version2 === 0 ? `<p class="myio-goals-muted">${i18n2.empty}</p>` : "";
78245
78250
  const drillHint = state6.level !== "hour" ? `<p class="myio-goals-microhint">${state6.level === "month" ? i18n2.drill.openMonthHint : i18n2.drill.openDayHint}</p>` : "";
@@ -78249,14 +78254,14 @@ function openGoalsPanel(params) {
78249
78254
  const confirmed = node && node.derived === false;
78250
78255
  const cellLabel = state6.level === "month" ? i18n2.months[key] : state6.level === "day" ? i18n2.dayCell.replace("{day}", Number(key)) : `${key}:00`;
78251
78256
  const canDrill = state6.level !== "hour";
78252
- const labelEl = canDrill ? `<button class="myio-goals-cell-drill" data-action="${state6.level === "month" ? "open-month" : "open-day"}" data-key="${key}" title="${i18n2.drill.openTitle}">${cellLabel} ${icon("chevron-sm")}</button>` : `<span class="myio-goals-cell-label">${cellLabel}</span>`;
78257
+ const labelEl = canDrill ? `<button class="myio-goals-cell-drill" data-action="${state6.level === "month" ? "open-month" : "open-day"}" data-key="${key}" title="${i18n2.drill.openTitle}">${cellLabel} ${icon2("chevron-sm")}</button>` : `<span class="myio-goals-cell-label">${cellLabel}</span>`;
78253
78258
  const val = state6.draft[key] !== void 0 ? esc4(state6.draft[key]) : "";
78254
78259
  const minAttr = cfg.allowsNegative ? "" : 'min="0"';
78255
78260
  return `
78256
78261
  <div class="myio-goals-cell">
78257
78262
  <div class="myio-goals-cell-head">
78258
78263
  ${labelEl}
78259
- ${icon("pencil-sm")}
78264
+ ${icon2("pencil-sm")}
78260
78265
  </div>
78261
78266
  <div class="myio-goals-cell-input">
78262
78267
  <input type="number" step="any" ${minAttr} data-cell="${key}" value="${val}" placeholder="\u2014" />
@@ -78266,7 +78271,7 @@ function openGoalsPanel(params) {
78266
78271
  </div>`;
78267
78272
  }).join("");
78268
78273
  const totalLabel = state6.level === "month" ? avg ? i18n2.summary.yearAverage : i18n2.summary.yearTotal : state6.level === "day" ? avg ? i18n2.monthAverage : i18n2.monthTotal : avg ? i18n2.dayAverage : i18n2.dayTotal;
78269
- const glyph = avg ? `<span class="myio-goals-glyph">x\u0304</span>` : icon("sigma");
78274
+ const glyph = avg ? `<span class="myio-goals-glyph">x\u0304</span>` : icon2("sigma");
78270
78275
  const total = computedTotal();
78271
78276
  return `
78272
78277
  <div class="myio-goals-editor">
@@ -78279,7 +78284,7 @@ function openGoalsPanel(params) {
78279
78284
  <span class="myio-goals-total-val" id="myio-goals-computed-total">${total === null ? "\u2014" : fmt2(total)}</span>
78280
78285
  </div>
78281
78286
  <div class="myio-goals-legend">
78282
- <span>${icon("pencil-sm")} ${i18n2.legendEditable}</span>
78287
+ <span>${icon2("pencil-sm")} ${i18n2.legendEditable}</span>
78283
78288
  <span>${glyph} ${i18n2.legendComputed}</span>
78284
78289
  </div>
78285
78290
  </div>`;
@@ -78300,12 +78305,12 @@ function openGoalsPanel(params) {
78300
78305
  const diff = Math.max(0, Date.now() - then);
78301
78306
  const s = Math.floor(diff / 1e3);
78302
78307
  const m = Math.floor(s / 60);
78303
- const h2 = Math.floor(m / 60);
78304
- const d = Math.floor(h2 / 24);
78308
+ const h3 = Math.floor(m / 60);
78309
+ const d = Math.floor(h3 / 24);
78305
78310
  const T = i18n2.time;
78306
78311
  if (s < 60) return T.now;
78307
78312
  if (m < 60) return T.min.replace("{n}", m);
78308
- if (h2 < 24) return T.hour.replace("{n}", h2);
78313
+ if (h3 < 24) return T.hour.replace("{n}", h3);
78309
78314
  if (d < 30) return T.day.replace("{n}", d);
78310
78315
  return new Date(iso).toLocaleDateString(locale);
78311
78316
  }
@@ -78314,7 +78319,7 @@ function openGoalsPanel(params) {
78314
78319
  const history = state6.goals && state6.goals.history || [];
78315
78320
  const version2 = state6.goals ? state6.goals.version : 0;
78316
78321
  const DETAIL_PREVIEW = 8;
78317
- const items = history.length === 0 ? `<div class="myio-goals-center myio-goals-center-col myio-goals-hist-empty">${icon("clock")}<p>${i18n2.history.empty}</p></div>` : `<ol class="myio-goals-timeline">${history.map((ev, idx) => {
78322
+ const items = history.length === 0 ? `<div class="myio-goals-center myio-goals-center-col myio-goals-hist-empty">${icon2("clock")}<p>${i18n2.history.empty}</p></div>` : `<ol class="myio-goals-timeline">${history.map((ev, idx) => {
78318
78323
  const actor = ev.actor ? `${String(ev.actor).slice(0, 8)}\u2026` : i18n2.history.system;
78319
78324
  const extra = ev.bucketCount - (ev.details ? ev.details.length : 0);
78320
78325
  const chips = (ev.details || []).slice(0, DETAIL_PREVIEW).map(
@@ -78323,7 +78328,7 @@ function openGoalsPanel(params) {
78323
78328
  const more = extra > 0 ? `<span class="myio-goals-tl-more">${i18n2.history.moreDetails.replace("{n}", extra)}</span>` : "";
78324
78329
  return `
78325
78330
  <li class="myio-goals-tl-item">
78326
- <span class="myio-goals-tl-dot">${icon(ev.source === "IMPORT" ? "upload-sm" : ev.source === "DELETE" ? "trash-sm" : "pencil-sm")}</span>
78331
+ <span class="myio-goals-tl-dot">${icon2(ev.source === "IMPORT" ? "upload-sm" : ev.source === "DELETE" ? "trash-sm" : "pencil-sm")}</span>
78327
78332
  <div class="myio-goals-tl-head">
78328
78333
  <span class="myio-goals-tl-title">${i18n2.history.source[ev.source] || i18n2.history.source.EDIT}</span>
78329
78334
  <span class="myio-goals-tl-ver">v${ev.version}</span>
@@ -78336,7 +78341,7 @@ function openGoalsPanel(params) {
78336
78341
  return `
78337
78342
  <div class="myio-goals-history">
78338
78343
  <div class="myio-goals-history-head">
78339
- <h3>${icon("clock")} ${i18n2.history.title}</h3>
78344
+ <h3>${icon2("clock")} ${i18n2.history.title}</h3>
78340
78345
  <span class="myio-goals-history-meta">${i18n2.domains[state6.domain]} \xB7 ${state6.year} \xB7 ${i18n2.currentVersion.replace("{n}", version2)}</span>
78341
78346
  </div>
78342
78347
  ${items}
@@ -78348,7 +78353,7 @@ function openGoalsPanel(params) {
78348
78353
  <div class="myio-goals-import-dialog">
78349
78354
  <div class="myio-goals-import-card">
78350
78355
  <div class="myio-goals-import-header">
78351
- <span class="myio-goals-import-icon">${icon("upload")}</span>
78356
+ <span class="myio-goals-import-icon">${icon2("upload")}</span>
78352
78357
  <div>
78353
78358
  <h3>${i18n2.import.title}</h3>
78354
78359
  <p>${i18n2.import.subtitle.replace("{domain}", i18n2.domains[state6.domain]).replace("{year}", state6.year)}</p>
@@ -78383,9 +78388,9 @@ ${state6.year}-03-15T08,15`;
78383
78388
  <div class="myio-goals-import-inputhead">
78384
78389
  <label>${i18n2.import.csvLabel}</label>
78385
78390
  <div class="myio-goals-import-links">
78386
- <button data-action="download-template">${icon("download")} ${i18n2.import.downloadTemplate}</button>
78387
- <button data-action="download-hourly">${icon("download")} ${i18n2.import.downloadHourlyExample}</button>
78388
- <button data-action="import-upload">${icon("upload")} ${i18n2.import.uploadFile}</button>
78391
+ <button data-action="download-template">${icon2("download")} ${i18n2.import.downloadTemplate}</button>
78392
+ <button data-action="download-hourly">${icon2("download")} ${i18n2.import.downloadHourlyExample}</button>
78393
+ <button data-action="import-upload">${icon2("upload")} ${i18n2.import.uploadFile}</button>
78389
78394
  <input type="file" id="myio-goals-csv-file" accept=".csv,.txt,text/csv,text/plain" style="display:none" />
78390
78395
  </div>
78391
78396
  </div>
@@ -78398,22 +78403,22 @@ ${state6.year}-03-15T08,15`)}">${esc4(state6.csv)}</textarea>
78398
78403
  </div>`;
78399
78404
  }
78400
78405
  if (state6.saveError && state6.conflictVersion === null) {
78401
- html += `<div class="myio-goals-alert myio-goals-alert-red">${icon("alert")} ${esc4(state6.saveError)}</div>`;
78406
+ html += `<div class="myio-goals-alert myio-goals-alert-red">${icon2("alert")} ${esc4(state6.saveError)}</div>`;
78402
78407
  }
78403
78408
  if (state6.conflictVersion !== null) {
78404
- html += `<div class="myio-goals-alert myio-goals-alert-amber">${icon("alert")} ${i18n2.import.conflict}</div>`;
78409
+ html += `<div class="myio-goals-alert myio-goals-alert-amber">${icon2("alert")} ${i18n2.import.conflict}</div>`;
78405
78410
  }
78406
78411
  if (result) html += renderImportSummary(result, counts);
78407
78412
  return html;
78408
78413
  }
78409
78414
  function renderImportSummary(result, counts) {
78410
78415
  const persisted = result.dryRun === false;
78411
- const badge = persisted ? `<span class="myio-goals-chip myio-goals-chip-accent">${icon("check")} ${i18n2.import.appliedBadge.replace("{version}", result.version || 0)}</span>` : `<span class="myio-goals-chip myio-goals-chip-mono">${i18n2.import.previewBadge}</span>`;
78416
+ const badge = persisted ? `<span class="myio-goals-chip myio-goals-chip-accent">${icon2("check")} ${i18n2.import.appliedBadge.replace("{version}", result.version || 0)}</span>` : `<span class="myio-goals-chip myio-goals-chip-mono">${i18n2.import.previewBadge}</span>`;
78412
78417
  let html = `
78413
78418
  <div class="myio-goals-import-summary">
78414
78419
  <div class="myio-goals-import-counts">
78415
- <span class="myio-goals-chip myio-goals-chip-accent">${icon("check")} ${i18n2.import.okCount.replace("{n}", result.okCount)}</span>
78416
- ${result.errorCount > 0 ? `<span class="myio-goals-chip myio-goals-chip-red">${icon("alert")} ${i18n2.import.errorCount.replace("{n}", result.errorCount)}</span>` : ""}
78420
+ <span class="myio-goals-chip myio-goals-chip-accent">${icon2("check")} ${i18n2.import.okCount.replace("{n}", result.okCount)}</span>
78421
+ ${result.errorCount > 0 ? `<span class="myio-goals-chip myio-goals-chip-red">${icon2("alert")} ${i18n2.import.errorCount.replace("{n}", result.errorCount)}</span>` : ""}
78417
78422
  ${badge}
78418
78423
  </div>`;
78419
78424
  if (!persisted && counts && result.okCount > 0) {
@@ -78427,7 +78432,7 @@ ${state6.year}-03-15T08,15`)}">${esc4(state6.csv)}</textarea>
78427
78432
  <div class="myio-goals-import-diags">
78428
78433
  <p class="myio-goals-import-diags-title">${i18n2.import.diagnosticsTitle}</p>
78429
78434
  <ul>${result.diagnostics.map(
78430
- (d) => `<li>${icon("alert-sm")} <span><span class="myio-goals-diag-line">${i18n2.import.line.replace("{line}", d.line)}</span>${d.bucket ? ` <span class="myio-goals-diag-bucket">[${esc4(d.bucket)}]</span>` : ""} ${esc4(d.reason)}</span></li>`
78435
+ (d) => `<li>${icon2("alert-sm")} <span><span class="myio-goals-diag-line">${i18n2.import.line.replace("{line}", d.line)}</span>${d.bucket ? ` <span class="myio-goals-diag-bucket">[${esc4(d.bucket)}]</span>` : ""} ${esc4(d.reason)}</span></li>`
78431
78436
  ).join("")}</ul>
78432
78437
  </div>`;
78433
78438
  }
@@ -78447,7 +78452,7 @@ ${state6.year}-03-15T08,15`)}">${esc4(state6.csv)}</textarea>
78447
78452
  }
78448
78453
  const canPreview = state6.csv.trim().length > 0 && !state6.saving;
78449
78454
  const canConfirm = !!state6.importPreview && state6.importPreview.okCount > 0 && !state6.saving && !state6.importApplied;
78450
- const right = state6.importPreview ? `<button class="myio-goals-btn myio-goals-btn-primary" data-action="import-confirm" ${canConfirm ? "" : "disabled"}>${icon("upload")} ${i18n2.import.confirm.replace("{n}", state6.importPreview.okCount)}</button>` : `<button class="myio-goals-btn myio-goals-btn-primary" data-action="import-preview" ${canPreview ? "" : "disabled"}>${icon("upload")} ${i18n2.import.preview}</button>`;
78455
+ const right = state6.importPreview ? `<button class="myio-goals-btn myio-goals-btn-primary" data-action="import-confirm" ${canConfirm ? "" : "disabled"}>${icon2("upload")} ${i18n2.import.confirm.replace("{n}", state6.importPreview.okCount)}</button>` : `<button class="myio-goals-btn myio-goals-btn-primary" data-action="import-preview" ${canPreview ? "" : "disabled"}>${icon2("upload")} ${i18n2.import.preview}</button>`;
78451
78456
  return `
78452
78457
  <button class="myio-goals-btn myio-goals-btn-outline" data-action="import-close" ${state6.saving ? "disabled" : ""}>${i18n2.import.cancel}</button>
78453
78458
  ${right}`;
@@ -78459,7 +78464,7 @@ ${state6.year}-03-15T08,15`)}">${esc4(state6.csv)}</textarea>
78459
78464
  if (body) body.innerHTML = renderImportInner();
78460
78465
  if (footer) footer.innerHTML = renderImportFooter();
78461
78466
  }
78462
- function icon(name) {
78467
+ function icon2(name) {
78463
78468
  const S2 = (p2) => `<svg class="myio-goals-ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${p2}</svg>`;
78464
78469
  switch (name) {
78465
78470
  case "target":
@@ -82001,7 +82006,7 @@ var EnergySummaryTooltip = {
82001
82006
  }))
82002
82007
  });
82003
82008
  categories.forEach((cat, catIndex) => {
82004
- const icon = CATEGORY_ICONS[cat.id] || CATEGORY_ICONS.outros;
82009
+ const icon2 = CATEGORY_ICONS[cat.id] || CATEGORY_ICONS.outros;
82005
82010
  const hasChildren = cat.children && cat.children.length > 0;
82006
82011
  const hasShoppingBreakdown = cat.byShoppingBreakdown && cat.byShoppingBreakdown.length > 0;
82007
82012
  const isExpandable = hasChildren || hasShoppingBreakdown;
@@ -82011,7 +82016,7 @@ var EnergySummaryTooltip = {
82011
82016
  ${isExpandable ? `
82012
82017
  <button class="energy-summary-tooltip__expand-toggle" data-target="cat-${catIndex}" title="Expandir">+</button>
82013
82018
  ` : ""}
82014
- <span class="energy-summary-tooltip__category-icon">${icon}</span>
82019
+ <span class="energy-summary-tooltip__category-icon">${icon2}</span>
82015
82020
  <span>${cat.name}</span>
82016
82021
  </span>
82017
82022
  <span class="energy-summary-tooltip__category-count">${cat.deviceCount}</span>
@@ -82678,10 +82683,10 @@ var EnergySummaryTooltip = {
82678
82683
  return;
82679
82684
  }
82680
82685
  this._cancelDevicePopupDelayedHide();
82681
- const icon = this._getStatusIcon(statusKey);
82686
+ const icon2 = this._getStatusIcon(statusKey);
82682
82687
  const content = this._buildDeviceListContent(statusKey, label, count);
82683
82688
  InfoTooltip2.show(triggerElement, {
82684
- icon,
82689
+ icon: icon2,
82685
82690
  title: `${label} (${count})`,
82686
82691
  content
82687
82692
  });
@@ -83995,7 +84000,7 @@ var WaterSummaryTooltip = {
83995
84000
  return html;
83996
84001
  }
83997
84002
  categories.forEach((cat, catIndex) => {
83998
- const icon = WATER_CATEGORY_ICONS[cat.id] || WATER_CATEGORY_ICONS.areaComum;
84003
+ const icon2 = WATER_CATEGORY_ICONS[cat.id] || WATER_CATEGORY_ICONS.areaComum;
83999
84004
  const hasChildren = cat.children && cat.children.length > 0;
84000
84005
  const hasShoppingBreakdown = cat.byShoppingBreakdown && cat.byShoppingBreakdown.length > 0;
84001
84006
  const isExpandable = hasChildren || hasShoppingBreakdown;
@@ -84005,7 +84010,7 @@ var WaterSummaryTooltip = {
84005
84010
  ${isExpandable ? `
84006
84011
  <button class="water-summary-tooltip__expand-toggle" data-target="water-cat-${catIndex}" title="Expandir">+</button>
84007
84012
  ` : ""}
84008
- <span class="water-summary-tooltip__category-icon">${icon}</span>
84013
+ <span class="water-summary-tooltip__category-icon">${icon2}</span>
84009
84014
  <span>${cat.name}</span>
84010
84015
  </span>
84011
84016
  <span class="water-summary-tooltip__category-count">${cat.deviceCount}</span>
@@ -84603,10 +84608,10 @@ var WaterSummaryTooltip = {
84603
84608
  return;
84604
84609
  }
84605
84610
  this._cancelDevicePopupDelayedHide();
84606
- const icon = this._getStatusIcon(statusKey);
84611
+ const icon2 = this._getStatusIcon(statusKey);
84607
84612
  const content = this._buildDeviceListContent(statusKey, label, count);
84608
84613
  InfoTooltip2.show(triggerElement, {
84609
- icon,
84614
+ icon: icon2,
84610
84615
  title: `${label} (${count})`,
84611
84616
  content
84612
84617
  });
@@ -86198,10 +86203,10 @@ function generateContentHTML(data) {
86198
86203
  <div class="myio-temp-sensor-tooltip__list">
86199
86204
  ${displayDevices.map((d) => {
86200
86205
  const statusClass = d.status === "ok" ? "ok" : d.status === "warn" ? "warn" : "unknown";
86201
- const icon = d.status === "ok" ? "\u2714" : d.status === "warn" ? "\u26A0" : "?";
86206
+ const icon2 = d.status === "ok" ? "\u2714" : d.status === "warn" ? "\u26A0" : "?";
86202
86207
  return `
86203
86208
  <div class="myio-temp-sensor-tooltip__list-item myio-temp-sensor-tooltip__list-item--${statusClass}">
86204
- <span class="myio-temp-sensor-tooltip__list-icon">${icon}</span>
86209
+ <span class="myio-temp-sensor-tooltip__list-icon">${icon2}</span>
86205
86210
  <span class="myio-temp-sensor-tooltip__list-name">${d.name}</span>
86206
86211
  <span class="myio-temp-sensor-tooltip__list-value">${d.temp.toFixed(1)}\xB0C</span>
86207
86212
  </div>
@@ -87059,7 +87064,7 @@ function generateHeaderHTML5(data) {
87059
87064
  </div>
87060
87065
  `;
87061
87066
  }
87062
- function generateDomainHTML(domain, icon, name, counts, isTemperature = false) {
87067
+ function generateDomainHTML(domain, icon2, name, counts, isTemperature = false) {
87063
87068
  const isExpanded = state5.expandedDomains.has(domain);
87064
87069
  const expandedClass = isExpanded ? "expanded" : "";
87065
87070
  let detailsHTML = "";
@@ -87096,7 +87101,7 @@ function generateDomainHTML(domain, icon, name, counts, isTemperature = false) {
87096
87101
  <div class="myio-contract-summary-tooltip__domain ${expandedClass}" data-domain="${domain}">
87097
87102
  <div class="myio-contract-summary-tooltip__domain-header" data-toggle-domain="${domain}">
87098
87103
  <div class="myio-contract-summary-tooltip__domain-info">
87099
- <span class="myio-contract-summary-tooltip__domain-icon">${icon}</span>
87104
+ <span class="myio-contract-summary-tooltip__domain-icon">${icon2}</span>
87100
87105
  <span class="myio-contract-summary-tooltip__domain-name">${name}</span>
87101
87106
  </div>
87102
87107
  <div style="display: flex; align-items: center; gap: 8px;">
@@ -93236,11 +93241,11 @@ function renderRow(row, level) {
93236
93241
  const pct = row.pct;
93237
93242
  const caret = hasChildren ? `<button class="myio-gbt__caret${open ? " is-open" : ""}" data-caret="${id}" title="Expandir/recolher">\u25B8</button>` : `<span class="myio-gbt__caret-spacer"></span>`;
93238
93243
  const swatch = row.color ? `<span class="myio-gbt__swatch" style="background:${esc6(row.color)}"></span>` : "";
93239
- const icon = row.icon ? `<span class="myio-gbt__icon">${esc6(row.icon)}</span>` : "";
93244
+ const icon2 = row.icon ? `<span class="myio-gbt__icon">${esc6(row.icon)}</span>` : "";
93240
93245
  const chipHtml = row.delta ? renderDeltaChip(row.delta) : "";
93241
93246
  const pctHtml = !row.delta && pct != null && isFinite(pct) ? `<span class="myio-gbt__pct">${esc6(fmtPct3(pct))}</span>` : "";
93242
93247
  const rowClass = level > 0 ? "myio-gbt__row myio-gbt__row--child" : "myio-gbt__row";
93243
- let html = `<div class="${rowClass}">` + caret + swatch + icon + `<span class="myio-gbt__label">${esc6(row.label)}</span><span class="myio-gbt__value">${esc6(row.valueText)}</span>` + chipHtml + pctHtml + `</div>`;
93248
+ let html = `<div class="${rowClass}">` + caret + swatch + icon2 + `<span class="myio-gbt__label">${esc6(row.label)}</span><span class="myio-gbt__value">${esc6(row.valueText)}</span>` + chipHtml + pctHtml + `</div>`;
93244
93249
  if (hasChildren) {
93245
93250
  const childHtml = row.children.map((c) => renderRow(c, level + 1)).join("");
93246
93251
  html += `<div class="myio-gbt__children${open ? " is-open" : ""}" data-children="${id}">${childHtml}</div>`;
@@ -93275,16 +93280,16 @@ function createGoalsBarTooltip(opts) {
93275
93280
  function positionAt(clientX, clientY) {
93276
93281
  const rect = el2.getBoundingClientRect();
93277
93282
  const w = rect.width || 280;
93278
- const h2 = rect.height || 200;
93283
+ const h3 = rect.height || 200;
93279
93284
  const pad = 12;
93280
93285
  const gap = 16;
93281
93286
  let left = clientX + gap;
93282
93287
  let top = clientY + gap;
93283
93288
  if (left + w > window.innerWidth - pad) left = clientX - w - gap;
93284
93289
  if (left < pad) left = Math.max(pad, (window.innerWidth - w) / 2);
93285
- if (top + h2 > window.innerHeight - pad) top = clientY - h2 - gap;
93290
+ if (top + h3 > window.innerHeight - pad) top = clientY - h3 - gap;
93286
93291
  if (top < pad) top = pad;
93287
- if (top + h2 > window.innerHeight - pad) top = Math.max(pad, window.innerHeight - h2 - pad);
93292
+ if (top + h3 > window.innerHeight - pad) top = Math.max(pad, window.innerHeight - h3 - pad);
93288
93293
  el2.style.left = `${Math.round(left)}px`;
93289
93294
  el2.style.top = `${Math.round(top)}px`;
93290
93295
  }
@@ -93524,13 +93529,13 @@ function _buildDayBoundaries(startISO, endISO) {
93524
93529
  }
93525
93530
  function _buildHourBoundaries(dateISO) {
93526
93531
  const result = [];
93527
- for (let h2 = 0; h2 < 24; h2++) {
93532
+ for (let h3 = 0; h3 < 24; h3++) {
93528
93533
  const start = /* @__PURE__ */ new Date(`${dateISO}T00:00:00`);
93529
- start.setHours(h2, 0, 0, 0);
93534
+ start.setHours(h3, 0, 0, 0);
93530
93535
  const end = new Date(start);
93531
- end.setHours(h2, 59, 59, 999);
93536
+ end.setHours(h3, 59, 59, 999);
93532
93537
  result.push({
93533
- label: `${String(h2).padStart(2, "0")}h`,
93538
+ label: `${String(h3).padStart(2, "0")}h`,
93534
93539
  startTs: start.getTime(),
93535
93540
  endTs: end.getTime()
93536
93541
  });
@@ -96905,7 +96910,7 @@ var MODE_DEFAULTS = {
96905
96910
  }
96906
96911
  };
96907
96912
  function mixHex2(hexA, hexB, pctB) {
96908
- const n = (h2) => parseInt(h2.slice(1), 16);
96913
+ const n = (h3) => parseInt(h3.slice(1), 16);
96909
96914
  const a = n(hexA);
96910
96915
  const b = n(hexB);
96911
96916
  const ch = (sa, sb) => Math.round(sa + (sb - sa) * pctB);
@@ -97851,11 +97856,11 @@ var TariffApiClient = class {
97851
97856
  this.basePath = config2.basePath ?? "api/v1";
97852
97857
  }
97853
97858
  authHeaders() {
97854
- const h2 = {};
97855
- if (this.cfg.apiKey) h2["X-API-Key"] = this.cfg.apiKey;
97856
- if (this.cfg.jwt) h2["Authorization"] = `Bearer ${this.cfg.jwt}`;
97857
- if (this.cfg.tenantId) h2["X-Tenant-Id"] = this.cfg.tenantId;
97858
- return h2;
97859
+ const h3 = {};
97860
+ if (this.cfg.apiKey) h3["X-API-Key"] = this.cfg.apiKey;
97861
+ if (this.cfg.jwt) h3["Authorization"] = `Bearer ${this.cfg.jwt}`;
97862
+ if (this.cfg.tenantId) h3["X-Tenant-Id"] = this.cfg.tenantId;
97863
+ return h3;
97859
97864
  }
97860
97865
  /** Read the tariff tree. `granularity` defaults to `day` server-side. */
97861
97866
  async getTariff(sel, granularity = "hour") {
@@ -98117,7 +98122,7 @@ function bandToPanelEntry(band, customerId) {
98117
98122
  function expandDayToHourBuckets(date, price) {
98118
98123
  assertValidCivilDate(date);
98119
98124
  const out = [];
98120
- for (let h2 = 0; h2 < 24; h2++) out.push({ level: "HOUR", ref: `${date}T${pad23(h2)}`, price });
98125
+ for (let h3 = 0; h3 < 24; h3++) out.push({ level: "HOUR", ref: `${date}T${pad23(h3)}`, price });
98121
98126
  return out;
98122
98127
  }
98123
98128
  function expandBandHours(date, startHour, endHour, price) {
@@ -98126,7 +98131,7 @@ function expandBandHours(date, startHour, endHour, price) {
98126
98131
  throw new Error(`Invalid hour band ${startHour}-${endHour} for ${date}`);
98127
98132
  }
98128
98133
  const out = [];
98129
- for (let h2 = startHour; h2 <= endHour; h2++) out.push({ level: "HOUR", ref: `${date}T${pad23(h2)}`, price });
98134
+ for (let h3 = startHour; h3 <= endHour; h3++) out.push({ level: "HOUR", ref: `${date}T${pad23(h3)}`, price });
98130
98135
  return out;
98131
98136
  }
98132
98137
  function bandDateBounds(band) {
@@ -98176,12 +98181,12 @@ function expandBandToHourBucketsByYear(band) {
98176
98181
  function collapseHoursToBands(date, hours, dims) {
98177
98182
  const sorted = [...hours].sort((a, b) => a.hour - b.hour);
98178
98183
  const runs = [];
98179
- for (const h2 of sorted) {
98184
+ for (const h3 of sorted) {
98180
98185
  const cur = runs[runs.length - 1];
98181
- if (cur && h2.hour === cur.endHour + 1 && h2.price === cur.price) {
98182
- cur.endHour = h2.hour;
98186
+ if (cur && h3.hour === cur.endHour + 1 && h3.price === cur.price) {
98187
+ cur.endHour = h3.hour;
98183
98188
  } else {
98184
- runs.push({ startHour: h2.hour, endHour: h2.hour, price: h2.price });
98189
+ runs.push({ startHour: h3.hour, endHour: h3.hour, price: h3.price });
98185
98190
  }
98186
98191
  }
98187
98192
  return runs.map(
@@ -98201,13 +98206,13 @@ function dayNodeToHours(node) {
98201
98206
  const hourly = node.hourly || {};
98202
98207
  const hourKeys = Object.keys(hourly);
98203
98208
  if (hourKeys.length === 0) {
98204
- return dayPrice != null ? Array.from({ length: 24 }, (_, h2) => ({ hour: h2, price: dayPrice })) : null;
98209
+ return dayPrice != null ? Array.from({ length: 24 }, (_, h3) => ({ hour: h3, price: dayPrice })) : null;
98205
98210
  }
98206
98211
  const out = [];
98207
- for (let h2 = 0; h2 < 24; h2++) {
98208
- const ov = hourly[String(h2)];
98212
+ for (let h3 = 0; h3 < 24; h3++) {
98213
+ const ov = hourly[String(h3)];
98209
98214
  const price = ov && typeof ov.price === "string" ? ov.price : dayPrice;
98210
- if (price != null) out.push({ hour: h2, price });
98215
+ if (price != null) out.push({ hour: h3, price });
98211
98216
  }
98212
98217
  return out.length ? out : null;
98213
98218
  }
@@ -98994,11 +98999,11 @@ var GoalsMoneyClient = class {
98994
98999
  this.basePath = config2.basePath ?? "api/v1";
98995
99000
  }
98996
99001
  authHeaders() {
98997
- const h2 = {};
98998
- if (this.cfg.apiKey) h2["X-API-Key"] = this.cfg.apiKey;
98999
- if (this.cfg.jwt) h2["Authorization"] = `Bearer ${this.cfg.jwt}`;
99000
- if (this.cfg.tenantId) h2["X-Tenant-Id"] = this.cfg.tenantId;
99001
- return h2;
99002
+ const h3 = {};
99003
+ if (this.cfg.apiKey) h3["X-API-Key"] = this.cfg.apiKey;
99004
+ if (this.cfg.jwt) h3["Authorization"] = `Bearer ${this.cfg.jwt}`;
99005
+ if (this.cfg.tenantId) h3["X-Tenant-Id"] = this.cfg.tenantId;
99006
+ return h3;
99002
99007
  }
99003
99008
  goalsPath(sel) {
99004
99009
  return `/customers/${encodeURIComponent(sel.customerId)}/goals`;
@@ -103905,14 +103910,14 @@ function renderLojasStep3(state6, modalId, colors2, t) {
103905
103910
  }
103906
103911
  function renderAttrRow(key, value, readonly, suggestion, colors2, modalId, t, isFetchable = false, helpText) {
103907
103912
  const hasValue = value !== null && value !== void 0 && value !== "";
103908
- const icon = hasValue ? "\u2705" : "\u26A0\uFE0F";
103913
+ const icon2 = hasValue ? "\u2705" : "\u26A0\uFE0F";
103909
103914
  const inputBorder = hasValue ? colors2.border : colors2.warning;
103910
103915
  return `
103911
103916
  <div style="
103912
103917
  display: flex; align-items: center; gap: 12px;
103913
103918
  padding: 12px 16px; border-bottom: 1px solid ${colors2.border};
103914
103919
  ">
103915
- <span style="font-size: 16px;">${icon}</span>
103920
+ <span style="font-size: 16px;">${icon2}</span>
103916
103921
  <span style="width: 110px; font-size: 13px; color: ${colors2.textMuted}; font-weight: 500; display: flex; align-items: center; gap: 4px;">
103917
103922
  ${key}
103918
103923
  ${helpText ? `<span title="${helpText}" style="cursor: help; font-size: 12px; color: ${colors2.primary};">\u2139\uFE0F</span>` : ""}
@@ -103947,7 +103952,7 @@ function renderAttrRow(key, value, readonly, suggestion, colors2, modalId, t, is
103947
103952
  }
103948
103953
  function renderDeviceTypeSelect(value, suggested, colors2, modalId, t) {
103949
103954
  const hasValue = !!value;
103950
- const icon = hasValue ? "\u2705" : "\u26A0\uFE0F";
103955
+ const icon2 = hasValue ? "\u2705" : "\u26A0\uFE0F";
103951
103956
  const options = [
103952
103957
  "3F_MEDIDOR",
103953
103958
  "HIDROMETRO",
@@ -103966,7 +103971,7 @@ function renderDeviceTypeSelect(value, suggested, colors2, modalId, t) {
103966
103971
  display: flex; align-items: center; gap: 12px;
103967
103972
  padding: 12px 16px; border-bottom: 1px solid ${colors2.border};
103968
103973
  ">
103969
- <span style="font-size: 16px;">${icon}</span>
103974
+ <span style="font-size: 16px;">${icon2}</span>
103970
103975
  <span style="width: 110px; font-size: 13px; color: ${colors2.textMuted}; font-weight: 500;">deviceType</span>
103971
103976
  <div style="flex: 1;">
103972
103977
  <select id="${modalId}-deviceType" style="
@@ -103992,7 +103997,7 @@ function renderDeviceTypeSelect(value, suggested, colors2, modalId, t) {
103992
103997
  }
103993
103998
  function renderDeviceProfileSelect(deviceType, value, colors2, modalId) {
103994
103999
  const hasValue = !!value;
103995
- const icon = hasValue ? "\u2705" : "\u26A0\uFE0F";
104000
+ const icon2 = hasValue ? "\u2705" : "\u26A0\uFE0F";
103996
104001
  const profiles = getSuggestedProfiles(deviceType);
103997
104002
  const helpText = "IMPORTANTE: deviceType + deviceProfile definem o tipo do device. Se ambos = 3F_MEDIDOR \u2192 device \xE9 LOJA (energia). Se ambos = HIDROMETRO \u2192 device \xE9 LOJA (\xE1gua).";
103998
104003
  return `
@@ -104000,7 +104005,7 @@ function renderDeviceProfileSelect(deviceType, value, colors2, modalId) {
104000
104005
  display: flex; align-items: center; gap: 12px;
104001
104006
  padding: 12px 16px; border-bottom: 1px solid ${colors2.border};
104002
104007
  ">
104003
- <span style="font-size: 16px;">${icon}</span>
104008
+ <span style="font-size: 16px;">${icon2}</span>
104004
104009
  <span style="width: 110px; font-size: 13px; color: ${colors2.textMuted}; font-weight: 500; display: flex; align-items: center; gap: 4px;">
104005
104010
  deviceProfile
104006
104011
  <span title="${helpText}" style="cursor: help; font-size: 12px; color: ${colors2.primary};">\u2139\uFE0F</span>
@@ -104021,7 +104026,7 @@ function renderDeviceProfileSelect(deviceType, value, colors2, modalId) {
104021
104026
  }
104022
104027
  function renderEntityLabelRow(currentLabel, deviceName, colors2, modalId, t) {
104023
104028
  const hasValue = !!currentLabel;
104024
- const icon = hasValue ? "\u2705" : "\u26A0\uFE0F";
104029
+ const icon2 = hasValue ? "\u2705" : "\u26A0\uFE0F";
104025
104030
  const suggestedValue = currentLabel || deviceName;
104026
104031
  const helpText = "Etiqueta do dispositivo (entityLabel) - aparece no nome exibido da entidade no ThingsBoard";
104027
104032
  return `
@@ -104029,7 +104034,7 @@ function renderEntityLabelRow(currentLabel, deviceName, colors2, modalId, t) {
104029
104034
  display: flex; align-items: center; gap: 12px;
104030
104035
  padding: 12px 16px; border-bottom: 1px solid ${colors2.border};
104031
104036
  ">
104032
- <span style="font-size: 16px;">${icon}</span>
104037
+ <span style="font-size: 16px;">${icon2}</span>
104033
104038
  <span style="width: 110px; font-size: 13px; color: ${colors2.textMuted}; font-weight: 500; display: flex; align-items: center; gap: 4px;">
104034
104039
  etiqueta
104035
104040
  <span title="${helpText}" style="cursor: help; font-size: 12px; color: ${colors2.primary};">\u2139\uFE0F</span>
@@ -104303,8 +104308,8 @@ async function openClearGcdrIdsModal(state6) {
104303
104308
  </div>
104304
104309
  </div>`;
104305
104310
  }
104306
- function keyBadges(present, keys) {
104307
- return keys.filter((k) => present[k]).map((k) => `<span style="font-size:9px; background:rgba(220,38,38,0.25); color:#fca5a5; padding:1px 5px; border-radius:3px; margin:1px; display:inline-block;">${k}</span>`).join("");
104311
+ function keyBadges(present2, keys) {
104312
+ return keys.filter((k) => present2[k]).map((k) => `<span style="font-size:9px; background:rgba(220,38,38,0.25); color:#fca5a5; padding:1px 5px; border-radius:3px; margin:1px; display:inline-block;">${k}</span>`).join("");
104308
104313
  }
104309
104314
  function tableHtml(rows, keys) {
104310
104315
  if (rows.length === 0) return '<div style="font-size:12px;color:#6b7280;padding:6px 0;">Nenhum item a limpar.</div>';
@@ -104365,13 +104370,13 @@ async function openClearGcdrIdsModal(state6) {
104365
104370
  await Promise.all(chunks[ci].map(async (entity) => {
104366
104371
  const tbId = entity.id?.id || "";
104367
104372
  const name = entity.name || entity.label || tbId;
104368
- let present = {};
104373
+ let present2 = {};
104369
104374
  try {
104370
104375
  const attrs = await fetchAttrs(tbId);
104371
- for (const k of keysToCheck) present[k] = attrs[k] != null && attrs[k] !== "";
104376
+ for (const k of keysToCheck) present2[k] = attrs[k] != null && attrs[k] !== "";
104372
104377
  } catch {
104373
104378
  }
104374
- targetRows.push({ tbId, name, entityType, present, hasAny: keysToCheck.some((k) => present[k]) });
104379
+ targetRows.push({ tbId, name, entityType, present: present2, hasAny: keysToCheck.some((k) => present2[k]) });
104375
104380
  }));
104376
104381
  const done = deviceRows.length + assetRows.length;
104377
104382
  const bodyEl = overlay.querySelector("#gcdr-clear-body");
@@ -107781,6 +107786,2089 @@ function openGenericModal(params) {
107781
107786
  };
107782
107787
  }
107783
107788
 
107789
+ // src/components/myio-gcdr-login/dom.ts
107790
+ function h2(doc, tag, attrs = {}, ...children) {
107791
+ const el2 = doc.createElement(tag);
107792
+ for (const [k, v] of Object.entries(attrs)) {
107793
+ if (v === null || v === void 0 || v === false) continue;
107794
+ if (k === "class") el2.className = String(v);
107795
+ else if (k === "text") el2.textContent = String(v);
107796
+ else el2.setAttribute(k, v === true ? "" : String(v));
107797
+ }
107798
+ for (const c of children) {
107799
+ if (c === null || c === void 0 || c === false) continue;
107800
+ el2.appendChild(typeof c === "string" ? doc.createTextNode(c) : c);
107801
+ }
107802
+ return el2;
107803
+ }
107804
+ function icon(doc, markup, cls) {
107805
+ const span = doc.createElement("span");
107806
+ if (cls) span.className = cls;
107807
+ span.setAttribute("aria-hidden", "true");
107808
+ span.innerHTML = markup;
107809
+ return span;
107810
+ }
107811
+ function safeCall(label, fn, ...args) {
107812
+ if (!fn) return;
107813
+ try {
107814
+ const r = fn(...args);
107815
+ if (r && typeof r.catch === "function") {
107816
+ r.catch(() => console.error(`[MYIO Login] ${label} failed`));
107817
+ }
107818
+ } catch {
107819
+ console.error(`[MYIO Login] ${label} failed`);
107820
+ }
107821
+ }
107822
+ function storageGet(key) {
107823
+ try {
107824
+ return typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
107825
+ } catch {
107826
+ return null;
107827
+ }
107828
+ }
107829
+ function storageSet(key, value) {
107830
+ try {
107831
+ if (typeof localStorage === "undefined") return;
107832
+ if (value === null) localStorage.removeItem(key);
107833
+ else localStorage.setItem(key, value);
107834
+ } catch {
107835
+ }
107836
+ }
107837
+ function prefersDark() {
107838
+ try {
107839
+ return typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: dark)").matches;
107840
+ } catch {
107841
+ return false;
107842
+ }
107843
+ }
107844
+ function isCoarsePointer() {
107845
+ try {
107846
+ return typeof matchMedia === "function" && matchMedia("(pointer: coarse)").matches;
107847
+ } catch {
107848
+ return false;
107849
+ }
107850
+ }
107851
+
107852
+ // src/components/myio-gcdr-login/icons.ts
107853
+ var svg = (body, size = 16) => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${body}</svg>`;
107854
+ var ICONS = {
107855
+ eye: (s) => svg('<path d="M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0"/><circle cx="12" cy="12" r="3"/>', s),
107856
+ eyeOff: (s) => svg('<path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c4.97 0 8.9 3.12 10 7a10.7 10.7 0 0 1-1.67 3.13"/><path d="M14.08 14.16a3 3 0 1 1-4.24-4.24"/><path d="M17.48 17.5A10.7 10.7 0 0 1 12 19c-4.97 0-8.9-3.12-10-7a10.7 10.7 0 0 1 4.52-5.5"/><path d="m2 2 20 20"/>', s),
107857
+ lock: (s) => svg('<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>', s),
107858
+ shieldAlert: (s) => svg('<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="M12 8v4"/><path d="M12 16h.01"/>', s),
107859
+ alert: (s) => svg('<circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/>', s),
107860
+ info: (s) => svg('<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>', s),
107861
+ sun: (s) => svg('<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>', s),
107862
+ moon: (s) => svg('<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>', s),
107863
+ globe: (s) => svg('<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>', s),
107864
+ x: (s) => svg('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>', s),
107865
+ arrowLeft: (s) => svg('<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>', s),
107866
+ chevronRight: (s) => svg('<path d="m9 18 6-6-6-6"/>', s),
107867
+ external: (s) => svg('<path d="M7 7h10v10"/><path d="M7 17 17 7"/>', s),
107868
+ book: (s) => svg('<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/>', s),
107869
+ headset: (s) => svg('<path d="M3 11h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Zm0 0a9 9 0 1 1 18 0m0 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3Z"/><path d="M21 16v2a4 4 0 0 1-4 4h-5"/>', s),
107870
+ plug: (s) => svg('<path d="M12 22v-5"/><path d="M9 8V2"/><path d="M15 8V2"/><path d="M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z"/>', s),
107871
+ grid: (s) => svg('<rect width="7" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="14" y="3" rx="1"/><rect width="7" height="7" x="14" y="14" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/>', s),
107872
+ building: (s) => svg('<rect width="16" height="20" x="4" y="2" rx="2" ry="2"/><path d="M9 22v-4h6v4"/><path d="M8 6h.01"/><path d="M16 6h.01"/><path d="M12 6h.01"/><path d="M12 10h.01"/><path d="M12 14h.01"/><path d="M16 10h.01"/><path d="M16 14h.01"/><path d="M8 10h.01"/><path d="M8 14h.01"/>', s),
107873
+ activity: (s) => svg('<path d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"/>', s),
107874
+ spinner: (s) => svg('<path d="M21 12a9 9 0 1 1-6.219-8.56"/>', s)
107875
+ };
107876
+
107877
+ // src/components/myio-gcdr-login/about.ts
107878
+ var CATEGORIES = [
107879
+ { key: "wiki", icon: "book", items: [
107880
+ { key: "wikiHome", to: "/wiki/p", web: true },
107881
+ { key: "wikiSearch", to: "/wiki/p/search", web: true },
107882
+ { key: "accountGuide", to: "/wiki/p/User-Guides/acesso-a-conta", web: true }
107883
+ ] },
107884
+ { key: "support", icon: "headset", items: [
107885
+ { key: "openTicket", to: "/support", web: true },
107886
+ { key: "forgotPassword", to: "/forgot-password", web: true }
107887
+ ] },
107888
+ { key: "integrations", icon: "plug", items: [
107889
+ { key: "docsAlarms", to: "https://alarms-api.a.myio-bas.com/docs" },
107890
+ { key: "docsGcdr", to: "https://gcdr-api.a.myio-bas.com/docs/" },
107891
+ { key: "docsIngestion", to: "https://api.data.apps.myio-bas.com/api/docs/" },
107892
+ { key: "docsThingsboard", to: "https://dashboard.myio-bas.com/swagger-ui/index.html" },
107893
+ { key: "integrationsGuide", to: "/wiki/p/Integrations/index", web: true },
107894
+ { key: "newIntegration", to: "/wiki/p/integrations/new", web: true }
107895
+ ] },
107896
+ { key: "systems", icon: "grid", items: [
107897
+ { key: "app", to: "https://app.apps.myio-bas.com" },
107898
+ { key: "dashboards", to: "https://dashboard.myio-bas.com" },
107899
+ { key: "alarms", to: "https://alarms-web.a.myio-bas.com" }
107900
+ ] },
107901
+ { key: "institutional", icon: "building", items: [
107902
+ { key: "site", to: "https://myio.com.br" },
107903
+ { key: "privacy", to: "https://myio.com.br/politica-de-privacidade" },
107904
+ { key: "terms" }
107905
+ ] },
107906
+ { key: "status", icon: "activity", items: [{ key: "gcdrHealth", health: true }] }
107907
+ ];
107908
+ function defaultSupportHref(webUrl) {
107909
+ return webUrl ? `${webUrl.replace(/\/+$/, "")}/support` : void 0;
107910
+ }
107911
+ function renderAbout(el2, ctx, t, opts) {
107912
+ const doc = el2.ownerDocument;
107913
+ const { body } = ctx.panel({ eyebrow: t("about.eyebrow"), fill: true, logo: false, bandColor: opts.bandColor ?? "#2E8B57" });
107914
+ const web = opts.webUrl?.replace(/\/+$/, "");
107915
+ const visibleCats = CATEGORIES.filter((c) => c.key === "status" ? !!opts.healthUrl : true);
107916
+ let healthAbort = null;
107917
+ const showGrid = () => {
107918
+ body.textContent = "";
107919
+ const title = h2(doc, "h2", { class: "myio-gcdr-about__title" }, `${t("about.title")} `, h2(doc, "em", { text: t("about.titleHighlight") }));
107920
+ const intro = h2(doc, "p", { class: "myio-gcdr-about__intro", text: t("about.text") });
107921
+ const grid = h2(doc, "div", { class: "myio-gcdr-about__grid" });
107922
+ for (const c of visibleCats) {
107923
+ const btn = h2(
107924
+ doc,
107925
+ "button",
107926
+ { type: "button", class: "myio-gcdr-about__tile" },
107927
+ icon(doc, ICONS[c.icon](22), "myio-gcdr-about__tileicon"),
107928
+ h2(doc, "span", { class: "myio-gcdr-about__tiletitle", text: t(`about.cat.${c.key}`) }),
107929
+ h2(doc, "span", { class: "myio-gcdr-about__tiletext", text: t(`about.cat.${c.key}.text`) })
107930
+ );
107931
+ btn.addEventListener("click", () => showCategory(c));
107932
+ grid.appendChild(btn);
107933
+ }
107934
+ body.append(title, intro, grid, h2(doc, "p", { class: "myio-gcdr-about__tagline", text: t("about.tagline") }));
107935
+ };
107936
+ const showCategory = (c) => {
107937
+ body.textContent = "";
107938
+ const back = h2(doc, "button", { type: "button", class: "myio-gcdr-login__link myio-gcdr-about__back" }, icon(doc, ICONS.arrowLeft(14)), ` ${t("about.back")}`);
107939
+ back.addEventListener("click", () => {
107940
+ showGrid();
107941
+ body.querySelector("button")?.focus();
107942
+ });
107943
+ const title = h2(doc, "h2", { class: "myio-gcdr-about__title", text: t(`about.cat.${c.key}`) });
107944
+ const grid = h2(doc, "div", { class: "myio-gcdr-about__grid" });
107945
+ for (const it of c.items) {
107946
+ const label = t(`about.item.${it.key}`);
107947
+ if (it.health) {
107948
+ const dot = h2(doc, "span", { class: "myio-gcdr-about__dot", "data-state": "checking" });
107949
+ const state6 = h2(doc, "span", { class: "myio-gcdr-about__health", role: "status" }, dot, h2(doc, "span", { text: t("about.health.checking") }));
107950
+ grid.appendChild(h2(
107951
+ doc,
107952
+ "div",
107953
+ { class: "myio-gcdr-about__tile", "aria-disabled": "true" },
107954
+ h2(doc, "span", { class: "myio-gcdr-about__tiletitle", text: label }),
107955
+ state6
107956
+ ));
107957
+ checkHealth(dot, state6.lastChild);
107958
+ continue;
107959
+ }
107960
+ const href = it.to ? it.web ? web ? `${web}${it.to}` : void 0 : it.to : void 0;
107961
+ if (it.web && !href) continue;
107962
+ if (!href) {
107963
+ grid.appendChild(h2(
107964
+ doc,
107965
+ "div",
107966
+ { class: "myio-gcdr-about__tile", "aria-disabled": "true" },
107967
+ h2(doc, "span", { class: "myio-gcdr-about__tiletitle", text: label }),
107968
+ h2(doc, "span", { class: "myio-gcdr-about__tiletext", text: t("about.soon") })
107969
+ ));
107970
+ continue;
107971
+ }
107972
+ grid.appendChild(h2(
107973
+ doc,
107974
+ "a",
107975
+ { class: "myio-gcdr-about__tile", href, target: "_blank", rel: "noopener noreferrer" },
107976
+ h2(doc, "span", { class: "myio-gcdr-about__tiletitle", text: label }),
107977
+ h2(doc, "span", { class: "myio-gcdr-about__tiletext" }, `${t("about.open")} `, icon(doc, ICONS.external(12)))
107978
+ ));
107979
+ }
107980
+ body.append(back, title, grid);
107981
+ back.focus();
107982
+ };
107983
+ const checkHealth = (dot, label) => {
107984
+ if (!opts.healthUrl) return;
107985
+ const f = opts.fetchImpl ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : void 0);
107986
+ if (!f) return;
107987
+ healthAbort?.abort();
107988
+ const ac = new AbortController();
107989
+ healthAbort = ac;
107990
+ const timer = setTimeout(() => ac.abort(), 5e3);
107991
+ f(opts.healthUrl, { signal: ac.signal, credentials: "omit" }).then((r) => r.ok).catch(() => false).then((up4) => {
107992
+ clearTimeout(timer);
107993
+ if (ac.signal.aborted && healthAbort !== ac) return;
107994
+ dot.setAttribute("data-state", up4 ? "online" : "offline");
107995
+ label.textContent = t(up4 ? "about.health.online" : "about.health.offline");
107996
+ });
107997
+ };
107998
+ showGrid();
107999
+ return () => healthAbort?.abort();
108000
+ }
108001
+ function renderSignedOutPrompt(el2, ctx, text2) {
108002
+ const doc = el2.ownerDocument;
108003
+ const { body } = ctx.panel({ eyebrow: "", fill: true, logo: false });
108004
+ const band = body.parentElement?.querySelector(".myio-gcdr-panel__band");
108005
+ band?.remove();
108006
+ body.appendChild(
108007
+ h2(
108008
+ doc,
108009
+ "div",
108010
+ { class: "myio-gcdr-prompt" },
108011
+ icon(doc, ICONS.lock(28), "myio-gcdr-prompt__icon"),
108012
+ h2(doc, "p", { class: "myio-gcdr-prompt__text", text: text2 })
108013
+ )
108014
+ );
108015
+ }
108016
+
108017
+ // src/components/myio-gcdr-login/i18n.ts
108018
+ var PT = {
108019
+ "login.eyebrow": "Acesso",
108020
+ "login.title": "Login",
108021
+ "login.email": "E-mail",
108022
+ "login.password": "Senha",
108023
+ "login.rememberMe": "Lembrar de mim",
108024
+ "login.forgotPassword": "Esqueceu a senha?",
108025
+ "login.signIn": "Entrar",
108026
+ "login.signingIn": "Entrando...",
108027
+ "login.noAccount": "N\xE3o tem uma conta?",
108028
+ "login.createAccount": "Criar conta",
108029
+ "login.emailRequired": "Informe o seu e-mail.",
108030
+ "login.emailInvalid": "Informe um e-mail v\xE1lido, como nome@empresa.com.",
108031
+ "login.emailPlaceholder": "nome@empresa.com",
108032
+ // new
108033
+ "login.passwordRequired": "Informe a sua senha.",
108034
+ "login.showPassword": "Mostrar senha",
108035
+ "login.hidePassword": "Ocultar senha",
108036
+ "login.capsLockOn": "Caps Lock est\xE1 ativado.",
108037
+ "login.notYou": "N\xE3o \xE9 voc\xEA?",
108038
+ "login.askAdmin": "Precisa de acesso? Fale com o administrador do sistema.",
108039
+ "login.newTab": "(abre em nova aba)",
108040
+ "login.gcdrWeb": "Entrar pelo GCDR Web",
108041
+ "login.support": "Falar com o suporte",
108042
+ "login.leaving": "Saindo...",
108043
+ "errors.invalidCredentials": "E-mail ou senha inv\xE1lidos",
108044
+ "errors.networkError": "Erro de conex\xE3o. Verifique sua internet.",
108045
+ "errors.loginFailed": "N\xE3o foi poss\xEDvel entrar no momento. Tente novamente em instantes.",
108046
+ "errors.lockedTitle": "Conta bloqueada",
108047
+ "errors.lockedText": "Esta conta foi bloqueada ap\xF3s 6 tentativas de login com senha incorreta (ou por um administrador). Por seguran\xE7a, somente um administrador pode liberar o acesso \u2014 os administradores j\xE1 foram avisados por e-mail.",
108048
+ "errors.attemptsLeft_one": "Senha incorreta \u2014 resta {{count}} tentativa.",
108049
+ "errors.attemptsLeft_other": "Senha incorreta \u2014 restam {{count}} tentativas.",
108050
+ "errors.lastAttempt": "Senha incorreta \u2014 esta \xE9 a sua \xFAltima tentativa.",
108051
+ "errors.lockWarning": "Na 6\xAA senha errada a conta \xE9 bloqueada e s\xF3 um administrador consegue liberar. Se n\xE3o lembra a senha, redefina agora em vez de tentar de novo.",
108052
+ "errors.goToForgot": "Esqueci minha senha \u2014 redefinir agora",
108053
+ "errors.invalidWithAttempts_one": "E-mail ou senha inv\xE1lidos. Resta {{count}} tentativa antes do bloqueio.",
108054
+ "errors.invalidWithAttempts_other": "E-mail ou senha inv\xE1lidos. Restam {{count}} tentativas antes do bloqueio.",
108055
+ "errors.captchaFailed": "N\xE3o foi poss\xEDvel confirmar que voc\xEA n\xE3o \xE9 um rob\xF4. Aguarde a verifica\xE7\xE3o e tente de novo.",
108056
+ // new
108057
+ "errors.tooManyRequests": "Muitas tentativas. Aguarde alguns minutos e tente novamente.",
108058
+ "errors.timeout": "O servidor demorou para responder. Tente novamente.",
108059
+ "errors.integrationError": "N\xE3o foi poss\xEDvel entrar no momento. Tente novamente em instantes.",
108060
+ "errors.mfaUnsupported": "Esta conta exige verifica\xE7\xE3o em duas etapas, ainda n\xE3o dispon\xEDvel nesta tela.",
108061
+ "errors.postLoginFailed": "N\xE3o foi poss\xEDvel concluir a entrada. Tente novamente.",
108062
+ "errors.leaveFailed": "N\xE3o foi poss\xEDvel sair agora. Tente novamente.",
108063
+ "errors.captchaLoadFailed": "N\xE3o foi poss\xEDvel carregar a verifica\xE7\xE3o.",
108064
+ "errors.invalidCredentialsHelp": "Confira o e-mail digitado. Se estiver correto e voc\xEA tiver certeza da senha, sua conta pode ainda n\xE3o estar liberada \u2014 {{who}}.",
108065
+ "errors.helpSupport": "fale com o suporte",
108066
+ "errors.helpAdmin": "fale com o administrador do sistema",
108067
+ "notice.sessionExpired": "Sua sess\xE3o expirou. Por favor, entre novamente.",
108068
+ "notice.sessionExpiredModal": "Sua sess\xE3o expirou. Entre novamente \u2014 esta tela ser\xE1 mantida.",
108069
+ "aside.signedOutPrompt": "Fa\xE7a o login para ter acesso \xE0s funcionalidades.",
108070
+ "about.eyebrow": "Sobre a MYIO",
108071
+ "about.title": "Medi\xE7\xE3o e atua\xE7\xE3o remota",
108072
+ "about.titleHighlight": "IoT",
108073
+ "about.text": "Escolha um assunto para ver o que voc\xEA pode acessar sem entrar na conta.",
108074
+ "about.tagline": "Efici\xEAncia | Seguran\xE7a | Sustentabilidade",
108075
+ "about.health.checking": "Verificando\u2026",
108076
+ "about.health.online": "No ar",
108077
+ "about.health.offline": "Indispon\xEDvel",
108078
+ "about.back": "Voltar",
108079
+ "about.open": "Abrir",
108080
+ "about.soon": "Em breve",
108081
+ "about.cat.wiki": "Wiki",
108082
+ "about.cat.wiki.text": "Base de conhecimento, guias e respostas.",
108083
+ "about.cat.support": "Atendimento",
108084
+ "about.cat.support.text": "Chamados, tickets e d\xFAvidas.",
108085
+ "about.cat.integrations": "Integra\xE7\xF5es",
108086
+ "about.cat.integrations.text": "Documenta\xE7\xE3o das APIs e guias de integra\xE7\xE3o.",
108087
+ "about.cat.systems": "Sistemas",
108088
+ "about.cat.systems.text": "Acesso aos sistemas MYIO.",
108089
+ "about.cat.institutional": "Institucional",
108090
+ "about.cat.institutional.text": "Sobre a MYIO, site, privacidade e termos.",
108091
+ "about.cat.status": "Status",
108092
+ "about.cat.status.text": "Situa\xE7\xE3o dos sistemas agora.",
108093
+ "about.item.wikiHome": "Wiki p\xFAblica",
108094
+ "about.item.wikiSearch": "Buscar na wiki",
108095
+ "about.item.accountGuide": "Acesso \xE0 conta",
108096
+ "about.item.openTicket": "Abrir chamado",
108097
+ "about.item.forgotPassword": "Esqueci minha senha",
108098
+ "about.item.docsAlarms": "Alarms",
108099
+ "about.item.docsGcdr": "GCDR",
108100
+ "about.item.docsIngestion": "Ingestion",
108101
+ "about.item.docsThingsboard": "ThingsBoard",
108102
+ "about.item.integrationsGuide": "Guia de integra\xE7\xF5es",
108103
+ "about.item.newIntegration": "Cadastrar integra\xE7\xE3o",
108104
+ "about.item.app": "App MYIO",
108105
+ "about.item.dashboards": "Dashboards",
108106
+ "about.item.alarms": "Alarmes",
108107
+ "about.item.site": "Site da MYIO",
108108
+ "about.item.privacy": "Privacidade",
108109
+ "about.item.terms": "Termos de servi\xE7o",
108110
+ "about.item.gcdrHealth": "GCDR",
108111
+ "toolbar.toDark": "Usar tema escuro",
108112
+ "toolbar.toLight": "Usar tema claro",
108113
+ "toolbar.language": "Idioma",
108114
+ "modal.close": "Fechar"
108115
+ };
108116
+ var EN = {
108117
+ "login.eyebrow": "Access",
108118
+ "login.title": "Login",
108119
+ "login.email": "Email",
108120
+ "login.password": "Password",
108121
+ "login.rememberMe": "Remember me",
108122
+ "login.forgotPassword": "Forgot password?",
108123
+ "login.signIn": "Sign In",
108124
+ "login.signingIn": "Signing in...",
108125
+ "login.noAccount": "Don't have an account?",
108126
+ "login.createAccount": "Create account",
108127
+ "login.emailRequired": "Enter your e-mail.",
108128
+ "login.emailInvalid": "Enter a valid e-mail, like name@company.com.",
108129
+ "login.emailPlaceholder": "name@company.com",
108130
+ "login.passwordRequired": "Enter your password.",
108131
+ "login.showPassword": "Show password",
108132
+ "login.hidePassword": "Hide password",
108133
+ "login.capsLockOn": "Caps Lock is on.",
108134
+ "login.notYou": "Not you?",
108135
+ "login.askAdmin": "Need access? Contact your system administrator.",
108136
+ "login.newTab": "(opens in a new tab)",
108137
+ "login.gcdrWeb": "Sign in on GCDR Web",
108138
+ "login.support": "Contact support",
108139
+ "login.leaving": "Leaving...",
108140
+ "errors.invalidCredentials": "Invalid e-mail or password",
108141
+ "errors.networkError": "Network error. Please check your connection.",
108142
+ "errors.loginFailed": "Unable to sign in right now. Please try again shortly.",
108143
+ "errors.lockedTitle": "Account locked",
108144
+ "errors.lockedText": "This account was locked after 6 sign-in attempts with a wrong password (or by an administrator). For security, only an administrator can unlock it \u2014 the administrators were already notified by e-mail.",
108145
+ "errors.attemptsLeft_one": "Wrong password \u2014 {{count}} attempt left.",
108146
+ "errors.attemptsLeft_other": "Wrong password \u2014 {{count}} attempts left.",
108147
+ "errors.lastAttempt": "Wrong password \u2014 this is your last attempt.",
108148
+ "errors.lockWarning": "On the 6th wrong password the account is locked and only an administrator can unlock it. If you don't remember the password, reset it now instead of trying again.",
108149
+ "errors.goToForgot": "Forgot my password \u2014 reset now",
108150
+ "errors.invalidWithAttempts_one": "Invalid e-mail or password. {{count}} attempt left before the lock.",
108151
+ "errors.invalidWithAttempts_other": "Invalid e-mail or password. {{count}} attempts left before the lock.",
108152
+ "errors.captchaFailed": "Could not confirm you are not a robot. Wait for the check and try again.",
108153
+ "errors.tooManyRequests": "Too many attempts. Wait a few minutes and try again.",
108154
+ "errors.timeout": "The server took too long to answer. Please try again.",
108155
+ "errors.integrationError": "Unable to sign in right now. Please try again shortly.",
108156
+ "errors.mfaUnsupported": "This account requires two-step verification, not yet available on this screen.",
108157
+ "errors.postLoginFailed": "Could not finish signing in. Please try again.",
108158
+ "errors.leaveFailed": "Could not leave right now. Please try again.",
108159
+ "errors.captchaLoadFailed": "Could not load the verification.",
108160
+ "errors.invalidCredentialsHelp": "Check the e-mail you typed. If it is right and you are sure of the password, your account may not be enabled yet \u2014 {{who}}.",
108161
+ "errors.helpSupport": "contact support",
108162
+ "errors.helpAdmin": "contact your system administrator",
108163
+ "notice.sessionExpired": "Your session has expired. Please sign in again.",
108164
+ "notice.sessionExpiredModal": "Your session has expired. Sign in again \u2014 this screen will be kept.",
108165
+ "aside.signedOutPrompt": "Sign in to access the features.",
108166
+ "about.eyebrow": "About MYIO",
108167
+ "about.title": "Remote metering and control",
108168
+ "about.titleHighlight": "IoT",
108169
+ "about.text": "Pick a subject to see what you can reach without signing in.",
108170
+ "about.tagline": "Efficiency | Safety | Sustainability",
108171
+ "about.health.checking": "Checking\u2026",
108172
+ "about.health.online": "Up",
108173
+ "about.health.offline": "Unavailable",
108174
+ "about.back": "Back",
108175
+ "about.open": "Open",
108176
+ "about.soon": "Coming soon",
108177
+ "about.cat.wiki": "Wiki",
108178
+ "about.cat.wiki.text": "Knowledge base, guides and answers.",
108179
+ "about.cat.support": "Support",
108180
+ "about.cat.support.text": "Tickets and questions.",
108181
+ "about.cat.integrations": "Integrations",
108182
+ "about.cat.integrations.text": "API documentation and integration guides.",
108183
+ "about.cat.systems": "Systems",
108184
+ "about.cat.systems.text": "Access to the MYIO systems.",
108185
+ "about.cat.institutional": "About us",
108186
+ "about.cat.institutional.text": "About MYIO, website, privacy and terms.",
108187
+ "about.cat.status": "Status",
108188
+ "about.cat.status.text": "How the systems are right now.",
108189
+ "about.item.wikiHome": "Public wiki",
108190
+ "about.item.wikiSearch": "Search the wiki",
108191
+ "about.item.accountGuide": "Account access",
108192
+ "about.item.openTicket": "Open a ticket",
108193
+ "about.item.forgotPassword": "Forgot my password",
108194
+ "about.item.docsAlarms": "Alarms",
108195
+ "about.item.docsGcdr": "GCDR",
108196
+ "about.item.docsIngestion": "Ingestion",
108197
+ "about.item.docsThingsboard": "ThingsBoard",
108198
+ "about.item.integrationsGuide": "Integrations guide",
108199
+ "about.item.newIntegration": "Submit an integration",
108200
+ "about.item.app": "MYIO App",
108201
+ "about.item.dashboards": "Dashboards",
108202
+ "about.item.alarms": "Alarms",
108203
+ "about.item.site": "MYIO website",
108204
+ "about.item.privacy": "Privacy",
108205
+ "about.item.terms": "Terms of service",
108206
+ "about.item.gcdrHealth": "GCDR",
108207
+ "toolbar.toDark": "Use dark theme",
108208
+ "toolbar.toLight": "Use light theme",
108209
+ "toolbar.language": "Language",
108210
+ "modal.close": "Close"
108211
+ };
108212
+ var DICTIONARIES = { "pt-BR": PT, en: EN };
108213
+ function interpolate(text2, vars) {
108214
+ if (!vars) return text2;
108215
+ return text2.replace(/\{\{(\w+)\}\}/g, (_m, k) => vars[k] != null ? String(vars[k]) : "");
108216
+ }
108217
+ function translate(locale, key, vars, overrides) {
108218
+ let k = key;
108219
+ if (vars && typeof vars.count === "number") {
108220
+ const cat = new Intl.PluralRules(locale).select(vars.count);
108221
+ k = `${key}_${cat === "one" ? "one" : "other"}`;
108222
+ }
108223
+ const text2 = overrides?.[locale]?.[k] ?? DICTIONARIES[locale][k] ?? overrides?.["pt-BR"]?.[k] ?? DICTIONARIES["pt-BR"][k] ?? k;
108224
+ return interpolate(text2, vars);
108225
+ }
108226
+ function localize(value, locale) {
108227
+ if (value == null) return "";
108228
+ if (typeof value === "string") return value;
108229
+ return value[locale] ?? value["pt-BR"] ?? value.en ?? "";
108230
+ }
108231
+ function detectLocale(stored) {
108232
+ if (stored === "pt-BR" || stored === "en") return stored;
108233
+ const nav = typeof navigator !== "undefined" ? navigator.language || "" : "";
108234
+ return nav.toLowerCase().startsWith("en") ? "en" : "pt-BR";
108235
+ }
108236
+
108237
+ // src/components/myio-gcdr-login/styles.ts
108238
+ var STYLE_VERSION = "1";
108239
+ var STYLE_ATTR = "data-myio-gcdr-version";
108240
+ var REFS_ATTR = "data-myio-gcdr-refs";
108241
+ var FONT_ID = "myio-gcdr-font-nunito";
108242
+ var CSS3 = `
108243
+ .myio-gcdr-shell, .myio-gcdr-overlay {
108244
+ --myio-gcdr-accent: #6B4ABF;
108245
+ --myio-gcdr-accent-hover: #5A3CA8;
108246
+ --myio-gcdr-card: #FBFAFE;
108247
+ --myio-gcdr-ring: #E1DAF4;
108248
+ --myio-gcdr-title: #1E1B2E;
108249
+ --myio-gcdr-text: #55506A;
108250
+ --myio-gcdr-footer: #F0ECFA;
108251
+ --myio-gcdr-input: #FFFFFF;
108252
+ --myio-gcdr-input-border: #D1D5DB;
108253
+ --myio-gcdr-link: #6B4ABF;
108254
+ --myio-gcdr-pill: rgba(255,255,255,0.70);
108255
+ --myio-gcdr-aside-band: #2E8B57;
108256
+ box-sizing: border-box;
108257
+ font-family: 'Nunito', ui-sans-serif, system-ui, sans-serif;
108258
+ line-height: 1.5;
108259
+ color: var(--myio-gcdr-title);
108260
+ -webkit-font-smoothing: antialiased;
108261
+ }
108262
+ .myio-gcdr-shell[data-theme="dark"], .myio-gcdr-overlay[data-theme="dark"] {
108263
+ --myio-gcdr-card: #1E1A2E;
108264
+ --myio-gcdr-ring: #3A3158;
108265
+ --myio-gcdr-title: #FFFFFF;
108266
+ --myio-gcdr-text: #D1D5DB;
108267
+ --myio-gcdr-footer: #251F3A;
108268
+ --myio-gcdr-input: #2B2440;
108269
+ --myio-gcdr-input-border: #3A3158;
108270
+ --myio-gcdr-link: #B9A5F0;
108271
+ --myio-gcdr-pill: rgba(43,36,64,0.80);
108272
+ }
108273
+ .myio-gcdr-shell [hidden], .myio-gcdr-overlay [hidden] { display: none !important; }
108274
+ .myio-gcdr-shell *, .myio-gcdr-shell *::before, .myio-gcdr-shell *::after,
108275
+ .myio-gcdr-overlay *, .myio-gcdr-overlay *::before, .myio-gcdr-overlay *::after { box-sizing: border-box; }
108276
+
108277
+ /* \u2500\u2500 Shell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
108278
+ .myio-gcdr-shell {
108279
+ position: relative; min-height: 100%; width: 100%;
108280
+ display: flex; flex-direction: column; align-items: center;
108281
+ padding: 16px; isolation: isolate;
108282
+ }
108283
+ .myio-gcdr-shell__wallpaper {
108284
+ position: absolute; inset: 0; z-index: -1; overflow: hidden;
108285
+ background-color: #EEEAF8;
108286
+ background-image: var(--myio-gcdr-wp, none), linear-gradient(180deg, #DCD2F3 0%, #EEEAF8 45%, #F7F5FC 100%);
108287
+ background-position: center; background-size: cover; background-repeat: no-repeat;
108288
+ }
108289
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-shell__wallpaper {
108290
+ background-color: #15121F;
108291
+ background-image: var(--myio-gcdr-wp, none), linear-gradient(180deg, #1B1530 0%, #15121F 45%, #111827 100%);
108292
+ }
108293
+ .myio-gcdr-shell__wallpaper::before { content: ''; position: absolute; inset: 0;
108294
+ background: rgba(255,255,255,0.22); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
108295
+ .myio-gcdr-shell__wallpaper::after { content: ''; position: absolute; inset: 0;
108296
+ background: linear-gradient(135deg, rgba(107,74,191,0.34) 0%, rgba(107,74,191,0.14) 50%, rgba(107,74,191,0.34) 100%); }
108297
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-shell__wallpaper::before { background: rgba(255,255,255,0.05); }
108298
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-shell__wallpaper::after {
108299
+ background: linear-gradient(135deg, rgba(45,22,105,0.55) 0%, rgba(27,21,48,0.30) 50%, rgba(45,22,105,0.55) 100%); }
108300
+
108301
+ .myio-gcdr-shell__top { width: 100%; }
108302
+ .myio-gcdr-shell__block { width: 100%; max-width: 28rem; margin: auto 0; display: flex; flex-direction: column; }
108303
+ .myio-gcdr-shell[data-size="lg"] .myio-gcdr-shell__block { max-width: 32rem; }
108304
+ .myio-gcdr-shell[data-size="xl"] .myio-gcdr-shell__block { max-width: 37rem; }
108305
+ @media (min-width: 1024px) {
108306
+ .myio-gcdr-shell[data-has-aside="true"] .myio-gcdr-shell__block { max-width: 72rem; }
108307
+ }
108308
+ .myio-gcdr-shell[data-width="cockpit"] .myio-gcdr-shell__block { max-width: 28rem; }
108309
+ @media (min-width: 640px) { .myio-gcdr-shell[data-width="cockpit"] .myio-gcdr-shell__block { max-width: 42rem; } }
108310
+ @media (min-width: 1024px) { .myio-gcdr-shell[data-width="cockpit"] .myio-gcdr-shell__block { max-width: 1800px; padding: 0 12px; } }
108311
+
108312
+ .myio-gcdr-shell__toprow { display: flex; justify-content: flex-end; margin-bottom: 12px; }
108313
+ .myio-gcdr-shell__pill {
108314
+ display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; justify-content: flex-end;
108315
+ border-radius: 9999px; background: var(--myio-gcdr-pill); padding: 4px 8px;
108316
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
108317
+ }
108318
+ .myio-gcdr-shell__iconbtn {
108319
+ display: inline-flex; align-items: center; gap: 6px; min-height: 36px; min-width: 36px; justify-content: center;
108320
+ border: 0; background: transparent; color: var(--myio-gcdr-text); border-radius: 8px; padding: 6px 10px;
108321
+ font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
108322
+ }
108323
+ .myio-gcdr-shell__iconbtn:hover { background: rgba(107,74,191,0.10); color: var(--myio-gcdr-title); }
108324
+ .myio-gcdr-shell__iconbtn:focus-visible { outline: 2px solid var(--myio-gcdr-accent); outline-offset: 2px; }
108325
+
108326
+ .myio-gcdr-shell__split { display: flex; flex-direction: column; gap: 24px; }
108327
+ @media (min-width: 1024px) {
108328
+ .myio-gcdr-shell__split { flex-direction: row; align-items: stretch; }
108329
+ .myio-gcdr-shell[data-has-aside="true"] .myio-gcdr-shell__split { height: clamp(600px, calc(100vh - 10rem), 880px); }
108330
+ .myio-gcdr-shell__aside { flex: 1 1 0; min-width: 0; display: flex; }
108331
+ .myio-gcdr-shell[data-has-aside="true"] .myio-gcdr-shell__main { flex: 0 0 28rem; }
108332
+ .myio-gcdr-shell[data-width="cockpit"][data-has-aside="true"] .myio-gcdr-shell__main { flex: 1 1 0; }
108333
+ }
108334
+ .myio-gcdr-shell__main { display: flex; min-width: 0; min-height: 0; }
108335
+ .myio-gcdr-shell__main > * { flex: 1 1 auto; min-width: 0; }
108336
+ @media (max-width: 1023.98px) {
108337
+ .myio-gcdr-shell[data-aside-compact="hide"] .myio-gcdr-shell__aside { display: none; }
108338
+ .myio-gcdr-shell[data-aside-compact="stack"] .myio-gcdr-shell__aside { order: 2; display: flex; }
108339
+ }
108340
+ .myio-gcdr-shell__aside[hidden], .myio-gcdr-shell__below[hidden], .myio-gcdr-shell__top[hidden] { display: none !important; }
108341
+ .myio-gcdr-shell__below { margin-top: 16px; text-align: center; }
108342
+ .myio-gcdr-shell__build { display: inline-block; font-size: 12px; color: #55506A; border-radius: 9999px;
108343
+ background: var(--myio-gcdr-pill); padding: 4px 12px; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
108344
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-shell__build { color: #E5E7EB; }
108345
+ .myio-gcdr-shell__slot:focus { outline: none; }
108346
+ .myio-gcdr-sr { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
108347
+
108348
+ /* \u2500\u2500 Card panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
108349
+ .myio-gcdr-panel {
108350
+ display: flex; flex-direction: column; overflow: hidden; width: 100%;
108351
+ border-radius: 16px; background: var(--myio-gcdr-card);
108352
+ box-shadow: 0 18px 50px rgba(40,20,90,0.30), 0 0 0 1px var(--myio-gcdr-ring);
108353
+ }
108354
+ .myio-gcdr-panel[data-fill="true"] { height: 100%; }
108355
+ .myio-gcdr-panel__band {
108356
+ position: relative; display: flex; flex-shrink: 0; align-items: center; justify-content: space-between; gap: 16px;
108357
+ height: 68px; padding: 0 32px; background: var(--myio-gcdr-band, var(--myio-gcdr-accent));
108358
+ }
108359
+ .myio-gcdr-panel__tint { position: absolute; inset: 0; background: var(--myio-gcdr-tint, transparent); pointer-events: none; }
108360
+ .myio-gcdr-panel__eyebrow { position: relative; font-size: 14px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.14em; color: #FFFFFF; }
108361
+ .myio-gcdr-panel__logo { position: relative; height: 28px; width: auto; display: block; }
108362
+ .myio-gcdr-panel__wordmark { position: relative; color: #fff; font-weight: 900; font-size: 20px; letter-spacing: 0.04em; }
108363
+ .myio-gcdr-panel__body { padding: 28px 32px 32px; flex: 1 1 auto; overflow-y: auto; min-height: 0; }
108364
+ .myio-gcdr-panel__title { margin: 0 0 20px; font-size: 26px; font-weight: 800; line-height: 1.2; color: var(--myio-gcdr-title); }
108365
+ .myio-gcdr-panel__footer { padding: 16px 32px; text-align: center; font-size: 14px; color: var(--myio-gcdr-text);
108366
+ background: var(--myio-gcdr-footer); border-top: 1px solid var(--myio-gcdr-ring); }
108367
+
108368
+ /* \u2500\u2500 Form \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
108369
+ .myio-gcdr-login__form { display: flex; flex-direction: column; gap: 20px; margin: 0; }
108370
+ .myio-gcdr-login__field { display: flex; flex-direction: column; gap: 6px; }
108371
+ .myio-gcdr-login__label { font-size: 14px; font-weight: 700; color: var(--myio-gcdr-title); }
108372
+ .myio-gcdr-login__control { position: relative; display: flex; }
108373
+ .myio-gcdr-login__input {
108374
+ width: 100%; font: inherit; font-size: 16px; color: var(--myio-gcdr-title);
108375
+ background: var(--myio-gcdr-input); border: 1px solid var(--myio-gcdr-input-border);
108376
+ border-radius: 12px; padding: 10px 14px; outline: none; transition: border-color .15s, box-shadow .15s;
108377
+ }
108378
+ .myio-gcdr-login__input::placeholder { color: #9CA3AF; }
108379
+ .myio-gcdr-login__input:focus { border-color: var(--myio-gcdr-accent); box-shadow: 0 0 0 3px rgba(107,74,191,0.30); }
108380
+ .myio-gcdr-login__input[aria-invalid="true"] { border-color: #FCA5A5; }
108381
+ .myio-gcdr-login__input[readonly] { opacity: .75; }
108382
+ .myio-gcdr-login__input--password { padding-right: 48px; }
108383
+ .myio-gcdr-login__eye {
108384
+ position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px;
108385
+ display: inline-flex; align-items: center; justify-content: center; border: 0; background: transparent;
108386
+ color: var(--myio-gcdr-text); border-radius: 8px; cursor: pointer;
108387
+ }
108388
+ .myio-gcdr-login__eye:focus-visible { outline: 2px solid var(--myio-gcdr-accent); }
108389
+ .myio-gcdr-login__fielderror { font-size: 13px; color: #DC2626; }
108390
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-login__fielderror { color: #FCA5A5; }
108391
+ .myio-gcdr-login__hint { font-size: 12px; color: #B45309; }
108392
+ .myio-gcdr-login__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
108393
+ .myio-gcdr-login__remember { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; color: var(--myio-gcdr-text); cursor: pointer; min-height: 32px; }
108394
+ .myio-gcdr-login__remember input { width: 16px; height: 16px; accent-color: var(--myio-gcdr-accent); }
108395
+ .myio-gcdr-login__link { font-size: 14px; font-weight: 600; color: var(--myio-gcdr-link); text-decoration: none; background: none; border: 0; padding: 0; cursor: pointer; font-family: inherit; }
108396
+ .myio-gcdr-login__link:hover { color: var(--myio-gcdr-accent-hover); text-decoration: underline; }
108397
+ .myio-gcdr-login__submit {
108398
+ display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 48px;
108399
+ border: 0; border-radius: 12px; padding: 12px 24px; font: inherit; font-size: 16px; font-weight: 700;
108400
+ color: #fff; background: var(--myio-gcdr-accent); cursor: pointer; transition: background .15s, opacity .15s;
108401
+ }
108402
+ .myio-gcdr-login__submit:hover { background: var(--myio-gcdr-accent-hover); }
108403
+ .myio-gcdr-login__submit[aria-disabled="true"], .myio-gcdr-login__submit:disabled { opacity: .55; cursor: not-allowed; }
108404
+ .myio-gcdr-login__submit:focus-visible { outline: 2px solid var(--myio-gcdr-accent); outline-offset: 2px; }
108405
+ .myio-gcdr-login__submit[data-style="hotPage"] { border-radius: 10px; min-height: 52px; font-size: 17px; letter-spacing: .01em; box-shadow: 0 6px 16px rgba(107,74,191,0.35); }
108406
+ .myio-gcdr-login__spin { display: inline-flex; animation: myio-gcdr-spin 0.9s linear infinite; }
108407
+ @keyframes myio-gcdr-spin { to { transform: rotate(360deg); } }
108408
+
108409
+ /* \u2500\u2500 Banners \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
108410
+ .myio-gcdr-login__alerts { display: flex; flex-direction: column; gap: 12px; }
108411
+ .myio-gcdr-login__alerts:empty { display: none; }
108412
+ .myio-gcdr-login__alerts:not(:empty) { margin-bottom: 20px; }
108413
+ .myio-gcdr-login__field > .myio-gcdr-login__link { align-self: flex-start; }
108414
+ .myio-gcdr-banner { display: flex; gap: 10px; align-items: flex-start; border-radius: 12px; padding: 12px 14px; font-size: 14px; line-height: 1.45; border: 1px solid; }
108415
+ .myio-gcdr-banner:focus { outline: 2px solid var(--myio-gcdr-accent); outline-offset: 2px; }
108416
+ .myio-gcdr-banner__icon { flex-shrink: 0; margin-top: 2px; }
108417
+ .myio-gcdr-banner__body { display: flex; flex-direction: column; gap: 6px; }
108418
+ .myio-gcdr-banner__title { font-weight: 800; }
108419
+ .myio-gcdr-banner--error { background: #FEF2F2; border-color: #FECACA; color: #991B1B; }
108420
+ .myio-gcdr-banner--warning { background: #FFFBEB; border-color: #FDE68A; color: #92400E; }
108421
+ .myio-gcdr-banner--info { background: #F5F3FF; border-color: #DDD6FE; color: #4C1D95; }
108422
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-banner--error { background: rgba(127,29,29,0.35); border-color: rgba(248,113,113,0.45); color: #FECACA; }
108423
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-banner--warning { background: rgba(120,53,15,0.35); border-color: rgba(251,191,36,0.45); color: #FDE68A; }
108424
+ .myio-gcdr-shell[data-theme="dark"] .myio-gcdr-banner--info { background: rgba(76,29,149,0.35); border-color: rgba(167,139,250,0.45); color: #DDD6FE; }
108425
+ .myio-gcdr-banner a, .myio-gcdr-banner button { color: inherit; font-weight: 700; text-decoration: underline; background: none; border: 0; padding: 0; font: inherit; cursor: pointer; text-align: left; }
108426
+
108427
+ /* \u2500\u2500 Aside: about / signed-out prompt \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
108428
+ .myio-gcdr-about__intro { color: var(--myio-gcdr-text); font-size: 14px; margin: 0 0 16px; }
108429
+ .myio-gcdr-about__title { font-size: 24px; font-weight: 800; margin: 0 0 6px; color: var(--myio-gcdr-title); }
108430
+ .myio-gcdr-about__title em { font-style: normal; color: var(--myio-gcdr-aside-band); }
108431
+ .myio-gcdr-about__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
108432
+ .myio-gcdr-about__tile {
108433
+ display: flex; flex-direction: column; gap: 6px; text-align: left; padding: 14px; border-radius: 12px; min-height: 110px;
108434
+ border: 1px solid var(--myio-gcdr-ring); background: var(--myio-gcdr-input); color: var(--myio-gcdr-title);
108435
+ font: inherit; cursor: pointer; text-decoration: none; transition: transform .15s, box-shadow .15s;
108436
+ }
108437
+ .myio-gcdr-about__tile:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(40,20,90,0.12); }
108438
+ .myio-gcdr-about__tile:focus-visible { outline: 2px solid var(--myio-gcdr-accent); outline-offset: 2px; }
108439
+ .myio-gcdr-about__tile[aria-disabled="true"] { opacity: .6; cursor: default; }
108440
+ .myio-gcdr-about__tileicon { color: var(--myio-gcdr-aside-band); }
108441
+ .myio-gcdr-about__tiletitle { font-weight: 800; font-size: 15px; }
108442
+ .myio-gcdr-about__tiletext { font-size: 13px; color: var(--myio-gcdr-text); }
108443
+ .myio-gcdr-about__back { margin-bottom: 12px; }
108444
+ .myio-gcdr-about__tagline { margin-top: 16px; font-size: 13px; font-weight: 700; color: var(--myio-gcdr-text); text-align: center; }
108445
+ .myio-gcdr-about__health { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 700; }
108446
+ .myio-gcdr-about__dot { width: 8px; height: 8px; border-radius: 50%; background: #9CA3AF; }
108447
+ .myio-gcdr-about__dot[data-state="online"] { background: #16A34A; }
108448
+ .myio-gcdr-about__dot[data-state="offline"] { background: #DC2626; }
108449
+ .myio-gcdr-prompt { display: flex; flex: 1; flex-direction: column; align-items: center; justify-content: center; gap: 16px; padding: 32px 20px; text-align: center; height: 100%; }
108450
+ .myio-gcdr-prompt__icon { display: inline-flex; width: 56px; height: 56px; align-items: center; justify-content: center; border-radius: 50%; background: #6B4ABF; color: #fff; }
108451
+ .myio-gcdr-prompt__text { margin: 0; font-size: 22px; font-weight: 800; line-height: 1.35; color: var(--myio-gcdr-title); }
108452
+
108453
+ /* \u2500\u2500 Modal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
108454
+ .myio-gcdr-overlay { position: fixed; inset: 0; overflow-y: auto; display: flex; }
108455
+ .myio-gcdr-overlay[data-scope="element"] { position: absolute; }
108456
+ .myio-gcdr-overlay__layer { position: fixed; inset: 0; pointer-events: none; }
108457
+ .myio-gcdr-overlay[data-scope="element"] .myio-gcdr-overlay__layer { position: absolute; }
108458
+ .myio-gcdr-overlay__content { position: relative; width: 100%; min-height: 100%; display: flex; }
108459
+ .myio-gcdr-overlay__content > .myio-gcdr-shell { min-height: 100%; background: transparent; }
108460
+ .myio-gcdr-overlay__close { position: absolute; top: 12px; right: 12px; z-index: 2; }
108461
+ @media (prefers-reduced-motion: reduce) {
108462
+ .myio-gcdr-shell *, .myio-gcdr-overlay * { transition: none !important; animation: none !important; }
108463
+ }
108464
+ `;
108465
+ function rootTarget(container) {
108466
+ const root = container.getRootNode ? container.getRootNode() : document;
108467
+ const doc = container.ownerDocument || document;
108468
+ if (typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot) return { head: root, doc };
108469
+ return { head: doc.head || doc.documentElement, doc };
108470
+ }
108471
+ function acquireStyles(container, opts = {}) {
108472
+ const { head, doc } = rootTarget(container);
108473
+ if (opts.loadFont !== false && !doc.getElementById(FONT_ID)) {
108474
+ const link = doc.createElement("link");
108475
+ link.id = FONT_ID;
108476
+ link.rel = "stylesheet";
108477
+ link.href = "https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700;800;900&display=swap";
108478
+ doc.head?.appendChild(link);
108479
+ }
108480
+ let style = head.querySelector(`style[${STYLE_ATTR}="${STYLE_VERSION}"]`);
108481
+ if (!style) {
108482
+ style = doc.createElement("style");
108483
+ style.setAttribute(STYLE_ATTR, STYLE_VERSION);
108484
+ style.setAttribute(REFS_ATTR, "0");
108485
+ if (opts.nonce) style.setAttribute("nonce", opts.nonce);
108486
+ style.textContent = CSS3;
108487
+ head.appendChild(style);
108488
+ }
108489
+ const el2 = style;
108490
+ el2.setAttribute(REFS_ATTR, String((parseInt(el2.getAttribute(REFS_ATTR) || "0", 10) || 0) + 1));
108491
+ let released = false;
108492
+ return () => {
108493
+ if (released) return;
108494
+ released = true;
108495
+ const n = (parseInt(el2.getAttribute(REFS_ATTR) || "1", 10) || 1) - 1;
108496
+ if (n <= 0) el2.remove();
108497
+ else el2.setAttribute(REFS_ATTR, String(n));
108498
+ };
108499
+ }
108500
+
108501
+ // src/components/myio-gcdr-login/shell.ts
108502
+ var SLOT_NAMES = ["top", "topRight", "aside", "main", "below"];
108503
+ function buildPanel(doc, el2, opts, locale, defaultLogoUrl) {
108504
+ const root = h2(doc, "section", { class: "myio-gcdr-panel", "data-fill": opts.fill ? "true" : null });
108505
+ if (opts.accent) root.style.setProperty("--myio-gcdr-accent", opts.accent);
108506
+ if (opts.bandColor) root.style.setProperty("--myio-gcdr-band", opts.bandColor);
108507
+ if (opts.tint) root.style.setProperty("--myio-gcdr-tint", opts.tint);
108508
+ const band = h2(doc, "header", { class: "myio-gcdr-panel__band" });
108509
+ if (opts.tint) band.appendChild(h2(doc, "span", { class: "myio-gcdr-panel__tint", "aria-hidden": "true" }));
108510
+ band.appendChild(h2(doc, "span", { class: "myio-gcdr-panel__eyebrow", text: localize(opts.eyebrow, locale) }));
108511
+ if (opts.logo !== false) {
108512
+ const url = opts.logoUrl ?? defaultLogoUrl;
108513
+ const wordmark = () => h2(doc, "span", { class: "myio-gcdr-panel__wordmark", text: "MYIO" });
108514
+ if (url) {
108515
+ const img = h2(doc, "img", { class: "myio-gcdr-panel__logo", src: url, alt: "MYIO" });
108516
+ img.addEventListener("error", () => img.replaceWith(wordmark()), { once: true });
108517
+ band.appendChild(img);
108518
+ } else band.appendChild(wordmark());
108519
+ }
108520
+ root.appendChild(band);
108521
+ const body = h2(doc, "div", { class: "myio-gcdr-panel__body" });
108522
+ let title;
108523
+ if (opts.title) {
108524
+ title = h2(doc, "h1", { class: "myio-gcdr-panel__title", text: localize(opts.title, locale), tabindex: "-1" });
108525
+ body.appendChild(title);
108526
+ }
108527
+ root.appendChild(body);
108528
+ let footer;
108529
+ if (opts.footer) {
108530
+ footer = h2(doc, "footer", { class: "myio-gcdr-panel__footer" });
108531
+ root.appendChild(footer);
108532
+ }
108533
+ el2.appendChild(root);
108534
+ return { root, body, footer, title };
108535
+ }
108536
+ function createShellImpl(container, options = {}, internals = {}) {
108537
+ if (!(container instanceof HTMLElement)) throw new TypeError("[MYIO Login] container must be an HTMLElement");
108538
+ const doc = container.ownerDocument;
108539
+ const prefix = options.storageKeyPrefix ?? "myio.login.";
108540
+ const releaseStyles = acquireStyles(container, { nonce: options.cspNonce, loadFont: options.fonts?.load !== false });
108541
+ let themeSetting = options.theme ?? (storageGet(`${prefix}theme`) || "system");
108542
+ let locale = options.locale ?? detectLocale(storageGet(`${prefix}locale`));
108543
+ let size = options.size ?? "md";
108544
+ let width = options.width ?? "auto";
108545
+ const show = { themeToggle: options.show?.themeToggle !== false, languageSelector: options.show?.languageSelector !== false };
108546
+ const listeners = /* @__PURE__ */ new Set();
108547
+ let destroyed = false;
108548
+ const resolvedTheme = () => themeSetting === "system" ? prefersDark() ? "dark" : "light" : themeSetting;
108549
+ const t = (key, vars) => translate(locale, key, vars, internals.messages);
108550
+ container.textContent = "";
108551
+ const root = h2(doc, "div", {
108552
+ class: "myio-gcdr-shell",
108553
+ "data-theme": resolvedTheme(),
108554
+ "data-size": size,
108555
+ "data-width": width,
108556
+ "data-aside-compact": options.asideCompact ?? "hide",
108557
+ "data-has-aside": "false",
108558
+ lang: locale
108559
+ });
108560
+ const wallpaper = h2(doc, "div", { class: "myio-gcdr-shell__wallpaper", "aria-hidden": "true" });
108561
+ const live = h2(doc, "div", { class: "myio-gcdr-sr", "aria-live": "polite", role: "status" });
108562
+ const top = h2(doc, "div", { class: "myio-gcdr-shell__top myio-gcdr-shell__slot", hidden: true });
108563
+ const block = h2(doc, "div", { class: "myio-gcdr-shell__block" });
108564
+ const toprow = h2(doc, "div", { class: "myio-gcdr-shell__toprow" });
108565
+ const pill = h2(doc, "div", { class: "myio-gcdr-shell__pill" });
108566
+ const langBtn = h2(doc, "button", { type: "button", class: "myio-gcdr-shell__iconbtn" });
108567
+ const themeBtn = h2(doc, "button", { type: "button", class: "myio-gcdr-shell__iconbtn" });
108568
+ const topRight = h2(doc, "div", { class: "myio-gcdr-shell__slot", style: "display:contents" });
108569
+ pill.append(langBtn, themeBtn, topRight);
108570
+ toprow.appendChild(pill);
108571
+ const split = h2(doc, "div", { class: "myio-gcdr-shell__split" });
108572
+ const aside = h2(doc, "section", { class: "myio-gcdr-shell__aside myio-gcdr-shell__slot", hidden: true, tabindex: "-1" });
108573
+ const main = h2(doc, "section", { class: "myio-gcdr-shell__main myio-gcdr-shell__slot", tabindex: "-1" });
108574
+ split.append(aside, main);
108575
+ const below = h2(doc, "div", { class: "myio-gcdr-shell__below myio-gcdr-shell__slot", hidden: true });
108576
+ block.append(toprow, split, below);
108577
+ root.append(wallpaper, live, top, block);
108578
+ container.appendChild(root);
108579
+ const applyWallpaper = () => {
108580
+ const wp = options.wallpaper;
108581
+ if (wp === false) {
108582
+ wallpaper.hidden = true;
108583
+ return;
108584
+ }
108585
+ wallpaper.hidden = false;
108586
+ const dark = resolvedTheme() === "dark";
108587
+ let portrait = false;
108588
+ try {
108589
+ portrait = typeof matchMedia === "function" && matchMedia("(orientation: portrait)").matches;
108590
+ } catch {
108591
+ }
108592
+ const url = wp ? dark ? portrait ? wp.mobileDark ?? wp.dark : wp.dark : portrait ? wp.mobileLight ?? wp.light : wp.light : void 0;
108593
+ if (url) wallpaper.style.setProperty("--myio-gcdr-wp", `url("${url.replace(/"/g, "%22")}")`);
108594
+ else wallpaper.style.removeProperty("--myio-gcdr-wp");
108595
+ };
108596
+ const renderControls = () => {
108597
+ langBtn.hidden = !show.languageSelector;
108598
+ themeBtn.hidden = !show.themeToggle;
108599
+ langBtn.textContent = "";
108600
+ langBtn.append(icon(doc, ICONS.globe(16)), h2(doc, "span", { text: locale === "en" ? "EN" : "PT" }));
108601
+ langBtn.setAttribute("aria-label", `${t("toolbar.language")}: ${locale === "en" ? "English" : "Portugu\xEAs"}`);
108602
+ const dark = resolvedTheme() === "dark";
108603
+ themeBtn.textContent = "";
108604
+ themeBtn.append(icon(doc, dark ? ICONS.sun(16) : ICONS.moon(16)));
108605
+ const lbl = dark ? t("toolbar.toLight") : t("toolbar.toDark");
108606
+ themeBtn.setAttribute("aria-label", lbl);
108607
+ themeBtn.setAttribute("title", lbl);
108608
+ };
108609
+ const emit = (what) => {
108610
+ for (const fn of Array.from(listeners)) safeCall("listener", fn, what);
108611
+ };
108612
+ const applyTheme = () => {
108613
+ root.setAttribute("data-theme", resolvedTheme());
108614
+ applyWallpaper();
108615
+ renderControls();
108616
+ emit("theme");
108617
+ };
108618
+ const applyLocale = () => {
108619
+ root.setAttribute("lang", locale);
108620
+ renderControls();
108621
+ emit("locale");
108622
+ };
108623
+ langBtn.addEventListener("click", () => {
108624
+ locale = locale === "en" ? "pt-BR" : "en";
108625
+ storageSet(`${prefix}locale`, locale);
108626
+ applyLocale();
108627
+ safeCall("onLocaleChange", options.onLocaleChange, locale);
108628
+ });
108629
+ themeBtn.addEventListener("click", () => {
108630
+ themeSetting = resolvedTheme() === "dark" ? "light" : "dark";
108631
+ storageSet(`${prefix}theme`, themeSetting);
108632
+ applyTheme();
108633
+ safeCall("onThemeChange", options.onThemeChange, themeSetting);
108634
+ });
108635
+ let mql = null;
108636
+ const onScheme = () => {
108637
+ if (themeSetting === "system") applyTheme();
108638
+ };
108639
+ try {
108640
+ if (typeof matchMedia === "function") {
108641
+ mql = matchMedia("(prefers-color-scheme: dark)");
108642
+ mql.addEventListener?.("change", onScheme);
108643
+ }
108644
+ } catch {
108645
+ mql = null;
108646
+ }
108647
+ const contextFor = (el2, signal) => ({
108648
+ get theme() {
108649
+ return resolvedTheme();
108650
+ },
108651
+ get locale() {
108652
+ return locale;
108653
+ },
108654
+ signal,
108655
+ on(event, fn) {
108656
+ const l = (w) => {
108657
+ if (w === event) fn(event === "theme" ? resolvedTheme() : locale);
108658
+ };
108659
+ listeners.add(l);
108660
+ const off = () => listeners.delete(l);
108661
+ signal.addEventListener("abort", off, { once: true });
108662
+ return off;
108663
+ },
108664
+ panel: (opts) => buildPanel(doc, el2, opts, locale, internals.logoUrl)
108665
+ });
108666
+ const slots = {};
108667
+ const slotEls = { top, topRight, aside, main, below };
108668
+ for (const n of SLOT_NAMES) slots[n] = { el: slotEls[n], kind: "empty", busy: false };
108669
+ const updateLayoutFlags = () => {
108670
+ root.setAttribute("data-has-aside", slots.aside.kind === "empty" ? "false" : "true");
108671
+ aside.hidden = slots.aside.kind === "empty";
108672
+ below.hidden = slots.below.kind === "empty";
108673
+ top.hidden = slots.top.kind === "empty";
108674
+ };
108675
+ const renderBuiltIn = (name, el2, ctx, b) => {
108676
+ if (b.kind === "buildInfo") {
108677
+ if (name !== "below") throw new TypeError("[MYIO Login] buildInfo is only valid in the below slot");
108678
+ el2.appendChild(h2(doc, "p", { class: "myio-gcdr-shell__build", text: b.text }));
108679
+ return;
108680
+ }
108681
+ if (name !== "aside") throw new TypeError(`[MYIO Login] ${b.kind} is only valid in the aside slot`);
108682
+ if (b.kind === "about") {
108683
+ const cleanupAbout = renderAbout(el2, ctx, t, { ...internals.about, healthUrl: b.healthUrl ?? false });
108684
+ const off2 = ctx.on("locale", () => {
108685
+ cleanupAbout();
108686
+ el2.textContent = "";
108687
+ renderAbout(el2, ctx, t, { ...internals.about, healthUrl: b.healthUrl ?? false });
108688
+ });
108689
+ return () => {
108690
+ off2();
108691
+ cleanupAbout();
108692
+ };
108693
+ }
108694
+ const text2 = () => b.text ? localize(b.text, locale) : t("aside.signedOutPrompt");
108695
+ renderSignedOutPrompt(el2, ctx, text2());
108696
+ const off = ctx.on("locale", () => {
108697
+ el2.textContent = "";
108698
+ renderSignedOutPrompt(el2, ctx, text2());
108699
+ });
108700
+ return off;
108701
+ };
108702
+ const setSlot = (name, content, opts) => {
108703
+ if (destroyed) return;
108704
+ if (!SLOT_NAMES.includes(name)) throw new TypeError(`[MYIO Login] unknown slot "${String(name)}"`);
108705
+ const s = slots[name];
108706
+ if (s.busy) {
108707
+ s.pending = { content, opts };
108708
+ queueMicrotask(() => {
108709
+ const p = s.pending;
108710
+ s.pending = void 0;
108711
+ if (p) setSlot(name, p.content, p.opts);
108712
+ });
108713
+ return;
108714
+ }
108715
+ const hadFocus = !!doc.activeElement && s.el.contains(doc.activeElement);
108716
+ s.busy = true;
108717
+ try {
108718
+ s.abort?.abort();
108719
+ if (s.cleanup) safeCall("slot cleanup", s.cleanup);
108720
+ s.cleanup = void 0;
108721
+ s.el.textContent = "";
108722
+ s.kind = "empty";
108723
+ if (content) {
108724
+ const ac = new AbortController();
108725
+ s.abort = ac;
108726
+ const ctx = contextFor(s.el, ac.signal);
108727
+ try {
108728
+ const r = typeof content === "function" ? content(s.el, ctx) : renderBuiltIn(name, s.el, ctx, content);
108729
+ if (typeof r === "function") s.cleanup = r;
108730
+ s.kind = typeof content === "function" ? "host" : "builtIn";
108731
+ } catch (err) {
108732
+ if (err instanceof TypeError && String(err.message).startsWith("[MYIO Login]")) throw err;
108733
+ console.error(`[MYIO Login] slot "${name}" renderer failed`);
108734
+ s.el.textContent = "";
108735
+ s.kind = "empty";
108736
+ }
108737
+ }
108738
+ } finally {
108739
+ s.busy = false;
108740
+ updateLayoutFlags();
108741
+ }
108742
+ const focus = opts?.focus ?? "auto";
108743
+ if (focus instanceof HTMLElement) focus.focus();
108744
+ else if (focus === "auto" && hadFocus && s.el.isConnected) {
108745
+ if (!s.el.hasAttribute("tabindex")) s.el.setAttribute("tabindex", "-1");
108746
+ s.el.focus();
108747
+ }
108748
+ if (opts?.announce) announce(localize(opts.announce, locale));
108749
+ };
108750
+ const announce = (text2) => {
108751
+ live.textContent = "";
108752
+ setTimeout(() => {
108753
+ if (!destroyed) live.textContent = text2;
108754
+ }, 30);
108755
+ };
108756
+ applyWallpaper();
108757
+ renderControls();
108758
+ if (options.buildInfo) setSlot("below", { kind: "buildInfo", text: options.buildInfo });
108759
+ const handle = {
108760
+ setSlot,
108761
+ setTheme(th) {
108762
+ if (destroyed) return;
108763
+ themeSetting = th;
108764
+ applyTheme();
108765
+ },
108766
+ setLocale(l) {
108767
+ if (destroyed || l !== "pt-BR" && l !== "en") return;
108768
+ locale = l;
108769
+ applyLocale();
108770
+ },
108771
+ setSize(sz, w) {
108772
+ if (destroyed) return;
108773
+ size = sz;
108774
+ if (w) width = w;
108775
+ root.setAttribute("data-size", size);
108776
+ root.setAttribute("data-width", width);
108777
+ },
108778
+ setShow(sh) {
108779
+ if (destroyed) return;
108780
+ if (sh.themeToggle !== void 0) show.themeToggle = sh.themeToggle;
108781
+ if (sh.languageSelector !== void 0) show.languageSelector = sh.languageSelector;
108782
+ renderControls();
108783
+ },
108784
+ getState() {
108785
+ const st = {};
108786
+ for (const n of SLOT_NAMES) st[n] = slots[n].kind;
108787
+ return { theme: resolvedTheme(), locale, size, width, slots: st };
108788
+ },
108789
+ get element() {
108790
+ return root;
108791
+ },
108792
+ destroy() {
108793
+ if (destroyed) return;
108794
+ for (const n of SLOT_NAMES) {
108795
+ const s = slots[n];
108796
+ s.abort?.abort();
108797
+ if (s.cleanup) safeCall("slot cleanup", s.cleanup);
108798
+ s.cleanup = void 0;
108799
+ }
108800
+ destroyed = true;
108801
+ listeners.clear();
108802
+ mql?.removeEventListener?.("change", onScheme);
108803
+ root.remove();
108804
+ releaseStyles();
108805
+ },
108806
+ t,
108807
+ contextFor,
108808
+ onChange(fn) {
108809
+ listeners.add(fn);
108810
+ return () => listeners.delete(fn);
108811
+ },
108812
+ announce
108813
+ };
108814
+ return handle;
108815
+ }
108816
+ function createMyioGcdrShell(container, options = {}) {
108817
+ const impl = createShellImpl(container, options);
108818
+ return {
108819
+ setSlot: impl.setSlot,
108820
+ setTheme: impl.setTheme,
108821
+ setLocale: impl.setLocale,
108822
+ setSize: impl.setSize,
108823
+ setShow: impl.setShow,
108824
+ getState: impl.getState,
108825
+ get element() {
108826
+ return impl.element;
108827
+ },
108828
+ destroy: impl.destroy
108829
+ };
108830
+ }
108831
+
108832
+ // src/components/myio-gcdr-login/controller.ts
108833
+ var EMAIL_PATTERN = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
108834
+ function validate(emailRaw, password) {
108835
+ const email = emailRaw.trim();
108836
+ let emailError;
108837
+ if (!email) emailError = "login.emailRequired";
108838
+ else if (!EMAIL_PATTERN.test(email)) emailError = "login.emailInvalid";
108839
+ const passwordError = password.length === 0 ? "login.passwordRequired" : void 0;
108840
+ return { email, emailError, passwordError };
108841
+ }
108842
+ function emailKey(email) {
108843
+ return email.trim().toLowerCase();
108844
+ }
108845
+ var KNOWN = /* @__PURE__ */ new Set([
108846
+ "INVALID_CREDENTIALS",
108847
+ "ACCOUNT_LOCKED",
108848
+ "CAPTCHA_FAILED",
108849
+ "TOO_MANY_REQUESTS",
108850
+ "MFA_REQUIRED",
108851
+ "NETWORK",
108852
+ "TIMEOUT",
108853
+ "SERVER",
108854
+ "INTEGRATION_ERROR",
108855
+ "CUSTOM"
108856
+ ]);
108857
+ var ALIASES = {
108858
+ UNAUTHORIZED: "INVALID_CREDENTIALS",
108859
+ HTTP_401: "INVALID_CREDENTIALS",
108860
+ ACCOUNT_PENDING: "INVALID_CREDENTIALS",
108861
+ PENDING_APPROVAL: "INVALID_CREDENTIALS",
108862
+ ACCOUNT_SUSPENDED: "INVALID_CREDENTIALS",
108863
+ ACCOUNT_INACTIVE: "INVALID_CREDENTIALS",
108864
+ EMAIL_NOT_VERIFIED: "INVALID_CREDENTIALS",
108865
+ RATE_LIMITED: "TOO_MANY_REQUESTS",
108866
+ NETWORK_ERROR: "NETWORK"
108867
+ };
108868
+ function normaliseCode(code) {
108869
+ if (typeof code !== "string") return "SERVER";
108870
+ if (KNOWN.has(code)) return code;
108871
+ return ALIASES[code] ?? "SERVER";
108872
+ }
108873
+ function usableCounter(n) {
108874
+ return typeof n === "number" && Number.isInteger(n) && n >= 1 ? n : void 0;
108875
+ }
108876
+ function normaliseResult(raw) {
108877
+ if (!raw || typeof raw !== "object" || typeof raw.ok !== "boolean") {
108878
+ return { kind: "error", code: "INTEGRATION_ERROR" };
108879
+ }
108880
+ const r = raw;
108881
+ if (r.ok) return { kind: "ok", session: r.session };
108882
+ const code = normaliseCode(r.code);
108883
+ return {
108884
+ kind: "error",
108885
+ code,
108886
+ remainingAttempts: code === "INVALID_CREDENTIALS" ? usableCounter(r.remainingAttempts) : void 0,
108887
+ message: code === "CUSTOM" && typeof r.message === "string" ? r.message : void 0,
108888
+ clearPassword: code === "CUSTOM" ? r.clearPassword !== false : void 0
108889
+ };
108890
+ }
108891
+ function normaliseThrown(err) {
108892
+ if (err && typeof err === "object" && err.myioGcdrCode === "TIMEOUT") return "TIMEOUT";
108893
+ return err instanceof TypeError ? "NETWORK" : "SERVER";
108894
+ }
108895
+ var ATTEMPTS_THRESHOLD = 3;
108896
+ function present(o) {
108897
+ switch (o.code) {
108898
+ case "INVALID_CREDENTIALS": {
108899
+ const n = o.remainingAttempts;
108900
+ if (n === void 0)
108901
+ return { tone: "error", keys: ["errors.invalidCredentials"], icon: "alert", clearPassword: true, focus: "password" };
108902
+ if (n > ATTEMPTS_THRESHOLD)
108903
+ return { tone: "error", keys: ["errors.invalidWithAttempts"], count: n, icon: "alert", clearPassword: true, focus: "password" };
108904
+ if (n === 1)
108905
+ return { tone: "warning", keys: ["errors.lastAttempt", "errors.lockWarning"], icon: "shieldAlert", forgotLink: true, clearPassword: true, focus: "password" };
108906
+ return { tone: "warning", keys: ["errors.attemptsLeft", "errors.lockWarning"], count: n, icon: "shieldAlert", forgotLink: true, clearPassword: true, focus: "password" };
108907
+ }
108908
+ case "ACCOUNT_LOCKED":
108909
+ return { tone: "error", keys: ["errors.lockedText"], title: "errors.lockedTitle", icon: "lock", support: true, clearPassword: true, focus: "banner" };
108910
+ case "MFA_REQUIRED":
108911
+ return { tone: "error", keys: ["errors.mfaUnsupported"], icon: "shieldAlert", gcdrWebLink: true, support: true, clearPassword: true, focus: "banner" };
108912
+ case "CAPTCHA_FAILED":
108913
+ return { tone: "error", keys: ["errors.captchaFailed"], icon: "alert", clearPassword: false, focus: "captcha" };
108914
+ case "TOO_MANY_REQUESTS":
108915
+ return { tone: "error", keys: ["errors.tooManyRequests"], icon: "alert", clearPassword: false, focus: "submit" };
108916
+ case "NETWORK":
108917
+ return { tone: "error", keys: ["errors.networkError"], icon: "alert", clearPassword: false, focus: "submit" };
108918
+ case "TIMEOUT":
108919
+ return { tone: "error", keys: ["errors.timeout"], icon: "alert", clearPassword: false, focus: "submit" };
108920
+ case "INTEGRATION_ERROR":
108921
+ return { tone: "error", keys: ["errors.integrationError"], icon: "alert", clearPassword: false, focus: "submit" };
108922
+ case "CUSTOM": {
108923
+ const clear = o.clearPassword !== false;
108924
+ return {
108925
+ tone: "error",
108926
+ keys: o.message ? [] : ["errors.loginFailed"],
108927
+ text: o.message,
108928
+ icon: "alert",
108929
+ clearPassword: clear,
108930
+ focus: clear ? "password" : "submit"
108931
+ };
108932
+ }
108933
+ case "SERVER":
108934
+ default:
108935
+ return { tone: "error", keys: ["errors.loginFailed"], icon: "alert", clearPassword: false, focus: "submit" };
108936
+ }
108937
+ }
108938
+
108939
+ // src/components/myio-gcdr-login/gcdrClient.ts
108940
+ var DEFAULT_TIMEOUT_MS = 15e3;
108941
+ function timeoutError() {
108942
+ const e = new Error("GCDR login timed out");
108943
+ e.myioGcdrCode = "TIMEOUT";
108944
+ return e;
108945
+ }
108946
+ function createMyioGcdrLoginSubmit(options) {
108947
+ if (!options || typeof options.apiUrl !== "string" || !options.apiUrl.trim()) {
108948
+ throw new TypeError("[MYIO Login] gcdr.apiUrl must be a non-empty string");
108949
+ }
108950
+ if (typeof options.tenantId !== "string" || !options.tenantId.trim()) {
108951
+ throw new TypeError("[MYIO Login] gcdr.tenantId must be a non-empty string");
108952
+ }
108953
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
108954
+ if (!(typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0)) {
108955
+ throw new TypeError("[MYIO Login] gcdr.timeoutMs must be a positive number");
108956
+ }
108957
+ const base = options.apiUrl.replace(/\/+$/, "").replace(/\/api\/v\d+$/, "");
108958
+ const url = `${base}/api/v1/auth/login`;
108959
+ return async (input, ctx) => {
108960
+ const doFetch = options.fetch ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : void 0);
108961
+ if (!doFetch) throw new TypeError("fetch is not available");
108962
+ const ac = new AbortController();
108963
+ let timedOut = false;
108964
+ const onOuterAbort = () => ac.abort();
108965
+ if (ctx?.signal) {
108966
+ if (ctx.signal.aborted) ac.abort();
108967
+ else ctx.signal.addEventListener("abort", onOuterAbort, { once: true });
108968
+ }
108969
+ const timer = setTimeout(() => {
108970
+ timedOut = true;
108971
+ ac.abort();
108972
+ }, timeoutMs);
108973
+ const body = { email: input.email, password: input.password };
108974
+ if (input.captchaToken) body.captchaToken = input.captchaToken;
108975
+ let res;
108976
+ try {
108977
+ res = await doFetch(url, {
108978
+ method: "POST",
108979
+ headers: { "Content-Type": "application/json", "x-tenant-id": options.tenantId, ...options.extraHeaders ?? {} },
108980
+ body: JSON.stringify(body),
108981
+ credentials: "omit",
108982
+ redirect: "error",
108983
+ signal: ac.signal
108984
+ });
108985
+ } catch (err) {
108986
+ if (timedOut) throw timeoutError();
108987
+ if (ac.signal.aborted) throw err;
108988
+ return { ok: false, code: "NETWORK" };
108989
+ } finally {
108990
+ clearTimeout(timer);
108991
+ ctx?.signal?.removeEventListener("abort", onOuterAbort);
108992
+ }
108993
+ let json = void 0;
108994
+ try {
108995
+ json = await res.json();
108996
+ } catch {
108997
+ json = void 0;
108998
+ }
108999
+ return mapGcdrResponse(res.status, json);
109000
+ };
109001
+ }
109002
+ function mapGcdrResponse(status, json) {
109003
+ const j = json && typeof json === "object" ? json : {};
109004
+ if (status >= 200 && status < 300) {
109005
+ const data = j.data;
109006
+ if (data && data.mfaRequired === true) return { ok: false, code: "MFA_REQUIRED" };
109007
+ if (data && typeof data.accessToken === "string" && data.accessToken) return { ok: true, session: data };
109008
+ return { ok: false, code: "INTEGRATION_ERROR" };
109009
+ }
109010
+ const code = typeof j.error?.code === "string" ? j.error.code : void 0;
109011
+ const remaining = j.error?.details?.remainingAttempts;
109012
+ switch (status) {
109013
+ case 400:
109014
+ return { ok: false, code: code === "CAPTCHA_FAILED" ? "CAPTCHA_FAILED" : "SERVER" };
109015
+ case 401:
109016
+ return code === "INVALID_CREDENTIALS" && typeof remaining === "number" ? { ok: false, code: "INVALID_CREDENTIALS", remainingAttempts: remaining } : { ok: false, code: "INVALID_CREDENTIALS" };
109017
+ case 403:
109018
+ return { ok: false, code: code === "ACCOUNT_LOCKED" ? "ACCOUNT_LOCKED" : "SERVER" };
109019
+ case 429:
109020
+ return { ok: false, code: "TOO_MANY_REQUESTS" };
109021
+ default:
109022
+ return { ok: false, code: "SERVER" };
109023
+ }
109024
+ }
109025
+
109026
+ // src/components/myio-gcdr-login/loginView.ts
109027
+ var DEFAULT_SUBMIT_TIMEOUT_MS = 3e4;
109028
+ function fail(msg, code) {
109029
+ const e = new TypeError(`[MYIO Login] ${msg}`);
109030
+ if (code) e.code = code;
109031
+ throw e;
109032
+ }
109033
+ function validateOptions3(container, o) {
109034
+ if (!(container instanceof HTMLElement)) fail("container must be an HTMLElement");
109035
+ if (!o || typeof o !== "object") fail("options are required");
109036
+ const n = [o.onSubmit, o.gcdr, o.auth].filter((x) => x != null).length;
109037
+ if (n !== 1) fail("exactly one of onSubmit, gcdr or auth is required");
109038
+ if (o.auth && o.auth.kind !== "credentials") {
109039
+ fail(`auth.kind "${String(o.auth.kind)}" is not supported`, "MYIO_GCDR_AUTH_UNSUPPORTED");
109040
+ }
109041
+ if (o.auth && typeof o.auth.submit !== "function") fail("auth.submit must be a function");
109042
+ if (o.onSubmit && typeof o.onSubmit !== "function") fail("onSubmit must be a function");
109043
+ if (typeof o.onSuccess !== "function") fail("onSuccess must be a function");
109044
+ if (o.submitTimeoutMs != null && !(Number.isFinite(o.submitTimeoutMs) && o.submitTimeoutMs > 0)) fail("submitTimeoutMs must be a positive number");
109045
+ if (o.captcha) fail("captcha is not available in this version (RFC-0236 PR 2)", "MYIO_GCDR_CAPTCHA_UNSUPPORTED");
109046
+ const kinds = ["about", "signedOutPrompt", "custom", "none"];
109047
+ if (o.aside && !kinds.includes(o.aside.kind)) fail(`unknown aside.kind "${String(o.aside.kind)}"`);
109048
+ if (o.aside?.kind === "custom" && typeof o.aside.render !== "function") fail("aside.render must be a function");
109049
+ if (o.support && (typeof o.support.href !== "string" || !o.support.href)) fail("support.href must be a non-empty string");
109050
+ if (o.embed) {
109051
+ const bad = ["aside", "buildInfo", "theme", "locale", "assets"].filter((k) => o[k] !== void 0);
109052
+ if (o.show?.themeToggle !== void 0 || o.show?.languageSelector !== void 0 || o.show?.wallpaper !== void 0) bad.push("show.(theme|language|wallpaper)");
109053
+ if (bad.length) fail(`with embed, these options belong to the host shell: ${bad.join(", ")}`);
109054
+ if (!o.embed.context || typeof o.embed.context.on !== "function") fail("embed.context must be a slot context");
109055
+ }
109056
+ }
109057
+ function createLoginViewImpl(container, options, internals = {}) {
109058
+ validateOptions3(container, options);
109059
+ const doc = container.ownerDocument;
109060
+ const presentation = internals.presentation ?? "inline";
109061
+ const prefix = options.storageKeyPrefix ?? "myio.login.";
109062
+ const isGcdr = !!options.gcdr;
109063
+ const webUrl = options.links?.gcdrWebUrl?.replace(/\/+$/, "");
109064
+ const strategy = options.gcdr ? createMyioGcdrLoginSubmit(options.gcdr) : options.auth ? options.auth.submit : options.onSubmit;
109065
+ const viewTimeoutMs = isGcdr ? void 0 : options.submitTimeoutMs ?? DEFAULT_SUBMIT_TIMEOUT_MS;
109066
+ let shell;
109067
+ let embedCtx;
109068
+ let releaseEmbedStyles;
109069
+ let cardHost;
109070
+ if (options.embed) {
109071
+ embedCtx = options.embed.context;
109072
+ releaseEmbedStyles = acquireStyles(container, { nonce: options.cspNonce, loadFont: options.fonts?.load !== false });
109073
+ container.textContent = "";
109074
+ cardHost = container;
109075
+ } else {
109076
+ const wpOpt = internals.shellWallpaper === false || options.show?.wallpaper === false ? false : options.assets?.wallpaper ?? {};
109077
+ shell = createShellImpl(
109078
+ container,
109079
+ {
109080
+ size: options.size ?? "md",
109081
+ theme: options.theme,
109082
+ locale: options.locale,
109083
+ show: { themeToggle: options.show?.themeToggle, languageSelector: options.show?.languageSelector },
109084
+ buildInfo: options.buildInfo,
109085
+ storageKeyPrefix: options.storageKeyPrefix,
109086
+ fonts: options.fonts,
109087
+ cspNonce: options.cspNonce,
109088
+ wallpaper: wpOpt === false ? false : wpOpt,
109089
+ onThemeChange: options.onThemeChange,
109090
+ onLocaleChange: options.onLocaleChange
109091
+ },
109092
+ {
109093
+ messages: options.messages,
109094
+ logoUrl: options.assets?.logoUrl,
109095
+ about: { webUrl, fetchImpl: options.gcdr?.fetch, bandColor: options.brand?.asideHeaderColor }
109096
+ }
109097
+ );
109098
+ cardHost = h2(doc, "div", { style: "display:flex;width:100%" });
109099
+ }
109100
+ const getLocale = () => shell ? shell.getState().locale : embedCtx.locale;
109101
+ const getTheme = () => shell ? shell.getState().theme : embedCtx.theme;
109102
+ const t = (key, vars) => translate(getLocale(), key, vars, options.messages);
109103
+ let phase = "idle";
109104
+ let destroyed = false;
109105
+ let attempt = 0;
109106
+ let attemptAbort = null;
109107
+ let abortCause = null;
109108
+ let successAbort = null;
109109
+ let err = {};
109110
+ let lockedKey = null;
109111
+ let noCounterStreak = 0;
109112
+ let streakKey = null;
109113
+ let notice = options.notice ?? null;
109114
+ let fieldErrors = {};
109115
+ const remembered = storageGet(`${prefix}rememberedEmail`);
109116
+ let emailValue = options.initialEmail ?? remembered ?? "";
109117
+ let rememberValue = !options.initialEmail && !!remembered;
109118
+ let passwordValue = "";
109119
+ let passwordVisible = false;
109120
+ let leaving = false;
109121
+ const linkTarget = options.links?.target ?? (presentation === "modal" ? "_blank" : "_self");
109122
+ const forgot = options.links?.forgotPassword;
109123
+ const forgotShown = forgot === false ? false : !!forgot || isGcdr && !!webUrl;
109124
+ const supportHref = options.support === false ? void 0 : options.support ? options.support.href : (options.aside?.kind ?? "about") === "about" ? defaultSupportHref(webUrl) : void 0;
109125
+ let els = {};
109126
+ const linkEl = (label, target, cls = "myio-gcdr-login__link") => {
109127
+ if (typeof target === "function") {
109128
+ const b = h2(doc, "button", { type: "button", class: cls, text: label });
109129
+ b.addEventListener("click", () => safeCall("link", target, { email: emailValue.trim() }));
109130
+ return b;
109131
+ }
109132
+ const a = h2(doc, "a", { class: cls, href: target, target: linkTarget, rel: linkTarget === "_blank" ? "noopener noreferrer" : null }, label);
109133
+ if (linkTarget === "_blank") a.appendChild(h2(doc, "span", { class: "myio-gcdr-sr", text: ` ${t("login.newTab")}` }));
109134
+ return a;
109135
+ };
109136
+ const forgotTarget = () => !forgotShown ? void 0 : typeof forgot === "string" || typeof forgot === "function" ? forgot : `${webUrl}/forgot-password`;
109137
+ const renderNotice = () => {
109138
+ if (!els.notice) return;
109139
+ els.notice.textContent = "";
109140
+ if (!notice) return;
109141
+ const key = presentation === "modal" ? "notice.sessionExpiredModal" : "notice.sessionExpired";
109142
+ els.notice.appendChild(
109143
+ h2(
109144
+ doc,
109145
+ "div",
109146
+ { class: "myio-gcdr-banner myio-gcdr-banner--info" },
109147
+ icon(doc, ICONS.info(16), "myio-gcdr-banner__icon"),
109148
+ h2(doc, "div", { class: "myio-gcdr-banner__body" }, h2(doc, "span", { text: t(key) }))
109149
+ )
109150
+ );
109151
+ };
109152
+ const renderAlerts = () => {
109153
+ if (!els.alerts) return;
109154
+ els.alerts.textContent = "";
109155
+ els.banner = void 0;
109156
+ if (!err.pres && !err.messageKey) return;
109157
+ const p = err.pres;
109158
+ const tone = p?.tone ?? "error";
109159
+ const body = h2(doc, "div", { class: "myio-gcdr-banner__body" });
109160
+ if (p?.title) body.appendChild(h2(doc, "span", { class: "myio-gcdr-banner__title", text: t(p.title) }));
109161
+ if (p) {
109162
+ if (p.text) body.appendChild(h2(doc, "span", { text: p.text }));
109163
+ p.keys.forEach((k, i) => body.appendChild(h2(doc, "span", { text: t(k, i === 0 && p.count !== void 0 ? { count: p.count } : void 0) })));
109164
+ if (p.forgotLink) {
109165
+ const ft = forgotTarget();
109166
+ if (ft) body.appendChild(linkEl(t("errors.goToForgot"), ft, ""));
109167
+ }
109168
+ if (p.gcdrWebLink && webUrl) body.appendChild(linkEl(t("login.gcdrWeb"), `${webUrl}/login`, ""));
109169
+ if (p.support && supportHref) body.appendChild(linkEl(t("login.support"), supportHref, ""));
109170
+ } else if (err.messageKey) {
109171
+ body.appendChild(h2(doc, "span", { text: t(err.messageKey) }));
109172
+ }
109173
+ if (err.help) {
109174
+ const who = supportHref ? t("errors.helpSupport") : t("errors.helpAdmin");
109175
+ body.appendChild(h2(doc, "span", { text: t("errors.invalidCredentialsHelp", { who }) }));
109176
+ if (supportHref) body.appendChild(linkEl(t("login.support"), supportHref, ""));
109177
+ }
109178
+ const ic = p?.icon === "lock" ? ICONS.lock(16) : p?.icon === "shieldAlert" ? ICONS.shieldAlert(16) : ICONS.alert(16);
109179
+ const banner = h2(doc, "div", { class: `myio-gcdr-banner myio-gcdr-banner--${tone}`, tabindex: "-1" }, icon(doc, ic, "myio-gcdr-banner__icon"), body);
109180
+ els.alerts.appendChild(banner);
109181
+ els.banner = banner;
109182
+ };
109183
+ const syncControls = () => {
109184
+ if (!els.submit || !els.email || !els.password) return;
109185
+ const busy = phase === "submitting" || phase === "success";
109186
+ const blocked = busy || leaving || !!lockedKey;
109187
+ els.submit.setAttribute("aria-disabled", blocked ? "true" : "false");
109188
+ els.submit.setAttribute("aria-busy", busy ? "true" : "false");
109189
+ if (lockedKey && els.banner) {
109190
+ if (!els.banner.id) els.banner.id = `myio-gcdr-lock-${Math.random().toString(36).slice(2, 8)}`;
109191
+ els.submit.setAttribute("aria-describedby", els.banner.id);
109192
+ } else els.submit.removeAttribute("aria-describedby");
109193
+ els.submit.textContent = "";
109194
+ if (busy) {
109195
+ els.submit.append(icon(doc, ICONS.spinner(18), "myio-gcdr-login__spin"), h2(doc, "span", { text: t("login.signingIn") }));
109196
+ } else els.submit.append(h2(doc, "span", { text: t("login.signIn") }));
109197
+ els.email.readOnly = busy || leaving;
109198
+ els.password.readOnly = busy || leaving;
109199
+ };
109200
+ const render3 = () => {
109201
+ if (destroyed) return;
109202
+ if (els.email) emailValue = els.email.value;
109203
+ if (els.password) passwordValue = els.password.value;
109204
+ const hadFocusId = doc.activeElement && cardHost.contains(doc.activeElement) ? doc.activeElement.getAttribute("data-k") : null;
109205
+ cardHost.textContent = "";
109206
+ const locale = getLocale();
109207
+ const { root, body, footer, title } = buildPanel(
109208
+ doc,
109209
+ cardHost,
109210
+ { eyebrow: options.brand?.label ?? t("login.eyebrow"), title: t("login.title"), footer: true, accent: options.brand?.accent, bandColor: options.brand?.bandColor, tint: options.brand?.tint, logoUrl: options.assets?.logoUrl },
109211
+ locale
109212
+ );
109213
+ if (options.size && options.embed) root.style.maxWidth = options.size === "xl" ? "37rem" : options.size === "lg" ? "32rem" : "28rem";
109214
+ else if (options.embed) root.style.maxWidth = "28rem";
109215
+ root.style.margin = "0 auto";
109216
+ if (options.brand?.accent) root.style.setProperty("--myio-gcdr-accent-hover", options.brand.accent);
109217
+ root.setAttribute("data-theme", getTheme());
109218
+ els = { root, title };
109219
+ const noticeEl = h2(doc, "div", { class: "myio-gcdr-login__alerts", role: "status", "aria-live": "polite" });
109220
+ const alerts = h2(doc, "div", { class: "myio-gcdr-login__alerts", role: "alert" });
109221
+ els.notice = noticeEl;
109222
+ els.alerts = alerts;
109223
+ const form = h2(doc, "form", { class: "myio-gcdr-login__form", novalidate: true });
109224
+ const uid2 = Math.random().toString(36).slice(2, 8);
109225
+ const email = h2(doc, "input", {
109226
+ id: `myio-gcdr-email-${uid2}`,
109227
+ "data-k": "email",
109228
+ class: "myio-gcdr-login__input",
109229
+ type: "email",
109230
+ inputmode: "email",
109231
+ autocomplete: "username",
109232
+ autocapitalize: "none",
109233
+ spellcheck: "false",
109234
+ placeholder: t("login.emailPlaceholder"),
109235
+ "aria-invalid": fieldErrors.email ? "true" : "false"
109236
+ });
109237
+ email.value = emailValue;
109238
+ const emailErr = h2(doc, "span", { id: `myio-gcdr-email-err-${uid2}`, class: "myio-gcdr-login__fielderror", text: fieldErrors.email ? t(fieldErrors.email) : "" });
109239
+ if (fieldErrors.email) email.setAttribute("aria-describedby", emailErr.id);
109240
+ const emailField = h2(
109241
+ doc,
109242
+ "div",
109243
+ { class: "myio-gcdr-login__field" },
109244
+ h2(doc, "label", { class: "myio-gcdr-login__label", for: email.id, text: t("login.email") }),
109245
+ email,
109246
+ fieldErrors.email ? emailErr : null
109247
+ );
109248
+ if (options.initialEmail) {
109249
+ const notYou = h2(doc, "button", { type: "button", class: "myio-gcdr-login__link", text: t("login.notYou") });
109250
+ notYou.addEventListener("click", () => {
109251
+ email.value = "";
109252
+ emailValue = "";
109253
+ onEmailInput();
109254
+ email.focus();
109255
+ });
109256
+ emailField.appendChild(notYou);
109257
+ }
109258
+ const password = h2(doc, "input", {
109259
+ id: `myio-gcdr-pass-${uid2}`,
109260
+ "data-k": "password",
109261
+ class: "myio-gcdr-login__input myio-gcdr-login__input--password",
109262
+ type: passwordVisible ? "text" : "password",
109263
+ autocomplete: "current-password",
109264
+ enterkeyhint: "go",
109265
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
109266
+ "aria-invalid": fieldErrors.password ? "true" : "false"
109267
+ });
109268
+ password.value = passwordValue;
109269
+ const passErr = h2(doc, "span", { id: `myio-gcdr-pass-err-${uid2}`, class: "myio-gcdr-login__fielderror", text: fieldErrors.password ? t(fieldErrors.password) : "" });
109270
+ if (fieldErrors.password) password.setAttribute("aria-describedby", passErr.id);
109271
+ const control = h2(doc, "div", { class: "myio-gcdr-login__control" }, password);
109272
+ if (options.show?.passwordToggle !== false) {
109273
+ const eye = h2(doc, "button", { type: "button", class: "myio-gcdr-login__eye", "aria-pressed": passwordVisible ? "true" : "false", "aria-label": t(passwordVisible ? "login.hidePassword" : "login.showPassword"), "aria-controls": password.id });
109274
+ eye.appendChild(icon(doc, passwordVisible ? ICONS.eyeOff(18) : ICONS.eye(18)));
109275
+ eye.addEventListener("click", () => {
109276
+ passwordVisible = !passwordVisible;
109277
+ password.type = passwordVisible ? "text" : "password";
109278
+ eye.setAttribute("aria-pressed", passwordVisible ? "true" : "false");
109279
+ eye.setAttribute("aria-label", t(passwordVisible ? "login.hidePassword" : "login.showPassword"));
109280
+ eye.textContent = "";
109281
+ eye.appendChild(icon(doc, passwordVisible ? ICONS.eyeOff(18) : ICONS.eye(18)));
109282
+ });
109283
+ control.appendChild(eye);
109284
+ }
109285
+ const caps = h2(doc, "span", { class: "myio-gcdr-login__hint", "aria-live": "polite" });
109286
+ const capsCheck = (e) => {
109287
+ const on = typeof e.getModifierState === "function" && e.getModifierState("CapsLock");
109288
+ caps.textContent = on ? t("login.capsLockOn") : "";
109289
+ };
109290
+ password.addEventListener("keydown", capsCheck);
109291
+ password.addEventListener("keyup", capsCheck);
109292
+ const passField = h2(
109293
+ doc,
109294
+ "div",
109295
+ { class: "myio-gcdr-login__field" },
109296
+ h2(doc, "label", { class: "myio-gcdr-login__label", for: password.id, text: t("login.password") }),
109297
+ control,
109298
+ caps,
109299
+ fieldErrors.password ? passErr : null
109300
+ );
109301
+ const row = h2(doc, "div", { class: "myio-gcdr-login__row" });
109302
+ if (options.show?.rememberMe !== false) {
109303
+ const cb = h2(doc, "input", { type: "checkbox" });
109304
+ cb.checked = rememberValue;
109305
+ cb.addEventListener("change", () => {
109306
+ rememberValue = cb.checked;
109307
+ });
109308
+ row.appendChild(h2(doc, "label", { class: "myio-gcdr-login__remember" }, cb, h2(doc, "span", { text: t("login.rememberMe") })));
109309
+ } else row.appendChild(h2(doc, "span"));
109310
+ const ft = forgotTarget();
109311
+ if (ft) row.appendChild(linkEl(t("login.forgotPassword"), ft));
109312
+ const submit = h2(doc, "button", { type: "submit", "data-k": "submit", class: "myio-gcdr-login__submit", "data-style": options.submitStyle ?? "auth" });
109313
+ form.append(emailField, passField, row, submit);
109314
+ form.addEventListener("submit", (e) => {
109315
+ e.preventDefault();
109316
+ void doSubmit();
109317
+ });
109318
+ email.addEventListener("input", () => {
109319
+ emailValue = email.value;
109320
+ onEmailInput();
109321
+ });
109322
+ password.addEventListener("input", () => {
109323
+ passwordValue = password.value;
109324
+ if (fieldErrors.password) {
109325
+ fieldErrors.password = validate(email.value, password.value).passwordError;
109326
+ if (!fieldErrors.password) {
109327
+ password.setAttribute("aria-invalid", "false");
109328
+ passErr.remove();
109329
+ }
109330
+ }
109331
+ });
109332
+ body.append(noticeEl, alerts, form);
109333
+ if (footer) {
109334
+ const reg = options.links?.register;
109335
+ if (reg) {
109336
+ footer.append(h2(doc, "span", { text: `${t("login.noAccount")} ` }), linkEl(t("login.createAccount"), reg));
109337
+ } else footer.appendChild(h2(doc, "span", { text: options.footerText ? localize(options.footerText, locale) : t("login.askAdmin") }));
109338
+ internals.decorateFooter?.(footer, api);
109339
+ }
109340
+ els = { ...els, email, password, submit, caps };
109341
+ renderNotice();
109342
+ renderAlerts();
109343
+ syncControls();
109344
+ if (hadFocusId) cardHost.querySelector(`[data-k="${hadFocusId}"]`)?.focus();
109345
+ };
109346
+ const onEmailInput = () => {
109347
+ const key = emailKey(emailValue);
109348
+ if (fieldErrors.email) {
109349
+ fieldErrors.email = validate(emailValue, "").emailError;
109350
+ if (!fieldErrors.email) render3();
109351
+ }
109352
+ if (lockedKey && key !== lockedKey) {
109353
+ lockedKey = null;
109354
+ err = {};
109355
+ renderAlerts();
109356
+ syncControls();
109357
+ }
109358
+ if (streakKey && key !== streakKey) {
109359
+ noCounterStreak = 0;
109360
+ streakKey = null;
109361
+ }
109362
+ };
109363
+ const focusTarget = (f) => {
109364
+ const el2 = f === "password" ? els.password : f === "email" ? els.email : f === "banner" ? els.banner : els.submit;
109365
+ el2?.focus();
109366
+ };
109367
+ const setError = (code, pres, opts) => {
109368
+ err = { code, pres, help: opts.help };
109369
+ if (pres.clearPassword && els.password) {
109370
+ els.password.value = "";
109371
+ passwordValue = "";
109372
+ }
109373
+ renderAlerts();
109374
+ syncControls();
109375
+ focusTarget(pres.focus);
109376
+ if (opts.notify !== false) safeCall("onError", options.onError, { code, remainingAttempts: opts.remaining });
109377
+ };
109378
+ const doSubmit = async () => {
109379
+ if (destroyed || phase !== "idle" || leaving || lockedKey) return;
109380
+ const email = els.email.value;
109381
+ const password = els.password.value;
109382
+ const v = validate(email, password);
109383
+ fieldErrors = { email: v.emailError, password: v.passwordError };
109384
+ if (v.emailError || v.passwordError) {
109385
+ render3();
109386
+ (v.emailError ? els.email : els.password)?.focus();
109387
+ return;
109388
+ }
109389
+ fieldErrors = {};
109390
+ attempt += 1;
109391
+ const my = attempt;
109392
+ phase = "submitting";
109393
+ err = { ...err, pres: void 0, messageKey: void 0, help: false, code: void 0 };
109394
+ if (passwordVisible) {
109395
+ passwordVisible = false;
109396
+ els.password.type = "password";
109397
+ }
109398
+ renderAlerts();
109399
+ syncControls();
109400
+ const ac = new AbortController();
109401
+ attemptAbort = ac;
109402
+ abortCause = null;
109403
+ let timer;
109404
+ const timeout = new Promise((_, reject) => {
109405
+ if (viewTimeoutMs) timer = setTimeout(() => {
109406
+ abortCause = "timeout";
109407
+ ac.abort();
109408
+ reject(Object.assign(new Error("timeout"), { myioGcdrCode: "TIMEOUT" }));
109409
+ }, viewTimeoutMs);
109410
+ });
109411
+ let outcome;
109412
+ try {
109413
+ const raw = await Promise.race([strategy({ email: v.email, password, remember: rememberValue, locale: getLocale() }, { signal: ac.signal, attempt: my }), timeout]);
109414
+ outcome = normaliseResult(raw);
109415
+ if (outcome.kind === "error" && outcome.code === "INTEGRATION_ERROR" && !(raw && typeof raw === "object" && typeof raw.ok === "boolean")) {
109416
+ console.error("[MYIO Login] INTEGRATION_ERROR: invalid onSubmit result");
109417
+ }
109418
+ } catch (e) {
109419
+ outcome = { kind: "thrown", err: e };
109420
+ } finally {
109421
+ if (timer) clearTimeout(timer);
109422
+ }
109423
+ if (destroyed || my !== attempt || abortCause === "destroy" || abortCause === "exit") return;
109424
+ attemptAbort = null;
109425
+ if (outcome.kind === "thrown") {
109426
+ phase = "idle";
109427
+ const code = abortCause === "timeout" ? "TIMEOUT" : normaliseThrown(outcome.err);
109428
+ setError(code, present({ kind: "error", code }), {});
109429
+ return;
109430
+ }
109431
+ if (outcome.kind === "error") {
109432
+ phase = "idle";
109433
+ const k = emailKey(v.email);
109434
+ let help = false;
109435
+ if (outcome.code === "INVALID_CREDENTIALS" && outcome.remainingAttempts === void 0) {
109436
+ noCounterStreak = streakKey === k ? noCounterStreak + 1 : 1;
109437
+ streakKey = k;
109438
+ help = noCounterStreak >= 2;
109439
+ } else {
109440
+ noCounterStreak = 0;
109441
+ streakKey = null;
109442
+ }
109443
+ if (outcome.code === "ACCOUNT_LOCKED") lockedKey = k;
109444
+ setError(outcome.code, present(outcome), { help, remaining: outcome.remainingAttempts });
109445
+ return;
109446
+ }
109447
+ phase = "success";
109448
+ if (els.password) els.password.value = "";
109449
+ passwordValue = "";
109450
+ err = {};
109451
+ noCounterStreak = 0;
109452
+ if (options.show?.rememberMe !== false) storageSet(`${prefix}rememberedEmail`, rememberValue ? v.email : null);
109453
+ renderAlerts();
109454
+ syncControls();
109455
+ const sa = new AbortController();
109456
+ successAbort = sa;
109457
+ try {
109458
+ await options.onSuccess(outcome.session, { signal: sa.signal });
109459
+ } catch {
109460
+ if (destroyed || sa.signal.aborted) return;
109461
+ console.error("[MYIO Login] onSuccess failed");
109462
+ phase = "idle";
109463
+ err = { messageKey: "errors.postLoginFailed", pres: { tone: "error", keys: ["errors.postLoginFailed"], icon: "alert", clearPassword: true, focus: "password" } };
109464
+ renderAlerts();
109465
+ syncControls();
109466
+ els.password?.focus();
109467
+ return;
109468
+ }
109469
+ if (destroyed || sa.signal.aborted) return;
109470
+ internals.afterSuccess?.();
109471
+ };
109472
+ const api = {
109473
+ abortAttempt() {
109474
+ if (attemptAbort) {
109475
+ abortCause = "exit";
109476
+ attemptAbort.abort();
109477
+ attemptAbort = null;
109478
+ attempt += 1;
109479
+ }
109480
+ if (phase === "submitting") phase = "idle";
109481
+ leaving = true;
109482
+ syncControls();
109483
+ },
109484
+ clearPassword() {
109485
+ if (els.password) els.password.value = "";
109486
+ passwordValue = "";
109487
+ },
109488
+ showLeaveFailed() {
109489
+ leaving = false;
109490
+ err = { messageKey: "errors.leaveFailed", pres: { tone: "error", keys: ["errors.leaveFailed"], icon: "alert", clearPassword: false, focus: "submit" } };
109491
+ renderAlerts();
109492
+ syncControls();
109493
+ },
109494
+ t: (k) => t(k),
109495
+ locale: getLocale,
109496
+ phase: () => phase
109497
+ };
109498
+ let offChange;
109499
+ if (shell) {
109500
+ const asideOpt = options.aside ?? { kind: "about" };
109501
+ if (asideOpt.kind === "about") {
109502
+ const healthUrl = asideOpt.healthUrl !== void 0 ? asideOpt.healthUrl : options.gcdr ? `${options.gcdr.apiUrl.replace(/\/+$/, "").replace(/\/api\/v\d+$/, "")}/health` : false;
109503
+ shell.setSlot("aside", { kind: "about", healthUrl });
109504
+ } else if (asideOpt.kind === "signedOutPrompt") shell.setSlot("aside", { kind: "signedOutPrompt", text: asideOpt.text });
109505
+ else if (asideOpt.kind === "custom") shell.setSlot("aside", asideOpt.render);
109506
+ shell.setSlot("main", (el2) => {
109507
+ el2.appendChild(cardHost);
109508
+ });
109509
+ offChange = shell.onChange(() => render3());
109510
+ } else if (embedCtx) {
109511
+ const offT = embedCtx.on("theme", () => render3());
109512
+ const offL = embedCtx.on("locale", () => render3());
109513
+ offChange = () => {
109514
+ offT();
109515
+ offL();
109516
+ };
109517
+ embedCtx.signal.addEventListener("abort", () => handle.destroy(), { once: true });
109518
+ }
109519
+ render3();
109520
+ const autoFocus = options.autoFocus ?? !isCoarsePointer();
109521
+ if (autoFocus && presentation === "inline") (options.initialEmail ? els.password : els.email)?.focus();
109522
+ const restricted = shell ? {
109523
+ setSlot: (name, content, o) => {
109524
+ if (name === "main") fail("the main slot belongs to the login view");
109525
+ shell.setSlot(name, content, o);
109526
+ },
109527
+ setShow: (s) => shell.setShow(s)
109528
+ } : void 0;
109529
+ const handle = {
109530
+ getState() {
109531
+ return {
109532
+ phase: destroyed ? "destroyed" : leaving ? "leaving" : phase,
109533
+ error: err.code,
109534
+ message: err.messageKey ?? err.pres?.keys[0],
109535
+ locked: !!lockedKey,
109536
+ notice: notice?.code,
109537
+ captcha: "none",
109538
+ email: emailValue.trim() || void 0,
109539
+ locale: getLocale(),
109540
+ theme: getTheme()
109541
+ };
109542
+ },
109543
+ setLocale(l) {
109544
+ if (shell) shell.setLocale(l);
109545
+ },
109546
+ setTheme(th) {
109547
+ if (shell) shell.setTheme(th);
109548
+ },
109549
+ showError(code, extra) {
109550
+ if (destroyed) return;
109551
+ const o = normaliseResult({ ok: false, code, remainingAttempts: extra?.remainingAttempts, message: extra?.message });
109552
+ if (o.kind !== "error") return;
109553
+ if (o.code === "ACCOUNT_LOCKED") lockedKey = emailKey(emailValue);
109554
+ const pres = present(o);
109555
+ err = { code: o.code, pres };
109556
+ renderAlerts();
109557
+ syncControls();
109558
+ },
109559
+ clearError() {
109560
+ if (destroyed) return;
109561
+ err = {};
109562
+ lockedKey = null;
109563
+ renderAlerts();
109564
+ syncControls();
109565
+ },
109566
+ setNotice(n) {
109567
+ if (destroyed) return;
109568
+ notice = n && n.code === "SESSION_EXPIRED" ? n : null;
109569
+ renderNotice();
109570
+ },
109571
+ reset() {
109572
+ if (destroyed || phase !== "success") return;
109573
+ successAbort?.abort();
109574
+ phase = "idle";
109575
+ syncControls();
109576
+ },
109577
+ focus() {
109578
+ (options.initialEmail ? els.password : els.email)?.focus();
109579
+ },
109580
+ get shell() {
109581
+ return restricted;
109582
+ },
109583
+ destroy() {
109584
+ if (destroyed) return;
109585
+ destroyed = true;
109586
+ abortCause = "destroy";
109587
+ attemptAbort?.abort();
109588
+ successAbort?.abort();
109589
+ offChange?.();
109590
+ if (els.password) els.password.value = "";
109591
+ passwordValue = "";
109592
+ if (shell) shell.destroy();
109593
+ else {
109594
+ cardHost.textContent = "";
109595
+ releaseEmbedStyles?.();
109596
+ }
109597
+ },
109598
+ _api: api
109599
+ };
109600
+ return handle;
109601
+ }
109602
+ function createMyioGcdrLoginView(container, options) {
109603
+ const impl = createLoginViewImpl(container, options, { presentation: "inline" });
109604
+ const { _api, ...pub } = impl;
109605
+ void _api;
109606
+ return Object.defineProperty(pub, "shell", { get: () => impl.shell, enumerable: true });
109607
+ }
109608
+
109609
+ // src/components/myio-gcdr-login/modal.ts
109610
+ var MODAL_ATTR = "data-myio-gcdr-modal";
109611
+ var LOCK_ATTR = "data-myio-gcdr-scroll-lock";
109612
+ var INERT_PREV = "data-myio-gcdr-inert-prev";
109613
+ function isMyioGcdrLoginModalOpen(target) {
109614
+ if (target instanceof HTMLElement) return !!target.querySelector(`:scope > [${MODAL_ATTR}]`);
109615
+ const doc = target ?? (typeof document !== "undefined" ? document : void 0);
109616
+ return !!doc?.querySelector(`[${MODAL_ATTR}]`);
109617
+ }
109618
+ function conflict() {
109619
+ const e = new Error("[MYIO Login] a login modal is already open here");
109620
+ e.code = "LOGIN_MODAL_ALREADY_OPEN";
109621
+ throw e;
109622
+ }
109623
+ function openMyioGcdrLoginModal(options) {
109624
+ const ov = options.overlay ?? {};
109625
+ const scopeEl = typeof ov.scope === "object" && ov.scope ? ov.scope.element : null;
109626
+ const doc = scopeEl?.ownerDocument ?? document;
109627
+ const viewport = !scopeEl;
109628
+ const dismissible = ov.dismissible === true;
109629
+ if (viewport && !dismissible && !ov.exit) {
109630
+ throw new TypeError("[MYIO Login] a viewport modal that is not dismissible needs overlay.exit (a way out)");
109631
+ }
109632
+ if (ov.exit && (!ov.exit.href || typeof ov.exit.href !== "string")) throw new TypeError("[MYIO Login] overlay.exit.href is required");
109633
+ if (ov.secondaryAction) {
109634
+ const e = new TypeError("[MYIO Login] overlay.secondaryAction is not available in this version (RFC-0236 PR 4)");
109635
+ e.code = "MYIO_GCDR_SECONDARY_UNSUPPORTED";
109636
+ throw e;
109637
+ }
109638
+ if (viewport ? isMyioGcdrLoginModalOpen(doc) : isMyioGcdrLoginModalOpen(scopeEl)) conflict();
109639
+ const backdrop = ov.backdrop ?? "solid";
109640
+ const opacity = typeof ov.opacity === "number" ? Math.min(1, Math.max(0, ov.opacity)) : 0.5;
109641
+ const blur = typeof ov.blur === "number" ? ov.blur : backdrop === "blur" ? 8 : 4;
109642
+ const previouslyFocused = doc.activeElement;
109643
+ const releaseStyles = acquireStyles(viewport ? doc.body : scopeEl, { nonce: options.cspNonce, loadFont: options.fonts?.load !== false });
109644
+ const overlay = h2(doc, "div", {
109645
+ class: "myio-gcdr-overlay",
109646
+ [MODAL_ATTR]: "1",
109647
+ role: "dialog",
109648
+ "aria-modal": viewport ? "true" : null,
109649
+ "data-scope": viewport ? "viewport" : "element",
109650
+ "data-backdrop": backdrop
109651
+ });
109652
+ overlay.style.zIndex = String(ov.zIndex ?? 1e4);
109653
+ const layers = [];
109654
+ const layer = (bg, extra = "") => {
109655
+ const l = h2(doc, "div", { class: "myio-gcdr-overlay__layer", "aria-hidden": "true" });
109656
+ l.setAttribute("style", `background:${bg};${extra}`);
109657
+ layers.push(l);
109658
+ overlay.appendChild(l);
109659
+ return l;
109660
+ };
109661
+ const paintBackdrop = (dark) => {
109662
+ layers.splice(0).forEach((l) => l.remove());
109663
+ const blurCss = `-webkit-backdrop-filter:blur(${blur}px);backdrop-filter:blur(${blur}px)`;
109664
+ if (backdrop === "blur") {
109665
+ layer(`rgba(20,12,40,${opacity})`, blurCss);
109666
+ } else {
109667
+ layer(dark ? "linear-gradient(180deg,#1B1530 0%,#15121F 45%,#111827 100%)" : "linear-gradient(180deg,#DCD2F3 0%,#EEEAF8 45%,#F7F5FC 100%)");
109668
+ if (backdrop === "image" && options.assets?.wallpaper) {
109669
+ const wp = options.assets.wallpaper;
109670
+ let portrait = false;
109671
+ try {
109672
+ portrait = matchMedia("(orientation: portrait)").matches;
109673
+ } catch {
109674
+ }
109675
+ const url = dark ? portrait ? wp.mobileDark ?? wp.dark : wp.dark : portrait ? wp.mobileLight ?? wp.light : wp.light;
109676
+ if (url) layer(`url("${url.replace(/"/g, "%22")}") center/cover no-repeat`);
109677
+ }
109678
+ layer(`rgba(255,255,255,${(dark ? 0.1 : 0.44) * opacity})`, blurCss);
109679
+ layer(dark ? "linear-gradient(135deg,rgba(45,22,105,.55) 0%,rgba(27,21,48,.30) 50%,rgba(45,22,105,.55) 100%)" : "linear-gradient(135deg,rgba(107,74,191,.34) 0%,rgba(107,74,191,.14) 50%,rgba(107,74,191,.34) 100%)");
109680
+ }
109681
+ layers.forEach((l) => overlay.insertBefore(l, content));
109682
+ };
109683
+ const content = h2(doc, "div", { class: "myio-gcdr-overlay__content" });
109684
+ overlay.appendChild(content);
109685
+ let restoreStatic = null;
109686
+ if (viewport) doc.body.appendChild(overlay);
109687
+ else {
109688
+ const el2 = scopeEl;
109689
+ if (getComputedStyle(el2).position === "static") {
109690
+ const prev = el2.style.position;
109691
+ el2.style.position = "relative";
109692
+ restoreStatic = () => {
109693
+ el2.style.position = prev;
109694
+ };
109695
+ }
109696
+ el2.appendChild(overlay);
109697
+ }
109698
+ let open = true;
109699
+ let closing = false;
109700
+ let exitTimer;
109701
+ const close = (reason) => {
109702
+ if (!open || closing) return;
109703
+ closing = true;
109704
+ if (exitTimer) clearTimeout(exitTimer);
109705
+ mo?.disconnect();
109706
+ try {
109707
+ view.destroy();
109708
+ } catch {
109709
+ }
109710
+ doc.removeEventListener("keydown", onKey, true);
109711
+ overlay.removeEventListener("keydown", onKey, true);
109712
+ if (viewport) {
109713
+ releaseInert();
109714
+ releaseScroll();
109715
+ }
109716
+ overlay.remove();
109717
+ restoreStatic?.();
109718
+ releaseStyles();
109719
+ open = false;
109720
+ if (previouslyFocused && previouslyFocused.isConnected && typeof previouslyFocused.focus === "function") previouslyFocused.focus();
109721
+ else if (viewport) doc.body.focus?.();
109722
+ safeCall("onClose", options.onClose, reason);
109723
+ };
109724
+ const { overlay: _o, onOpen, onClose, ...viewOpts } = options;
109725
+ void _o;
109726
+ void onClose;
109727
+ const view = createLoginViewImpl(content, { ...viewOpts, aside: options.aside ?? { kind: "none" }, autoFocus: false }, {
109728
+ presentation: "modal",
109729
+ shellWallpaper: false,
109730
+ afterSuccess: () => {
109731
+ if (ov.closeOnSuccess !== false) close("success");
109732
+ },
109733
+ decorateFooter: (footer, api) => {
109734
+ if (!ov.exit) return;
109735
+ const label = localize(ov.exit.label, api.locale());
109736
+ const a = h2(doc, "a", { class: "myio-gcdr-login__link", href: ov.exit.href, style: "display:inline-block;margin-left:12px" }, label);
109737
+ a.addEventListener("click", () => {
109738
+ if (api.phase() === "success") return;
109739
+ api.abortAttempt();
109740
+ api.clearPassword();
109741
+ a.textContent = api.t("login.leaving");
109742
+ a.setAttribute("aria-busy", "true");
109743
+ exitTimer = setTimeout(() => {
109744
+ if (!open) return;
109745
+ a.textContent = label;
109746
+ a.removeAttribute("aria-busy");
109747
+ api.showLeaveFailed();
109748
+ a.focus();
109749
+ }, 2e3);
109750
+ });
109751
+ footer.appendChild(a);
109752
+ }
109753
+ });
109754
+ const shellRoot = content.querySelector(".myio-gcdr-shell");
109755
+ const syncTheme = () => {
109756
+ const dark = view.getState().theme === "dark";
109757
+ overlay.setAttribute("data-theme", dark ? "dark" : "light");
109758
+ paintBackdrop(dark);
109759
+ };
109760
+ syncTheme();
109761
+ const mo = shellRoot ? new MutationObserver(syncTheme) : null;
109762
+ mo?.observe(shellRoot, { attributes: true, attributeFilter: ["data-theme"] });
109763
+ if (backdrop === "blur" && options.show?.themeToggle === void 0) view.shell?.setShow({ themeToggle: false });
109764
+ const title = content.querySelector(".myio-gcdr-panel__title");
109765
+ if (title) {
109766
+ if (!title.id) title.id = `myio-gcdr-title-${Math.random().toString(36).slice(2, 8)}`;
109767
+ overlay.setAttribute("aria-labelledby", title.id);
109768
+ }
109769
+ if (dismissible) {
109770
+ const x = h2(doc, "button", { type: "button", class: "myio-gcdr-shell__iconbtn myio-gcdr-overlay__close", "aria-label": view._api.t("modal.close") });
109771
+ x.appendChild(icon(doc, ICONS.x(18)));
109772
+ x.addEventListener("click", () => {
109773
+ const p = view.getState().phase;
109774
+ if (p !== "submitting" && p !== "success") close("dismiss");
109775
+ });
109776
+ content.appendChild(x);
109777
+ }
109778
+ const inerted = [];
109779
+ const releaseInert = () => {
109780
+ for (const el2 of inerted) {
109781
+ const prev = el2.getAttribute(INERT_PREV);
109782
+ if (prev === "true") el2.setAttribute("inert", "");
109783
+ else el2.removeAttribute("inert");
109784
+ el2.removeAttribute(INERT_PREV);
109785
+ }
109786
+ inerted.length = 0;
109787
+ };
109788
+ let scrollPrev = null;
109789
+ const releaseScroll = () => {
109790
+ const html = doc.documentElement;
109791
+ const n = Math.max(0, (parseInt(html.getAttribute(LOCK_ATTR) || "1", 10) || 1) - 1);
109792
+ if (n === 0) {
109793
+ html.removeAttribute(LOCK_ATTR);
109794
+ if (scrollPrev) {
109795
+ html.style.overflow = scrollPrev.html;
109796
+ doc.body.style.overflow = scrollPrev.body;
109797
+ }
109798
+ } else html.setAttribute(LOCK_ATTR, String(n));
109799
+ };
109800
+ if (viewport) {
109801
+ for (const el2 of Array.from(doc.body.children)) {
109802
+ if (el2 === overlay || el2.tagName === "SCRIPT" || el2.tagName === "STYLE") continue;
109803
+ el2.setAttribute(INERT_PREV, el2.hasAttribute("inert") ? "true" : "false");
109804
+ el2.setAttribute("inert", "");
109805
+ inerted.push(el2);
109806
+ }
109807
+ const html = doc.documentElement;
109808
+ const n = parseInt(html.getAttribute(LOCK_ATTR) || "0", 10) || 0;
109809
+ if (n === 0) scrollPrev = { html: html.style.overflow, body: doc.body.style.overflow };
109810
+ html.setAttribute(LOCK_ATTR, String(n + 1));
109811
+ html.style.overflow = "hidden";
109812
+ doc.body.style.overflow = "hidden";
109813
+ }
109814
+ const focusables = () => Array.from(overlay.querySelectorAll('a[href],button:not([disabled]),input:not([disabled]),select,textarea,[tabindex]:not([tabindex="-1"])')).filter((el2) => !el2.hidden && el2.offsetParent !== null);
109815
+ const onKey = (e) => {
109816
+ if (!open) return;
109817
+ if (e.key === "Escape" && dismissible) {
109818
+ const p = view.getState().phase;
109819
+ if (p !== "submitting" && p !== "success") {
109820
+ e.preventDefault();
109821
+ close("dismiss");
109822
+ }
109823
+ return;
109824
+ }
109825
+ if (e.key === "Tab" && viewport) {
109826
+ const list = focusables();
109827
+ if (!list.length) return;
109828
+ const first = list[0];
109829
+ const last = list[list.length - 1];
109830
+ const active = doc.activeElement;
109831
+ if (e.shiftKey && (active === first || !overlay.contains(active))) {
109832
+ e.preventDefault();
109833
+ last.focus();
109834
+ } else if (!e.shiftKey && (active === last || !overlay.contains(active))) {
109835
+ e.preventDefault();
109836
+ first.focus();
109837
+ }
109838
+ }
109839
+ };
109840
+ if (viewport) doc.addEventListener("keydown", onKey, true);
109841
+ else overlay.addEventListener("keydown", onKey, true);
109842
+ const emailInput = content.querySelector('[data-k="email"]');
109843
+ const passInput = content.querySelector('[data-k="password"]');
109844
+ const coarse = (() => {
109845
+ try {
109846
+ return matchMedia("(pointer: coarse)").matches;
109847
+ } catch {
109848
+ return false;
109849
+ }
109850
+ })();
109851
+ const wantInput = options.autoFocus ?? !coarse;
109852
+ ((wantInput ? options.initialEmail ? passInput : emailInput : title) ?? title)?.focus();
109853
+ safeCall("onOpen", onOpen);
109854
+ const handle = {
109855
+ getState: () => view.getState(),
109856
+ setLocale: (l) => view.setLocale(l),
109857
+ setTheme: (th) => view.setTheme(th),
109858
+ showError: (c, x) => view.showError(c, x),
109859
+ clearError: () => view.clearError(),
109860
+ setNotice: (n) => view.setNotice(n),
109861
+ reset: () => view.reset(),
109862
+ focus: () => view.focus(),
109863
+ close: () => close("api"),
109864
+ destroy: () => close("api"),
109865
+ get isOpen() {
109866
+ return open;
109867
+ }
109868
+ };
109869
+ return handle;
109870
+ }
109871
+
107784
109872
  // src/components/img-gallery/ScrollableTabs.ts
107785
109873
  var STYLE_ID11 = "myio-tabs-styles";
107786
109874
  var FONT_LINK_ID3 = "myio-dialog-font-nunito";
@@ -108417,13 +110505,13 @@ function createImgGallery(options) {
108417
110505
  grid.appendChild(item);
108418
110506
  });
108419
110507
  }
108420
- function actionBtn(icon, label, danger, onClick) {
110508
+ function actionBtn(icon2, label, danger, onClick) {
108421
110509
  const b = document.createElement("button");
108422
110510
  b.type = "button";
108423
110511
  b.className = `myio-gallery__abtn${danger ? " myio-gallery__abtn--danger" : ""}`;
108424
110512
  b.setAttribute("aria-label", label);
108425
110513
  b.title = label;
108426
- b.innerHTML = icon;
110514
+ b.innerHTML = icon2;
108427
110515
  b.addEventListener("click", onClick);
108428
110516
  return b;
108429
110517
  }
@@ -116563,7 +118651,7 @@ var MenuView = class {
116563
118651
  */
116564
118652
  bindFilterTooltipEvents(listEl) {
116565
118653
  const icons = listEl.querySelectorAll(".filter-icon[data-tooltip-type]");
116566
- icons.forEach((icon) => {
118654
+ icons.forEach((icon2) => {
116567
118655
  const showHandler = (e) => {
116568
118656
  e.stopPropagation();
116569
118657
  const el2 = e.currentTarget;
@@ -116574,9 +118662,9 @@ var MenuView = class {
116574
118662
  const hideHandler = () => {
116575
118663
  this.hideFilterTooltips();
116576
118664
  };
116577
- icon.addEventListener("mouseenter", showHandler);
116578
- icon.addEventListener("click", showHandler);
116579
- icon.addEventListener("mouseleave", hideHandler);
118665
+ icon2.addEventListener("mouseenter", showHandler);
118666
+ icon2.addEventListener("click", showHandler);
118667
+ icon2.addEventListener("mouseleave", hideHandler);
116580
118668
  });
116581
118669
  }
116582
118670
  /**
@@ -120398,11 +122486,11 @@ var FilterModalView = class {
120398
122486
  const allTab = this.filterTabs.find((t) => t.id === "all");
120399
122487
  let html = "";
120400
122488
  if (allTab) {
120401
- const icon = FILTER_TAB_ICONS["all"] || "";
122489
+ const icon2 = FILTER_TAB_ICONS["all"] || "";
120402
122490
  html += `
120403
122491
  <div class="filter-group filter-group-all">
120404
122492
  <button class="filter-tab active" data-filter="all">
120405
- ${icon} ${allTab.label} (<span id="countAll">${counts["all"] || 0}</span>)
122493
+ ${icon2} ${allTab.label} (<span id="countAll">${counts["all"] || 0}</span>)
120406
122494
  </button>
120407
122495
  </div>
120408
122496
  `;
@@ -120415,12 +122503,12 @@ var FilterModalView = class {
120415
122503
  <span class="filter-group-label">${group.label}</span>
120416
122504
  <div class="filter-group-tabs">
120417
122505
  ${groupTabs.map((tab) => {
120418
- const icon = FILTER_TAB_ICONS[tab.id] || "";
122506
+ const icon2 = FILTER_TAB_ICONS[tab.id] || "";
120419
122507
  const count = counts[tab.id] || 0;
120420
122508
  const expandBtn = count > 0 ? `<button class="filter-tab-expand" data-expand-filter="${tab.id}" title="Ver dispositivos">+</button>` : "";
120421
122509
  return `
120422
122510
  <button class="filter-tab active" data-filter="${tab.id}">
120423
- ${icon} ${tab.label} (<span id="count${tab.id.charAt(0).toUpperCase() + tab.id.slice(1)}">${count}</span>)${expandBtn}
122511
+ ${icon2} ${tab.label} (<span id="count${tab.id.charAt(0).toUpperCase() + tab.id.slice(1)}">${count}</span>)${expandBtn}
120424
122512
  </button>
120425
122513
  `;
120426
122514
  }).join("")}
@@ -120797,7 +122885,7 @@ var FilterModalView = class {
120797
122885
  if (!InfoTooltip2?.InfoTooltip) return;
120798
122886
  const filterTabConfig = this.filterTabs.find((t) => t.id === filterId);
120799
122887
  const label = filterTabConfig?.label || filterId;
120800
- const icon = FILTER_TAB_ICONS[filterId] || "\u{1F4CB}";
122888
+ const icon2 = FILTER_TAB_ICONS[filterId] || "\u{1F4CB}";
120801
122889
  let devicesHtml = "";
120802
122890
  if (devices.length === 0) {
120803
122891
  devicesHtml = `
@@ -120849,7 +122937,7 @@ var FilterModalView = class {
120849
122937
  `;
120850
122938
  }
120851
122939
  InfoTooltip2.InfoTooltip.show(triggerEl, {
120852
- icon,
122940
+ icon: icon2,
120853
122941
  title: `${label} (${devices.length})`,
120854
122942
  content: devicesHtml
120855
122943
  });
@@ -121714,7 +123802,7 @@ var FilterModalComponent = class {
121714
123802
  }
121715
123803
  // ── Private ────────────────────────────────
121716
123804
  render() {
121717
- const { title, icon, categories, sortOptions, devices = [] } = this.options;
123805
+ const { title, icon: icon2, categories, sortOptions, devices = [] } = this.options;
121718
123806
  const hasDevices = this.showDeviceGrid && devices.length > 0;
121719
123807
  const modalClass = `myio-fm myio-fm--${this.themeMode}${hasDevices ? " myio-fm--with-devices" : ""}`;
121720
123808
  const bodyClass = `myio-fm__body${hasDevices ? " myio-fm__body--two-col" : ""}`;
@@ -121722,7 +123810,7 @@ var FilterModalComponent = class {
121722
123810
  <div class="${modalClass}">
121723
123811
  <div class="myio-fm__header">
121724
123812
  <div class="myio-fm__header-left">
121725
- ${icon ? `<span class="myio-fm__icon">${icon}</span>` : ""}
123813
+ ${icon2 ? `<span class="myio-fm__icon">${icon2}</span>` : ""}
121726
123814
  <h2 class="myio-fm__title">${this.escapeHtml(title)}</h2>
121727
123815
  </div>
121728
123816
  <button class="myio-fm__close" title="Fechar">
@@ -121801,7 +123889,7 @@ var FilterModalComponent = class {
121801
123889
  renderDeviceItem(device) {
121802
123890
  const isSelected = this.selectedDeviceIds.has(device.id);
121803
123891
  const statusClass = device.status ? `myio-fm__device-status--${device.status}` : "";
121804
- const icon = device.icon || this.getDefaultDeviceIcon(device.type, device.context);
123892
+ const icon2 = device.icon || this.getDefaultDeviceIcon(device.type, device.context);
121805
123893
  return `
121806
123894
  <div class="myio-fm__device-item${isSelected ? " myio-fm__device-item--selected" : ""}"
121807
123895
  data-device-id="${device.id}"
@@ -121809,7 +123897,7 @@ var FilterModalComponent = class {
121809
123897
  <div class="myio-fm__device-checkbox">
121810
123898
  ${ICON_CHECK}
121811
123899
  </div>
121812
- ${icon ? `<span class="myio-fm__device-icon">${icon}</span>` : ""}
123900
+ ${icon2 ? `<span class="myio-fm__device-icon">${icon2}</span>` : ""}
121813
123901
  <div class="myio-fm__device-info">
121814
123902
  <p class="myio-fm__device-label" title="${this.escapeHtml(device.label)}">${this.escapeHtml(device.label)}</p>
121815
123903
  ${device.type ? `<p class="myio-fm__device-type">${this.escapeHtml(device.type)}</p>` : ""}
@@ -122577,7 +124665,7 @@ function createCustomerCardV1(params) {
122577
124665
 
122578
124666
  // src/components/cards/customer-goals/v1.0.0/styles.ts
122579
124667
  var STYLE_ID13 = "myio-customer-goals-card-css";
122580
- var CSS3 = `
124668
+ var CSS4 = `
122581
124669
  .myio-cgc{
122582
124670
  --cgc-surface:#ffffff;
122583
124671
  --cgc-border:#e2e8f0;
@@ -122680,7 +124768,7 @@ function injectCustomerGoalsCardStyles() {
122680
124768
  if (document.getElementById(STYLE_ID13)) return;
122681
124769
  const tag = document.createElement("style");
122682
124770
  tag.id = STYLE_ID13;
122683
- tag.textContent = CSS3;
124771
+ tag.textContent = CSS4;
122684
124772
  document.head.appendChild(tag);
122685
124773
  }
122686
124774
 
@@ -123795,13 +125883,13 @@ var EnergyPanelView = class {
123795
125883
  /**
123796
125884
  * Build a single card HTML with the TELEMETRY_INFO-inspired layout
123797
125885
  */
123798
- buildCardHTML(type, icon, title, value, percentage, tooltip) {
125886
+ buildCardHTML(type, icon2, title, value, percentage, tooltip) {
123799
125887
  const percDisplay = percentage !== null ? `(${percentage}%)` : "";
123800
125888
  const tooltipHTML = tooltip ? `<span class="energy-panel__card-tooltip" title="${tooltip}">\u2139\uFE0F</span>` : "";
123801
125889
  return `
123802
125890
  <div class="energy-panel__card" data-type="${type}">
123803
125891
  <div class="energy-panel__card-header">
123804
- <span class="energy-panel__card-icon">${icon}</span>
125892
+ <span class="energy-panel__card-icon">${icon2}</span>
123805
125893
  <h3 class="energy-panel__card-title">${title}</h3>
123806
125894
  ${tooltipHTML}
123807
125895
  </div>
@@ -126942,7 +129030,7 @@ var HeaderShoppingView = class {
126942
129030
  emit(event, ...args) {
126943
129031
  const handlers = this.eventHandlers.get(event);
126944
129032
  if (handlers) {
126945
- handlers.forEach((h2) => h2(...args));
129033
+ handlers.forEach((h3) => h3(...args));
126946
129034
  }
126947
129035
  }
126948
129036
  /**
@@ -127398,7 +129486,7 @@ function createHeaderShoppingComponent(params) {
127398
129486
  function emit(event, ...args) {
127399
129487
  const handlers = eventHandlers.get(event);
127400
129488
  if (handlers) {
127401
- handlers.forEach((h2) => h2(...args));
129489
+ handlers.forEach((h3) => h3(...args));
127402
129490
  }
127403
129491
  }
127404
129492
  function on(event, handler) {
@@ -128288,7 +130376,7 @@ var MenuShoppingView = class {
128288
130376
  emit(event, ...args) {
128289
130377
  const handlers = this.eventHandlers.get(event);
128290
130378
  if (handlers) {
128291
- handlers.forEach((h2) => h2(...args));
130379
+ handlers.forEach((h3) => h3(...args));
128292
130380
  }
128293
130381
  }
128294
130382
  /**
@@ -128457,7 +130545,7 @@ function createMenuShoppingComponent(params) {
128457
130545
  function emitEvent(event, ...args) {
128458
130546
  const handlers = eventHandlers.get(event);
128459
130547
  if (handlers) {
128460
- handlers.forEach((h2) => h2(...args));
130548
+ handlers.forEach((h3) => h3(...args));
128461
130549
  }
128462
130550
  }
128463
130551
  function cleanup() {
@@ -130450,8 +132538,8 @@ var TelemetryGridShoppingView = class {
130450
132538
  }
130451
132539
  }
130452
132540
  }
130453
- const icon = this.isMaximized ? '<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/>' : '<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>';
130454
- this.maximizeBtnEl.innerHTML = `<svg viewBox="0 0 24 24" width="18" height="18">${icon}</svg>`;
132541
+ const icon2 = this.isMaximized ? '<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/>' : '<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>';
132542
+ this.maximizeBtnEl.innerHTML = `<svg viewBox="0 0 24 24" width="18" height="18">${icon2}</svg>`;
130455
132543
  }
130456
132544
  };
130457
132545
 
@@ -132382,9 +134470,9 @@ var TelemetryInfoShoppingView = class _TelemetryInfoShoppingView {
132382
134470
  this.maximizeBtnEl.style.opacity = "0";
132383
134471
  }
132384
134472
  }
132385
- const icon = this.isMaximized ? '<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" fill="currentColor"/>' : '<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" fill="currentColor"/>';
134473
+ const icon2 = this.isMaximized ? '<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" fill="currentColor"/>' : '<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" fill="currentColor"/>';
132386
134474
  if (this.maximizeBtnEl) {
132387
- this.maximizeBtnEl.innerHTML = `<svg viewBox="0 0 24 24" width="18" height="18">${icon}</svg>`;
134475
+ this.maximizeBtnEl.innerHTML = `<svg viewBox="0 0 24 24" width="18" height="18">${icon2}</svg>`;
132388
134476
  }
132389
134477
  this.params.onExpandClick?.();
132390
134478
  }
@@ -139424,7 +141512,7 @@ function renderTrendChart(data, options = {}) {
139424
141512
  Cr\xEDticos
139425
141513
  </span>
139426
141514
  </div>`;
139427
- const svg = `
141515
+ const svg2 = `
139428
141516
  <svg class="alarms-trend-chart" viewBox="0 0 ${width} ${height}" preserveAspectRatio="xMidYMid meet">
139429
141517
  <defs>
139430
141518
  <linearGradient id="gradTotal" x1="0" y1="0" x2="0" y2="1">
@@ -139445,7 +141533,7 @@ function renderTrendChart(data, options = {}) {
139445
141533
  <circle cx="${lastCritical[0].toFixed(1)}" cy="${lastCritical[1].toFixed(1)}" r="4" fill="${criticalColor}" />
139446
141534
  ${xLabels}
139447
141535
  </svg>`;
139448
- return `<div class="alarms-trend-wrap">${svg}${legend}</div>`;
141536
+ return `<div class="alarms-trend-wrap">${svg2}${legend}</div>`;
139449
141537
  }
139450
141538
  function renderStateDonutChart(byState, options = {}) {
139451
141539
  if (!byState) return renderEmptyChart(200, 200, "Sem dados");
@@ -140489,8 +142577,8 @@ var AlarmsNotificationsPanelView = class {
140489
142577
  }
140490
142578
  const th = (label, col, extraClass = "") => {
140491
142579
  const active = this.sortCol === col;
140492
- const icon = active ? `<span class="atbl-sort-icon is-active">${this.sortDir === "asc" ? "\u25B2" : "\u25BC"}</span>` : `<span class="atbl-sort-icon">\u21C5</span>`;
140493
- return `<th class="atbl-th atbl-th--sortable${extraClass ? " " + extraClass : ""}${active ? " is-sorted" : ""}" data-sort-col="${col}">${label}${icon}</th>`;
142580
+ const icon2 = active ? `<span class="atbl-sort-icon is-active">${this.sortDir === "asc" ? "\u25B2" : "\u25BC"}</span>` : `<span class="atbl-sort-icon">\u21C5</span>`;
142581
+ return `<th class="atbl-th atbl-th--sortable${extraClass ? " " + extraClass : ""}${active ? " is-sorted" : ""}" data-sort-col="${col}">${label}${icon2}</th>`;
140494
142582
  };
140495
142583
  const rows = alarms.map((alarm) => {
140496
142584
  const sev = SEVERITY_CONFIG[alarm.severity];
@@ -144097,9 +146185,9 @@ function renderDualLineChart(data) {
144097
146185
  }
144098
146186
  function formatTrendIndicator(trend) {
144099
146187
  if (trend === void 0 || trend === 0) return "";
144100
- const icon = trend > 0 ? "\u2191" : "\u2193";
146188
+ const icon2 = trend > 0 ? "\u2191" : "\u2193";
144101
146189
  const cls = trend > 0 ? "trend-up" : "trend-down";
144102
- return `<span class="trend-indicator ${cls}">${icon}${Math.abs(trend)}</span>`;
146190
+ return `<span class="trend-indicator ${cls}">${icon2}${Math.abs(trend)}</span>`;
144103
146191
  }
144104
146192
  function renderStatusDonutChart(kpis, period) {
144105
146193
  const offlineCritical = kpis.offlineCriticalCount || 0;
@@ -144405,10 +146493,10 @@ function formatHoursDisplay(hours) {
144405
146493
  const mins = Math.round(hours * 60);
144406
146494
  return `${mins}min`;
144407
146495
  }
144408
- const h2 = Math.floor(hours);
144409
- const m = Math.round((hours - h2) * 60);
144410
- if (m === 0) return `${h2}h`;
144411
- return `${h2}h${String(m).padStart(2, "0")}`;
146496
+ const h3 = Math.floor(hours);
146497
+ const m = Math.round((hours - h3) * 60);
146498
+ if (m === 0) return `${h3}h`;
146499
+ return `${h3}h${String(m).padStart(2, "0")}`;
144412
146500
  }
144413
146501
  function renderMTBFTimelineChart(data) {
144414
146502
  if (!data.segments || data.segments.length === 0) {
@@ -147860,12 +149948,12 @@ var SwitchControlView = class {
147860
149948
  document.querySelectorAll(`.${SWITCH_CONTROL_CSS_PREFIX}__modal-overlay`).forEach((el2) => el2.remove());
147861
149949
  const { labels } = this.settings;
147862
149950
  const newStatus = this.state.status === "on" ? "off" : "on";
147863
- const icon = newStatus === "on" ? "\u{1F4A1}" : "\u{1F50C}";
149951
+ const icon2 = newStatus === "on" ? "\u{1F4A1}" : "\u{1F50C}";
147864
149952
  const modal = document.createElement("div");
147865
149953
  modal.className = `${SWITCH_CONTROL_CSS_PREFIX}__modal-overlay`;
147866
149954
  modal.innerHTML = `
147867
149955
  <div class="${SWITCH_CONTROL_CSS_PREFIX}__modal">
147868
- <div class="${SWITCH_CONTROL_CSS_PREFIX}__modal-icon">${icon}</div>
149956
+ <div class="${SWITCH_CONTROL_CSS_PREFIX}__modal-icon">${icon2}</div>
147869
149957
  <h3 class="${SWITCH_CONTROL_CSS_PREFIX}__modal-title">${this.escapeHtml(this.state.name)}</h3>
147870
149958
  <p class="${SWITCH_CONTROL_CSS_PREFIX}__modal-message">${message}</p>
147871
149959
  <div class="${SWITCH_CONTROL_CSS_PREFIX}__modal-actions">
@@ -148192,7 +150280,7 @@ var ActionButtonView = class {
148192
150280
  return classes.join(" ");
148193
150281
  }
148194
150282
  applyAll() {
148195
- const { label, icon, variant, color, textColor, borderRadius, disabled, tooltip } = this.settings;
150283
+ const { label, icon: icon2, variant, color, textColor, borderRadius, disabled, tooltip } = this.settings;
148196
150284
  this.root.className = this.buildClassName();
148197
150285
  this.root.disabled = disabled;
148198
150286
  this.root.style.borderRadius = `${borderRadius}px`;
@@ -148205,8 +150293,8 @@ var ActionButtonView = class {
148205
150293
  this.root.style.color = textColor || color;
148206
150294
  }
148207
150295
  let html = "";
148208
- if (icon) {
148209
- html += `<span class="${ACTION_BUTTON_CSS_PREFIX}__icon">${this.escapeHtml(icon)}</span>`;
150296
+ if (icon2) {
150297
+ html += `<span class="${ACTION_BUTTON_CSS_PREFIX}__icon">${this.escapeHtml(icon2)}</span>`;
148210
150298
  }
148211
150299
  if (label) {
148212
150300
  html += `<span>${this.escapeHtml(label)}</span>`;
@@ -152476,12 +154564,12 @@ function renderTimelineSVG(data, config2) {
152476
154564
  const segWidth = Math.max(x2 - x1, 4);
152477
154565
  const isOn = seg.state === "on";
152478
154566
  const y = isOn ? onY : offY - 15;
152479
- const h2 = isOn ? barHeight : 15;
154567
+ const h3 = isOn ? barHeight : 15;
152480
154568
  const color = isOn ? onColor : offColor;
152481
154569
  const stateClass = isOn ? "on" : "off";
152482
154570
  segmentPaths += `
152483
154571
  <rect
152484
- x="${x1}" y="${y}" width="${segWidth}" height="${h2}"
154572
+ x="${x1}" y="${y}" width="${segWidth}" height="${h3}"
152485
154573
  fill="${color}" rx="3"
152486
154574
  class="${ONOFF_TIMELINE_CSS_PREFIX}__segment ${ONOFF_TIMELINE_CSS_PREFIX}__segment--${stateClass}"
152487
154575
  data-index="${index}"
@@ -152489,7 +154577,7 @@ function renderTimelineSVG(data, config2) {
152489
154577
  `;
152490
154578
  if (showDurationLabels && segWidth > 45) {
152491
154579
  const centerX = x1 + segWidth / 2;
152492
- const centerY = y + h2 / 2 + 3;
154580
+ const centerY = y + h3 / 2 + 3;
152493
154581
  durationLabels += `
152494
154582
  <text
152495
154583
  x="${centerX}" y="${centerY}"
@@ -152516,7 +154604,7 @@ function renderTimelineSVG(data, config2) {
152516
154604
  }
152517
154605
  tooltipAreas += `
152518
154606
  <rect
152519
- x="${x1}" y="${y}" width="${segWidth}" height="${h2}"
154607
+ x="${x1}" y="${y}" width="${segWidth}" height="${h3}"
152520
154608
  fill="transparent"
152521
154609
  class="tooltip-trigger"
152522
154610
  data-state="${stateClass}"
@@ -153925,15 +156013,15 @@ var OnOffDeviceModalView = class {
153925
156013
  if (!anchor) return;
153926
156014
  const ev = this.evalDeviceStatus();
153927
156015
  if (!ev.statusStale && !ev.connectionStale) return;
153928
- const icon = document.createElement("span");
153929
- icon.className = `${ON_OFF_MODAL_CSS_PREFIX}__status-warning`;
153930
- icon.textContent = "\u26A0\uFE0F";
153931
- icon.style.cssText = "cursor: help; font-size: 16px; margin-left: 8px; line-height: 1; user-select: none; display: inline-block;";
153932
- icon.setAttribute("aria-label", "Telemetria de status desatualizada");
153933
- anchor.appendChild(icon);
156016
+ const icon2 = document.createElement("span");
156017
+ icon2.className = `${ON_OFF_MODAL_CSS_PREFIX}__status-warning`;
156018
+ icon2.textContent = "\u26A0\uFE0F";
156019
+ icon2.style.cssText = "cursor: help; font-size: 16px; margin-left: 8px; line-height: 1; user-select: none; display: inline-block;";
156020
+ icon2.setAttribute("aria-label", "Telemetria de status desatualizada");
156021
+ anchor.appendChild(icon2);
153934
156022
  const when = formatStatusTimestamp(ev.statusTs);
153935
156023
  const lastValue = (ev.value || "\u2014").toString().toUpperCase();
153936
- this.statusWarnTooltipCleanup = InfoTooltip_default.attach(icon, () => ({
156024
+ this.statusWarnTooltipCleanup = InfoTooltip_default.attach(icon2, () => ({
153937
156025
  icon: "\u26A0\uFE0F",
153938
156026
  title: "Status possivelmente desatualizado",
153939
156027
  content: `A \xFAltima telemetria de <b>status</b> foi em <b>${when}</b>, h\xE1 mais de ${STATUS_FRESHNESS_MAX_HOURS} horas.<br><br>O estado exibido (<b>${lastValue}</b>) \xE9 o \xFAltimo conhecido e pode n\xE3o refletir o estado atual do dispositivo.`
@@ -154072,8 +156160,8 @@ var OnOffDeviceModalView = class {
154072
156160
  actions.appendChild(btnYes);
154073
156161
  actions.appendChild(btnNo);
154074
156162
  } else {
154075
- const icon = type === "success" ? "\u2705" : "\u274C";
154076
- msg.textContent = `${icon} ${message}`;
156163
+ const icon2 = type === "success" ? "\u2705" : "\u274C";
156164
+ msg.textContent = `${icon2} ${message}`;
154077
156165
  const btnClose = document.createElement("button");
154078
156166
  btnClose.textContent = "Fechar";
154079
156167
  btnClose.style.cssText = `
@@ -154207,12 +156295,12 @@ var OnOffDeviceModalView = class {
154207
156295
  this.updateScheduleButton("\u{1F4C5}", "Agendamento");
154208
156296
  }
154209
156297
  }
154210
- updateScheduleButton(icon, label) {
156298
+ updateScheduleButton(icon2, label) {
154211
156299
  const btn = this.scheduleButtonContainer?.querySelector(`.${ON_OFF_MODAL_CSS_PREFIX}__schedule-btn`);
154212
156300
  if (btn) {
154213
156301
  const iconEl = btn.querySelector("[data-icon]");
154214
156302
  const labelEl = btn.querySelector("[data-label]");
154215
- if (iconEl) iconEl.textContent = icon;
156303
+ if (iconEl) iconEl.textContent = icon2;
154216
156304
  if (labelEl) labelEl.textContent = label;
154217
156305
  }
154218
156306
  }
@@ -159292,10 +161380,10 @@ function renderStep22(plan) {
159292
161380
  const customers = nonSkip.filter((a) => a.entityKind === "customer");
159293
161381
  const assets = nonSkip.filter((a) => a.entityKind === "asset");
159294
161382
  const devices = nonSkip.filter((a) => a.entityKind === "device");
159295
- function sectionHtml(icon, title, actions) {
161383
+ function sectionHtml(icon2, title, actions) {
159296
161384
  if (actions.length === 0) return "";
159297
161385
  return `
159298
- <div class="gcdr-section-title">${icon} ${title} (${actions.length})</div>
161386
+ <div class="gcdr-section-title">${icon2} ${title} (${actions.length})</div>
159299
161387
  <ul class="gcdr-action-list">
159300
161388
  ${actions.map((a) => `
159301
161389
  <li class="gcdr-action-item">
@@ -159986,9 +162074,9 @@ function formatDuration3(ms) {
159986
162074
  if (!ms) return "";
159987
162075
  const min = Math.round(ms / 6e4);
159988
162076
  if (min < 60) return `${min} min`;
159989
- const h2 = Math.floor(min / 60);
162077
+ const h3 = Math.floor(min / 60);
159990
162078
  const rem = min % 60;
159991
- return rem > 0 ? `${h2}h ${rem}min` : `${h2}h`;
162079
+ return rem > 0 ? `${h3}h ${rem}min` : `${h3}h`;
159992
162080
  }
159993
162081
  function renderDaysOfWeek(daysOfWeek) {
159994
162082
  if (!daysOfWeek) return "";
@@ -161120,9 +163208,9 @@ var ProvisioningApiClient = class {
161120
163208
  const newLogs = logs.filter((l) => l.id > lastLogId);
161121
163209
  for (const entry of newLogs) {
161122
163210
  const time = (entry.timestamp ?? "").split(" ")[1] ?? "";
161123
- const icon = STEP_ICONS[entry.step] ?? "\u{1F4CB}";
163211
+ const icon2 = STEP_ICONS[entry.step] ?? "\u{1F4CB}";
161124
163212
  if (entry.level === "INFO" && !entry.message.includes("Progress updated to")) {
161125
- onLog(`${icon} [${time}] ${entry.message}`);
163213
+ onLog(`${icon2} [${time}] ${entry.message}`);
161126
163214
  }
161127
163215
  }
161128
163216
  if (newLogs.length > 0) {
@@ -161245,22 +163333,22 @@ function drawFooter(doc, pageW, pageH, footerH, pageNo, pageCount) {
161245
163333
  doc.setTextColor(40);
161246
163334
  doc.text(label, bx + padX, baseline);
161247
163335
  }
161248
- async function drawTag(doc, x, y, w, h2, device, gateway, allDevices) {
163336
+ async function drawTag(doc, x, y, w, h3, device, gateway, allDevices) {
161249
163337
  const FRAME_SCALE_Y = 1.05;
161250
163338
  const QR_SCALE = 1.7;
161251
163339
  const QR_SHIFT_Y = 3;
161252
163340
  const GAP_AFTER_QR = 6;
161253
- const frameH = h2 * FRAME_SCALE_Y;
161254
- const frameY = y - (frameH - h2) / 2;
163341
+ const frameH = h3 * FRAME_SCALE_Y;
163342
+ const frameY = y - (frameH - h3) / 2;
161255
163343
  doc.setDrawColor(235);
161256
163344
  doc.setLineWidth(0.15);
161257
163345
  doc.rect(x, frameY, w, frameH);
161258
- const pad = Math.max(2, h2 * 0.05);
163346
+ const pad = Math.max(2, h3 * 0.05);
161259
163347
  const innerX = x + pad;
161260
163348
  const innerW = w - pad * 2;
161261
- const titleAreaH = h2 * 0.15;
163349
+ const titleAreaH = h3 * 0.15;
161262
163350
  const qrAreaTop = y + titleAreaH;
161263
- const qrAreaH = h2 - titleAreaH - 12;
163351
+ const qrAreaH = h3 - titleAreaH - 12;
161264
163352
  const displayName = generateDeviceNameWithPrefix(device, void 0, allDevices);
161265
163353
  const rawName = sanitizePdf(displayName);
161266
163354
  const nameFont = Math.max(6, Math.min(11, titleAreaH * 0.45));
@@ -165869,10 +167957,10 @@ ${this._renderToolbar(filteredCount, totalAllUnfiltered)}
165869
167957
  const collapseAllBtn = this.root.querySelector('[data-action="collapse-all"]');
165870
167958
  if (collapseAllBtn) collapseAllBtn.addEventListener("click", () => this._collapseAll());
165871
167959
  const groupHeaders = this.root.querySelectorAll("[data-group-toggle]");
165872
- groupHeaders.forEach((h2) => {
165873
- const key = h2.getAttribute("data-group-toggle") || "";
165874
- h2.addEventListener("click", () => this._toggleGroupCollapsed(key));
165875
- h2.addEventListener("keydown", (e) => {
167960
+ groupHeaders.forEach((h3) => {
167961
+ const key = h3.getAttribute("data-group-toggle") || "";
167962
+ h3.addEventListener("click", () => this._toggleGroupCollapsed(key));
167963
+ h3.addEventListener("keydown", (e) => {
165876
167964
  const ke = e;
165877
167965
  if (ke.key === "Enter" || ke.key === " ") {
165878
167966
  ke.preventDefault();
@@ -166220,26 +168308,26 @@ var ENTRIES = [
166220
168308
  // GCDR reconciled it to the hydrometer device type. The decodable name
166221
168309
  // prefix is HIDR — `switch` survives only as the byte's legacy/internal
166222
168310
  // label (GCDR's own generator UI shows it as "12 · switch/HIDR").
168311
+ // Thermostats and tank-level sensors are manufactured on this same switch
168312
+ // hardware, so they are also 12 — they have no type byte of their own
168313
+ // (the former 16=TEMP / 17=TANK drafts were a misreading; removed 2026-10-01).
166223
168314
  { byte: 12, prefix: "HIDR", status: "ratified", legacyLabel: "switch" },
166224
168315
  { byte: 14, prefix: "REM", status: "ratified" },
166225
168316
  { byte: 15, prefix: "3F", status: "ratified" },
166226
- // Proposed, not ratified — DEVICE-PRODUCT-CODE-NUMBERING.md.
166227
- { byte: 16, prefix: "TEMP", status: "draft" },
166228
- { byte: 17, prefix: "TANK", status: "draft" },
166229
- // Ratified 2026-08-25 (GCDR PR #39, DEVICE-NAME-SPEC.md §3a). Type-byte
166230
- // entry only — the BOX device *profile*'s own fields/parsing stay out of
166231
- // scope (RFC-0230 Non-goals). Registered here so a code with B4=18
166232
- // decodes as BOX instead of falling through to the unknown-type
168317
+ // 16, 17 and 18 are intentionally not registered (see above for 16/17; 18
168318
+ // was BOX until it moved to 50). 19 is reserved in GCDR for BOX_GROUP
168319
+ // (RFC-0058, optional). All of them fall through to the `T{B4}` fallback.
168320
+ // Central (gateway). Ratified by the owner on 2026-10-01. Type-byte entry
168321
+ // only — a code with B4=20 decodes as CENTRAL instead of the unknown-type
166233
168322
  // (`T{B4}`) fallback.
166234
- { byte: 18, prefix: "BOX", status: "ratified" },
166235
- // 19 is reserved in GCDR for BOX_GROUP (RFC-0058, optional) — intentionally
166236
- // not registered here.
166237
- // Central (gateway). Added 2026-10-01 at the owner's request; not yet in
166238
- // GCDR's DEVICE-NAME-SPEC.md / DEVICE-PRODUCT-CODE-NUMBERING.md, so it is
166239
- // carried as draft until ratified there. Type-byte entry only — a code
166240
- // with B4=20 decodes as CENTRAL instead of the unknown-type (`T{B4}`)
166241
- // fallback.
166242
- { byte: 20, prefix: "CENTRAL", status: "draft" }
168323
+ { byte: 20, prefix: "CENTRAL", status: "ratified" },
168324
+ // BOX (device enclosure, GCDR RFC-0058). Ratified by the owner on 2026-10-01
168325
+ // as byte 50; GCDR's docs had only ever *proposed* 18. Type-byte entry only
168326
+ // — the BOX device *profile*'s own fields/parsing stay out of scope
168327
+ // (RFC-0230 Non-goals).
168328
+ // GCDR's specs are being updated to match (see
168329
+ // gcdr.git/docs/specs/rules-devices-code/v2/DEVICE-NAME-SPEC-updates-draft.md).
168330
+ { byte: 50, prefix: "BOX", status: "ratified" }
166243
168331
  ];
166244
168332
  var BY_BYTE = new Map(ENTRIES.map((e) => [e.byte, e]));
166245
168333
  var BY_PREFIX = new Map(ENTRIES.map((e) => [e.prefix, e]));
@@ -166359,11 +168447,9 @@ var PRESENTATION = {
166359
168447
  // REM: no dedicated art and no confirmed friendly name yet — label stays the prefix.
166360
168448
  14: { label: "REM", icon: null },
166361
168449
  15: { label: "Medidor 3F", icon: DeviceIconType.MEDIDOR_3F },
166362
- 16: { label: "Termostato", icon: DeviceIconType.TERMOSTATO },
166363
- 17: { label: "Caixa d'\xC1gua", icon: DeviceIconType.CAIXA_DAGUA },
166364
- 18: { label: "Box", icon: DeviceIconType.BOX },
166365
168450
  // Central (gateway hardware) reuses the existing GATEWAY art.
166366
- 20: { label: "Central", icon: DeviceIconType.GATEWAY }
168451
+ 20: { label: "Central", icon: DeviceIconType.GATEWAY },
168452
+ 50: { label: "Box", icon: DeviceIconType.BOX }
166367
168453
  };
166368
168454
  function iconFor(byte) {
166369
168455
  const key = PRESENTATION[byte]?.icon;
@@ -166406,7 +168492,7 @@ function validateDeviceProductCode(code) {
166406
168492
 
166407
168493
  // src/components/cards/central-status/v1.0.0/styles.ts
166408
168494
  var STYLE_ID16 = "myio-central-status-card-styles";
166409
- var CSS4 = `
168495
+ var CSS5 = `
166410
168496
  .myio-cscard{
166411
168497
  --cscard-surface:#ffffff;
166412
168498
  --cscard-border:#e2e8f0;
@@ -166711,7 +168797,7 @@ function injectCentralStatusCardStyles() {
166711
168797
  if (document.getElementById(STYLE_ID16)) return;
166712
168798
  const tag = document.createElement("style");
166713
168799
  tag.id = STYLE_ID16;
166714
- tag.textContent = CSS4;
168800
+ tag.textContent = CSS5;
166715
168801
  document.head.appendChild(tag);
166716
168802
  }
166717
168803
 
@@ -168314,6 +170400,9 @@ var version = package_default.version || "0.0.0";
168314
170400
  createModalHeader,
168315
170401
  createMoneyVarianceColumn,
168316
170402
  createMyIOTheme,
170403
+ createMyioGcdrLoginSubmit,
170404
+ createMyioGcdrLoginView,
170405
+ createMyioGcdrShell,
168317
170406
  createNewTicketWizard,
168318
170407
  createOnOffDeviceModal,
168319
170408
  createOnOffTimelineChart,
@@ -168554,6 +170643,7 @@ var version = package_default.version || "0.0.0";
168554
170643
  isInRange,
168555
170644
  isLeapYear,
168556
170645
  isMoneyColumnConfident,
170646
+ isMyioGcdrLoginModalOpen,
168557
170647
  isOnOffDeviceProfile,
168558
170648
  isSolenoidDevice,
168559
170649
  isStoreDevice,
@@ -168615,6 +170705,7 @@ var version = package_default.version || "0.0.0";
168615
170705
  openMeasurementSetupModal,
168616
170706
  openMessageDialog,
168617
170707
  openMetasGuide,
170708
+ openMyioGcdrLoginModal,
168618
170709
  openOnOffDeviceModal,
168619
170710
  openOnboardModal,
168620
170711
  openOperationalComparisonModal,