ngx-xtroedge-cms 1.1.0 → 1.2.0

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.d.mts CHANGED
@@ -68,6 +68,8 @@ declare class XtroedgeCMS {
68
68
  private highlightColor;
69
69
  private brandingEl;
70
70
  private historyRetentionMs;
71
+ private siteIdentifier;
72
+ private siteIdEl;
71
73
  private editMode;
72
74
  private currentLang;
73
75
  private pageTexts;
@@ -218,6 +220,10 @@ declare class XtroedgeCMS {
218
220
  private detectCurrentLanguage;
219
221
  private createElement;
220
222
  private formatDate;
223
+ private resolveSiteIdentifier;
224
+ private hexToRgb;
225
+ private getDarkerColor;
226
+ private applyThemeColor;
221
227
  /** Quick init - create and start CMS in one call */
222
228
  static create(config?: XtroedgeCmsConfig): XtroedgeCMS;
223
229
  /** Auto-init: called automatically when package is loaded. No user code needed. */
package/dist/index.d.ts CHANGED
@@ -68,6 +68,8 @@ declare class XtroedgeCMS {
68
68
  private highlightColor;
69
69
  private brandingEl;
70
70
  private historyRetentionMs;
71
+ private siteIdentifier;
72
+ private siteIdEl;
71
73
  private editMode;
72
74
  private currentLang;
73
75
  private pageTexts;
@@ -218,6 +220,10 @@ declare class XtroedgeCMS {
218
220
  private detectCurrentLanguage;
219
221
  private createElement;
220
222
  private formatDate;
223
+ private resolveSiteIdentifier;
224
+ private hexToRgb;
225
+ private getDarkerColor;
226
+ private applyThemeColor;
221
227
  /** Quick init - create and start CMS in one call */
222
228
  static create(config?: XtroedgeCmsConfig): XtroedgeCMS;
223
229
  /** Auto-init: called automatically when package is loaded. No user code needed. */
@@ -1,36 +1,36 @@
1
- "use strict";var XtroedgeCMSLib=(()=>{var b=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var w=(d,t)=>{for(var e in t)b(d,e,{get:t[e],enumerable:!0})},T=(d,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of E(t))!x.call(d,i)&&i!==e&&b(d,i,{get:()=>t[i],enumerable:!(s=y(t,i))||s.enumerable});return d};var C=d=>T(b({},"__esModule",{value:!0}),d);var L={};w(L,{XtroedgeCMS:()=>g});var v=`
1
+ "use strict";var XtroedgeCMSLib=(()=>{var y=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var L=(h,t)=>{for(var e in t)y(h,e,{get:t[e],enumerable:!0})},k=(h,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of M(t))!I.call(h,s)&&s!==e&&y(h,s,{get:()=>t[s],enumerable:!(i=S(t,s))||i.enumerable});return h};var P=h=>k(y({},"__esModule",{value:!0}),h);var O={};L(O,{XtroedgeCMS:()=>b});var E=`
2
2
  /* ===== XTROEDGE CMS ===== */
3
3
 
4
4
  /* LOADER */
5
5
  .lcms-loader-overlay {
6
6
  position: fixed; inset: 0; z-index: 10003;
7
7
  display: flex; align-items: center; justify-content: center;
8
- background: rgba(5, 20, 10, 0.45);
8
+ background: rgba(8, 8, 15, 0.45);
9
9
  backdrop-filter: blur(12px) saturate(1.4);
10
10
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
11
11
  }
12
12
  .lcms-loader-content { display: flex; flex-direction: column; align-items: center; gap: 28px; }
13
13
  .lcms-orbit-loader { position: relative; width: 90px; height: 90px; }
14
14
  .lcms-orbit { position: absolute; inset: 0; border-radius: 50%; border: 1px solid transparent; }
15
- .lcms-orbit-1 { border-top-color: rgba(0,200,83,0.5); animation: lcmsSpin 2.4s linear infinite; }
16
- .lcms-orbit-2 { inset: 10px; border-right-color: rgba(76,175,80,0.5); animation: lcmsSpin 3.2s linear infinite reverse; }
17
- .lcms-orbit-3 { inset: 20px; border-bottom-color: rgba(129,199,132,0.5); animation: lcmsSpin 4.2s linear infinite; }
15
+ .lcms-orbit-1 { border-top-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.5); animation: lcmsSpin 2.4s linear infinite; }
16
+ .lcms-orbit-2 { inset: 10px; border-right-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.4); animation: lcmsSpin 3.2s linear infinite reverse; }
17
+ .lcms-orbit-3 { inset: 20px; border-bottom-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.35); animation: lcmsSpin 4.2s linear infinite; }
18
18
  .lcms-particle {
19
19
  position: absolute; width: 8px; height: 8px; border-radius: 50%; top: -4px; left: 50%; margin-left: -4px;
20
20
  box-shadow: 0 0 12px 3px currentColor;
21
21
  }
22
- .lcms-orbit-1 .lcms-particle { background: #00C853; color: #00C853; }
23
- .lcms-orbit-2 .lcms-particle { background: #4CAF50; color: #4CAF50; top: 50%; left: auto; right: -4px; margin-left: 0; margin-top: -4px; }
24
- .lcms-orbit-3 .lcms-particle { background: #81C784; color: #81C784; top: auto; bottom: -4px; }
22
+ .lcms-orbit-1 .lcms-particle { background: var(--lcms-primary, #00C853); color: var(--lcms-primary, #00C853); }
23
+ .lcms-orbit-2 .lcms-particle { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.8); color: rgba(var(--lcms-primary-rgb, 0,200,83),0.8); top: 50%; left: auto; right: -4px; margin-left: 0; margin-top: -4px; }
24
+ .lcms-orbit-3 .lcms-particle { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.6); color: rgba(var(--lcms-primary-rgb, 0,200,83),0.6); top: auto; bottom: -4px; }
25
25
  .lcms-core-glow {
26
26
  position: absolute; width: 30px; height: 30px; top: 50%; left: 50%; transform: translate(-50%,-50%);
27
- border-radius: 50%; background: radial-gradient(circle, rgba(0,200,83,0.4), transparent 70%);
27
+ border-radius: 50%; background: radial-gradient(circle, rgba(var(--lcms-primary-rgb, 0,200,83),0.4), transparent 70%);
28
28
  animation: lcmsPulse 2s ease-in-out infinite;
29
29
  }
30
30
  .lcms-core {
31
31
  position: absolute; width: 12px; height: 12px; top: 50%; left: 50%; transform: translate(-50%,-50%);
32
- border-radius: 50%; background: linear-gradient(135deg, #00C853, #81C784);
33
- box-shadow: 0 0 20px rgba(0,200,83,0.6);
32
+ border-radius: 50%; background: linear-gradient(135deg, var(--lcms-primary, #00C853), rgba(var(--lcms-primary-rgb, 0,200,83),0.6));
33
+ box-shadow: 0 0 20px rgba(var(--lcms-primary-rgb, 0,200,83),0.6);
34
34
  }
35
35
  .lcms-loader-text {
36
36
  font-family: system-ui, -apple-system, sans-serif; font-size: 12px; font-weight: 600;
@@ -47,10 +47,10 @@
47
47
  padding: 10px 20px; border-radius: 10px; font-size: 13px; font-weight: 600;
48
48
  font-family: system-ui, -apple-system, sans-serif; color: white;
49
49
  display: flex; align-items: center; gap: 8px;
50
- box-shadow: 0 8px 32px rgba(0,200,83,0.25);
50
+ box-shadow: 0 8px 32px rgba(var(--lcms-primary-rgb, 0,200,83),0.25);
51
51
  animation: lcmsToastIn 0.3s ease, lcmsToastOut 0.3s ease 2.7s forwards; white-space: nowrap;
52
52
  }
53
- .lcms-toast-success { background: linear-gradient(135deg, #00C853, #2E7D32); }
53
+ .lcms-toast-success { background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32)); }
54
54
  .lcms-toast-error { background: linear-gradient(135deg, #dc2626, #ef4444); }
55
55
  @keyframes lcmsToastIn { from { opacity: 0; transform: translateX(-50%) translateY(-12px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
56
56
  @keyframes lcmsToastOut { from { opacity: 1; transform: translateX(-50%) translateY(0); } to { opacity: 0; transform: translateX(-50%) translateY(-12px); } }
@@ -59,15 +59,15 @@
59
59
  .lcms-fab { position: fixed; z-index: 10001; user-select: none; touch-action: none; }
60
60
  .lcms-fab-btn {
61
61
  width: 52px; height: 52px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.2);
62
- background: rgba(0,200,83,0.35); color: white;
62
+ background: rgba(var(--lcms-primary-rgb, 0,200,83),0.35); color: white;
63
63
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
64
64
  cursor: grab; display: flex; align-items: center; justify-content: center;
65
- box-shadow: 0 4px 20px rgba(0,200,83,0.3), inset 0 1px 0 rgba(255,255,255,0.15);
65
+ box-shadow: 0 4px 20px rgba(var(--lcms-primary-rgb, 0,200,83),0.3), inset 0 1px 0 rgba(255,255,255,0.15);
66
66
  transition: transform 0.2s, box-shadow 0.2s, background 0.2s; position: relative;
67
67
  }
68
- .lcms-fab-btn:not(.lcms-fab-active) { background: rgba(0,200,83,0.25); box-shadow: 0 4px 16px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.1); }
69
- .lcms-fab-btn.lcms-fab-active { background: rgba(0,200,83,0.4); box-shadow: 0 4px 24px rgba(0,200,83,0.4), 0 0 16px rgba(0,200,83,0.2), inset 0 1px 0 rgba(255,255,255,0.2); }
70
- .lcms-fab-btn:hover { transform: scale(1.08); background: rgba(0,200,83,0.5); box-shadow: 0 6px 28px rgba(0,200,83,0.4), inset 0 1px 0 rgba(255,255,255,0.2); }
68
+ .lcms-fab-btn:not(.lcms-fab-active) { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.25); box-shadow: 0 4px 16px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.1); }
69
+ .lcms-fab-btn.lcms-fab-active { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.4); box-shadow: 0 4px 24px rgba(var(--lcms-primary-rgb, 0,200,83),0.4), 0 0 16px rgba(var(--lcms-primary-rgb, 0,200,83),0.2), inset 0 1px 0 rgba(255,255,255,0.2); }
70
+ .lcms-fab-btn:hover { transform: scale(1.08); background: rgba(var(--lcms-primary-rgb, 0,200,83),0.5); box-shadow: 0 6px 28px rgba(var(--lcms-primary-rgb, 0,200,83),0.4), inset 0 1px 0 rgba(255,255,255,0.2); }
71
71
  .lcms-badge {
72
72
  position: absolute; top: -4px; right: -4px; background: #ef4444; color: white;
73
73
  font-size: 11px; font-weight: 700; width: 20px; height: 20px; border-radius: 50%;
@@ -76,27 +76,44 @@
76
76
 
77
77
  /* PANEL */
78
78
  .lcms-panel {
79
- background: rgba(10,30,15,0.55); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
80
- border: 1px solid rgba(76,175,80,0.25); border-radius: 16px; padding: 16px; min-width: 230px;
79
+ background: rgba(12,12,18,0.55); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
80
+ border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.25); border-radius: 16px; padding: 16px; min-width: 230px;
81
81
  box-shadow: 0 8px 32px rgba(0,0,0,0.25), inset 0 1px 0 rgba(255,255,255,0.06);
82
82
  color: white; font-family: system-ui, -apple-system, sans-serif;
83
83
  animation: lcmsPanelIn 0.25s ease; position: absolute;
84
84
  }
85
85
  @keyframes lcmsPanelIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
86
86
 
87
+ /* SITE IDENTIFIER */
88
+ .lcms-site-id {
89
+ display: flex; align-items: center; gap: 5px;
90
+ font-size: 10px; color: rgba(255,255,255,0.4);
91
+ padding: 0 0 8px; margin-bottom: 8px;
92
+ border-bottom: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.12);
93
+ font-family: system-ui, -apple-system, sans-serif;
94
+ letter-spacing: 0.3px;
95
+ }
96
+ .lcms-site-id-icon { font-size: 12px; opacity: 0.7; }
97
+ .lcms-site-id-text {
98
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 180px;
99
+ font-weight: 500;
100
+ }
101
+
87
102
  /* BRANDING */
88
103
  .lcms-branding {
89
104
  display: flex; align-items: center; gap: 6px; padding: 8px 0 4px;
90
- border-top: 1px solid rgba(76,175,80,0.15); margin-top: 10px;
105
+ border-top: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.15); margin-top: 10px;
106
+ cursor: pointer; transition: opacity 0.2s; user-select: none;
91
107
  }
108
+ .lcms-branding:hover { opacity: 0.8; }
92
109
  .lcms-branding-logo {
93
- width: 18px; height: 18px; border-radius: 4px; background: linear-gradient(135deg, #00C853, #2E7D32);
110
+ width: 18px; height: 18px; border-radius: 4px; background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));
94
111
  display: flex; align-items: center; justify-content: center;
95
112
  }
96
113
  .lcms-branding-text {
97
114
  font-size: 10px; font-weight: 600; color: rgba(255,255,255,0.35); letter-spacing: 0.5px;
98
115
  }
99
- .lcms-branding-text span { color: #00C853; font-weight: 700; }
116
+ .lcms-branding-text span { color: var(--lcms-primary, #00C853); font-weight: 700; }
100
117
 
101
118
  .lcms-panel-header { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
102
119
  .lcms-toggle { display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
@@ -109,53 +126,84 @@
109
126
  content: ''; position: absolute; width: 16px; height: 16px; border-radius: 50%;
110
127
  top: 2px; left: 2px; background: rgba(255,255,255,0.6); transition: transform 0.25s, background 0.25s;
111
128
  }
112
- .lcms-toggle input:checked + .lcms-toggle-slider { background: #00C853; }
129
+ .lcms-toggle input:checked + .lcms-toggle-slider { background: var(--lcms-primary, #00C853); }
113
130
  .lcms-toggle input:checked + .lcms-toggle-slider::after { transform: translateX(16px); background: white; }
114
131
  .lcms-toggle-label { font-size: 12px; font-weight: 700; color: rgba(255,255,255,0.5); letter-spacing: 0.5px; transition: color 0.25s; }
115
- .lcms-toggle input:checked ~ .lcms-toggle-label { color: #81C784; }
116
- .lcms-lang-switch { display: flex; border: 1px solid rgba(0,200,83,0.4); border-radius: 6px; overflow: hidden; margin-left: auto; }
132
+ .lcms-toggle input:checked ~ .lcms-toggle-label { color: rgba(var(--lcms-primary-rgb, 0,200,83),0.75); }
133
+ .lcms-lang-switch { display: flex; border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.4); border-radius: 6px; overflow: hidden; margin-left: auto; }
117
134
  .lcms-lang-btn { background: transparent; border: none; color: rgba(255,255,255,0.45); padding: 3px 12px; font-size: 11px; font-weight: 600; cursor: pointer; transition: all 0.2s; }
118
- .lcms-lang-btn.active { background: #00C853; color: white; }
119
- .lcms-lang-btn:hover:not(.active) { color: white; background: rgba(0,200,83,0.2); }
135
+ .lcms-lang-btn.active { background: var(--lcms-primary, #00C853); color: white; }
136
+ .lcms-lang-btn:hover:not(.active) { color: white; background: rgba(var(--lcms-primary-rgb, 0,200,83),0.2); }
120
137
  .lcms-close-btn { background: transparent; border: none; color: rgba(255,255,255,0.4); cursor: pointer; padding: 2px; display: flex; transition: color 0.2s; }
121
138
  .lcms-close-btn:hover { color: white; }
122
- .lcms-changes-info { font-size: 12px; color: #81C784; margin-bottom: 10px; padding-left: 2px; }
139
+ .lcms-changes-info { font-size: 12px; color: rgba(var(--lcms-primary-rgb, 0,200,83),0.75); margin-bottom: 10px; padding-left: 2px; }
123
140
 
124
141
  .lcms-undo-row { display: flex; gap: 6px; margin-bottom: 12px; }
125
142
  .lcms-icon-btn {
126
- width: 36px; height: 32px; border-radius: 8px; border: 1px solid rgba(0,200,83,0.3);
127
- background: rgba(0,200,83,0.1); color: rgba(255,255,255,0.8); cursor: pointer;
143
+ width: 36px; height: 32px; border-radius: 8px; border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.3);
144
+ background: rgba(var(--lcms-primary-rgb, 0,200,83),0.1); color: rgba(255,255,255,0.8); cursor: pointer;
128
145
  display: flex; align-items: center; justify-content: center; transition: all 0.2s;
129
146
  }
130
- .lcms-icon-btn:hover:not(:disabled) { background: rgba(0,200,83,0.25); border-color: rgba(0,200,83,0.5); color: white; }
147
+ .lcms-icon-btn:hover:not(:disabled) { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.25); border-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.5); color: white; }
131
148
  .lcms-icon-btn:disabled { opacity: 0.25; cursor: not-allowed; }
132
149
 
150
+ /* COLOR THEME PICKER */
151
+ .lcms-theme-row {
152
+ display: flex; align-items: center; gap: 8px; margin-bottom: 12px;
153
+ padding: 6px 0;
154
+ }
155
+ .lcms-theme-label {
156
+ font-size: 10px; font-weight: 700; color: rgba(255,255,255,0.45);
157
+ text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap;
158
+ }
159
+ .lcms-theme-colors {
160
+ display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
161
+ }
162
+ .lcms-theme-swatch {
163
+ width: 20px; height: 20px; border-radius: 50%; border: 2px solid transparent;
164
+ cursor: pointer; transition: all 0.2s; position: relative;
165
+ }
166
+ .lcms-theme-swatch:hover { transform: scale(1.15); }
167
+ .lcms-theme-swatch.active { border-color: white; box-shadow: 0 0 8px rgba(255,255,255,0.3); }
168
+ .lcms-theme-custom {
169
+ width: 20px; height: 20px; border-radius: 50%; border: 1px dashed rgba(255,255,255,0.3);
170
+ cursor: pointer; overflow: hidden; position: relative;
171
+ }
172
+ .lcms-theme-custom input {
173
+ position: absolute; inset: -4px; width: 28px; height: 28px; border: none;
174
+ background: transparent; cursor: pointer; opacity: 0;
175
+ }
176
+ .lcms-theme-custom-preview {
177
+ width: 100%; height: 100%; border-radius: 50%;
178
+ background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
179
+ }
180
+
133
181
  .lcms-history-btn {
134
182
  width: 100%; padding: 7px 12px; border-radius: 8px;
135
- border: 1px dashed rgba(76,175,80,0.35); background: rgba(0,200,83,0.08);
183
+ border: 1px dashed rgba(var(--lcms-primary-rgb, 0,200,83),0.35); background: rgba(var(--lcms-primary-rgb, 0,200,83),0.08);
136
184
  color: rgba(255,255,255,0.6); font-size: 12px; font-weight: 500; cursor: pointer;
137
185
  display: flex; align-items: center; justify-content: center; gap: 6px;
138
186
  transition: all 0.2s; margin-bottom: 12px; font-family: system-ui, -apple-system, sans-serif;
139
187
  }
140
- .lcms-history-btn:hover { background: rgba(0,200,83,0.18); border-color: rgba(76,175,80,0.5); color: white; }
141
- .lcms-history-btn.active { background: rgba(0,200,83,0.25); border-color: #00C853; border-style: solid; color: white; }
188
+ .lcms-history-btn:hover { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.18); border-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.5); color: white; }
189
+ .lcms-history-btn.active { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.25); border-color: var(--lcms-primary, #00C853); border-style: solid; color: white; }
142
190
 
143
- .lcms-history-panel { margin-top: 8px; border-top: 1px solid rgba(76,175,80,0.15); padding-top: 10px; }
191
+ .lcms-history-panel { margin-top: 8px; border-top: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.15); padding-top: 10px; }
144
192
  .lcms-history-title { font-size: 11px; font-weight: 700; color: rgba(255,255,255,0.5); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; }
145
193
  .lcms-history-empty { font-size: 12px; color: rgba(255,255,255,0.3); text-align: center; padding: 12px 0; }
146
194
  .lcms-history-list { max-height: 200px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
147
195
  .lcms-history-list::-webkit-scrollbar { width: 4px; }
148
196
  .lcms-history-list::-webkit-scrollbar-track { background: transparent; }
149
- .lcms-history-list::-webkit-scrollbar-thumb { background: rgba(0,200,83,0.3); border-radius: 4px; }
197
+ .lcms-history-list::-webkit-scrollbar-thumb { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.3); border-radius: 4px; }
150
198
  .lcms-history-item {
151
- width: 100%; text-align: left; background: rgba(0,200,83,0.06);
152
- border: 1px solid rgba(0,200,83,0.12); border-radius: 8px; padding: 8px 10px;
199
+ width: 100%; text-align: left; background: rgba(var(--lcms-primary-rgb, 0,200,83),0.06);
200
+ border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.12); border-radius: 8px; padding: 8px 10px;
153
201
  cursor: pointer; transition: all 0.2s; color: white; font-family: system-ui, -apple-system, sans-serif;
154
202
  }
155
- .lcms-history-item:hover { background: rgba(0,200,83,0.15); border-color: rgba(0,200,83,0.3); }
203
+ .lcms-history-item:hover { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.15); border-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.3); }
156
204
  .lcms-history-label { font-size: 12px; font-weight: 500; margin-bottom: 2px; }
157
205
  .lcms-history-meta { font-size: 10px; color: rgba(255,255,255,0.4); display: flex; align-items: center; gap: 6px; }
158
- .lcms-history-lang { background: rgba(0,200,83,0.2); padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 600; color: #81C784; }
206
+ .lcms-history-lang { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.2); padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 600; color: rgba(var(--lcms-primary-rgb, 0,200,83),0.75); }
159
207
 
160
208
  .lcms-actions { display: flex; flex-direction: column; gap: 6px; }
161
209
  .lcms-actions button {
@@ -163,14 +211,14 @@
163
211
  cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; gap: 6px; border: none;
164
212
  font-family: system-ui, -apple-system, sans-serif;
165
213
  }
166
- .lcms-btn-save { background: #00C853; color: white; }
167
- .lcms-btn-save:hover { background: #00E676; }
168
- .lcms-btn-save:disabled { background: rgba(0,200,83,0.2); color: rgba(255,255,255,0.35); cursor: not-allowed; }
214
+ .lcms-btn-save { background: var(--lcms-primary, #00C853); color: white; }
215
+ .lcms-btn-save:hover { background: var(--lcms-primary, #00C853); filter: brightness(1.15); }
216
+ .lcms-btn-save:disabled { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.2); color: rgba(255,255,255,0.35); cursor: not-allowed; filter: none; }
169
217
  .lcms-btn-publish { background: linear-gradient(135deg, #2196F3, #1976D2); color: white; }
170
218
  .lcms-btn-publish:hover { background: linear-gradient(135deg, #1976D2, #1565C0); }
171
- .lcms-btn-publish:disabled { background: rgba(0,200,83,0.2); color: rgba(255,255,255,0.35); cursor: not-allowed; }
172
- .lcms-btn-cancel { background: transparent; color: rgba(255,255,255,0.5); border: 1px solid rgba(0,200,83,0.25) !important; }
173
- .lcms-btn-cancel:hover { color: white; border-color: rgba(0,200,83,0.5) !important; background: rgba(0,200,83,0.08); }
219
+ .lcms-btn-publish:disabled { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.2); color: rgba(255,255,255,0.35); cursor: not-allowed; }
220
+ .lcms-btn-cancel { background: transparent; color: rgba(255,255,255,0.5); border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.25) !important; }
221
+ .lcms-btn-cancel:hover { color: white; border-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.5) !important; background: rgba(var(--lcms-primary-rgb, 0,200,83),0.08); }
174
222
  .lcms-btn-cancel:disabled { opacity: 0.3; cursor: not-allowed; }
175
223
 
176
224
  .lcms-spinner { display: inline-block; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,0.3); border-top-color: white; border-radius: 50%; animation: lcmsSpin 0.6s linear infinite; }
@@ -179,18 +227,18 @@
179
227
  .lcms-img-upload-overlay {
180
228
  position: fixed; inset: 0; z-index: 10005;
181
229
  display: flex; align-items: center; justify-content: center;
182
- background: rgba(5, 20, 10, 0.5); backdrop-filter: blur(8px);
230
+ background: rgba(8, 8, 15, 0.5); backdrop-filter: blur(8px);
183
231
  }
184
232
  .lcms-img-upload-content {
185
233
  display: flex; flex-direction: column; align-items: center; gap: 16px;
186
234
  color: white; font-family: system-ui, -apple-system, sans-serif;
187
235
  font-size: 13px; font-weight: 600;
188
236
  }
189
- .lcms-spinner-lg { width: 36px; height: 36px; border: 3px solid rgba(255,255,255,0.2); border-top-color: #00C853; border-radius: 50%; animation: lcmsSpin 0.6s linear infinite; }
237
+ .lcms-spinner-lg { width: 36px; height: 36px; border: 3px solid rgba(255,255,255,0.2); border-top-color: var(--lcms-primary, #00C853); border-radius: 50%; animation: lcmsSpin 0.6s linear infinite; }
190
238
 
191
239
  /* HIDDEN ELEMENTS */
192
240
  .lcms-hidden { display: none !important; }
193
- `;var l={edit:'<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>',close:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',undo:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>',redo:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.13-9.36L23 10"/></svg>',history:'<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',save:'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>',publish:'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/></svg>',image:'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>',check:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>',error:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>'},M="xtroedge_cms_history",h="history",S=["h1","h2","h3","h4","h5","h6","p","span","b","strong","i","em","a","button","li","label","small","blockquote","td","th"],g=class d{constructor(t){this.brandingEl=null;this.editMode=!1;this.currentLang="en";this.pageTexts={};this.pageImages={};this.originalTexts={};this.originalImages={};this.unsavedChanges=0;this.isSaving=!1;this.isPublishing=!1;this.loading=!1;this.canUndo=!1;this.canRedo=!1;this.showHistory=!1;this.historyList=[];this.isOpen=!1;this.isEditAllowed=!1;this.imageUploading=!1;this.toastMessage="";this.toastType="success";this.undoStack=[];this.redoStack=[];this.dirtyKeys=new Set;this.dirtyImageKeys=new Set;this.registeredKeys=new Set;this.managedElements=new Map;this.managedImages=new Map;this.autoDetectedElements=new Set;this.observer=null;this.scanTimeout=null;this.activeImageEl=null;this.imageCtxMenu=null;this.currentSlug="";this.currentTitle="";this.origPushState=null;this.origReplaceState=null;this.styleEl=null;this.rootEl=null;this.loaderEl=null;this.toastEl=null;this.fabEl=null;this.fabBtn=null;this.badgeEl=null;this.panelEl=null;this.editToggle=null;this.langSwitchEl=null;this.changesInfoEl=null;this.undoBtn=null;this.redoBtn=null;this.historyBtnEl=null;this.historyPanelEl=null;this.historyListEl=null;this.saveBtn=null;this.publishBtn=null;this.cancelBtn=null;this.actionsEl=null;this.editModeContent=null;this.fileInput=null;this.imgOverlay=null;this.posX=20;this.posY=20;this.isDragging=!1;this.dragStartX=0;this.dragStartY=0;this.startPosX=0;this.startPosY=0;this.hasMoved=!1;this.toastTimer=null;this.db=null;this.translationCache=new Map;this.config=t||{},this.containerSelector=this.config.containerSelector||"",this.editableTags=(this.config.editableTags||S).map(e=>e.toLowerCase()),this.languages=this.config.languages||["en"],this.defaultLanguage=this.config.defaultLanguage||this.languages[0]||"en",this.highlightColor=this.config.highlightColor||"#00C853",this.historyRetentionMs=(this.config.historyRetentionDays||7)*24*60*60*1e3,this.currentLang=this.defaultLanguage,this.boundMouseMove=e=>this.onDragMove(e),this.boundMouseUp=()=>this.onDragEnd(),this.boundTouchMove=e=>this.onTouchMove(e),this.boundTouchEnd=()=>this.onTouchEnd(),this.boundPopState=()=>this.handleNavigation(),this.boundHashChange=()=>this.handleNavigation()}init(){this.posY=window.innerHeight-72,this.injectStyles(),this.buildUI(),this.interceptNavigation(),this.observer=new MutationObserver(()=>{this.rootEl&&!document.contains(this.rootEl)&&document.body.appendChild(this.rootEl),this.styleEl&&!document.contains(this.styleEl)&&document.head.appendChild(this.styleEl),this.scanTimeout&&clearTimeout(this.scanTimeout),this.scanTimeout=setTimeout(()=>this.autoDetectAndScan(),150)}),this.observer.observe(document.body,{childList:!0,subtree:!0}),window.addEventListener("popstate",this.boundPopState),window.addEventListener("hashchange",this.boundHashChange),this.handleNavigation()}destroy(){this.cleanupManagedElements(),this.styleEl?.remove(),this.rootEl?.remove(),window.removeEventListener("popstate",this.boundPopState),window.removeEventListener("hashchange",this.boundHashChange),document.removeEventListener("mousemove",this.boundMouseMove),document.removeEventListener("mouseup",this.boundMouseUp),document.removeEventListener("touchmove",this.boundTouchMove),document.removeEventListener("touchend",this.boundTouchEnd),this.origPushState&&(history.pushState=this.origPushState),this.origReplaceState&&(history.replaceState=this.origReplaceState),this.observer?.disconnect(),this.scanTimeout&&clearTimeout(this.scanTimeout),this.toastTimer&&clearTimeout(this.toastTimer),this.db?.close()}injectStyles(){document.getElementById("xtroedge-cms-styles")||(this.styleEl=document.createElement("style"),this.styleEl.id="xtroedge-cms-styles",this.styleEl.textContent=v,document.head.appendChild(this.styleEl))}interceptNavigation(){this.origPushState=history.pushState.bind(history),this.origReplaceState=history.replaceState.bind(history);let t=this;history.pushState=function(...e){t.origPushState(...e),setTimeout(()=>t.handleNavigation(),0)},history.replaceState=function(...e){t.origReplaceState(...e),setTimeout(()=>t.handleNavigation(),0)}}handleNavigation(){let t=window.location.href,e=window.location.pathname||"/",s=window.location.hash||"",i,n;if(s.startsWith("#/")||s.startsWith("#!")){let p=s.replace(/^#[!/]*/,""),u=p.indexOf("?");i=u>=0?p.substring(0,u):p,n=u>=0?p.substring(u):""}else i=e.replace(/^\//,"")||"home",n=window.location.search;let a="/"+(i.replace(/^\//,"")||"home"),o=new URLSearchParams(n).get("edit")==="true";this.isEditAllowed=o||sessionStorage.getItem("builder_edit_mode")==="true",a!==this.currentSlug&&(this.cleanupManagedElements(),this.currentSlug=a,this.currentTitle=(i.replace(/^\//,"")||"home").replace(/-/g," ").replace(/\b\w/g,p=>p.toUpperCase())+" Page",this.resetAll());let c=sessionStorage.getItem("builder_edit_mode")==="true";(o||c)&&(this.editMode=!0),this.currentLang=this.detectCurrentLanguage(),this.setLoading(!0);let m=o||c;setTimeout(()=>{this.loadTranslationsAndInit(m)},300)}buildUI(){this.rootEl=document.createElement("div"),this.rootEl.id="xtroedge-cms-root",this.loaderEl=this.createElement("div","lcms-loader-overlay lcms-hidden"),this.loaderEl.innerHTML=`<div class="lcms-loader-content">
241
+ `;var d={edit:'<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>',close:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',undo:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>',redo:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.13-9.36L23 10"/></svg>',history:'<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',save:'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>',publish:'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/></svg>',image:'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>',check:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>',error:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>'},H="xtroedge_cms_history",m="history",B=["h1","h2","h3","h4","h5","h6","p","span","b","strong","i","em","a","button","li","label","small","blockquote","td","th"],b=class h{constructor(t){this.brandingEl=null;this.siteIdentifier="";this.siteIdEl=null;this.editMode=!1;this.currentLang="en";this.pageTexts={};this.pageImages={};this.originalTexts={};this.originalImages={};this.unsavedChanges=0;this.isSaving=!1;this.isPublishing=!1;this.loading=!1;this.canUndo=!1;this.canRedo=!1;this.showHistory=!1;this.historyList=[];this.isOpen=!1;this.isEditAllowed=!1;this.imageUploading=!1;this.toastMessage="";this.toastType="success";this.undoStack=[];this.redoStack=[];this.dirtyKeys=new Set;this.dirtyImageKeys=new Set;this.registeredKeys=new Set;this.managedElements=new Map;this.managedImages=new Map;this.autoDetectedElements=new Set;this.observer=null;this.scanTimeout=null;this.activeImageEl=null;this.imageCtxMenu=null;this.currentSlug="";this.currentTitle="";this.origPushState=null;this.origReplaceState=null;this.styleEl=null;this.rootEl=null;this.loaderEl=null;this.toastEl=null;this.fabEl=null;this.fabBtn=null;this.badgeEl=null;this.panelEl=null;this.editToggle=null;this.langSwitchEl=null;this.changesInfoEl=null;this.undoBtn=null;this.redoBtn=null;this.historyBtnEl=null;this.historyPanelEl=null;this.historyListEl=null;this.saveBtn=null;this.publishBtn=null;this.cancelBtn=null;this.actionsEl=null;this.editModeContent=null;this.fileInput=null;this.imgOverlay=null;this.posX=20;this.posY=20;this.isDragging=!1;this.dragStartX=0;this.dragStartY=0;this.startPosX=0;this.startPosY=0;this.hasMoved=!1;this.toastTimer=null;this.db=null;this.translationCache=new Map;this.config=t||{},this.containerSelector=this.config.containerSelector||"",this.editableTags=(this.config.editableTags||B).map(i=>i.toLowerCase()),this.languages=this.config.languages||["en"],this.defaultLanguage=this.config.defaultLanguage||this.languages[0]||"en",this.highlightColor=this.config.highlightColor||"#00C853",this.historyRetentionMs=(this.config.historyRetentionDays||7)*24*60*60*1e3,this.currentLang=this.defaultLanguage,this.siteIdentifier=this.resolveSiteIdentifier();let e=localStorage.getItem("xtroedge_theme_color");e&&(this.highlightColor=e),this.boundMouseMove=i=>this.onDragMove(i),this.boundMouseUp=()=>this.onDragEnd(),this.boundTouchMove=i=>this.onTouchMove(i),this.boundTouchEnd=()=>this.onTouchEnd(),this.boundPopState=()=>this.handleNavigation(),this.boundHashChange=()=>this.handleNavigation()}init(){this.posY=window.innerHeight-72,this.injectStyles(),this.applyThemeColor(this.highlightColor),this.buildUI(),this.interceptNavigation(),this.observer=new MutationObserver(()=>{this.rootEl&&!document.contains(this.rootEl)&&document.body.appendChild(this.rootEl),this.styleEl&&!document.contains(this.styleEl)&&document.head.appendChild(this.styleEl),this.scanTimeout&&clearTimeout(this.scanTimeout),this.scanTimeout=setTimeout(()=>this.autoDetectAndScan(),150)}),this.observer.observe(document.body,{childList:!0,subtree:!0}),window.addEventListener("popstate",this.boundPopState),window.addEventListener("hashchange",this.boundHashChange),this.handleNavigation()}destroy(){this.cleanupManagedElements(),this.styleEl?.remove(),this.rootEl?.remove(),window.removeEventListener("popstate",this.boundPopState),window.removeEventListener("hashchange",this.boundHashChange),document.removeEventListener("mousemove",this.boundMouseMove),document.removeEventListener("mouseup",this.boundMouseUp),document.removeEventListener("touchmove",this.boundTouchMove),document.removeEventListener("touchend",this.boundTouchEnd),this.origPushState&&(history.pushState=this.origPushState),this.origReplaceState&&(history.replaceState=this.origReplaceState),this.observer?.disconnect(),this.scanTimeout&&clearTimeout(this.scanTimeout),this.toastTimer&&clearTimeout(this.toastTimer),this.db?.close()}injectStyles(){document.getElementById("xtroedge-cms-styles")||(this.styleEl=document.createElement("style"),this.styleEl.id="xtroedge-cms-styles",this.styleEl.textContent=E,document.head.appendChild(this.styleEl))}interceptNavigation(){this.origPushState=history.pushState.bind(history),this.origReplaceState=history.replaceState.bind(history);let t=this;history.pushState=function(...e){t.origPushState(...e),setTimeout(()=>t.handleNavigation(),0)},history.replaceState=function(...e){t.origReplaceState(...e),setTimeout(()=>t.handleNavigation(),0)}}handleNavigation(){let t=window.location.href,e=window.location.pathname||"/",i=window.location.hash||"",s,n;if(i.startsWith("#/")||i.startsWith("#!")){let p=i.replace(/^#[!/]*/,""),g=p.indexOf("?");s=g>=0?p.substring(0,g):p,n=g>=0?p.substring(g):""}else s=e.replace(/^\//,"")||"home",n=window.location.search;let a="/"+(s.replace(/^\//,"")||"home"),l=new URLSearchParams(n).get("edit")==="true";this.isEditAllowed=l||sessionStorage.getItem("builder_edit_mode")==="true",a!==this.currentSlug&&(this.cleanupManagedElements(),this.currentSlug=a,this.currentTitle=(s.replace(/^\//,"")||"home").replace(/-/g," ").replace(/\b\w/g,p=>p.toUpperCase())+" Page",this.resetAll());let c=sessionStorage.getItem("builder_edit_mode")==="true";(l||c)&&(this.editMode=!0),this.currentLang=this.detectCurrentLanguage(),this.setLoading(!0);let u=l||c;setTimeout(()=>{this.loadTranslationsAndInit(u)},300)}buildUI(){this.rootEl=document.createElement("div"),this.rootEl.id="xtroedge-cms-root",this.loaderEl=this.createElement("div","lcms-loader-overlay lcms-hidden"),this.loaderEl.innerHTML=`<div class="lcms-loader-content">
194
242
  <div class="lcms-orbit-loader">
195
243
  <div class="lcms-orbit lcms-orbit-1"><span class="lcms-particle"></span></div>
196
244
  <div class="lcms-orbit lcms-orbit-2"><span class="lcms-particle"></span></div>
@@ -199,4 +247,4 @@
199
247
  <div class="lcms-core"></div>
200
248
  </div>
201
249
  <span class="lcms-loader-text">Loading</span>
202
- </div>`,this.rootEl.appendChild(this.loaderEl),this.toastEl=this.createElement("div","lcms-toast lcms-hidden"),this.rootEl.appendChild(this.toastEl),this.fabEl=this.createElement("div","lcms-fab"),this.fabEl.style.left=this.posX+"px",this.fabEl.style.top=this.posY+"px",this.fabEl.addEventListener("mousedown",t=>this.onDragStart(t)),this.fabEl.addEventListener("touchstart",t=>this.onTouchStart(t),{passive:!0}),this.fabBtn=document.createElement("button"),this.fabBtn.className="lcms-fab-btn",this.fabBtn.innerHTML=l.edit,this.fabBtn.addEventListener("click",t=>this.onFabClick(t)),this.badgeEl=this.createElement("span","lcms-badge lcms-hidden"),this.fabBtn.appendChild(this.badgeEl),this.fabEl.appendChild(this.fabBtn),this.panelEl=this.createElement("div","lcms-panel lcms-hidden"),this.buildPanel(),this.fabEl.appendChild(this.panelEl),this.rootEl.appendChild(this.fabEl),this.fileInput=document.createElement("input"),this.fileInput.type="file",this.fileInput.accept="image/*",this.fileInput.style.display="none",this.fileInput.addEventListener("change",t=>this.onImageFileSelected(t)),this.rootEl.appendChild(this.fileInput),this.imgOverlay=this.createElement("div","lcms-img-upload-overlay lcms-hidden"),this.imgOverlay.innerHTML='<div class="lcms-img-upload-content"><div class="lcms-spinner-lg"></div><span>Uploading image...</span></div>',this.rootEl.appendChild(this.imgOverlay),document.body.appendChild(this.rootEl)}buildPanel(){if(!this.panelEl)return;let t=this.createElement("div","lcms-panel-header"),e=this.createElement("label","lcms-toggle");e.addEventListener("click",o=>o.stopPropagation()),this.editToggle=document.createElement("input"),this.editToggle.type="checkbox",this.editToggle.checked=this.editMode,this.editToggle.addEventListener("change",o=>this.toggleEditMode(o));let s=this.createElement("span","lcms-toggle-slider"),i=this.createElement("span","lcms-toggle-label");i.textContent="Edit",e.appendChild(this.editToggle),e.appendChild(s),e.appendChild(i),t.appendChild(e),this.langSwitchEl=this.createElement("div","lcms-lang-switch lcms-hidden"),this.buildLangButtons(),t.appendChild(this.langSwitchEl);let n=document.createElement("button");n.className="lcms-close-btn",n.innerHTML=l.close,n.addEventListener("click",o=>{o.stopPropagation(),this.togglePanel()}),t.appendChild(n),this.panelEl.appendChild(t),this.editModeContent=this.createElement("div","lcms-hidden"),this.changesInfoEl=this.createElement("div","lcms-changes-info lcms-hidden"),this.editModeContent.appendChild(this.changesInfoEl);let a=this.createElement("div","lcms-undo-row");this.undoBtn=document.createElement("button"),this.undoBtn.className="lcms-icon-btn",this.undoBtn.innerHTML=l.undo,this.undoBtn.disabled=!0,this.undoBtn.addEventListener("click",o=>{o.stopPropagation(),this.onUndo()}),this.redoBtn=document.createElement("button"),this.redoBtn.className="lcms-icon-btn",this.redoBtn.innerHTML=l.redo,this.redoBtn.disabled=!0,this.redoBtn.addEventListener("click",o=>{o.stopPropagation(),this.onRedo()}),a.appendChild(this.undoBtn),a.appendChild(this.redoBtn),this.editModeContent.appendChild(a),this.historyBtnEl=document.createElement("button"),this.historyBtnEl.className="lcms-history-btn",this.historyBtnEl.innerHTML=`${l.history} History (7 days)`,this.historyBtnEl.addEventListener("click",o=>{o.stopPropagation(),this.toggleHistory()}),this.editModeContent.appendChild(this.historyBtnEl),this.historyPanelEl=this.createElement("div","lcms-history-panel lcms-hidden");let r=this.createElement("div","lcms-history-title");r.textContent="Edit History",this.historyPanelEl.appendChild(r),this.historyListEl=this.createElement("div","lcms-history-list"),this.historyPanelEl.appendChild(this.historyListEl),this.editModeContent.appendChild(this.historyPanelEl),this.actionsEl=this.createElement("div","lcms-actions"),this.saveBtn=document.createElement("button"),this.saveBtn.className="lcms-btn-save",this.saveBtn.innerHTML=`${l.save} Save Draft`,this.saveBtn.addEventListener("click",o=>{o.stopPropagation(),this.saveChanges()}),this.publishBtn=document.createElement("button"),this.publishBtn.className="lcms-btn-publish",this.publishBtn.innerHTML=`${l.publish} Publish`,this.publishBtn.addEventListener("click",o=>{o.stopPropagation(),this.publishChanges()}),this.cancelBtn=document.createElement("button"),this.cancelBtn.className="lcms-btn-cancel",this.cancelBtn.textContent="Cancel",this.cancelBtn.addEventListener("click",o=>{o.stopPropagation(),this.cancelEditing()}),this.actionsEl.appendChild(this.saveBtn),this.actionsEl.appendChild(this.publishBtn),this.actionsEl.appendChild(this.cancelBtn),this.editModeContent.appendChild(this.actionsEl),this.panelEl.appendChild(this.editModeContent),this.brandingEl=this.createElement("div","lcms-branding"),this.brandingEl.innerHTML='<div class="lcms-branding-logo"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg></div><div class="lcms-branding-text">Powered by <span>XtroEdge</span></div>',this.panelEl.appendChild(this.brandingEl)}buildLangButtons(){if(this.langSwitchEl){this.langSwitchEl.innerHTML="";for(let t of this.languages){let e=document.createElement("button");e.className="lcms-lang-btn"+(this.currentLang===t?" active":""),e.textContent=t.toUpperCase(),e.addEventListener("click",s=>{s.stopPropagation(),this.switchLang(t)}),this.langSwitchEl.appendChild(e)}}}updateUI(){if(this.fabEl&&(this.fabEl.style.display=this.isEditAllowed?"":"none"),this.fabBtn&&(this.fabBtn.style.display=this.isOpen?"none":"",this.fabBtn.classList.toggle("lcms-fab-active",this.editMode)),this.panelEl&&(this.panelEl.classList.toggle("lcms-hidden",!this.isOpen),this.isOpen)){let t=this.posY>window.innerHeight/2,e=this.posX>window.innerWidth/2;this.panelEl.style.bottom=t?"0":"",this.panelEl.style.top=t?"":"0",this.panelEl.style.right=e?"0":"",this.panelEl.style.left=e?"":"0"}this.badgeEl&&(this.badgeEl.classList.toggle("lcms-hidden",this.unsavedChanges===0),this.badgeEl.textContent=String(this.unsavedChanges)),this.editToggle&&(this.editToggle.checked=this.editMode),this.langSwitchEl&&(this.langSwitchEl.classList.toggle("lcms-hidden",!this.editMode||this.languages.length<=1),this.langSwitchEl.querySelectorAll(".lcms-lang-btn").forEach(e=>{e.classList.toggle("active",e.textContent===this.currentLang.toUpperCase())})),this.editModeContent&&this.editModeContent.classList.toggle("lcms-hidden",!this.editMode),this.changesInfoEl&&(this.changesInfoEl.classList.toggle("lcms-hidden",this.unsavedChanges===0),this.changesInfoEl.textContent=`${this.unsavedChanges} unsaved change${this.unsavedChanges>1?"s":""}`),this.undoBtn&&(this.undoBtn.disabled=!this.canUndo),this.redoBtn&&(this.redoBtn.disabled=!this.canRedo),this.historyBtnEl&&this.historyBtnEl.classList.toggle("active",this.showHistory),this.historyPanelEl&&this.historyPanelEl.classList.toggle("lcms-hidden",!this.showHistory),this.saveBtn&&(this.saveBtn.disabled=this.isSaving||this.isPublishing||this.unsavedChanges===0,this.saveBtn.innerHTML=this.isSaving?'<span class="lcms-spinner"></span> Saving...':`${l.save} Save Draft`),this.publishBtn&&(this.publishBtn.disabled=this.isSaving||this.isPublishing,this.publishBtn.innerHTML=this.isPublishing?'<span class="lcms-spinner"></span> Publishing...':`${l.publish} Publish`),this.cancelBtn&&(this.cancelBtn.disabled=this.isSaving||this.isPublishing),this.loaderEl&&this.loaderEl.classList.toggle("lcms-hidden",!this.loading),this.imgOverlay&&this.imgOverlay.classList.toggle("lcms-hidden",!this.imageUploading)}autoDetectAndScan(){this.autoDetectElements(),this.scanDOM(),this.scanImages()}resolveContainer(){return this.containerSelector?document.querySelector(this.containerSelector)||document.body:document.querySelector(".layout")||document.body}autoDetectElements(){let t=this.resolveContainer();if(!t)return;for(let n of this.autoDetectedElements)document.contains(n)||this.autoDetectedElements.delete(n);let e={},s=this.editableTags.join(",");t.querySelectorAll(s).forEach(n=>{if(n.hasAttribute("data-cms")||n.closest("#xtroedge-cms-root, script, style, noscript")||n.children.length>3||this.getDirectTextContent(n).trim().length<2)return;let r=n.tagName.toLowerCase();e[r]||(e[r]=0);let o=`xcms_${r}_${e[r]}`;e[r]++,n.setAttribute("data-cms",o),this.autoDetectedElements.add(n)})}scanDOM(){document.querySelectorAll("[data-cms]").forEach(e=>{if(e.closest("#xtroedge-cms-root"))return;let s=e.getAttribute("data-cms");this.registeredKeys.add(s),this.managedElements.has(e)||this.attachElement(e,s)});for(let[e]of this.managedElements)document.contains(e)||this.detachElement(e)}scanImages(){let t=this.resolveContainer();if(!t)return;let e={...this.pageImages},s=!1;t.querySelectorAll("img").forEach(n=>{if(n.closest("#xtroedge-cms-root")||this.managedImages.has(n))return;let a=n.getAttribute("src")||"";!a||a.startsWith("data:")||(this.attachImage(n,a),e[a]||(e[a]=a,s=!0))}),s&&(this.pageImages=e,this.originalImages=JSON.parse(JSON.stringify(e)));for(let[n]of this.managedImages)document.contains(n)||this.detachImage(n)}getDirectTextContent(t){let e="";for(let s=0;s<t.childNodes.length;s++)t.childNodes[s].nodeType===Node.TEXT_NODE&&(e+=t.childNodes[s].textContent||"");return e}attachElement(t,e){let s=()=>{let a=t.textContent?.trim()||"",r=this.getPageText(e);a!==r&&this.onTextChanged(e,a)},i=a=>{a.key==="Enter"&&(a.preventDefault(),t.blur())},n=()=>{let a=t.textContent?.trim()||"",r=this.getPageText(e);a!==r&&this.onTextChanged(e,a)};this.managedElements.set(t,{key:e,blurHandler:s,keydownHandler:i,inputHandler:n}),this.editMode&&this.enableElementEdit(t,e,s,i,n)}detachElement(t){let e=this.managedElements.get(t);e&&(t.removeEventListener("blur",e.blurHandler),t.removeEventListener("keydown",e.keydownHandler),t.removeEventListener("input",e.inputHandler),t.removeAttribute("contenteditable"),this.managedElements.delete(t))}enableElementEdit(t,e,s,i,n){let a=this.getPageText(e);a&&(t.textContent=a),t.setAttribute("contenteditable","true"),t.style.borderBottom=`2px dashed ${this.highlightColor}`,t.style.padding="2px 4px",t.style.borderRadius="3px",t.style.cursor="text",t.style.outline="none",t.style.transition="background 0.2s",t.style.minWidth="20px",t.addEventListener("blur",s),t.addEventListener("keydown",i),t.addEventListener("input",n)}disableElementEdit(t,e,s,i,n){t.removeAttribute("contenteditable"),t.style.borderBottom="",t.style.padding="",t.style.borderRadius="",t.style.cursor="",t.style.outline="",t.style.transition="",t.style.minWidth="";let a=this.getPageText(e);a&&(t.textContent=a),t.removeEventListener("blur",s),t.removeEventListener("keydown",i),t.removeEventListener("input",n)}applyEditMode(t){for(let[e,s]of this.managedElements)t?this.enableElementEdit(e,s.key,s.blurHandler,s.keydownHandler,s.inputHandler):this.disableElementEdit(e,s.key,s.blurHandler,s.keydownHandler,s.inputHandler);this.applyImageEditMode(t)}updateElementTexts(){this.observer?.disconnect();for(let[t,e]of this.managedElements){if(document.activeElement===t)continue;let s=this.getPageText(e.key);s&&t.textContent!==s&&(t.textContent=s)}this.observer?.observe(document.body,{childList:!0,subtree:!0})}cleanupManagedElements(){for(let[t]of this.managedElements)this.detachElement(t);this.managedElements.clear();for(let t of this.autoDetectedElements)t.removeAttribute("data-cms");this.autoDetectedElements.clear(),this.cleanupManagedImages()}attachImage(t,e){let s=i=>{this.editMode&&(i.preventDefault(),i.stopPropagation(),this.showImageContextMenu(i.clientX,i.clientY,t))};this.managedImages.set(t,{key:e,ctxHandler:s}),this.editMode&&this.enableImageEdit(t,s)}detachImage(t){let e=this.managedImages.get(t);e&&(t.removeEventListener("contextmenu",e.ctxHandler),t.style.outline="",t.style.cursor="",this.managedImages.delete(t))}cleanupManagedImages(){for(let[t]of this.managedImages)this.detachImage(t);this.managedImages.clear(),this.dismissImageCtxMenu()}applyImageEditMode(t){for(let[e,s]of this.managedImages)t?this.enableImageEdit(e,s.ctxHandler):this.disableImageEdit(e,s.ctxHandler);t||this.dismissImageCtxMenu()}enableImageEdit(t,e){t.style.outline=`2px dashed ${this.highlightColor}`,t.style.cursor="context-menu",t.addEventListener("contextmenu",e)}disableImageEdit(t,e){t.style.outline="",t.style.cursor="",t.removeEventListener("contextmenu",e)}showImageContextMenu(t,e,s){this.dismissImageCtxMenu();let i=document.createElement("div");Object.assign(i.style,{position:"fixed",zIndex:"10005",minWidth:"160px",background:"rgba(30,15,60,0.85)",backdropFilter:"blur(16px)",webkitBackdropFilter:"blur(16px)",border:"1px solid rgba(139,92,246,0.3)",borderRadius:"10px",padding:"4px",boxShadow:"0 8px 32px rgba(0,0,0,0.4)",fontFamily:"system-ui, -apple-system, sans-serif",left:Math.min(t,window.innerWidth-180)+"px",top:Math.min(e,window.innerHeight-50)+"px"});let n=document.createElement("button");Object.assign(n.style,{width:"100%",padding:"8px 12px",border:"none",borderRadius:"7px",background:"transparent",color:"white",fontSize:"12px",fontWeight:"500",cursor:"pointer",display:"flex",alignItems:"center",gap:"8px"}),n.innerHTML=`${l.image} Upload Image`,n.addEventListener("mouseenter",()=>n.style.background="rgba(103,34,251,0.3)"),n.addEventListener("mouseleave",()=>n.style.background="transparent"),n.addEventListener("click",()=>{this.activeImageEl=s,this.fileInput&&(this.fileInput.value="",this.fileInput.click()),this.dismissImageCtxMenu()}),i.appendChild(n),document.body.appendChild(i),this.imageCtxMenu=i;let a=r=>{i.contains(r.target)||(this.dismissImageCtxMenu(),document.removeEventListener("mousedown",a))};setTimeout(()=>document.addEventListener("mousedown",a),0)}dismissImageCtxMenu(){this.imageCtxMenu&&(this.imageCtxMenu.remove(),this.imageCtxMenu=null)}onImageFileSelected(t){let s=t.target.files?.[0];if(!s||!this.activeImageEl)return;this.imageUploading=!0,this.updateUI();let i=new FileReader;i.onload=()=>{let n=i.result;this.uploadImageToApi(n)},i.readAsDataURL(s)}async uploadImageToApi(t){try{let e=await fetch(`${this.config.apiBase}/web/upload-image`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:t})});if(!e.ok)throw new Error(`HTTP ${e.status}`);let s=await e.json(),n=(this.config.imageBaseUrl||(this.config.apiBase?new URL(this.config.apiBase).origin:""))+s.path;if(this.activeImageEl){let a=this.managedImages.get(this.activeImageEl)?.key||"";this.activeImageEl.src=n,this.onImageChanged(a,n)}this.imageUploading=!1,this.activeImageEl=null,this.updateUI(),this.showToast("Image updated!","success")}catch(e){this.imageUploading=!1,this.activeImageEl=null,this.updateUI(),this.showToast("Image upload failed.","error"),this.config.onError?.("upload-image",e)}}applyPageImages(){for(let[t,e]of this.managedImages){let s=this.pageImages[e.key];s&&t.src!==s&&(t.src=s)}}getPageText(t){return this.pageTexts[t]?.[this.currentLang]||""}onTextChanged(t,e){this.undoStack.push(this.createSnapshot()),this.redoStack=[],this.canUndo=!0,this.canRedo=!1,this.pageTexts[t]||(this.pageTexts[t]={}),this.pageTexts[t]={...this.pageTexts[t],[this.currentLang]:e},this.dirtyKeys.add(t),this.unsavedChanges=this.dirtyKeys.size+this.dirtyImageKeys.size,this.pushHistory(t,this.currentLang),this.updateUI()}onImageChanged(t,e){this.undoStack.push(this.createSnapshot()),this.redoStack=[],this.canUndo=!0,this.canRedo=!1,this.pageImages={...this.pageImages,[t]:e},this.dirtyImageKeys.add(t),this.unsavedChanges=this.dirtyKeys.size+this.dirtyImageKeys.size,this.pushHistory(t,"img"),this.updateUI()}createSnapshot(){return JSON.stringify({texts:this.pageTexts,images:this.pageImages})}applySnapshot(t){let e=JSON.parse(t);e.texts?(this.pageTexts=e.texts,e.images&&(this.pageImages=e.images)):this.pageTexts=e}onUndo(){this.undoStack.length!==0&&(this.redoStack.push(this.createSnapshot()),this.applySnapshot(this.undoStack.pop()),this.canUndo=this.undoStack.length>0,this.canRedo=!0,this.recalcDirtyKeys(),this.updateElementTexts(),this.applyPageImages(),this.updateUI())}onRedo(){this.redoStack.length!==0&&(this.undoStack.push(this.createSnapshot()),this.applySnapshot(this.redoStack.pop()),this.canUndo=!0,this.canRedo=this.redoStack.length>0,this.recalcDirtyKeys(),this.updateElementTexts(),this.applyPageImages(),this.updateUI())}recalcDirtyKeys(){this.dirtyKeys.clear();for(let t of this.registeredKeys)JSON.stringify(this.pageTexts[t])!==JSON.stringify(this.originalTexts[t])&&this.dirtyKeys.add(t);this.unsavedChanges=this.dirtyKeys.size+this.dirtyImageKeys.size}resetAll(){this.dirtyKeys.clear(),this.dirtyImageKeys.clear(),this.unsavedChanges=0,this.undoStack=[],this.redoStack=[],this.canUndo=!1,this.canRedo=!1,this.updateUI()}resetAfterSave(){this.dirtyKeys.clear(),this.dirtyImageKeys.clear(),this.unsavedChanges=0,this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages))}cancelEditing(){this.pageTexts=JSON.parse(JSON.stringify(this.originalTexts)),this.pageImages=JSON.parse(JSON.stringify(this.originalImages)),this.dirtyKeys.clear(),this.dirtyImageKeys.clear(),this.unsavedChanges=0,this.updateElementTexts(),this.applyPageImages(),this.updateUI()}async loadTranslationsAndInit(t){if(this.config.i18nBasePath)try{let e=this.currentLang,s=await fetch(`${this.config.i18nBasePath}/${e}.json`);if(s.ok){let i=await s.json();this.translationCache.clear(),this.flattenTranslations(i,"",this.getPageSection())}}catch{}this.autoDetectAndScan(),this.editMode&&this.applyEditMode(!0),this.config.apiBase?t?this.loadPageContent("draft"):this.loadPublishedContent():(this.buildDefaultTexts(),this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages)),this.setLoading(!1)),this.updateUI()}flattenTranslations(t,e,s){for(let i of Object.keys(t)){let n=e?`${e}.${i}`:i;if(typeof t[i]=="string"){let a=t[i].trim();a.length>=2&&(!this.translationCache.get(a)||n.toUpperCase().startsWith(s))&&this.translationCache.set(a,n)}else typeof t[i]=="object"&&t[i]!==null&&!Array.isArray(t[i])&&this.flattenTranslations(t[i],n,s)}}getPageSection(){return this.currentSlug.replace(/^\//,"").replace(/-/g,"_").toUpperCase()}async loadPageContent(t){this.setLoading(!0),this.cleanOldHistory();try{let e=await fetch(`${this.config.apiBase}/web-page/get?slug=${encodeURIComponent(this.currentSlug)}&status=${t}`);if(!e.ok)throw new Error(`HTTP ${e.status}`);let s=await e.json(),i=s?.published_content?.texts||s?.content?.texts;i?this.pageTexts=JSON.parse(JSON.stringify(i)):this.buildDefaultTexts();let n=s?.published_content?.images||s?.content?.images;n&&(this.pageImages=JSON.parse(JSON.stringify(n)),this.applyPageImages()),this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages)),this.resetAll(),this.updateElementTexts()}catch{this.buildDefaultTexts(),this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages)),this.resetAll()}finally{this.setLoading(!1)}}async loadPublishedContent(){this.setLoading(!0);try{let t=await fetch(`${this.config.apiBase}/web-page/get?slug=${encodeURIComponent(this.currentSlug)}&status=published`);if(!t.ok)throw new Error(`HTTP ${t.status}`);let e=await t.json(),s=e?.published_content?.texts;s&&Object.keys(s).length>0&&(this.pageTexts=JSON.parse(JSON.stringify(s)),this.updateElementTexts());let i=e?.published_content?.images;i&&Object.keys(i).length>0&&(this.pageImages=JSON.parse(JSON.stringify(i)),this.applyPageImages())}catch{}finally{this.setLoading(!1)}}buildDefaultTexts(){let t={};for(let e of this.registeredKeys){let i=document.querySelector(`[data-cms="${e}"]`)?.textContent?.trim()||"";t[e]={[this.currentLang]:i}}if(this.pageTexts=t,this.config.i18nBasePath){let e=this.languages.filter(s=>s!==this.currentLang);for(let s of e)fetch(`${this.config.i18nBasePath}/${s}.json`).then(i=>i.json()).then(i=>{let n={...this.pageTexts};for(let a of this.registeredKeys){let r=a.split("."),o=i;for(let c of r)o=o?.[c];o&&typeof o=="string"&&(n[a]={...n[a],[s]:o})}this.pageTexts=n,this.originalTexts=JSON.parse(JSON.stringify(n)),this.updateElementTexts()}).catch(()=>{})}}async saveChanges(){if(!this.config.apiBase){this.showToast("No API configured. Set apiBase to enable save.","error");return}this.isSaving=!0,this.updateUI();let t={slug:this.currentSlug,title:this.currentTitle,content:{texts:this.pageTexts,images:this.pageImages}};try{let e=await fetch(`${this.config.apiBase}/web_page/save`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok)throw new Error(`HTTP ${e.status}`);this.isSaving=!1,this.resetAfterSave(),this.updateUI(),this.showToast("Draft saved successfully!","success"),this.config.onSaved?.()}catch(e){this.isSaving=!1,this.updateUI(),this.showToast("Save failed. Please try again.","error"),this.config.onError?.("save",e)}}async publishChanges(){if(!this.config.apiBase){this.showToast("No API configured. Set apiBase to enable publish.","error");return}this.isPublishing=!0,this.updateUI();let t={slug:this.currentSlug,title:this.currentTitle,published_content:{texts:this.pageTexts,images:this.pageImages}};try{let e=await fetch(`${this.config.apiBase}/web_page/publish`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok)throw new Error(`HTTP ${e.status}`);this.isPublishing=!1,this.resetAfterSave(),this.updateUI(),this.showToast("Published successfully!","success"),this.config.onPublished?.()}catch(e){this.isPublishing=!1,this.updateUI(),this.showToast("Publish failed. Please try again.","error"),this.config.onError?.("publish",e)}}async toggleHistory(){this.showHistory=!this.showHistory,this.showHistory&&await this.loadHistory(),this.updateUI()}async loadHistory(){try{let t=await this.openDB(),e=await new Promise((s,i)=>{let o=t.transaction(h,"readonly").objectStore(h).index("slug").getAll(this.currentSlug);o.onsuccess=()=>s(o.result.sort((c,m)=>m.timestamp-c.timestamp).slice(0,30)),o.onerror=()=>i(o.error)});this.historyList=e,this.renderHistoryList()}catch{}}renderHistoryList(){if(this.historyListEl){if(this.historyListEl.innerHTML="",this.historyList.length===0){let t=this.createElement("div","lcms-history-empty");t.textContent="No history yet",this.historyListEl.appendChild(t);return}for(let t of this.historyList){let e=document.createElement("button");e.className="lcms-history-item";let s=this.createElement("div","lcms-history-label");s.textContent=t.label;let i=this.createElement("div","lcms-history-meta"),n=this.createElement("span","lcms-history-lang");n.textContent=t.lang.toUpperCase();let a=document.createTextNode(" "+this.formatDate(t.timestamp));i.appendChild(n),i.appendChild(a),e.appendChild(s),e.appendChild(i),e.addEventListener("click",r=>{r.stopPropagation(),this.restoreHistory(t)}),this.historyListEl.appendChild(e)}}}restoreHistory(t){this.undoStack.push(this.createSnapshot()),this.canUndo=!0,this.applySnapshot(t.snapshot),this.recalcDirtyKeys(),this.showHistory=!1,this.updateElementTexts(),this.applyPageImages(),this.updateUI(),this.showToast("Restored from history","success")}pushHistory(t,e){let s=e==="img",i=s?t.split("/").pop()||"image":t.split("_").pop()||t,n=s?`Changed ${i}`:`Edited ${i}`;this.openDB().then(a=>{a.transaction(h,"readwrite").objectStore(h).add({slug:this.currentSlug,timestamp:Date.now(),label:n,lang:e,snapshot:JSON.stringify({texts:this.pageTexts,images:this.pageImages})})}).catch(()=>{})}async cleanOldHistory(){try{let t=await this.openDB(),e=Date.now()-this.historyRetentionMs,n=t.transaction(h,"readwrite").objectStore(h).index("timestamp").openCursor(IDBKeyRange.upperBound(e));n.onsuccess=()=>{let a=n.result;a&&(a.delete(),a.continue())}}catch{}}openDB(){return this.db?Promise.resolve(this.db):new Promise((t,e)=>{let s=indexedDB.open(M,1);s.onupgradeneeded=()=>{let i=s.result;if(!i.objectStoreNames.contains(h)){let n=i.createObjectStore(h,{keyPath:"id",autoIncrement:!0});n.createIndex("slug","slug",{unique:!1}),n.createIndex("timestamp","timestamp",{unique:!1})}},s.onsuccess=()=>{this.db=s.result,t(this.db)},s.onerror=()=>e(s.error)})}showToast(t,e){if(!this.toastEl)return;this.toastMessage=t,this.toastType=e;let s=e==="success"?l.check:l.error;this.toastEl.className=`lcms-toast lcms-toast-${e}`,this.toastEl.innerHTML=`${s} ${t}`,this.toastTimer&&clearTimeout(this.toastTimer),this.toastTimer=setTimeout(()=>{this.toastEl&&this.toastEl.classList.add("lcms-hidden")},3e3)}onFabClick(t){t.stopPropagation(),!this.hasMoved&&(this.isOpen=!this.isOpen,this.updateUI())}togglePanel(){this.hasMoved||(this.isOpen=!this.isOpen,this.updateUI())}toggleEditMode(t){t.stopPropagation(),t.target.checked?(sessionStorage.setItem("builder_edit_mode","true"),this.editMode=!0,this.currentLang=this.detectCurrentLanguage(),this.applyEditMode(!0),this.loadPageContent("draft")):(sessionStorage.removeItem("builder_edit_mode"),this.editMode=!1,this.applyEditMode(!1)),this.updateUI(),this.config.onEditModeChanged?.(this.editMode)}switchLang(t){this.currentLang=t,this.updateElementTexts(),this.buildLangButtons(),this.updateUI(),this.config.onLangChanged?.(t)}onDragStart(t){t.target.closest("button:not(.lcms-fab-btn)")||t.target.closest(".lcms-panel")||(this.isDragging=!0,this.hasMoved=!1,this.dragStartX=t.clientX,this.dragStartY=t.clientY,this.startPosX=this.posX,this.startPosY=this.posY,document.addEventListener("mousemove",this.boundMouseMove),document.addEventListener("mouseup",this.boundMouseUp))}onDragMove(t){if(!this.isDragging||!this.fabEl)return;let e=t.clientX-this.dragStartX,s=t.clientY-this.dragStartY;(Math.abs(e)>3||Math.abs(s)>3)&&(this.hasMoved=!0),this.posX=Math.max(0,Math.min(window.innerWidth-60,this.startPosX+e)),this.posY=Math.max(0,Math.min(window.innerHeight-60,this.startPosY+s)),this.fabEl.style.left=this.posX+"px",this.fabEl.style.top=this.posY+"px"}onDragEnd(){this.isDragging=!1,document.removeEventListener("mousemove",this.boundMouseMove),document.removeEventListener("mouseup",this.boundMouseUp)}onTouchStart(t){if(t.target.closest("button:not(.lcms-fab-btn)")||t.target.closest(".lcms-panel"))return;let e=t.touches[0];this.isDragging=!0,this.hasMoved=!1,this.dragStartX=e.clientX,this.dragStartY=e.clientY,this.startPosX=this.posX,this.startPosY=this.posY,document.addEventListener("touchmove",this.boundTouchMove,{passive:!1}),document.addEventListener("touchend",this.boundTouchEnd)}onTouchMove(t){if(!this.isDragging||!this.fabEl)return;t.preventDefault();let e=t.touches[0],s=e.clientX-this.dragStartX,i=e.clientY-this.dragStartY;(Math.abs(s)>3||Math.abs(i)>3)&&(this.hasMoved=!0),this.posX=Math.max(0,Math.min(window.innerWidth-60,this.startPosX+s)),this.posY=Math.max(0,Math.min(window.innerHeight-60,this.startPosY+i)),this.fabEl.style.left=this.posX+"px",this.fabEl.style.top=this.posY+"px"}onTouchEnd(){this.isDragging=!1,document.removeEventListener("touchmove",this.boundTouchMove),document.removeEventListener("touchend",this.boundTouchEnd)}setLoading(t){this.loading=t,this.updateUI()}detectCurrentLanguage(){let t=document.documentElement.getAttribute("lang");if(t&&this.languages.includes(t))return t;let e=localStorage.getItem("selectedLanguage");return e&&this.languages.includes(e)?e:this.defaultLanguage}createElement(t,e){let s=document.createElement(t);return s.className=e,s}formatDate(t){let e=new Date(t),s=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],i=e.getHours(),n=e.getMinutes().toString().padStart(2,"0"),a=i>=12?"PM":"AM",r=i%12||12;return`${s[e.getMonth()]} ${e.getDate()}, ${r}:${n} ${a}`}static create(t){let e=new d(t);return e.init(),e}static autoInit(){if(window.__xtroedge_cms_instance__)return;let t=window.__XTROEDGE_CMS_CONFIG__||{},e=d.create(t);window.__xtroedge_cms_instance__=e}};function f(){g.autoInit()}typeof window<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",f):f());return C(L);})();
250
+ </div>`,this.rootEl.appendChild(this.loaderEl),this.toastEl=this.createElement("div","lcms-toast lcms-hidden"),this.rootEl.appendChild(this.toastEl),this.fabEl=this.createElement("div","lcms-fab"),this.fabEl.style.left=this.posX+"px",this.fabEl.style.top=this.posY+"px",this.fabEl.addEventListener("mousedown",t=>this.onDragStart(t)),this.fabEl.addEventListener("touchstart",t=>this.onTouchStart(t),{passive:!0}),this.fabBtn=document.createElement("button"),this.fabBtn.className="lcms-fab-btn",this.fabBtn.innerHTML=d.edit,this.fabBtn.addEventListener("click",t=>this.onFabClick(t)),this.badgeEl=this.createElement("span","lcms-badge lcms-hidden"),this.fabBtn.appendChild(this.badgeEl),this.fabEl.appendChild(this.fabBtn),this.panelEl=this.createElement("div","lcms-panel lcms-hidden"),this.buildPanel(),this.fabEl.appendChild(this.panelEl),this.rootEl.appendChild(this.fabEl),this.fileInput=document.createElement("input"),this.fileInput.type="file",this.fileInput.accept="image/*",this.fileInput.style.display="none",this.fileInput.addEventListener("change",t=>this.onImageFileSelected(t)),this.rootEl.appendChild(this.fileInput),this.imgOverlay=this.createElement("div","lcms-img-upload-overlay lcms-hidden"),this.imgOverlay.innerHTML='<div class="lcms-img-upload-content"><div class="lcms-spinner-lg"></div><span>Uploading image...</span></div>',this.rootEl.appendChild(this.imgOverlay),document.body.appendChild(this.rootEl)}buildPanel(){if(!this.panelEl)return;let t=this.createElement("div","lcms-panel-header"),e=this.createElement("label","lcms-toggle");e.addEventListener("click",r=>r.stopPropagation()),this.editToggle=document.createElement("input"),this.editToggle.type="checkbox",this.editToggle.checked=this.editMode,this.editToggle.addEventListener("change",r=>this.toggleEditMode(r));let i=this.createElement("span","lcms-toggle-slider"),s=this.createElement("span","lcms-toggle-label");s.textContent="Edit",e.appendChild(this.editToggle),e.appendChild(i),e.appendChild(s),t.appendChild(e),this.langSwitchEl=this.createElement("div","lcms-lang-switch lcms-hidden"),this.buildLangButtons(),t.appendChild(this.langSwitchEl);let n=document.createElement("button");n.className="lcms-close-btn",n.innerHTML=d.close,n.addEventListener("click",r=>{r.stopPropagation(),this.togglePanel()}),t.appendChild(n),this.panelEl.appendChild(t),this.siteIdEl=this.createElement("div","lcms-site-id");let a=this.siteIdentifier.includes(".");this.siteIdEl.innerHTML=`<span class="lcms-site-id-icon">${a?"\u{1F310}":"\u{1F511}"}</span><span class="lcms-site-id-text">${a?this.siteIdentifier:this.siteIdentifier.substring(0,8)}</span>`,this.panelEl.appendChild(this.siteIdEl),this.editModeContent=this.createElement("div","lcms-hidden"),this.changesInfoEl=this.createElement("div","lcms-changes-info lcms-hidden"),this.editModeContent.appendChild(this.changesInfoEl);let o=this.createElement("div","lcms-undo-row");this.undoBtn=document.createElement("button"),this.undoBtn.className="lcms-icon-btn",this.undoBtn.innerHTML=d.undo,this.undoBtn.disabled=!0,this.undoBtn.addEventListener("click",r=>{r.stopPropagation(),this.onUndo()}),this.redoBtn=document.createElement("button"),this.redoBtn.className="lcms-icon-btn",this.redoBtn.innerHTML=d.redo,this.redoBtn.disabled=!0,this.redoBtn.addEventListener("click",r=>{r.stopPropagation(),this.onRedo()}),o.appendChild(this.undoBtn),o.appendChild(this.redoBtn),this.editModeContent.appendChild(o);let l=this.createElement("div","lcms-theme-row"),c=this.createElement("span","lcms-theme-label");c.textContent="Theme",l.appendChild(c);let u=this.createElement("div","lcms-theme-colors"),p=["#00C853","#6722FB","#2196F3","#FF5722","#E91E63","#FFD600"];for(let r of p){let v=this.createElement("div","lcms-theme-swatch");v.style.background=r,v.dataset.color=r,r===this.highlightColor&&v.classList.add("active"),v.addEventListener("click",C=>{C.stopPropagation(),this.applyThemeColor(r)}),u.appendChild(v)}let g=this.createElement("div","lcms-theme-custom"),T=this.createElement("div","lcms-theme-custom-preview"),f=document.createElement("input");f.type="color",f.value=this.highlightColor,f.addEventListener("input",r=>{r.stopPropagation(),this.applyThemeColor(r.target.value)}),g.appendChild(T),g.appendChild(f),u.appendChild(g),l.appendChild(u),this.editModeContent.appendChild(l),this.historyBtnEl=document.createElement("button"),this.historyBtnEl.className="lcms-history-btn",this.historyBtnEl.innerHTML=`${d.history} History (7 days)`,this.historyBtnEl.addEventListener("click",r=>{r.stopPropagation(),this.toggleHistory()}),this.editModeContent.appendChild(this.historyBtnEl),this.historyPanelEl=this.createElement("div","lcms-history-panel lcms-hidden");let x=this.createElement("div","lcms-history-title");x.textContent="Edit History",this.historyPanelEl.appendChild(x),this.historyListEl=this.createElement("div","lcms-history-list"),this.historyPanelEl.appendChild(this.historyListEl),this.editModeContent.appendChild(this.historyPanelEl),this.actionsEl=this.createElement("div","lcms-actions"),this.saveBtn=document.createElement("button"),this.saveBtn.className="lcms-btn-save",this.saveBtn.innerHTML=`${d.save} Save Draft`,this.saveBtn.addEventListener("click",r=>{r.stopPropagation(),this.saveChanges()}),this.publishBtn=document.createElement("button"),this.publishBtn.className="lcms-btn-publish",this.publishBtn.innerHTML=`${d.publish} Publish`,this.publishBtn.addEventListener("click",r=>{r.stopPropagation(),this.publishChanges()}),this.cancelBtn=document.createElement("button"),this.cancelBtn.className="lcms-btn-cancel",this.cancelBtn.textContent="Cancel",this.cancelBtn.addEventListener("click",r=>{r.stopPropagation(),this.cancelEditing()}),this.actionsEl.appendChild(this.saveBtn),this.actionsEl.appendChild(this.publishBtn),this.actionsEl.appendChild(this.cancelBtn),this.editModeContent.appendChild(this.actionsEl),this.panelEl.appendChild(this.editModeContent),this.brandingEl=this.createElement("div","lcms-branding"),this.brandingEl.innerHTML='<div class="lcms-branding-logo"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg></div><div class="lcms-branding-text">Powered by <span>XtroEdge</span></div>',this.brandingEl.addEventListener("click",r=>{r.stopPropagation(),window.open("https://xtro.vercel.app/","_blank")}),this.panelEl.appendChild(this.brandingEl)}buildLangButtons(){if(this.langSwitchEl){this.langSwitchEl.innerHTML="";for(let t of this.languages){let e=document.createElement("button");e.className="lcms-lang-btn"+(this.currentLang===t?" active":""),e.textContent=t.toUpperCase(),e.addEventListener("click",i=>{i.stopPropagation(),this.switchLang(t)}),this.langSwitchEl.appendChild(e)}}}updateUI(){if(this.fabEl&&(this.fabEl.style.display=this.isEditAllowed?"":"none"),this.fabBtn&&(this.fabBtn.style.display=this.isOpen?"none":"",this.fabBtn.classList.toggle("lcms-fab-active",this.editMode)),this.panelEl&&(this.panelEl.classList.toggle("lcms-hidden",!this.isOpen),this.isOpen)){let t=this.posY>window.innerHeight/2,e=this.posX>window.innerWidth/2;this.panelEl.style.bottom=t?"0":"",this.panelEl.style.top=t?"":"0",this.panelEl.style.right=e?"0":"",this.panelEl.style.left=e?"":"0"}this.badgeEl&&(this.badgeEl.classList.toggle("lcms-hidden",this.unsavedChanges===0),this.badgeEl.textContent=String(this.unsavedChanges)),this.editToggle&&(this.editToggle.checked=this.editMode),this.langSwitchEl&&(this.langSwitchEl.classList.toggle("lcms-hidden",!this.editMode||this.languages.length<=1),this.langSwitchEl.querySelectorAll(".lcms-lang-btn").forEach(e=>{e.classList.toggle("active",e.textContent===this.currentLang.toUpperCase())})),this.editModeContent&&this.editModeContent.classList.toggle("lcms-hidden",!this.editMode),this.changesInfoEl&&(this.changesInfoEl.classList.toggle("lcms-hidden",this.unsavedChanges===0),this.changesInfoEl.textContent=`${this.unsavedChanges} unsaved change${this.unsavedChanges>1?"s":""}`),this.undoBtn&&(this.undoBtn.disabled=!this.canUndo),this.redoBtn&&(this.redoBtn.disabled=!this.canRedo),this.historyBtnEl&&this.historyBtnEl.classList.toggle("active",this.showHistory),this.historyPanelEl&&this.historyPanelEl.classList.toggle("lcms-hidden",!this.showHistory),this.saveBtn&&(this.saveBtn.disabled=this.isSaving||this.isPublishing||this.unsavedChanges===0,this.saveBtn.innerHTML=this.isSaving?'<span class="lcms-spinner"></span> Saving...':`${d.save} Save Draft`),this.publishBtn&&(this.publishBtn.disabled=this.isSaving||this.isPublishing,this.publishBtn.innerHTML=this.isPublishing?'<span class="lcms-spinner"></span> Publishing...':`${d.publish} Publish`),this.cancelBtn&&(this.cancelBtn.disabled=this.isSaving||this.isPublishing),this.loaderEl&&this.loaderEl.classList.toggle("lcms-hidden",!this.loading),this.imgOverlay&&this.imgOverlay.classList.toggle("lcms-hidden",!this.imageUploading)}autoDetectAndScan(){this.autoDetectElements(),this.scanDOM(),this.scanImages()}resolveContainer(){return this.containerSelector?document.querySelector(this.containerSelector)||document.body:document.querySelector(".layout")||document.body}autoDetectElements(){let t=this.resolveContainer();if(!t)return;for(let n of this.autoDetectedElements)document.contains(n)||this.autoDetectedElements.delete(n);let e={},i=this.editableTags.join(",");t.querySelectorAll(i).forEach(n=>{if(n.hasAttribute("data-cms")||n.closest("#xtroedge-cms-root, script, style, noscript")||n.children.length>3||this.getDirectTextContent(n).trim().length<2)return;let o=n.tagName.toLowerCase();e[o]||(e[o]=0);let l=`xcms_${o}_${e[o]}`;e[o]++,n.setAttribute("data-cms",l),this.autoDetectedElements.add(n)})}scanDOM(){document.querySelectorAll("[data-cms]").forEach(e=>{if(e.closest("#xtroedge-cms-root"))return;let i=e.getAttribute("data-cms");this.registeredKeys.add(i),this.managedElements.has(e)||this.attachElement(e,i)});for(let[e]of this.managedElements)document.contains(e)||this.detachElement(e)}scanImages(){let t=this.resolveContainer();if(!t)return;let e={...this.pageImages},i=!1;t.querySelectorAll("img").forEach(n=>{if(n.closest("#xtroedge-cms-root")||this.managedImages.has(n))return;let a=n.getAttribute("src")||"";!a||a.startsWith("data:")||(this.attachImage(n,a),e[a]||(e[a]=a,i=!0))}),i&&(this.pageImages=e,this.originalImages=JSON.parse(JSON.stringify(e)));for(let[n]of this.managedImages)document.contains(n)||this.detachImage(n)}getDirectTextContent(t){let e="";for(let i=0;i<t.childNodes.length;i++)t.childNodes[i].nodeType===Node.TEXT_NODE&&(e+=t.childNodes[i].textContent||"");return e}attachElement(t,e){let i=()=>{let a=t.textContent?.trim()||"",o=this.getPageText(e);a!==o&&this.onTextChanged(e,a)},s=a=>{a.key==="Enter"&&(a.preventDefault(),t.blur())},n=()=>{let a=t.textContent?.trim()||"",o=this.getPageText(e);a!==o&&this.onTextChanged(e,a)};this.managedElements.set(t,{key:e,blurHandler:i,keydownHandler:s,inputHandler:n}),this.editMode&&this.enableElementEdit(t,e,i,s,n)}detachElement(t){let e=this.managedElements.get(t);e&&(t.removeEventListener("blur",e.blurHandler),t.removeEventListener("keydown",e.keydownHandler),t.removeEventListener("input",e.inputHandler),t.removeAttribute("contenteditable"),this.managedElements.delete(t))}enableElementEdit(t,e,i,s,n){let a=this.getPageText(e);a&&(t.textContent=a),t.setAttribute("contenteditable","true"),t.style.borderBottom=`2px dashed ${this.highlightColor}`,t.style.padding="2px 4px",t.style.borderRadius="3px",t.style.cursor="text",t.style.outline="none",t.style.transition="background 0.2s",t.style.minWidth="20px",t.addEventListener("blur",i),t.addEventListener("keydown",s),t.addEventListener("input",n)}disableElementEdit(t,e,i,s,n){t.removeAttribute("contenteditable"),t.style.borderBottom="",t.style.padding="",t.style.borderRadius="",t.style.cursor="",t.style.outline="",t.style.transition="",t.style.minWidth="";let a=this.getPageText(e);a&&(t.textContent=a),t.removeEventListener("blur",i),t.removeEventListener("keydown",s),t.removeEventListener("input",n)}applyEditMode(t){for(let[e,i]of this.managedElements)t?this.enableElementEdit(e,i.key,i.blurHandler,i.keydownHandler,i.inputHandler):this.disableElementEdit(e,i.key,i.blurHandler,i.keydownHandler,i.inputHandler);this.applyImageEditMode(t)}updateElementTexts(){this.observer?.disconnect();for(let[t,e]of this.managedElements){if(document.activeElement===t)continue;let i=this.getPageText(e.key);i&&t.textContent!==i&&(t.textContent=i)}this.observer?.observe(document.body,{childList:!0,subtree:!0})}cleanupManagedElements(){for(let[t]of this.managedElements)this.detachElement(t);this.managedElements.clear();for(let t of this.autoDetectedElements)t.removeAttribute("data-cms");this.autoDetectedElements.clear(),this.cleanupManagedImages()}attachImage(t,e){let i=s=>{this.editMode&&(s.preventDefault(),s.stopPropagation(),this.showImageContextMenu(s.clientX,s.clientY,t))};this.managedImages.set(t,{key:e,ctxHandler:i}),this.editMode&&this.enableImageEdit(t,i)}detachImage(t){let e=this.managedImages.get(t);e&&(t.removeEventListener("contextmenu",e.ctxHandler),t.style.outline="",t.style.cursor="",this.managedImages.delete(t))}cleanupManagedImages(){for(let[t]of this.managedImages)this.detachImage(t);this.managedImages.clear(),this.dismissImageCtxMenu()}applyImageEditMode(t){for(let[e,i]of this.managedImages)t?this.enableImageEdit(e,i.ctxHandler):this.disableImageEdit(e,i.ctxHandler);t||this.dismissImageCtxMenu()}enableImageEdit(t,e){t.style.outline=`2px dashed ${this.highlightColor}`,t.style.cursor="context-menu",t.addEventListener("contextmenu",e)}disableImageEdit(t,e){t.style.outline="",t.style.cursor="",t.removeEventListener("contextmenu",e)}showImageContextMenu(t,e,i){this.dismissImageCtxMenu();let s=document.createElement("div");Object.assign(s.style,{position:"fixed",zIndex:"10005",minWidth:"160px",background:"rgba(30,15,60,0.85)",backdropFilter:"blur(16px)",webkitBackdropFilter:"blur(16px)",border:"1px solid rgba(139,92,246,0.3)",borderRadius:"10px",padding:"4px",boxShadow:"0 8px 32px rgba(0,0,0,0.4)",fontFamily:"system-ui, -apple-system, sans-serif",left:Math.min(t,window.innerWidth-180)+"px",top:Math.min(e,window.innerHeight-50)+"px"});let n=document.createElement("button");Object.assign(n.style,{width:"100%",padding:"8px 12px",border:"none",borderRadius:"7px",background:"transparent",color:"white",fontSize:"12px",fontWeight:"500",cursor:"pointer",display:"flex",alignItems:"center",gap:"8px"}),n.innerHTML=`${d.image} Upload Image`,n.addEventListener("mouseenter",()=>n.style.background="rgba(103,34,251,0.3)"),n.addEventListener("mouseleave",()=>n.style.background="transparent"),n.addEventListener("click",()=>{this.activeImageEl=i,this.fileInput&&(this.fileInput.value="",this.fileInput.click()),this.dismissImageCtxMenu()}),s.appendChild(n),document.body.appendChild(s),this.imageCtxMenu=s;let a=o=>{s.contains(o.target)||(this.dismissImageCtxMenu(),document.removeEventListener("mousedown",a))};setTimeout(()=>document.addEventListener("mousedown",a),0)}dismissImageCtxMenu(){this.imageCtxMenu&&(this.imageCtxMenu.remove(),this.imageCtxMenu=null)}onImageFileSelected(t){let i=t.target.files?.[0];if(!i||!this.activeImageEl)return;this.imageUploading=!0,this.updateUI();let s=new FileReader;s.onload=()=>{let n=s.result;this.uploadImageToApi(n)},s.readAsDataURL(i)}async uploadImageToApi(t){try{let e=await fetch(`${this.config.apiBase}/web/upload-image`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:t})});if(!e.ok)throw new Error(`HTTP ${e.status}`);let i=await e.json(),n=(this.config.imageBaseUrl||(this.config.apiBase?new URL(this.config.apiBase).origin:""))+i.path;if(this.activeImageEl){let a=this.managedImages.get(this.activeImageEl)?.key||"";this.activeImageEl.src=n,this.onImageChanged(a,n)}this.imageUploading=!1,this.activeImageEl=null,this.updateUI(),this.showToast("Image updated!","success")}catch(e){this.imageUploading=!1,this.activeImageEl=null,this.updateUI(),this.showToast("Image upload failed.","error"),this.config.onError?.("upload-image",e)}}applyPageImages(){for(let[t,e]of this.managedImages){let i=this.pageImages[e.key];i&&t.src!==i&&(t.src=i)}}getPageText(t){return this.pageTexts[t]?.[this.currentLang]||""}onTextChanged(t,e){this.undoStack.push(this.createSnapshot()),this.redoStack=[],this.canUndo=!0,this.canRedo=!1,this.pageTexts[t]||(this.pageTexts[t]={}),this.pageTexts[t]={...this.pageTexts[t],[this.currentLang]:e},this.dirtyKeys.add(t),this.unsavedChanges=this.dirtyKeys.size+this.dirtyImageKeys.size,this.pushHistory(t,this.currentLang),this.updateUI()}onImageChanged(t,e){this.undoStack.push(this.createSnapshot()),this.redoStack=[],this.canUndo=!0,this.canRedo=!1,this.pageImages={...this.pageImages,[t]:e},this.dirtyImageKeys.add(t),this.unsavedChanges=this.dirtyKeys.size+this.dirtyImageKeys.size,this.pushHistory(t,"img"),this.updateUI()}createSnapshot(){return JSON.stringify({texts:this.pageTexts,images:this.pageImages})}applySnapshot(t){let e=JSON.parse(t);e.texts?(this.pageTexts=e.texts,e.images&&(this.pageImages=e.images)):this.pageTexts=e}onUndo(){this.undoStack.length!==0&&(this.redoStack.push(this.createSnapshot()),this.applySnapshot(this.undoStack.pop()),this.canUndo=this.undoStack.length>0,this.canRedo=!0,this.recalcDirtyKeys(),this.updateElementTexts(),this.applyPageImages(),this.updateUI())}onRedo(){this.redoStack.length!==0&&(this.undoStack.push(this.createSnapshot()),this.applySnapshot(this.redoStack.pop()),this.canUndo=!0,this.canRedo=this.redoStack.length>0,this.recalcDirtyKeys(),this.updateElementTexts(),this.applyPageImages(),this.updateUI())}recalcDirtyKeys(){this.dirtyKeys.clear();for(let t of this.registeredKeys)JSON.stringify(this.pageTexts[t])!==JSON.stringify(this.originalTexts[t])&&this.dirtyKeys.add(t);this.unsavedChanges=this.dirtyKeys.size+this.dirtyImageKeys.size}resetAll(){this.dirtyKeys.clear(),this.dirtyImageKeys.clear(),this.unsavedChanges=0,this.undoStack=[],this.redoStack=[],this.canUndo=!1,this.canRedo=!1,this.updateUI()}resetAfterSave(){this.dirtyKeys.clear(),this.dirtyImageKeys.clear(),this.unsavedChanges=0,this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages))}cancelEditing(){this.pageTexts=JSON.parse(JSON.stringify(this.originalTexts)),this.pageImages=JSON.parse(JSON.stringify(this.originalImages)),this.dirtyKeys.clear(),this.dirtyImageKeys.clear(),this.unsavedChanges=0,this.updateElementTexts(),this.applyPageImages(),this.updateUI()}async loadTranslationsAndInit(t){if(this.config.i18nBasePath)try{let e=this.currentLang,i=await fetch(`${this.config.i18nBasePath}/${e}.json`);if(i.ok){let s=await i.json();this.translationCache.clear(),this.flattenTranslations(s,"",this.getPageSection())}}catch{}this.autoDetectAndScan(),this.editMode&&this.applyEditMode(!0),this.config.apiBase?t?this.loadPageContent("draft"):this.loadPublishedContent():(this.buildDefaultTexts(),this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages)),this.setLoading(!1)),this.updateUI()}flattenTranslations(t,e,i){for(let s of Object.keys(t)){let n=e?`${e}.${s}`:s;if(typeof t[s]=="string"){let a=t[s].trim();a.length>=2&&(!this.translationCache.get(a)||n.toUpperCase().startsWith(i))&&this.translationCache.set(a,n)}else typeof t[s]=="object"&&t[s]!==null&&!Array.isArray(t[s])&&this.flattenTranslations(t[s],n,i)}}getPageSection(){return this.currentSlug.replace(/^\//,"").replace(/-/g,"_").toUpperCase()}async loadPageContent(t){this.setLoading(!0),this.cleanOldHistory();try{let e=await fetch(`${this.config.apiBase}/web-page/get?slug=${encodeURIComponent(this.currentSlug)}&status=${t}&site_identifier=${encodeURIComponent(this.siteIdentifier)}`);if(!e.ok)throw new Error(`HTTP ${e.status}`);let i=await e.json(),s=i?.published_content?.texts||i?.content?.texts;s?this.pageTexts=JSON.parse(JSON.stringify(s)):this.buildDefaultTexts();let n=i?.published_content?.images||i?.content?.images;n&&(this.pageImages=JSON.parse(JSON.stringify(n)),this.applyPageImages()),this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages)),this.resetAll(),this.updateElementTexts()}catch{this.buildDefaultTexts(),this.originalTexts=JSON.parse(JSON.stringify(this.pageTexts)),this.originalImages=JSON.parse(JSON.stringify(this.pageImages)),this.resetAll()}finally{this.setLoading(!1)}}async loadPublishedContent(){this.setLoading(!0);try{let t=await fetch(`${this.config.apiBase}/web-page/get?slug=${encodeURIComponent(this.currentSlug)}&status=published&site_identifier=${encodeURIComponent(this.siteIdentifier)}`);if(!t.ok)throw new Error(`HTTP ${t.status}`);let e=await t.json(),i=e?.published_content?.texts;i&&Object.keys(i).length>0&&(this.pageTexts=JSON.parse(JSON.stringify(i)),this.updateElementTexts());let s=e?.published_content?.images;s&&Object.keys(s).length>0&&(this.pageImages=JSON.parse(JSON.stringify(s)),this.applyPageImages())}catch{}finally{this.setLoading(!1)}}buildDefaultTexts(){let t={};for(let e of this.registeredKeys){let s=document.querySelector(`[data-cms="${e}"]`)?.textContent?.trim()||"";t[e]={[this.currentLang]:s}}if(this.pageTexts=t,this.config.i18nBasePath){let e=this.languages.filter(i=>i!==this.currentLang);for(let i of e)fetch(`${this.config.i18nBasePath}/${i}.json`).then(s=>s.json()).then(s=>{let n={...this.pageTexts};for(let a of this.registeredKeys){let o=a.split("."),l=s;for(let c of o)l=l?.[c];l&&typeof l=="string"&&(n[a]={...n[a],[i]:l})}this.pageTexts=n,this.originalTexts=JSON.parse(JSON.stringify(n)),this.updateElementTexts()}).catch(()=>{})}}async saveChanges(){if(!this.config.apiBase){this.showToast("No API configured. Set apiBase to enable save.","error");return}this.isSaving=!0,this.updateUI();let t={slug:this.currentSlug,title:this.currentTitle,site_identifier:this.siteIdentifier,content:{texts:this.pageTexts,images:this.pageImages}};try{let e=await fetch(`${this.config.apiBase}/web_page/save`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok)throw new Error(`HTTP ${e.status}`);this.isSaving=!1,this.resetAfterSave(),this.updateUI(),this.showToast("Draft saved successfully!","success"),this.config.onSaved?.()}catch(e){this.isSaving=!1,this.updateUI(),this.showToast("Save failed. Please try again.","error"),this.config.onError?.("save",e)}}async publishChanges(){if(!this.config.apiBase){this.showToast("No API configured. Set apiBase to enable publish.","error");return}this.isPublishing=!0,this.updateUI();let t={slug:this.currentSlug,title:this.currentTitle,site_identifier:this.siteIdentifier,published_content:{texts:this.pageTexts,images:this.pageImages}};try{let e=await fetch(`${this.config.apiBase}/web_page/publish`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok)throw new Error(`HTTP ${e.status}`);this.isPublishing=!1,this.resetAfterSave(),this.updateUI(),this.showToast("Published successfully!","success"),this.config.onPublished?.()}catch(e){this.isPublishing=!1,this.updateUI(),this.showToast("Publish failed. Please try again.","error"),this.config.onError?.("publish",e)}}async toggleHistory(){this.showHistory=!this.showHistory,this.showHistory&&await this.loadHistory(),this.updateUI()}async loadHistory(){try{let t=await this.openDB(),e=await new Promise((i,s)=>{let l=t.transaction(m,"readonly").objectStore(m).index("slug").getAll(this.currentSlug);l.onsuccess=()=>i(l.result.sort((c,u)=>u.timestamp-c.timestamp).slice(0,30)),l.onerror=()=>s(l.error)});this.historyList=e,this.renderHistoryList()}catch{}}renderHistoryList(){if(this.historyListEl){if(this.historyListEl.innerHTML="",this.historyList.length===0){let t=this.createElement("div","lcms-history-empty");t.textContent="No history yet",this.historyListEl.appendChild(t);return}for(let t of this.historyList){let e=document.createElement("button");e.className="lcms-history-item";let i=this.createElement("div","lcms-history-label");i.textContent=t.label;let s=this.createElement("div","lcms-history-meta"),n=this.createElement("span","lcms-history-lang");n.textContent=t.lang.toUpperCase();let a=document.createTextNode(" "+this.formatDate(t.timestamp));s.appendChild(n),s.appendChild(a),e.appendChild(i),e.appendChild(s),e.addEventListener("click",o=>{o.stopPropagation(),this.restoreHistory(t)}),this.historyListEl.appendChild(e)}}}restoreHistory(t){this.undoStack.push(this.createSnapshot()),this.canUndo=!0,this.applySnapshot(t.snapshot),this.recalcDirtyKeys(),this.showHistory=!1,this.updateElementTexts(),this.applyPageImages(),this.updateUI(),this.showToast("Restored from history","success")}pushHistory(t,e){let i=e==="img",s=i?t.split("/").pop()||"image":t.split("_").pop()||t,n=i?`Changed ${s}`:`Edited ${s}`;this.openDB().then(a=>{a.transaction(m,"readwrite").objectStore(m).add({slug:this.currentSlug,timestamp:Date.now(),label:n,lang:e,snapshot:JSON.stringify({texts:this.pageTexts,images:this.pageImages})})}).catch(()=>{})}async cleanOldHistory(){try{let t=await this.openDB(),e=Date.now()-this.historyRetentionMs,n=t.transaction(m,"readwrite").objectStore(m).index("timestamp").openCursor(IDBKeyRange.upperBound(e));n.onsuccess=()=>{let a=n.result;a&&(a.delete(),a.continue())}}catch{}}openDB(){return this.db?Promise.resolve(this.db):new Promise((t,e)=>{let i=indexedDB.open(H,1);i.onupgradeneeded=()=>{let s=i.result;if(!s.objectStoreNames.contains(m)){let n=s.createObjectStore(m,{keyPath:"id",autoIncrement:!0});n.createIndex("slug","slug",{unique:!1}),n.createIndex("timestamp","timestamp",{unique:!1})}},i.onsuccess=()=>{this.db=i.result,t(this.db)},i.onerror=()=>e(i.error)})}showToast(t,e){if(!this.toastEl)return;this.toastMessage=t,this.toastType=e;let i=e==="success"?d.check:d.error;this.toastEl.className=`lcms-toast lcms-toast-${e}`,this.toastEl.innerHTML=`${i} ${t}`,this.toastTimer&&clearTimeout(this.toastTimer),this.toastTimer=setTimeout(()=>{this.toastEl&&this.toastEl.classList.add("lcms-hidden")},3e3)}onFabClick(t){t.stopPropagation(),!this.hasMoved&&(this.isOpen=!this.isOpen,this.updateUI())}togglePanel(){this.hasMoved||(this.isOpen=!this.isOpen,this.updateUI())}toggleEditMode(t){t.stopPropagation(),t.target.checked?(sessionStorage.setItem("builder_edit_mode","true"),this.editMode=!0,this.currentLang=this.detectCurrentLanguage(),this.applyEditMode(!0),this.loadPageContent("draft")):(sessionStorage.removeItem("builder_edit_mode"),this.editMode=!1,this.applyEditMode(!1)),this.updateUI(),this.config.onEditModeChanged?.(this.editMode)}switchLang(t){this.currentLang=t,this.updateElementTexts(),this.buildLangButtons(),this.updateUI(),this.config.onLangChanged?.(t)}onDragStart(t){t.target.closest("button:not(.lcms-fab-btn)")||t.target.closest(".lcms-panel")||(this.isDragging=!0,this.hasMoved=!1,this.dragStartX=t.clientX,this.dragStartY=t.clientY,this.startPosX=this.posX,this.startPosY=this.posY,document.addEventListener("mousemove",this.boundMouseMove),document.addEventListener("mouseup",this.boundMouseUp))}onDragMove(t){if(!this.isDragging||!this.fabEl)return;let e=t.clientX-this.dragStartX,i=t.clientY-this.dragStartY;(Math.abs(e)>3||Math.abs(i)>3)&&(this.hasMoved=!0),this.posX=Math.max(0,Math.min(window.innerWidth-60,this.startPosX+e)),this.posY=Math.max(0,Math.min(window.innerHeight-60,this.startPosY+i)),this.fabEl.style.left=this.posX+"px",this.fabEl.style.top=this.posY+"px"}onDragEnd(){this.isDragging=!1,document.removeEventListener("mousemove",this.boundMouseMove),document.removeEventListener("mouseup",this.boundMouseUp)}onTouchStart(t){if(t.target.closest("button:not(.lcms-fab-btn)")||t.target.closest(".lcms-panel"))return;let e=t.touches[0];this.isDragging=!0,this.hasMoved=!1,this.dragStartX=e.clientX,this.dragStartY=e.clientY,this.startPosX=this.posX,this.startPosY=this.posY,document.addEventListener("touchmove",this.boundTouchMove,{passive:!1}),document.addEventListener("touchend",this.boundTouchEnd)}onTouchMove(t){if(!this.isDragging||!this.fabEl)return;t.preventDefault();let e=t.touches[0],i=e.clientX-this.dragStartX,s=e.clientY-this.dragStartY;(Math.abs(i)>3||Math.abs(s)>3)&&(this.hasMoved=!0),this.posX=Math.max(0,Math.min(window.innerWidth-60,this.startPosX+i)),this.posY=Math.max(0,Math.min(window.innerHeight-60,this.startPosY+s)),this.fabEl.style.left=this.posX+"px",this.fabEl.style.top=this.posY+"px"}onTouchEnd(){this.isDragging=!1,document.removeEventListener("touchmove",this.boundTouchMove),document.removeEventListener("touchend",this.boundTouchEnd)}setLoading(t){this.loading=t,this.updateUI()}detectCurrentLanguage(){let t=document.documentElement.getAttribute("lang");if(t&&this.languages.includes(t))return t;let e=localStorage.getItem("selectedLanguage");return e&&this.languages.includes(e)?e:this.defaultLanguage}createElement(t,e){let i=document.createElement(t);return i.className=e,i}formatDate(t){let e=new Date(t),i=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],s=e.getHours(),n=e.getMinutes().toString().padStart(2,"0"),a=s>=12?"PM":"AM",o=s%12||12;return`${i[e.getMonth()]} ${e.getDate()}, ${o}:${n} ${a}`}resolveSiteIdentifier(){let t=window.location.hostname;if(t&&t!=="localhost"&&t!=="127.0.0.1"&&!t.startsWith("192.168."))return t;let e=localStorage.getItem("xtroedge_site_id");return e||(e="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,i=>{let s=Math.random()*16|0;return(i==="x"?s:s&3|8).toString(16)}),localStorage.setItem("xtroedge_site_id",e)),e}hexToRgb(t){let e=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return e?`${parseInt(e[1],16)},${parseInt(e[2],16)},${parseInt(e[3],16)}`:"0,200,83"}getDarkerColor(t){let e=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);if(!e)return"#2E7D32";let i=Math.max(0,Math.floor(parseInt(e[1],16)*.6)),s=Math.max(0,Math.floor(parseInt(e[2],16)*.6)),n=Math.max(0,Math.floor(parseInt(e[3],16)*.6));return`#${i.toString(16).padStart(2,"0")}${s.toString(16).padStart(2,"0")}${n.toString(16).padStart(2,"0")}`}applyThemeColor(t){if(this.highlightColor=t,document.documentElement.style.setProperty("--lcms-primary",t),document.documentElement.style.setProperty("--lcms-primary-rgb",this.hexToRgb(t)),document.documentElement.style.setProperty("--lcms-primary-dark",this.getDarkerColor(t)),this.editMode){for(let[i]of this.managedElements)i.style.borderBottom=`2px dashed ${t}`;for(let[i]of this.managedImages)i.style.outline=`2px dashed ${t}`}this.panelEl?.querySelectorAll(".lcms-theme-swatch")?.forEach(i=>{i.classList.toggle("active",i.dataset.color===t)}),localStorage.setItem("xtroedge_theme_color",t)}static create(t){let e=new h(t);return e.init(),e}static autoInit(){if(window.__xtroedge_cms_instance__)return;let t=window.__XTROEDGE_CMS_CONFIG__||{},e=h.create(t);window.__xtroedge_cms_instance__=e}};function w(){b.autoInit()}typeof window<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",w):w());return P(O);})();