ngx-xtroedge-cms 1.4.3 → 1.4.4

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/styles.ts","../src/xtroedge-cms.ts"],"sourcesContent":["export { XtroedgeCMS } from './xtroedge-cms';\r\nexport type {\r\n XtroedgeCmsConfig,\r\n PageTextEntry,\r\n WebPageContent,\r\n EditHistoryEntry,\r\n LicenseStatus,\r\n} from './types';\r\n\r\n// ===== AUTO-INIT =====\r\n// Automatically initializes CMS when the script loads.\r\n// No manual code needed - just install the package.\r\n// To pass config, set window.__XTROEDGE_CMS_CONFIG__ before loading.\r\nimport { XtroedgeCMS } from './xtroedge-cms';\r\n\r\nasync function boot() {\r\n await XtroedgeCMS.autoInit();\r\n}\r\n\r\nif (typeof window !== 'undefined') {\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', boot);\r\n } else {\r\n // DOM already ready (script loaded async/defer or after DOMContentLoaded)\r\n boot();\r\n }\r\n}\r\n","export const CMS_STYLES = `\r\n/* ===== XTROEDGE CMS ===== */\r\n\r\n/* LOADER */\r\n.lcms-loader-overlay {\r\n position: fixed; inset: 0; z-index: 10003;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.45);\r\n backdrop-filter: blur(12px) saturate(1.4);\r\n -webkit-backdrop-filter: blur(12px) saturate(1.4);\r\n}\r\n.lcms-loader-content { display: flex; flex-direction: column; align-items: center; gap: 28px; }\r\n.lcms-orbit-loader { position: relative; width: 90px; height: 90px; }\r\n.lcms-orbit { position: absolute; inset: 0; border-radius: 50%; border: 1px solid transparent; }\r\n.lcms-orbit-1 { border-top-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.5); animation: lcmsSpin 2.4s linear infinite; }\r\n.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; }\r\n.lcms-orbit-3 { inset: 20px; border-bottom-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.35); animation: lcmsSpin 4.2s linear infinite; }\r\n.lcms-particle {\r\n position: absolute; width: 8px; height: 8px; border-radius: 50%; top: -4px; left: 50%; margin-left: -4px;\r\n box-shadow: 0 0 12px 3px currentColor;\r\n}\r\n.lcms-orbit-1 .lcms-particle { background: var(--lcms-primary, #00C853); color: var(--lcms-primary, #00C853); }\r\n.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; }\r\n.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; }\r\n.lcms-core-glow {\r\n position: absolute; width: 30px; height: 30px; top: 50%; left: 50%; transform: translate(-50%,-50%);\r\n border-radius: 50%; background: radial-gradient(circle, rgba(var(--lcms-primary-rgb, 0,200,83),0.4), transparent 70%);\r\n animation: lcmsPulse 2s ease-in-out infinite;\r\n}\r\n.lcms-core {\r\n position: absolute; width: 12px; height: 12px; top: 50%; left: 50%; transform: translate(-50%,-50%);\r\n border-radius: 50%; background: linear-gradient(135deg, var(--lcms-primary, #00C853), rgba(var(--lcms-primary-rgb, 0,200,83),0.6));\r\n box-shadow: 0 0 20px rgba(var(--lcms-primary-rgb, 0,200,83),0.6);\r\n}\r\n.lcms-loader-text {\r\n font-family: system-ui, -apple-system, sans-serif; font-size: 12px; font-weight: 600;\r\n color: rgba(255,255,255,0.5); letter-spacing: 4px; text-transform: uppercase;\r\n animation: lcmsBreath 2.5s ease-in-out infinite;\r\n}\r\n@keyframes lcmsSpin { to { transform: rotate(360deg); } }\r\n@keyframes lcmsPulse { 0%,100% { transform: translate(-50%,-50%) scale(1); opacity: 0.5; } 50% { transform: translate(-50%,-50%) scale(1.8); opacity: 0.2; } }\r\n@keyframes lcmsBreath { 0%,100% { letter-spacing: 4px; opacity: 0.5; } 50% { letter-spacing: 6px; opacity: 0.8; } }\r\n\r\n/* TOAST */\r\n.lcms-toast {\r\n position: fixed; top: 24px; left: 50%; transform: translateX(-50%); z-index: 10004;\r\n padding: 10px 20px; border-radius: 10px; font-size: 13px; font-weight: 600;\r\n font-family: system-ui, -apple-system, sans-serif; color: white;\r\n display: flex; align-items: center; gap: 8px;\r\n box-shadow: 0 8px 32px rgba(var(--lcms-primary-rgb, 0,200,83),0.25);\r\n animation: lcmsToastIn 0.3s ease, lcmsToastOut 0.3s ease 2.7s forwards; white-space: nowrap;\r\n}\r\n.lcms-toast-success { background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32)); }\r\n.lcms-toast-error { background: linear-gradient(135deg, #dc2626, #ef4444); }\r\n@keyframes lcmsToastIn { from { opacity: 0; transform: translateX(-50%) translateY(-12px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }\r\n@keyframes lcmsToastOut { from { opacity: 1; transform: translateX(-50%) translateY(0); } to { opacity: 0; transform: translateX(-50%) translateY(-12px); } }\r\n\r\n/* FAB */\r\n.lcms-fab { position: fixed; z-index: 10001; user-select: none; touch-action: none; }\r\n.lcms-fab-btn {\r\n width: 52px; height: 52px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.2);\r\n background: rgba(var(--lcms-primary-rgb, 0,200,83),0.35); color: white;\r\n backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);\r\n cursor: grab; display: flex; align-items: center; justify-content: center;\r\n 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);\r\n transition: transform 0.2s, box-shadow 0.2s, background 0.2s; position: relative;\r\n}\r\n.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); }\r\n.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); }\r\n.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); }\r\n.lcms-badge {\r\n position: absolute; top: -4px; right: -4px; background: #ef4444; color: white;\r\n font-size: 11px; font-weight: 700; width: 20px; height: 20px; border-radius: 50%;\r\n display: flex; align-items: center; justify-content: center; border: 2px solid white;\r\n}\r\n\r\n/* PANEL */\r\n.lcms-panel {\r\n background: rgba(12,12,18,0.55); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);\r\n border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.25); border-radius: 16px; padding: 16px; min-width: 230px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.25), inset 0 1px 0 rgba(255,255,255,0.06);\r\n color: white; font-family: system-ui, -apple-system, sans-serif;\r\n animation: lcmsPanelIn 0.25s ease; position: absolute;\r\n}\r\n@keyframes lcmsPanelIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }\r\n\r\n/* SITE IDENTIFIER */\r\n.lcms-site-id {\r\n display: flex; align-items: center; gap: 5px;\r\n font-size: 10px; color: rgba(255,255,255,0.4);\r\n padding: 0 0 8px; margin-bottom: 8px;\r\n border-bottom: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.12);\r\n font-family: system-ui, -apple-system, sans-serif;\r\n letter-spacing: 0.3px;\r\n}\r\n.lcms-site-id-icon { font-size: 12px; opacity: 0.7; }\r\n.lcms-site-id-text {\r\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 180px;\r\n font-weight: 500;\r\n}\r\n\r\n/* BRANDING */\r\n.lcms-branding {\r\n display: flex; align-items: center; gap: 6px; padding: 8px 0 4px;\r\n border-top: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.15); margin-top: 10px;\r\n cursor: pointer; transition: opacity 0.2s; user-select: none;\r\n}\r\n.lcms-branding:hover { opacity: 0.8; }\r\n.lcms-branding-logo {\r\n width: 18px; height: 18px; border-radius: 4px; background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n display: flex; align-items: center; justify-content: center;\r\n}\r\n.lcms-branding-text {\r\n font-size: 10px; font-weight: 600; color: rgba(255,255,255,0.35); letter-spacing: 0.5px;\r\n}\r\n.lcms-branding-text span { color: var(--lcms-primary, #00C853); font-weight: 700; }\r\n\r\n.lcms-panel-header { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }\r\n.lcms-toggle { display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }\r\n.lcms-toggle input { display: none; }\r\n.lcms-toggle-slider {\r\n width: 36px; height: 20px; border-radius: 10px; position: relative;\r\n background: rgba(255,255,255,0.15); transition: background 0.25s;\r\n}\r\n.lcms-toggle-slider::after {\r\n content: ''; position: absolute; width: 16px; height: 16px; border-radius: 50%;\r\n top: 2px; left: 2px; background: rgba(255,255,255,0.6); transition: transform 0.25s, background 0.25s;\r\n}\r\n.lcms-toggle input:checked + .lcms-toggle-slider { background: var(--lcms-primary, #00C853); }\r\n.lcms-toggle input:checked + .lcms-toggle-slider::after { transform: translateX(16px); background: white; }\r\n.lcms-toggle-label { font-size: 12px; font-weight: 700; color: rgba(255,255,255,0.5); letter-spacing: 0.5px; transition: color 0.25s; }\r\n.lcms-toggle input:checked ~ .lcms-toggle-label { color: rgba(var(--lcms-primary-rgb, 0,200,83),0.75); }\r\n.lcms-lang-switch { margin-left: auto; position: relative; }\r\n.lcms-lang-select { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.15); border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.4); border-radius: 6px; color: white; padding: 3px 24px 3px 8px; font-size: 11px; font-weight: 600; cursor: pointer; appearance: none; -webkit-appearance: none; outline: none; transition: all 0.2s; }\r\n.lcms-lang-select:hover { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.3); }\r\n.lcms-lang-select:focus { border-color: var(--lcms-primary, #00C853); }\r\n.lcms-lang-select option { background: #1a1a2e; color: white; }\r\n.lcms-lang-arrow { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); pointer-events: none; color: rgba(255,255,255,0.6); font-size: 10px; }\r\n.lcms-close-btn { background: transparent; border: none; color: rgba(255,255,255,0.4); cursor: pointer; padding: 2px; display: flex; transition: color 0.2s; }\r\n.lcms-close-btn:hover { color: white; }\r\n.lcms-changes-info { font-size: 12px; color: rgba(var(--lcms-primary-rgb, 0,200,83),0.75); margin-bottom: 10px; padding-left: 2px; }\r\n\r\n.lcms-undo-row { display: flex; gap: 6px; margin-bottom: 12px; }\r\n.lcms-icon-btn {\r\n width: 36px; height: 32px; border-radius: 8px; border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.3);\r\n background: rgba(var(--lcms-primary-rgb, 0,200,83),0.1); color: rgba(255,255,255,0.8); cursor: pointer;\r\n display: flex; align-items: center; justify-content: center; transition: all 0.2s;\r\n}\r\n.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; }\r\n.lcms-icon-btn:disabled { opacity: 0.25; cursor: not-allowed; }\r\n\r\n/* COLOR THEME PICKER */\r\n.lcms-theme-row {\r\n display: flex; align-items: center; gap: 8px; margin-bottom: 12px;\r\n padding: 6px 0;\r\n}\r\n.lcms-theme-label {\r\n font-size: 10px; font-weight: 700; color: rgba(255,255,255,0.45);\r\n text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap;\r\n}\r\n.lcms-theme-colors {\r\n display: flex; align-items: center; gap: 5px; flex-wrap: wrap;\r\n}\r\n.lcms-theme-swatch {\r\n width: 20px; height: 20px; border-radius: 50%; border: 2px solid transparent;\r\n cursor: pointer; transition: all 0.2s; position: relative;\r\n}\r\n.lcms-theme-swatch:hover { transform: scale(1.15); }\r\n.lcms-theme-swatch.active { border-color: white; box-shadow: 0 0 8px rgba(255,255,255,0.3); }\r\n.lcms-theme-custom {\r\n width: 20px; height: 20px; border-radius: 50%; border: 1px dashed rgba(255,255,255,0.3);\r\n cursor: pointer; overflow: hidden; position: relative;\r\n}\r\n.lcms-theme-custom input {\r\n position: absolute; inset: -4px; width: 28px; height: 28px; border: none;\r\n background: transparent; cursor: pointer; opacity: 0;\r\n}\r\n.lcms-theme-custom-preview {\r\n width: 100%; height: 100%; border-radius: 50%;\r\n background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);\r\n}\r\n\r\n.lcms-history-btn {\r\n width: 100%; padding: 7px 12px; border-radius: 8px;\r\n border: 1px dashed rgba(var(--lcms-primary-rgb, 0,200,83),0.35); background: rgba(var(--lcms-primary-rgb, 0,200,83),0.08);\r\n color: rgba(255,255,255,0.6); font-size: 12px; font-weight: 500; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center; gap: 6px;\r\n transition: all 0.2s; margin-bottom: 12px; font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.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; }\r\n.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; }\r\n\r\n.lcms-history-panel { margin-top: 8px; border-top: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.15); padding-top: 10px; }\r\n.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; }\r\n.lcms-history-empty { font-size: 12px; color: rgba(255,255,255,0.3); text-align: center; padding: 12px 0; }\r\n.lcms-history-list { max-height: 200px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }\r\n.lcms-history-list::-webkit-scrollbar { width: 4px; }\r\n.lcms-history-list::-webkit-scrollbar-track { background: transparent; }\r\n.lcms-history-list::-webkit-scrollbar-thumb { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.3); border-radius: 4px; }\r\n.lcms-history-item {\r\n width: 100%; text-align: left; background: rgba(var(--lcms-primary-rgb, 0,200,83),0.06);\r\n border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.12); border-radius: 8px; padding: 8px 10px;\r\n cursor: pointer; transition: all 0.2s; color: white; font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.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); }\r\n.lcms-history-label { font-size: 12px; font-weight: 500; margin-bottom: 2px; }\r\n.lcms-history-meta { font-size: 10px; color: rgba(255,255,255,0.4); display: flex; align-items: center; gap: 6px; }\r\n.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); }\r\n\r\n.lcms-actions { display: flex; flex-direction: column; gap: 6px; }\r\n.lcms-actions button {\r\n width: 100%; padding: 9px 14px; border-radius: 8px; font-size: 12px; font-weight: 600;\r\n cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; gap: 6px; border: none;\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-btn-save { background: var(--lcms-primary, #00C853); color: white; }\r\n.lcms-btn-save:hover { background: var(--lcms-primary, #00C853); filter: brightness(1.15); }\r\n.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; }\r\n.lcms-btn-publish { background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32)); color: white; }\r\n.lcms-btn-publish:hover { background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32)); filter: brightness(1.1); }\r\n.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; filter: none; }\r\n.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; }\r\n.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); }\r\n.lcms-btn-cancel:disabled { opacity: 0.3; cursor: not-allowed; }\r\n.lcms-btn-logout { background: rgba(244,67,54,0.12); color: rgba(244,67,54,0.85); border: 1px solid rgba(244,67,54,0.25) !important; margin-top: 4px; }\r\n.lcms-btn-logout:hover { background: rgba(244,67,54,0.2); color: #f44336; border-color: rgba(244,67,54,0.5) !important; }\r\n\r\n.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; }\r\n\r\n/* IMAGE UPLOAD OVERLAY */\r\n.lcms-img-upload-overlay {\r\n position: fixed; inset: 0; z-index: 10005;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.5); backdrop-filter: blur(8px);\r\n}\r\n.lcms-img-upload-content {\r\n display: flex; flex-direction: column; align-items: center; gap: 16px;\r\n color: white; font-family: system-ui, -apple-system, sans-serif;\r\n font-size: 13px; font-weight: 600;\r\n}\r\n.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; }\r\n\r\n/* LOGIN MODAL */\r\n.lcms-login-overlay {\r\n position: fixed; inset: 0; z-index: 10010;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.75);\r\n backdrop-filter: blur(16px) saturate(1.4);\r\n -webkit-backdrop-filter: blur(16px) saturate(1.4);\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-login-box {\r\n background: #13151a; border: 1px solid rgba(255,255,255,0.1);\r\n border-radius: 16px; padding: 36px 32px; width: 340px;\r\n box-shadow: 0 24px 60px rgba(0,0,0,0.6);\r\n}\r\n.lcms-login-logo {\r\n display: flex; align-items: center; justify-content: center;\r\n gap: 8px; margin-bottom: 24px;\r\n}\r\n.lcms-login-logo-icon {\r\n width: 32px; height: 32px; border-radius: 8px;\r\n background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n display: flex; align-items: center; justify-content: center;\r\n}\r\n.lcms-login-logo-text { color: white; font-size: 15px; font-weight: 700; letter-spacing: 0.5px; }\r\n.lcms-login-title { color: white; font-size: 18px; font-weight: 700; text-align: center; margin-bottom: 6px; }\r\n.lcms-login-sub { color: rgba(255,255,255,0.4); font-size: 12px; text-align: center; margin-bottom: 24px; }\r\n.lcms-login-field { margin-bottom: 14px; }\r\n.lcms-login-label { display: block; color: rgba(255,255,255,0.6); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 6px; }\r\n.lcms-login-input {\r\n width: 100%; box-sizing: border-box;\r\n background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12);\r\n border-radius: 8px; padding: 10px 12px;\r\n color: white; font-size: 13px; font-family: inherit; outline: none;\r\n transition: border-color 0.2s;\r\n}\r\n.lcms-login-input:focus { border-color: var(--lcms-primary, #00C853); }\r\n.lcms-login-input::placeholder { color: rgba(255,255,255,0.25); }\r\n.lcms-password-wrapper { position: relative; display: flex; align-items: center; }\r\n.lcms-password-wrapper .lcms-login-input { padding-right: 40px; width: 100%; }\r\n.lcms-password-toggle {\r\n position: absolute; right: 10px; top: 50%; transform: translateY(-50%);\r\n background: none; border: none !important; outline: none !important; cursor: pointer; padding: 4px;\r\n color: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center;\r\n transition: color 0.2s; line-height: 0; z-index: 1;\r\n}\r\n.lcms-password-toggle:hover { color: rgba(0,0,0,0.8); }\r\n.lcms-password-toggle svg { display: block; }\r\n.lcms-login-btn {\r\n width: 100%; padding: 11px; margin-top: 6px; border: none; border-radius: 8px; cursor: pointer;\r\n background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n color: white; font-size: 13px; font-weight: 700; font-family: inherit;\r\n letter-spacing: 0.3px; transition: filter 0.2s;\r\n}\r\n.lcms-login-btn:hover { filter: brightness(1.1); }\r\n.lcms-login-btn:disabled { opacity: 0.6; cursor: not-allowed; }\r\n.lcms-login-error {\r\n background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.3);\r\n border-radius: 8px; padding: 9px 12px; color: #f87171;\r\n font-size: 12px; text-align: center; margin-top: 12px; display: none;\r\n}\r\n.lcms-login-error.visible { display: block; }\r\n\r\n/* LICENSE OVERLAY */\r\n.lcms-license-overlay {\r\n position: fixed; inset: 0; z-index: 10020;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.85);\r\n backdrop-filter: blur(20px) saturate(1.4);\r\n -webkit-backdrop-filter: blur(20px) saturate(1.4);\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-license-box {\r\n background: #13151a; border: 1px solid rgba(255,255,255,0.1);\r\n border-radius: 20px; padding: 40px 36px; width: 380px; text-align: center;\r\n box-shadow: 0 24px 60px rgba(0,0,0,0.6);\r\n}\r\n.lcms-license-icon {\r\n width: 56px; height: 56px; border-radius: 16px; margin: 0 auto 20px;\r\n background: linear-gradient(135deg, rgba(239,68,68,0.2), rgba(239,68,68,0.1));\r\n border: 1px solid rgba(239,68,68,0.3);\r\n display: flex; align-items: center; justify-content: center;\r\n}\r\n.lcms-license-icon.trial {\r\n background: linear-gradient(135deg, rgba(251,191,36,0.2), rgba(251,191,36,0.1));\r\n border-color: rgba(251,191,36,0.3);\r\n}\r\n.lcms-license-title {\r\n color: white; font-size: 20px; font-weight: 700; margin-bottom: 8px;\r\n}\r\n.lcms-license-msg {\r\n color: rgba(255,255,255,0.5); font-size: 13px; line-height: 1.6; margin-bottom: 24px;\r\n}\r\n.lcms-license-btn {\r\n display: inline-block; padding: 11px 28px; border: none; border-radius: 8px; cursor: pointer;\r\n background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n color: white; font-size: 13px; font-weight: 700; font-family: inherit;\r\n letter-spacing: 0.3px; transition: filter 0.2s; text-decoration: none;\r\n}\r\n.lcms-license-btn:hover { filter: brightness(1.1); }\r\n.lcms-license-sub {\r\n color: rgba(255,255,255,0.3); font-size: 11px; margin-top: 16px;\r\n}\r\n.lcms-license-sub a { color: rgba(var(--lcms-primary-rgb, 0,200,83),0.7); text-decoration: none; }\r\n.lcms-license-sub a:hover { text-decoration: underline; }\r\n\r\n/* TRIAL BANNER */\r\n.lcms-trial-banner {\r\n display: flex; align-items: center; gap: 6px;\r\n background: rgba(251,191,36,0.12); border: 1px solid rgba(251,191,36,0.3);\r\n border-radius: 8px; padding: 6px 10px; margin-bottom: 10px;\r\n font-size: 11px; font-weight: 600; color: #fbbf24;\r\n}\r\n.lcms-trial-banner-icon { font-size: 14px; }\r\n.lcms-trial-banner-text { flex: 1; }\r\n.lcms-trial-banner-dismiss {\r\n background: none; border: none; color: rgba(251,191,36,0.5); cursor: pointer;\r\n padding: 0; font-size: 14px; line-height: 1; transition: color 0.2s;\r\n}\r\n.lcms-trial-banner-dismiss:hover { color: #fbbf24; }\r\n\r\n/* RICH TEXT TOOLBAR */\r\n.lcms-rich-toolbar {\r\n position: fixed; z-index: 10010;\r\n display: flex; align-items: center; gap: 2px;\r\n padding: 4px 6px;\r\n background: rgba(30, 15, 60, 0.92);\r\n backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);\r\n border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83), 0.3);\r\n border-radius: 8px;\r\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\r\n opacity: 0; transform: translateY(8px);\r\n transition: opacity 0.15s, transform 0.15s;\r\n pointer-events: none;\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-rich-toolbar.visible { opacity: 1; transform: translateY(0); pointer-events: auto; }\r\n.lcms-rich-toolbar button {\r\n width: 28px; height: 28px; border: none; border-radius: 4px;\r\n background: transparent; color: #d0d0d0; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center;\r\n font-size: 13px; font-weight: 700; padding: 0;\r\n transition: background 0.15s, color 0.15s;\r\n}\r\n.lcms-rich-toolbar button:hover { background: rgba(var(--lcms-primary-rgb, 0,200,83), 0.3); color: #fff; }\r\n.lcms-rich-toolbar button.active { background: rgba(var(--lcms-primary-rgb, 0,200,83), 0.5); color: #fff; }\r\n.lcms-rich-toolbar .lcms-tb-sep { width: 1px; height: 18px; background: rgba(255,255,255,0.12); margin: 0 3px; flex-shrink: 0; }\r\n\r\n/* HIDDEN ELEMENTS */\r\n.lcms-hidden { display: none !important; }\r\n\r\n/* EDIT MODE — keep animations running, just make CMS elements editable */\r\nbody.lcms-editing [data-cms] {\r\n user-select: text !important;\r\n -webkit-user-select: text !important;\r\n cursor: text !important;\r\n}\r\n\r\n/* Ensure editable elements appear above other content */\r\nbody.lcms-editing [contenteditable=\"true\"] {\r\n position: relative !important;\r\n z-index: 9999 !important;\r\n}\r\n`;\r\n","import { CMS_STYLES } from './styles';\r\nimport type {\r\n XtroedgeCmsConfig, PageTextEntry, WebPageContent,\r\n EditHistoryEntry, ManagedElementInfo, ManagedImageInfo, LicenseStatus\r\n} from './types';\r\n\r\n// ===== SVG Icons =====\r\nconst ICON = {\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n logout: '<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=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/><polyline points=\"16 17 21 12 16 7\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/></svg>',\r\n};\r\n\r\n// ===== IndexedDB constants =====\r\nconst DB_NAME = 'xtroedge_cms_history';\r\nconst STORE_NAME = 'history';\r\n\r\n// ===== Default editable tags =====\r\nconst DEFAULT_EDITABLE_TAGS = [\r\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\r\n 'p', 'span', 'b', 'strong', 'i', 'em',\r\n 'a', 'button', 'li', 'label', 'small', 'blockquote', 'td', 'th',\r\n 'div', 'header', 'footer',\r\n];\r\n\r\nexport class XtroedgeCMS {\r\n // ===== Encrypted vault (single key stores all sensitive data) =====\r\n private static readonly _SK = 'xTr0EdG3_s3cUr3_k3y!@#2024';\r\n private static readonly _VAULT_KEY = '_xtd';\r\n\r\n private static _enc(value: string): string {\r\n const k = XtroedgeCMS._SK;\r\n let result = '';\r\n for (let i = 0; i < value.length; i++) {\r\n result += String.fromCharCode(value.charCodeAt(i) ^ k.charCodeAt(i % k.length));\r\n }\r\n return btoa(result);\r\n }\r\n\r\n private static _dec(encoded: string): string {\r\n try {\r\n const k = XtroedgeCMS._SK;\r\n const decoded = atob(encoded);\r\n let result = '';\r\n for (let i = 0; i < decoded.length; i++) {\r\n result += String.fromCharCode(decoded.charCodeAt(i) ^ k.charCodeAt(i % k.length));\r\n }\r\n return result;\r\n } catch { return ''; }\r\n }\r\n\r\n private static _readVault(): Record<string, string> {\r\n try {\r\n const raw = localStorage.getItem(XtroedgeCMS._VAULT_KEY);\r\n if (!raw) return {};\r\n return JSON.parse(XtroedgeCMS._dec(raw));\r\n } catch { return {}; }\r\n }\r\n\r\n private static _writeVault(vault: Record<string, string>): void {\r\n try { localStorage.setItem(XtroedgeCMS._VAULT_KEY, XtroedgeCMS._enc(JSON.stringify(vault))); } catch { /* storage full */ }\r\n }\r\n\r\n private static secureSet(key: string, value: string): void {\r\n const v = XtroedgeCMS._readVault();\r\n v[key] = value;\r\n XtroedgeCMS._writeVault(v);\r\n }\r\n\r\n private static secureGet(key: string): string {\r\n return XtroedgeCMS._readVault()[key] || '';\r\n }\r\n\r\n private static secureRemove(key: string): void {\r\n const v = XtroedgeCMS._readVault();\r\n delete v[key];\r\n XtroedgeCMS._writeVault(v);\r\n }\r\n\r\n private static secureClear(): void {\r\n try { localStorage.removeItem(XtroedgeCMS._VAULT_KEY); } catch { /* ignore */ }\r\n }\r\n\r\n // ===== Config =====\r\n private config: XtroedgeCmsConfig;\r\n private containerSelector: string;\r\n private editableTags: string[];\r\n private languages: string[];\r\n private defaultLanguage: string;\r\n private highlightColor: string;\r\n private brandingEl: HTMLElement | null = null;\r\n private historyRetentionMs: number;\r\n private siteIdentifier = '';\r\n private siteIdEl: HTMLElement | null = null;\r\n private loginModalEl: HTMLElement | null = null;\r\n private pendingEditMode = false; // edit=true was requested but token missing\r\n\r\n // ===== State =====\r\n private editMode = false;\r\n private currentLang = 'en';\r\n private pageTexts: { [key: string]: PageTextEntry } = {};\r\n private pageImages: { [key: string]: string } = {};\r\n private originalTexts: { [key: string]: PageTextEntry } = {};\r\n private originalImages: { [key: string]: string } = {};\r\n private unsavedChanges = 0;\r\n private isSaving = false;\r\n private isPublishing = false;\r\n private loading = false;\r\n private canUndo = false;\r\n private canRedo = false;\r\n private showHistory = false;\r\n private historyList: EditHistoryEntry[] = [];\r\n private isOpen = false;\r\n private isEditAllowed = false;\r\n private imageUploading = false;\r\n private toastMessage = '';\r\n private toastType: 'success' | 'error' = 'success';\r\n\r\n // ===== Undo/Redo =====\r\n private undoStack: string[] = [];\r\n private redoStack: string[] = [];\r\n private dirtyKeys = new Set<string>();\r\n private dirtyImageKeys = new Set<string>();\r\n private registeredKeys = new Set<string>();\r\n\r\n // ===== DOM =====\r\n private domOriginals: { [key: string]: string } = {};\r\n private managedElements = new Map<HTMLElement, ManagedElementInfo>();\r\n private managedImages = new Map<HTMLImageElement, ManagedImageInfo>();\r\n private autoDetectedElements = new Set<HTMLElement>();\r\n private observer: MutationObserver | null = null;\r\n private scanTimeout: ReturnType<typeof setTimeout> | null = null;\r\n private activeImageEl: HTMLImageElement | null = null;\r\n private imageCtxMenu: HTMLElement | null = null;\r\n private floatingEditDialog: HTMLElement | null = null;\r\n\r\n // ===== Rich Text Toolbar =====\r\n private richToolbarEl: HTMLElement | null = null;\r\n private activeEditableEl: HTMLElement | null = null;\r\n private toolbarHideTimeout: ReturnType<typeof setTimeout> | null = null;\r\n private selectionChangeHandler: (() => void) | null = null;\r\n\r\n // ===== Navigation =====\r\n private currentSlug = '';\r\n private currentTitle = '';\r\n private initialized = false;\r\n private origPushState: typeof history.pushState | null = null;\r\n private origReplaceState: typeof history.replaceState | null = null;\r\n\r\n // ===== UI Elements =====\r\n private styleEl: HTMLStyleElement | null = null;\r\n private rootEl: HTMLElement | null = null;\r\n private loaderEl: HTMLElement | null = null;\r\n private toastEl: HTMLElement | null = null;\r\n private fabEl: HTMLElement | null = null;\r\n private fabBtn: HTMLButtonElement | null = null;\r\n private badgeEl: HTMLElement | null = null;\r\n private panelEl: HTMLElement | null = null;\r\n private editToggle: HTMLInputElement | null = null;\r\n private langSwitchEl: HTMLElement | null = null;\r\n private changesInfoEl: HTMLElement | null = null;\r\n private undoBtn: HTMLButtonElement | null = null;\r\n private redoBtn: HTMLButtonElement | null = null;\r\n private historyBtnEl: HTMLButtonElement | null = null;\r\n private historyPanelEl: HTMLElement | null = null;\r\n private historyListEl: HTMLElement | null = null;\r\n private saveBtn: HTMLButtonElement | null = null;\r\n private publishBtn: HTMLButtonElement | null = null;\r\n\r\n private actionsEl: HTMLElement | null = null;\r\n private editModeContent: HTMLElement | null = null;\r\n private fileInput: HTMLInputElement | null = null;\r\n private imgOverlay: HTMLElement | null = null;\r\n\r\n // ===== Edit-mode visibility tracking =====\r\n private editScrollHandler: (() => void) | null = null;\r\n private editScrollRAF: number | null = null;\r\n private editClickCaptureHandler: ((e: Event) => void) | null = null;\r\n\r\n // ===== FAB Drag =====\r\n private posX = 20;\r\n private posY = 20;\r\n private isDragging = false;\r\n private dragStartX = 0;\r\n private dragStartY = 0;\r\n private startPosX = 0;\r\n private startPosY = 0;\r\n private hasMoved = false;\r\n\r\n // ===== Timers =====\r\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // ===== License =====\r\n private licenseValid = false;\r\n private licenseStatus: LicenseStatus | null = null;\r\n private licenseOverlayEl: HTMLElement | null = null;\r\n private trialBannerDismissed = false;\r\n\r\n // ===== IndexedDB =====\r\n private db: IDBDatabase | null = null;\r\n\r\n // ===== Bound handlers =====\r\n private boundMouseMove: (e: MouseEvent) => void;\r\n private boundMouseUp: () => void;\r\n private boundTouchMove: (e: TouchEvent) => void;\r\n private boundTouchEnd: () => void;\r\n private boundPopState: () => void;\r\n private boundHashChange: () => void;\r\n\r\n // ===== i18n cache =====\r\n private translationCache = new Map<string, string>();\r\n\r\n constructor(config?: XtroedgeCmsConfig) {\r\n this.config = config || {};\r\n if (!this.config.apiBase) this.config.apiBase = 'https://backend-xi-lime-d90e4p1ysf.vercel.app/api';\r\n this.containerSelector = this.config.containerSelector || '';\r\n this.editableTags = (this.config.editableTags || DEFAULT_EDITABLE_TAGS).map(t => t.toLowerCase());\r\n this.languages = this.config.languages || ['en'];\r\n this.defaultLanguage = this.config.defaultLanguage || this.languages[0] || 'en';\r\n this.highlightColor = this.config.highlightColor || '#00C853';\r\n this.historyRetentionMs = (this.config.historyRetentionDays || 7) * 24 * 60 * 60 * 1000;\r\n this.currentLang = this.detectCurrentLanguage();\r\n this.siteIdentifier = this.resolveSiteIdentifier();\r\n\r\n // Restore client API base from vault (saved during login)\r\n const savedClientApi = XtroedgeCMS.secureGet('xtroedge_client_api');\r\n if (savedClientApi) this.config.clientApi = savedClientApi;\r\n\r\n // Load persisted theme color from localStorage\r\n const savedColor = localStorage.getItem('xtroedge_theme_color');\r\n if (savedColor) this.highlightColor = savedColor;\r\n\r\n // Bind handlers\r\n this.boundMouseMove = (e) => this.onDragMove(e);\r\n this.boundMouseUp = () => this.onDragEnd();\r\n this.boundTouchMove = (e) => this.onTouchMove(e);\r\n this.boundTouchEnd = () => this.onTouchEnd();\r\n this.boundPopState = () => this.handleNavigation();\r\n this.boundHashChange = () => this.handleNavigation();\r\n }\r\n\r\n // ===============================================\r\n // PUBLIC API\r\n // ===============================================\r\n\r\n async init(): Promise<void> {\r\n this.injectStyles();\r\n this.applyThemeColor(this.highlightColor);\r\n\r\n // Validate license (non-blocking — CMS always loads, only editing is gated)\r\n await this.validateLicense();\r\n\r\n this.posY = window.innerHeight - 72;\r\n this.buildUI();\r\n this.interceptNavigation();\r\n\r\n // MutationObserver for auto-scanning\r\n this.observer = new MutationObserver(() => {\r\n // Re-append CMS UI if removed by framework hydration (Next.js, React, etc.)\r\n if (this.rootEl && !document.contains(this.rootEl)) {\r\n document.body.appendChild(this.rootEl);\r\n }\r\n if (this.styleEl && !document.contains(this.styleEl)) {\r\n document.head.appendChild(this.styleEl);\r\n }\r\n if (this.scanTimeout) clearTimeout(this.scanTimeout);\r\n this.scanTimeout = setTimeout(() => {\r\n this.autoDetectAndScan();\r\n // Re-apply texts to any newly detected elements\r\n if (Object.keys(this.pageTexts).length > 0) {\r\n this.updateElementTexts();\r\n }\r\n }, 150);\r\n });\r\n this.observer.observe(document.body, { childList: true, subtree: true });\r\n\r\n // Listen for navigation events\r\n window.addEventListener('popstate', this.boundPopState);\r\n window.addEventListener('hashchange', this.boundHashChange);\r\n\r\n // Prevent anchor navigation when clicking on editable content inside anchors\r\n document.addEventListener('click', (e) => {\r\n if (!document.body.classList.contains('lcms-editing')) return;\r\n\r\n const target = e.target as HTMLElement;\r\n const anchor = target.closest('a');\r\n\r\n // If clicking inside an anchor\r\n if (anchor) {\r\n // Find the contenteditable element\r\n let editableEl: HTMLElement | null = null;\r\n\r\n if (target.getAttribute('contenteditable') === 'true') {\r\n editableEl = target;\r\n } else {\r\n editableEl = target.closest('[contenteditable=\"true\"]') as HTMLElement ||\r\n anchor.querySelector('[contenteditable=\"true\"]') as HTMLElement;\r\n }\r\n\r\n if (editableEl) {\r\n e.preventDefault(); // Prevent navigation\r\n e.stopPropagation(); // Stop event from bubbling\r\n\r\n // Actively focus the contenteditable element\r\n setTimeout(() => {\r\n editableEl!.focus();\r\n }, 0);\r\n }\r\n }\r\n }, true); // Use capture phase to intercept before other handlers\r\n\r\n // Initial navigation\r\n this.handleNavigation();\r\n }\r\n\r\n destroy(): void {\r\n this.cleanupManagedElements();\r\n\r\n // Remove UI\r\n this.styleEl?.remove();\r\n this.rootEl?.remove();\r\n this.licenseOverlayEl?.remove();\r\n\r\n // Remove listeners\r\n window.removeEventListener('popstate', this.boundPopState);\r\n window.removeEventListener('hashchange', this.boundHashChange);\r\n document.removeEventListener('mousemove', this.boundMouseMove);\r\n document.removeEventListener('mouseup', this.boundMouseUp);\r\n document.removeEventListener('touchmove', this.boundTouchMove);\r\n document.removeEventListener('touchend', this.boundTouchEnd);\r\n\r\n // Restore navigation\r\n if (this.origPushState) history.pushState = this.origPushState;\r\n if (this.origReplaceState) history.replaceState = this.origReplaceState;\r\n\r\n // Disconnect observer\r\n this.observer?.disconnect();\r\n if (this.scanTimeout) clearTimeout(this.scanTimeout);\r\n if (this.toastTimer) clearTimeout(this.toastTimer);\r\n\r\n this.db?.close();\r\n }\r\n\r\n /**\r\n * Manually trigger a rescan of the DOM to detect new editable elements.\r\n * Useful when elements are dynamically shown/hidden or added to the page.\r\n */\r\n rescan(): void {\r\n if (this.scanTimeout) clearTimeout(this.scanTimeout);\r\n this.autoDetectAndScan();\r\n }\r\n\r\n // ===============================================\r\n // LICENSE VALIDATION\r\n // ===============================================\r\n\r\n private static readonly LICENSE_CACHE_KEY = 'xtroedge_license_cache';\r\n private static readonly LICENSE_CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours\r\n\r\n private async validateLicense(): Promise<void> {\r\n const licenseKey = this.config.licenseKey || XtroedgeCMS.secureGet('builder_token') || '';\r\n\r\n if (!licenseKey) {\r\n // No license key — editing disabled, but CMS still loads published content\r\n this.licenseStatus = { valid: false, plan: 'invalid', message: 'No license key provided.' };\r\n this.licenseValid = false;\r\n return;\r\n }\r\n\r\n // Check cache first (avoid hitting API on every page load)\r\n const cached = this.getLicenseCache();\r\n if (cached) {\r\n this.licenseStatus = cached;\r\n this.licenseValid = cached.valid;\r\n return;\r\n }\r\n\r\n // Call license validation API\r\n const validateUrl = this.config.licenseValidateUrl\r\n || (this.config.apiBase ? `${this.config.apiBase}/license/validate` : '');\r\n\r\n if (!validateUrl) {\r\n // No validation URL configured — allow (graceful: don't block if no API is set up)\r\n this.licenseValid = true;\r\n this.licenseStatus = { valid: true, plan: 'trial', message: 'No license API configured.' };\r\n return;\r\n }\r\n\r\n try {\r\n const builderToken = XtroedgeCMS.secureGet('builder_token') || '';\r\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\r\n if (builderToken) headers['Authorization'] = `Bearer ${builderToken}`;\r\n\r\n const res = await fetch(validateUrl, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify({\r\n licenseKey,\r\n domain: window.location.hostname,\r\n }),\r\n });\r\n\r\n let data: LicenseStatus;\r\n try {\r\n data = await res.json();\r\n } catch {\r\n throw new Error('Invalid response from license server');\r\n }\r\n\r\n this.licenseStatus = data;\r\n this.setLicenseCache(data);\r\n this.licenseValid = data.valid;\r\n } catch {\r\n // Network error — check if we have any previous valid cache (even expired)\r\n const fallback = this.getLicenseCache(true); // ignore TTL\r\n if (fallback && fallback.valid) {\r\n // Grace period: allow editing with stale cache\r\n this.licenseValid = true;\r\n this.licenseStatus = fallback;\r\n } else {\r\n // No cache + network failed — content still loads, editing blocked\r\n this.licenseStatus = { valid: false, plan: 'invalid', message: 'Unable to verify license. Please check your internet connection.' };\r\n this.licenseValid = false;\r\n }\r\n }\r\n }\r\n\r\n private getLicenseCache(ignoreTTL = false): LicenseStatus | null {\r\n try {\r\n const raw = XtroedgeCMS.secureGet(XtroedgeCMS.LICENSE_CACHE_KEY);\r\n if (!raw) return null;\r\n const { status, timestamp, key } = JSON.parse(raw);\r\n // Invalidate cache if license key changed\r\n const currentKey = this.config.licenseKey || XtroedgeCMS.secureGet('builder_token') || '';\r\n if (key !== currentKey) return null;\r\n if (!ignoreTTL && (Date.now() - timestamp > XtroedgeCMS.LICENSE_CACHE_TTL)) return null;\r\n return status as LicenseStatus;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private setLicenseCache(status: LicenseStatus): void {\r\n try {\r\n const currentKey = this.config.licenseKey || XtroedgeCMS.secureGet('builder_token') || '';\r\n XtroedgeCMS.secureSet(XtroedgeCMS.LICENSE_CACHE_KEY, JSON.stringify({\r\n status,\r\n timestamp: Date.now(),\r\n key: currentKey,\r\n }));\r\n } catch { /* localStorage full or blocked — ignore */ }\r\n }\r\n\r\n /** Shows toast when user tries to edit with expired/invalid license */\r\n private showLicenseExpiredToast(): void {\r\n const isExpired = this.licenseStatus?.plan === 'expired';\r\n const msg = isExpired\r\n ? 'Your free trial has expired. Subscribe to enable editing.'\r\n : (this.licenseStatus?.message || 'License validation failed. Editing is disabled.');\r\n this.showToast(msg, 'error');\r\n }\r\n\r\n /** Returns trial/expired banner HTML if applicable, or empty string */\r\n private getTrialBannerHTML(): string {\r\n if (this.trialBannerDismissed || !this.licenseStatus) return '';\r\n\r\n // Expired or invalid license — show red banner\r\n if (!this.licenseValid) {\r\n const msg = this.licenseStatus.plan === 'expired'\r\n ? 'Trial expired — editing disabled. Subscribe to continue.'\r\n : 'License invalid — editing disabled.';\r\n return `\r\n <div class=\"lcms-trial-banner\" id=\"lcms-trial-banner\" style=\"background:rgba(239,68,68,0.12);border-color:rgba(239,68,68,0.3);color:#f87171;\">\r\n <span class=\"lcms-trial-banner-icon\">🔒</span>\r\n <span class=\"lcms-trial-banner-text\">${msg}</span>\r\n <button class=\"lcms-trial-banner-dismiss\" id=\"lcms-trial-dismiss\" title=\"Dismiss\" style=\"color:rgba(239,68,68,0.5);\">✕</button>\r\n </div>\r\n `;\r\n }\r\n\r\n // Active trial — show yellow banner with days remaining\r\n if (this.licenseStatus.plan === 'trial') {\r\n const days = this.licenseStatus.daysLeft ?? 0;\r\n return `\r\n <div class=\"lcms-trial-banner\" id=\"lcms-trial-banner\">\r\n <span class=\"lcms-trial-banner-icon\">⏳</span>\r\n <span class=\"lcms-trial-banner-text\">Free Trial: ${days} day${days !== 1 ? 's' : ''} remaining</span>\r\n <button class=\"lcms-trial-banner-dismiss\" id=\"lcms-trial-dismiss\" title=\"Dismiss\">✕</button>\r\n </div>\r\n `;\r\n }\r\n\r\n return '';\r\n }\r\n\r\n // ===============================================\r\n // STYLES INJECTION\r\n // ===============================================\r\n\r\n private injectStyles(): void {\r\n if (document.getElementById('xtroedge-cms-styles')) return;\r\n this.styleEl = document.createElement('style');\r\n this.styleEl.id = 'xtroedge-cms-styles';\r\n this.styleEl.textContent = CMS_STYLES;\r\n document.head.appendChild(this.styleEl);\r\n }\r\n\r\n // ===============================================\r\n // NAVIGATION INTERCEPTION\r\n // ===============================================\r\n\r\n private interceptNavigation(): void {\r\n this.origPushState = history.pushState.bind(history);\r\n this.origReplaceState = history.replaceState.bind(history);\r\n const self = this;\r\n history.pushState = function (...args) {\r\n self.origPushState!(...args);\r\n setTimeout(() => self.handleNavigation(), 0);\r\n };\r\n history.replaceState = function (...args) {\r\n self.origReplaceState!(...args);\r\n setTimeout(() => self.handleNavigation(), 0);\r\n };\r\n }\r\n\r\n private handleNavigation(): void {\r\n const url = window.location.href;\r\n const pathname = window.location.pathname || '/';\r\n const hash = window.location.hash || '';\r\n\r\n // Support hash routing: #/page?edit=true\r\n let path: string;\r\n let searchStr: string;\r\n if (hash.startsWith('#/') || hash.startsWith('#!')) {\r\n const hashPath = hash.replace(/^#[!/]*/, '');\r\n const qIdx = hashPath.indexOf('?');\r\n path = qIdx >= 0 ? hashPath.substring(0, qIdx) : hashPath;\r\n searchStr = qIdx >= 0 ? hashPath.substring(qIdx) : '';\r\n } else {\r\n path = pathname.replace(/^\\//, '') || 'home';\r\n searchStr = window.location.search;\r\n }\r\n\r\n const slug = '/' + (path.replace(/^\\//, '') || 'home');\r\n const params = new URLSearchParams(searchStr);\r\n const editViaParam = params.get('edit') === 'true';\r\n\r\n this.isEditAllowed = editViaParam || sessionStorage.getItem('builder_edit_mode') === 'true';\r\n\r\n const slugChanged = slug !== this.currentSlug;\r\n if (slugChanged) {\r\n this.cleanupManagedElements();\r\n this.currentSlug = slug;\r\n this.currentTitle = (path.replace(/^\\//, '') || 'home').replace(/-/g, ' ').replace(/\\b\\w/g, c => c.toUpperCase()) + ' Page';\r\n this.resetAll();\r\n }\r\n\r\n // Restore edit mode — check builder_token first\r\n const editFromSession = sessionStorage.getItem('builder_edit_mode') === 'true';\r\n const wantsEdit = editViaParam || editFromSession;\r\n\r\n if (wantsEdit) {\r\n const token = XtroedgeCMS.secureGet('builder_token');\r\n if (!token) {\r\n // No token → show login modal, do NOT enable edit mode yet\r\n if (!this.pendingEditMode) {\r\n this.pendingEditMode = true;\r\n this.currentLang = this.detectCurrentLanguage();\r\n this.setLoading(true);\r\n setTimeout(() => {\r\n this.loadTranslationsAndInit(false);\r\n this.showLoginModal();\r\n }, 300);\r\n }\r\n return;\r\n }\r\n\r\n // Block edit mode if license is not valid\r\n if (!this.licenseValid) {\r\n this.showLicenseExpiredToast();\r\n this.editMode = false;\r\n } else {\r\n this.editMode = true;\r\n }\r\n }\r\n\r\n // Skip reload if same slug and already initialized\r\n if (!slugChanged && this.initialized) {\r\n this.updateUI();\r\n return;\r\n }\r\n\r\n this.currentLang = this.detectCurrentLanguage();\r\n\r\n // Show loader\r\n this.setLoading(true);\r\n\r\n // Auto-detect after DOM settles, then load content\r\n this.initialized = true;\r\n const loadDraft = wantsEdit;\r\n setTimeout(() => {\r\n this.loadTranslationsAndInit(loadDraft);\r\n }, 300);\r\n }\r\n\r\n // ===============================================\r\n // BUILD UI\r\n // ===============================================\r\n\r\n private buildUI(): void {\r\n this.rootEl = document.createElement('div');\r\n this.rootEl.id = 'xtroedge-cms-root';\r\n\r\n // Loader\r\n this.loaderEl = this.createElement('div', 'lcms-loader-overlay lcms-hidden');\r\n this.loaderEl.innerHTML = `<div class=\"lcms-loader-content\">\r\n <div class=\"lcms-orbit-loader\">\r\n <div class=\"lcms-orbit lcms-orbit-1\"><span class=\"lcms-particle\"></span></div>\r\n <div class=\"lcms-orbit lcms-orbit-2\"><span class=\"lcms-particle\"></span></div>\r\n <div class=\"lcms-orbit lcms-orbit-3\"><span class=\"lcms-particle\"></span></div>\r\n <div class=\"lcms-core-glow\"></div>\r\n <div class=\"lcms-core\"></div>\r\n </div>\r\n <span class=\"lcms-loader-text\">Loading</span>\r\n </div>`;\r\n this.rootEl.appendChild(this.loaderEl);\r\n\r\n // Toast\r\n this.toastEl = this.createElement('div', 'lcms-toast lcms-hidden');\r\n this.rootEl.appendChild(this.toastEl);\r\n\r\n // FAB\r\n this.fabEl = this.createElement('div', 'lcms-fab');\r\n this.fabEl.style.left = this.posX + 'px';\r\n this.fabEl.style.top = this.posY + 'px';\r\n this.fabEl.addEventListener('mousedown', (e) => this.onDragStart(e));\r\n this.fabEl.addEventListener('touchstart', (e) => this.onTouchStart(e), { passive: true });\r\n\r\n // FAB button\r\n this.fabBtn = document.createElement('button');\r\n this.fabBtn.className = 'lcms-fab-btn';\r\n this.fabBtn.innerHTML = ICON.edit;\r\n this.fabBtn.addEventListener('click', (e) => this.onFabClick(e));\r\n this.badgeEl = this.createElement('span', 'lcms-badge lcms-hidden');\r\n this.fabBtn.appendChild(this.badgeEl);\r\n this.fabEl.appendChild(this.fabBtn);\r\n\r\n // Panel\r\n this.panelEl = this.createElement('div', 'lcms-panel lcms-hidden');\r\n this.buildPanel();\r\n this.fabEl.appendChild(this.panelEl);\r\n\r\n this.rootEl.appendChild(this.fabEl);\r\n\r\n // Hidden file input\r\n this.fileInput = document.createElement('input');\r\n this.fileInput.type = 'file';\r\n this.fileInput.accept = 'image/*';\r\n this.fileInput.style.display = 'none';\r\n this.fileInput.addEventListener('change', (e) => this.onImageFileSelected(e));\r\n this.rootEl.appendChild(this.fileInput);\r\n\r\n // Image upload overlay\r\n this.imgOverlay = this.createElement('div', 'lcms-img-upload-overlay lcms-hidden');\r\n this.imgOverlay.innerHTML = `<div class=\"lcms-img-upload-content\"><div class=\"lcms-spinner-lg\"></div><span>Uploading image...</span></div>`;\r\n this.rootEl.appendChild(this.imgOverlay);\r\n\r\n document.body.appendChild(this.rootEl);\r\n }\r\n\r\n private buildPanel(): void {\r\n if (!this.panelEl) return;\r\n\r\n // Header\r\n const header = this.createElement('div', 'lcms-panel-header');\r\n\r\n // Edit toggle\r\n const toggleLabel = this.createElement('label', 'lcms-toggle');\r\n toggleLabel.addEventListener('click', (e) => e.stopPropagation());\r\n this.editToggle = document.createElement('input');\r\n this.editToggle.type = 'checkbox';\r\n this.editToggle.checked = this.editMode;\r\n this.editToggle.addEventListener('change', (e) => this.toggleEditMode(e));\r\n const slider = this.createElement('span', 'lcms-toggle-slider');\r\n const labelText = this.createElement('span', 'lcms-toggle-label');\r\n labelText.textContent = 'Edit';\r\n toggleLabel.appendChild(this.editToggle);\r\n toggleLabel.appendChild(slider);\r\n toggleLabel.appendChild(labelText);\r\n header.appendChild(toggleLabel);\r\n\r\n // Language switch\r\n this.langSwitchEl = this.createElement('div', 'lcms-lang-switch lcms-hidden');\r\n this.buildLangButtons();\r\n header.appendChild(this.langSwitchEl);\r\n\r\n // Close button\r\n const closeBtn = document.createElement('button');\r\n closeBtn.className = 'lcms-close-btn';\r\n closeBtn.innerHTML = ICON.close;\r\n closeBtn.addEventListener('click', (e) => { e.stopPropagation(); this.togglePanel(); });\r\n header.appendChild(closeBtn);\r\n\r\n this.panelEl.appendChild(header);\r\n\r\n // Site identifier\r\n this.siteIdEl = this.createElement('div', 'lcms-site-id');\r\n const isDomain = this.siteIdentifier.includes('.');\r\n this.siteIdEl.innerHTML = `<span class=\"lcms-site-id-icon\">${isDomain ? '\\u{1F310}' : '\\u{1F511}'}</span><span class=\"lcms-site-id-text\">${isDomain ? this.siteIdentifier : this.siteIdentifier.substring(0, 8)}</span>`;\r\n this.panelEl.appendChild(this.siteIdEl);\r\n\r\n // Trial banner (shown only during free trial)\r\n const trialHTML = this.getTrialBannerHTML();\r\n if (trialHTML) {\r\n const trialWrap = this.createElement('div', '');\r\n trialWrap.innerHTML = trialHTML;\r\n this.panelEl.appendChild(trialWrap);\r\n // Attach dismiss handler after DOM insertion\r\n setTimeout(() => {\r\n const dismissBtn = document.getElementById('lcms-trial-dismiss');\r\n dismissBtn?.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.trialBannerDismissed = true;\r\n const banner = document.getElementById('lcms-trial-banner');\r\n banner?.remove();\r\n });\r\n }, 0);\r\n }\r\n\r\n // Edit mode content (hidden when edit mode off)\r\n this.editModeContent = this.createElement('div', 'lcms-hidden');\r\n\r\n // Changes info\r\n this.changesInfoEl = this.createElement('div', 'lcms-changes-info lcms-hidden');\r\n this.editModeContent.appendChild(this.changesInfoEl);\r\n\r\n // Undo/Redo row\r\n const undoRow = this.createElement('div', 'lcms-undo-row');\r\n this.undoBtn = document.createElement('button');\r\n this.undoBtn.className = 'lcms-icon-btn';\r\n this.undoBtn.innerHTML = ICON.undo;\r\n this.undoBtn.disabled = true;\r\n this.undoBtn.addEventListener('click', (e) => { e.stopPropagation(); this.onUndo(); });\r\n this.redoBtn = document.createElement('button');\r\n this.redoBtn.className = 'lcms-icon-btn';\r\n this.redoBtn.innerHTML = ICON.redo;\r\n this.redoBtn.disabled = true;\r\n this.redoBtn.addEventListener('click', (e) => { e.stopPropagation(); this.onRedo(); });\r\n undoRow.appendChild(this.undoBtn);\r\n undoRow.appendChild(this.redoBtn);\r\n this.editModeContent.appendChild(undoRow);\r\n\r\n // Color theme picker\r\n const themeRow = this.createElement('div', 'lcms-theme-row');\r\n const themeLabel = this.createElement('span', 'lcms-theme-label');\r\n themeLabel.textContent = 'Theme';\r\n themeRow.appendChild(themeLabel);\r\n const themeColors = this.createElement('div', 'lcms-theme-colors');\r\n const presetColors = ['#00C853', '#6722FB', '#2196F3', '#FF5722', '#E91E63', '#FFD600'];\r\n for (const color of presetColors) {\r\n const swatch = this.createElement('div', 'lcms-theme-swatch');\r\n swatch.style.background = color;\r\n swatch.dataset.color = color;\r\n if (color === this.highlightColor) swatch.classList.add('active');\r\n swatch.addEventListener('click', (e) => { e.stopPropagation(); this.applyThemeColor(color); });\r\n themeColors.appendChild(swatch);\r\n }\r\n // Custom color input\r\n const customSwatch = this.createElement('div', 'lcms-theme-custom');\r\n const customPreview = this.createElement('div', 'lcms-theme-custom-preview');\r\n const customInput = document.createElement('input');\r\n customInput.type = 'color';\r\n customInput.value = this.highlightColor;\r\n customInput.addEventListener('input', (e) => { e.stopPropagation(); this.applyThemeColor((e.target as HTMLInputElement).value); });\r\n customSwatch.appendChild(customPreview);\r\n customSwatch.appendChild(customInput);\r\n themeColors.appendChild(customSwatch);\r\n themeRow.appendChild(themeColors);\r\n this.editModeContent.appendChild(themeRow);\r\n\r\n // History button\r\n this.historyBtnEl = document.createElement('button');\r\n this.historyBtnEl.className = 'lcms-history-btn';\r\n this.historyBtnEl.innerHTML = `${ICON.history} History (7 days)`;\r\n this.historyBtnEl.addEventListener('click', (e) => { e.stopPropagation(); this.toggleHistory(); });\r\n this.editModeContent.appendChild(this.historyBtnEl);\r\n\r\n // History panel\r\n this.historyPanelEl = this.createElement('div', 'lcms-history-panel lcms-hidden');\r\n const historyTitle = this.createElement('div', 'lcms-history-title');\r\n historyTitle.textContent = 'Edit History';\r\n this.historyPanelEl.appendChild(historyTitle);\r\n this.historyListEl = this.createElement('div', 'lcms-history-list');\r\n this.historyPanelEl.appendChild(this.historyListEl);\r\n this.editModeContent.appendChild(this.historyPanelEl);\r\n\r\n // Actions\r\n this.actionsEl = this.createElement('div', 'lcms-actions');\r\n this.saveBtn = document.createElement('button');\r\n this.saveBtn.className = 'lcms-btn-save';\r\n this.saveBtn.innerHTML = `${ICON.save} Save Draft`;\r\n this.saveBtn.addEventListener('click', (e) => { e.stopPropagation(); this.saveChanges(); });\r\n this.publishBtn = document.createElement('button');\r\n this.publishBtn.className = 'lcms-btn-publish';\r\n this.publishBtn.innerHTML = `${ICON.publish} Publish`;\r\n this.publishBtn.addEventListener('click', (e) => { e.stopPropagation(); this.publishChanges(); });\r\n const logoutBtn = document.createElement('button');\r\n logoutBtn.className = 'lcms-btn-logout';\r\n logoutBtn.innerHTML = `${ICON.logout} Logout`;\r\n logoutBtn.addEventListener('click', (e) => { e.stopPropagation(); this.logout(); });\r\n this.actionsEl.appendChild(this.saveBtn);\r\n this.actionsEl.appendChild(this.publishBtn);\r\n this.actionsEl.appendChild(logoutBtn);\r\n this.editModeContent.appendChild(this.actionsEl);\r\n\r\n this.panelEl.appendChild(this.editModeContent);\r\n\r\n // Branding\r\n this.brandingEl = this.createElement('div', 'lcms-branding');\r\n 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>`;\r\n this.brandingEl.addEventListener('click', (e) => { e.stopPropagation(); window.open('https://xtro.vercel.app/', '_blank'); });\r\n this.panelEl.appendChild(this.brandingEl);\r\n }\r\n\r\n private buildLangButtons(): void {\r\n if (!this.langSwitchEl) return;\r\n this.langSwitchEl.innerHTML = '';\r\n const select = document.createElement('select');\r\n select.className = 'lcms-lang-select';\r\n for (const lang of this.languages) {\r\n const opt = document.createElement('option');\r\n opt.value = lang;\r\n opt.textContent = lang.toUpperCase();\r\n if (lang === this.currentLang) opt.selected = true;\r\n select.appendChild(opt);\r\n }\r\n select.addEventListener('change', (e) => { e.stopPropagation(); this.switchLang((e.target as HTMLSelectElement).value); });\r\n this.langSwitchEl.appendChild(select);\r\n const arrow = document.createElement('span');\r\n arrow.className = 'lcms-lang-arrow';\r\n arrow.textContent = '\\u25BC';\r\n this.langSwitchEl.appendChild(arrow);\r\n }\r\n\r\n // ===============================================\r\n // UI UPDATE\r\n // ===============================================\r\n\r\n private updateUI(): void {\r\n // FAB visibility\r\n if (this.fabEl) {\r\n this.fabEl.style.display = this.isEditAllowed ? '' : 'none';\r\n }\r\n\r\n // FAB button vs panel\r\n if (this.fabBtn) {\r\n this.fabBtn.style.display = this.isOpen ? 'none' : '';\r\n this.fabBtn.classList.toggle('lcms-fab-active', this.editMode);\r\n }\r\n if (this.panelEl) {\r\n this.panelEl.classList.toggle('lcms-hidden', !this.isOpen);\r\n // Position panel\r\n if (this.isOpen) {\r\n const openUp = this.posY > window.innerHeight / 2;\r\n const openLeft = this.posX > window.innerWidth / 2;\r\n this.panelEl.style.bottom = openUp ? '0' : '';\r\n this.panelEl.style.top = openUp ? '' : '0';\r\n this.panelEl.style.right = openLeft ? '0' : '';\r\n this.panelEl.style.left = openLeft ? '' : '0';\r\n }\r\n }\r\n\r\n // Badge\r\n if (this.badgeEl) {\r\n this.badgeEl.classList.toggle('lcms-hidden', this.unsavedChanges === 0);\r\n this.badgeEl.textContent = String(this.unsavedChanges);\r\n }\r\n\r\n // Edit toggle\r\n if (this.editToggle) this.editToggle.checked = this.editMode;\r\n\r\n // Lang switch\r\n if (this.langSwitchEl) {\r\n this.langSwitchEl.classList.toggle('lcms-hidden', !this.editMode || this.languages.length <= 1);\r\n const sel = this.langSwitchEl.querySelector('.lcms-lang-select') as HTMLSelectElement | null;\r\n if (sel) sel.value = this.currentLang;\r\n }\r\n\r\n // Edit mode content\r\n if (this.editModeContent) {\r\n this.editModeContent.classList.toggle('lcms-hidden', !this.editMode);\r\n }\r\n\r\n // Changes info\r\n if (this.changesInfoEl) {\r\n this.changesInfoEl.classList.toggle('lcms-hidden', this.unsavedChanges === 0);\r\n this.changesInfoEl.textContent = `${this.unsavedChanges} unsaved change${this.unsavedChanges > 1 ? 's' : ''}`;\r\n }\r\n\r\n // Undo/Redo\r\n if (this.undoBtn) this.undoBtn.disabled = !this.canUndo;\r\n if (this.redoBtn) this.redoBtn.disabled = !this.canRedo;\r\n\r\n // History button\r\n if (this.historyBtnEl) this.historyBtnEl.classList.toggle('active', this.showHistory);\r\n if (this.historyPanelEl) this.historyPanelEl.classList.toggle('lcms-hidden', !this.showHistory);\r\n\r\n // Save/Publish buttons\r\n if (this.saveBtn) {\r\n this.saveBtn.disabled = this.isSaving || this.isPublishing || this.unsavedChanges === 0;\r\n this.saveBtn.innerHTML = this.isSaving ? '<span class=\"lcms-spinner\"></span> Saving...' : `${ICON.save} Save Draft`;\r\n }\r\n if (this.publishBtn) {\r\n this.publishBtn.disabled = this.isSaving || this.isPublishing;\r\n this.publishBtn.innerHTML = this.isPublishing ? '<span class=\"lcms-spinner\"></span> Publishing...' : `${ICON.publish} Publish`;\r\n }\r\n\r\n // Loader\r\n if (this.loaderEl) this.loaderEl.classList.toggle('lcms-hidden', !this.loading);\r\n\r\n // Image overlay\r\n if (this.imgOverlay) this.imgOverlay.classList.toggle('lcms-hidden', !this.imageUploading);\r\n }\r\n\r\n // ===============================================\r\n // DOM SCANNING\r\n // ===============================================\r\n\r\n private autoDetectAndScan(): void {\r\n this.autoDetectElements();\r\n this.scanDOM();\r\n this.scanImages();\r\n }\r\n\r\n private resolveContainer(): Element {\r\n if (this.containerSelector) {\r\n return document.querySelector(this.containerSelector) || document.body;\r\n }\r\n return document.body;\r\n }\r\n\r\n private autoDetectElements(): void {\r\n const container = this.resolveContainer();\r\n if (!container) return;\r\n\r\n // Clean up stale auto-detected elements\r\n for (const el of this.autoDetectedElements) {\r\n if (!document.contains(el)) this.autoDetectedElements.delete(el);\r\n }\r\n\r\n // Detect section slug based on ancestor tag name\r\n // Only custom component tags ending with '-header'/'-footer' (e.g. <app-header>, <app-footer>)\r\n // get separate section slugs. Native HTML <header>/<footer> tags are treated as page content.\r\n const getSectionSlug = (el: HTMLElement): string => {\r\n let parent: HTMLElement | null = el.parentElement;\r\n while (parent && parent !== document.body) {\r\n const tag = parent.tagName.toLowerCase();\r\n if (tag.endsWith('-header')) return '/header';\r\n if (tag.endsWith('-footer')) return '/footer';\r\n parent = parent.parentElement;\r\n }\r\n return this.currentSlug;\r\n };\r\n\r\n // Section-aware tag counters to avoid key collisions across sections\r\n const tagCounters: { [section: string]: { [tag: string]: number } } = {};\r\n\r\n const hasCmsKey = (candidate: string) => {\r\n return Array.from(document.querySelectorAll<HTMLElement>('[data-cms]'))\r\n .some(node => node.getAttribute('data-cms') === candidate);\r\n };\r\n\r\n const assignKey = (el: HTMLElement, sectionSlug: string) => {\r\n const sectionKey = sectionSlug === '/header' ? 'header'\r\n : sectionSlug === '/footer' ? 'footer' : 'page';\r\n if (!tagCounters[sectionKey]) tagCounters[sectionKey] = {};\r\n const tag = el.tagName.toLowerCase();\r\n if (!tagCounters[sectionKey][tag]) tagCounters[sectionKey][tag] = 0;\r\n const prefix = sectionKey !== 'page' ? `${sectionKey}_` : '';\r\n let key = `${prefix}xcms_${tag}_${tagCounters[sectionKey][tag]}`;\r\n while (hasCmsKey(key)) {\r\n tagCounters[sectionKey][tag]++;\r\n key = `${prefix}xcms_${tag}_${tagCounters[sectionKey][tag]}`;\r\n }\r\n tagCounters[sectionKey][tag]++;\r\n el.setAttribute('data-cms', key);\r\n el.setAttribute('data-cms-section', sectionSlug); // used during save/load\r\n this.autoDetectedElements.add(el);\r\n };\r\n\r\n // Inline formatting tags created by rich text (execCommand) — never auto-scan these\r\n const RICH_TEXT_INLINE = new Set(['B', 'STRONG', 'I', 'EM', 'U', 'S', 'STRIKE', 'DEL', 'SUB', 'SUP', 'MARK']);\r\n\r\n // Scan standard editable tags (h1, p, div, etc.)\r\n const selector = this.editableTags.join(',');\r\n const elements = container.querySelectorAll<HTMLElement>(selector);\r\n elements.forEach(el => {\r\n if (el.hasAttribute('data-cms')) return;\r\n if (el.closest('#xtroedge-cms-root, #lcms-login-modal, script, style, noscript')) return;\r\n // Skip inline formatting tags inside elements already managed by CMS\r\n if (RICH_TEXT_INLINE.has(el.tagName) && el.parentElement?.closest('[data-cms]')) return;\r\n if (el.children.length > 3) return;\r\n const text = this.getDirectTextContent(el).trim();\r\n if (text.length < 2) return;\r\n assignKey(el, getSectionSlug(el));\r\n });\r\n\r\n // Scan [data-editable] elements — works with ANY tag (app-header, app-footer, custom components)\r\n // No children/text restrictions since user explicitly marked them\r\n const dataEditables = container.querySelectorAll<HTMLElement>('[data-editable]');\r\n dataEditables.forEach(el => {\r\n if (el.hasAttribute('data-cms')) return;\r\n if (el.closest('#xtroedge-cms-root, #lcms-login-modal, script, style, noscript')) return;\r\n assignKey(el, getSectionSlug(el));\r\n });\r\n }\r\n\r\n private scanDOM(): void {\r\n const elements = document.querySelectorAll<HTMLElement>('[data-cms]');\r\n const seenKeys = new Set<string>();\r\n elements.forEach(el => {\r\n if (el.closest('#xtroedge-cms-root, #lcms-login-modal')) return;\r\n let key = el.getAttribute('data-cms')!;\r\n if (seenKeys.has(key)) {\r\n let idx = 1;\r\n let repaired = `${key}__${idx}`;\r\n while (document.querySelector(`[data-cms=\"${repaired}\"]`)) {\r\n idx++;\r\n repaired = `${key}__${idx}`;\r\n }\r\n el.setAttribute('data-cms', repaired);\r\n key = repaired;\r\n }\r\n seenKeys.add(key);\r\n this.registeredKeys.add(key);\r\n if (!this.managedElements.has(el)) {\r\n this.attachElement(el, key);\r\n }\r\n });\r\n // Cleanup removed elements\r\n for (const [el] of this.managedElements) {\r\n if (!document.contains(el)) this.detachElement(el);\r\n }\r\n }\r\n\r\n private scanImages(): void {\r\n const container = this.resolveContainer();\r\n if (!container) return;\r\n const currentImages = { ...this.pageImages };\r\n let hasNew = false;\r\n const images = container.querySelectorAll<HTMLImageElement>('img');\r\n images.forEach(img => {\r\n if (img.closest('#xtroedge-cms-root')) return;\r\n if (this.managedImages.has(img)) return;\r\n const src = img.getAttribute('src') || '';\r\n if (!src || src.startsWith('data:')) return;\r\n this.attachImage(img, src);\r\n if (!currentImages[src]) {\r\n currentImages[src] = src;\r\n hasNew = true;\r\n }\r\n });\r\n if (hasNew) {\r\n this.pageImages = currentImages;\r\n this.originalImages = JSON.parse(JSON.stringify(currentImages));\r\n }\r\n for (const [img] of this.managedImages) {\r\n if (!document.contains(img)) this.detachImage(img);\r\n }\r\n }\r\n\r\n private getDirectTextContent(el: HTMLElement): string {\r\n let text = '';\r\n for (let i = 0; i < el.childNodes.length; i++) {\r\n if (el.childNodes[i].nodeType === Node.TEXT_NODE) {\r\n text += el.childNodes[i].textContent || '';\r\n }\r\n }\r\n return text;\r\n }\r\n\r\n private hasEditableChildren(el: HTMLElement): boolean {\r\n return !!el.querySelector('[data-cms]');\r\n }\r\n\r\n private getElementContent(el: HTMLElement): string {\r\n if (this.richTextEnabled) return el.innerHTML?.trim() || '';\r\n if (this.hasEditableChildren(el)) return this.getDirectTextContent(el).trim();\r\n return el.textContent?.trim() || '';\r\n }\r\n\r\n private setElementContent(el: HTMLElement, val: string): void {\r\n if (this.richTextEnabled) {\r\n el.innerHTML = this.sanitizeHTML(val);\r\n } else if (this.hasEditableChildren(el)) {\r\n const textNodes: Text[] = [];\r\n for (let i = 0; i < el.childNodes.length; i++) {\r\n if (el.childNodes[i].nodeType === Node.TEXT_NODE) textNodes.push(el.childNodes[i] as Text);\r\n }\r\n if (textNodes.length > 0) textNodes[0].textContent = val;\r\n else el.prepend(document.createTextNode(val));\r\n } else {\r\n el.textContent = val;\r\n }\r\n }\r\n\r\n // Legacy alias for backward compat with internal calls\r\n private setDirectTextContent(el: HTMLElement, val: string): void {\r\n this.setElementContent(el, val);\r\n }\r\n\r\n // ===============================================\r\n // ELEMENT EDITING\r\n // ===============================================\r\n\r\n private attachElement(el: HTMLElement, key: string): void {\r\n const getContent = () => this.getElementContent(el);\r\n const blurHandler = () => {\r\n const text = getContent();\r\n const currentVal = this.getPageText(key);\r\n if (text !== currentVal) this.onTextChanged(key, text);\r\n this.hideRichToolbar();\r\n };\r\n const keydownHandler = (e: KeyboardEvent) => {\r\n if (e.key === 'Enter') {\r\n // Allow Enter for multi-line elements when rich text is enabled\r\n if (this.richTextEnabled && !XtroedgeCMS.SINGLE_LINE_TAGS.has(el.tagName)) {\r\n return; // Allow default Enter behavior (line break)\r\n }\r\n e.preventDefault();\r\n el.blur();\r\n }\r\n };\r\n const inputHandler = () => {\r\n const text = getContent();\r\n const currentVal = this.getPageText(key);\r\n if (text !== currentVal) this.onTextChanged(key, text);\r\n };\r\n const focusEditableEnd = () => {\r\n if (document.activeElement !== el) el.focus();\r\n const selection = window.getSelection();\r\n if (!selection) return;\r\n const range = document.createRange();\r\n range.selectNodeContents(el);\r\n range.collapse(false);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n };\r\n\r\n // In edit mode: stop propagation to prevent dropdown close.\r\n // If editable is inside an anchor, block navigation.\r\n const clickHandler = (e: Event) => {\r\n e.stopPropagation();\r\n const inAnchor = el.tagName === 'A' || !!(e.target as HTMLElement).closest('a');\r\n if (inAnchor) {\r\n e.preventDefault();\r\n // Don't call focusEditableEnd() - let browser handle cursor positioning naturally\r\n // Element will focus automatically, and cursor will be placed where user clicked\r\n }\r\n };\r\n const sectionSlug = el.getAttribute('data-cms-section') || this.currentSlug;\r\n this.managedElements.set(el, { key, sectionSlug, blurHandler, keydownHandler, inputHandler, clickHandler });\r\n if (this.editMode) this.enableElementEdit(el, key, blurHandler, keydownHandler, inputHandler, clickHandler);\r\n }\r\n\r\n private detachElement(el: HTMLElement): void {\r\n const info = this.managedElements.get(el);\r\n if (info) {\r\n el.removeEventListener('blur', info.blurHandler);\r\n el.removeEventListener('keydown', info.keydownHandler as EventListener);\r\n el.removeEventListener('input', info.inputHandler);\r\n el.removeEventListener('click', info.clickHandler, true);\r\n el.removeAttribute('contenteditable');\r\n this.managedElements.delete(el);\r\n }\r\n }\r\n\r\n /** Stop propagation so parent carousels (Swiper, Owl, etc.) don't hijack the event */\r\n private static stopProp(e: Event): void { e.stopPropagation(); }\r\n\r\n private focusEditableEnd(el: HTMLElement): void {\r\n if (document.activeElement !== el) el.focus();\r\n const selection = window.getSelection();\r\n if (!selection) return;\r\n const range = document.createRange();\r\n range.selectNodeContents(el);\r\n range.collapse(false);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n }\r\n\r\n private enableElementEdit(el: HTMLElement, _key: string, blurH: (e: Event) => void, keyH: (e: KeyboardEvent) => void, inputH: (e: Event) => void, clickH: (e: Event) => void): void {\r\n const val = this.getPageText(_key);\r\n if (val) this.setElementContent(el, val);\r\n el.setAttribute('contenteditable', 'true');\r\n el.style.setProperty('outline', `2px dashed ${this.highlightColor}`, 'important');\r\n el.style.setProperty('outline-offset', '-2px', 'important');\r\n el.style.cursor = 'text';\r\n el.style.transition = 'background 0.2s';\r\n el.style.minWidth = '20px';\r\n\r\n // COMMENTED OUT: Double-click to show floating edit dialog\r\n // const dblClickHandler = (e: Event) => {\r\n // e.preventDefault();\r\n // e.stopPropagation();\r\n // this.showFloatingEditDialog(el, _key);\r\n // };\r\n // el.addEventListener('dblclick', dblClickHandler);\r\n // el.dataset.cmsDblClickAdded = 'true';\r\n\r\n el.addEventListener('blur', blurH);\r\n el.addEventListener('keydown', keyH as EventListener);\r\n el.addEventListener('input', inputH);\r\n el.addEventListener('click', clickH, true);\r\n // Prevent parent carousels/sliders from capturing pointer events on editable elements\r\n el.addEventListener('mousedown', XtroedgeCMS.stopProp, true);\r\n el.addEventListener('touchstart', XtroedgeCMS.stopProp, true);\r\n // Show rich text toolbar on focus\r\n el.addEventListener('focus', () => this.showRichToolbar(el));\r\n }\r\n\r\n private disableElementEdit(el: HTMLElement, _key: string, blurH: (e: Event) => void, keyH: (e: KeyboardEvent) => void, inputH: (e: Event) => void, clickH: (e: Event) => void): void {\r\n el.removeAttribute('contenteditable');\r\n el.style.removeProperty('outline');\r\n el.style.removeProperty('outline-offset');\r\n el.style.cursor = '';\r\n el.style.transition = '';\r\n el.style.minWidth = '';\r\n const val = this.getPageText(_key);\r\n if (val) this.setElementContent(el, val);\r\n el.removeEventListener('blur', blurH);\r\n el.removeEventListener('keydown', keyH as EventListener);\r\n el.removeEventListener('input', inputH);\r\n el.removeEventListener('click', clickH, true);\r\n el.removeEventListener('mousedown', XtroedgeCMS.stopProp, true);\r\n el.removeEventListener('touchstart', XtroedgeCMS.stopProp, true);\r\n }\r\n\r\n private applyEditMode(editMode: boolean): void {\r\n // Add/remove body class for edit-mode CSS overrides\r\n document.body.classList.toggle('lcms-editing', editMode);\r\n\r\n if (editMode) {\r\n // Document-level capture handler: stop pointer/click propagation on CMS-managed targets\r\n // so dropdowns, modals, etc. stay open while user edits content.\r\n this.editClickCaptureHandler = (e: Event) => {\r\n const target = e.target as HTMLElement;\r\n if (!target) return;\r\n\r\n const editable = target.closest('[contenteditable=\"true\"]') as HTMLElement | null;\r\n const imageTarget = target.closest('[data-cms-image-key], img[data-cms-key], [data-cms-key]') as HTMLElement | null;\r\n const isManagedEditable = !!editable && this.managedElements.has(editable);\r\n const isManagedImage = !!imageTarget && this.managedImages.has(imageTarget as HTMLImageElement);\r\n const isManagedTarget = isManagedEditable || isManagedImage || !!editable || !!imageTarget;\r\n\r\n if (isManagedTarget) {\r\n // Don't call focusEditableEnd - let browser handle cursor positioning naturally\r\n // Element will focus automatically, and cursor will be placed where user clicked\r\n e.stopPropagation();\r\n const anchor = target.closest('a');\r\n if (anchor) e.preventDefault();\r\n }\r\n };\r\n document.addEventListener('click', this.editClickCaptureHandler, true);\r\n document.addEventListener('mousedown', this.editClickCaptureHandler, true);\r\n document.addEventListener('pointerdown', this.editClickCaptureHandler, true);\r\n document.addEventListener('touchstart', this.editClickCaptureHandler, true);\r\n\r\n // Track scroll to toggle pointer-events on visible/hidden animated elements\r\n this.editScrollHandler = () => {\r\n if (this.editScrollRAF) return;\r\n this.editScrollRAF = requestAnimationFrame(() => {\r\n this.syncEditablePointerEvents();\r\n this.editScrollRAF = null;\r\n });\r\n };\r\n window.addEventListener('scroll', this.editScrollHandler, { passive: true });\r\n this.syncEditablePointerEvents();\r\n } else {\r\n // Clean up document-level capture handler\r\n if (this.editClickCaptureHandler) {\r\n document.removeEventListener('click', this.editClickCaptureHandler, true);\r\n document.removeEventListener('mousedown', this.editClickCaptureHandler, true);\r\n document.removeEventListener('pointerdown', this.editClickCaptureHandler, true);\r\n document.removeEventListener('touchstart', this.editClickCaptureHandler, true);\r\n this.editClickCaptureHandler = null;\r\n }\r\n // Clean up scroll listener\r\n if (this.editScrollHandler) {\r\n window.removeEventListener('scroll', this.editScrollHandler);\r\n this.editScrollHandler = null;\r\n }\r\n if (this.editScrollRAF) { cancelAnimationFrame(this.editScrollRAF); this.editScrollRAF = null; }\r\n // Restore pointer-events on all elements we modified\r\n for (const [el] of this.managedElements) el.style.pointerEvents = '';\r\n this.modifiedAncestors.forEach(a => { a.style.pointerEvents = ''; });\r\n this.modifiedAncestors.clear();\r\n }\r\n\r\n for (const [el, info] of this.managedElements) {\r\n if (editMode) this.enableElementEdit(el, info.key, info.blurHandler, info.keydownHandler, info.inputHandler, info.clickHandler);\r\n else this.disableElementEdit(el, info.key, info.blurHandler, info.keydownHandler, info.inputHandler, info.clickHandler);\r\n }\r\n this.applyImageEditMode(editMode);\r\n // Rich text toolbar lifecycle\r\n if (editMode) this.createRichToolbar();\r\n else this.destroyRichToolbar();\r\n }\r\n\r\n /** Set of positioned ancestors we added pointer-events:none to (for cleanup) */\r\n private modifiedAncestors = new Set<HTMLElement>();\r\n\r\n /**\r\n * For each managed element, find the nearest position:absolute/fixed ancestor.\r\n * If that ancestor is invisible (opacity ≈ 0), set pointer-events:none on it\r\n * so clicks pass through to the visible element behind it.\r\n */\r\n private syncEditablePointerEvents(): void {\r\n const checked = new Map<HTMLElement, boolean>();\r\n\r\n for (const [el] of this.managedElements) {\r\n const ancestor = this.findPositionedAncestor(el);\r\n if (!ancestor) continue;\r\n\r\n // Only compute once per ancestor\r\n if (!checked.has(ancestor)) {\r\n const cs = window.getComputedStyle(ancestor);\r\n const visible = parseFloat(cs.opacity) >= 0.15\r\n && cs.visibility !== 'hidden'\r\n && cs.display !== 'none';\r\n checked.set(ancestor, visible);\r\n\r\n if (!visible) {\r\n ancestor.style.pointerEvents = 'none';\r\n this.modifiedAncestors.add(ancestor);\r\n } else {\r\n if (this.modifiedAncestors.has(ancestor)) {\r\n ancestor.style.pointerEvents = '';\r\n this.modifiedAncestors.delete(ancestor);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** Walk up from el to find the nearest position:absolute or position:fixed ancestor */\r\n private findPositionedAncestor(el: HTMLElement): HTMLElement | null {\r\n let cur = el.parentElement;\r\n while (cur && cur !== document.body) {\r\n if (cur.closest('#xtroedge-cms-root')) return null;\r\n const pos = window.getComputedStyle(cur).position;\r\n if (pos === 'absolute' || pos === 'fixed') return cur;\r\n cur = cur.parentElement;\r\n }\r\n return null;\r\n }\r\n\r\n private killAnimations(): void {\r\n const win = window as any;\r\n\r\n // Kill GSAP ScrollTrigger (CDN or global version)\r\n if (win.ScrollTrigger) {\r\n try { win.ScrollTrigger.getAll().forEach((t: any) => t.kill(true)); } catch { /* ignore */ }\r\n }\r\n // Kill all GSAP tweens\r\n if (win.gsap) {\r\n try {\r\n win.gsap.globalTimeline.clear();\r\n win.gsap.killTweensOf('*');\r\n } catch { /* ignore */ }\r\n }\r\n // Disable AOS\r\n if (win.AOS) {\r\n try { win.AOS.refreshHard?.(); } catch { /* ignore */ }\r\n }\r\n\r\n // Remove GSAP pin-spacer wrappers\r\n this.removePinSpacers();\r\n\r\n // Clear GSAP-set inline styles from elements (one-time cleanup)\r\n this.clearAnimationInlineStyles();\r\n\r\n // Re-run after delay for late-initialized animations\r\n setTimeout(() => { this.removePinSpacers(); this.clearAnimationInlineStyles(); }, 500);\r\n setTimeout(() => { this.removePinSpacers(); this.clearAnimationInlineStyles(); }, 1500);\r\n }\r\n\r\n /** Remove GSAP ScrollTrigger pin-spacer wrapper divs and restore original elements */\r\n private removePinSpacers(): void {\r\n document.querySelectorAll('.pin-spacer').forEach(spacer => {\r\n const child = spacer.firstElementChild as HTMLElement;\r\n if (child) {\r\n spacer.parentNode?.insertBefore(child, spacer);\r\n child.style.cssText = '';\r\n }\r\n spacer.remove();\r\n });\r\n }\r\n\r\n /** Clear only animation-related inline styles (set by GSAP/ScrollTrigger) without breaking layout */\r\n private clearAnimationInlineStyles(): void {\r\n const container = this.containerSelector\r\n ? document.querySelector(this.containerSelector) || document.body\r\n : document.body;\r\n container.querySelectorAll<HTMLElement>('*').forEach(el => {\r\n if (el.closest('#xtroedge-cms-root')) return;\r\n const s = el.style;\r\n // Only clear properties that GSAP typically sets for animations\r\n if (s.pointerEvents === 'none') s.pointerEvents = '';\r\n if (s.userSelect === 'none') s.userSelect = '';\r\n if (s.visibility === 'hidden') s.visibility = '';\r\n if (s.clipPath && s.clipPath !== 'none') s.clipPath = '';\r\n });\r\n }\r\n\r\n /** Capture each element's current DOM text before CMS applies saved edits */\r\n private captureDomOriginals(): void {\r\n this.domOriginals = {};\r\n for (const [el, info] of this.managedElements) {\r\n this.domOriginals[info.key] = this.getElementContent(el);\r\n }\r\n }\r\n\r\n /** Ensure every entry in pageTexts has _orig for current language (from domOriginals) */\r\n private ensureOriginals(): void {\r\n const origKey = `_orig_${this.currentLang}`;\r\n for (const key of Object.keys(this.pageTexts)) {\r\n if (!this.pageTexts[key][origKey] && this.domOriginals[key]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key];\r\n }\r\n }\r\n }\r\n\r\n /** Find a managed element whose current text matches the given original text */\r\n private findElementByOriginal(originalText: string, tagName: string): HTMLElement | null {\r\n for (const [el] of this.managedElements) {\r\n if (el.tagName !== tagName) continue;\r\n const current = this.getElementContent(el);\r\n if (current === originalText) return el;\r\n }\r\n return null;\r\n }\r\n\r\n private updateElementTexts(): void {\r\n this.observer?.disconnect();\r\n let orphanedCount = 0;\r\n\r\n for (const [el, info] of this.managedElements) {\r\n if (document.activeElement === el) continue;\r\n const entry = this.pageTexts[info.key];\r\n if (!entry) continue;\r\n\r\n const val = entry[this.currentLang];\r\n if (!val) continue;\r\n\r\n const orig = entry[`_orig_${this.currentLang}`];\r\n\r\n // No original stored (old data) → apply directly (backward compat)\r\n if (!orig) {\r\n const current = this.getElementContent(el);\r\n if (val !== current) this.setElementContent(el, val);\r\n continue;\r\n }\r\n\r\n // Verify: does this element's DOM text match the saved original?\r\n const domText = this.domOriginals[info.key] || this.getElementContent(el);\r\n if (domText === orig) {\r\n // Match → apply\r\n if (val !== this.getElementContent(el)) this.setElementContent(el, val);\r\n } else {\r\n // Mismatch → structure may have changed\r\n // findElementByOriginal disabled: same text can appear multiple times on page\r\n // const found = this.findElementByOriginal(orig, el.tagName);\r\n // if (found) {\r\n // this.setElementContent(found, val);\r\n // } else {\r\n // orphanedCount++;\r\n // }\r\n orphanedCount++;\r\n }\r\n }\r\n\r\n // if (orphanedCount > 0) {\r\n // this.showToast(`${orphanedCount} edit(s) couldn't be matched to elements`, 'error');\r\n // }\r\n\r\n this.observer?.observe(document.body, { childList: true, subtree: true });\r\n\r\n // Rescan after a delay to ensure Angular/framework has finished re-rendering\r\n setTimeout(() => {\r\n if (this.editMode) {\r\n this.applyEditMode(true);\r\n }\r\n }, 200);\r\n }\r\n\r\n private cleanupManagedElements(): void {\r\n for (const [el] of this.managedElements) this.detachElement(el);\r\n this.managedElements.clear();\r\n for (const el of this.autoDetectedElements) el.removeAttribute('data-cms');\r\n this.autoDetectedElements.clear();\r\n this.domOriginals = {};\r\n this.cleanupManagedImages();\r\n }\r\n\r\n // ===============================================\r\n // IMAGE MANAGEMENT\r\n // ===============================================\r\n\r\n private attachImage(img: HTMLImageElement, key: string): void {\r\n const ctxHandler = (e: MouseEvent) => {\r\n if (!this.editMode) return;\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.showImageContextMenu(e.clientX, e.clientY, img);\r\n };\r\n this.managedImages.set(img, { key, ctxHandler });\r\n if (this.editMode) this.enableImageEdit(img, ctxHandler);\r\n }\r\n\r\n private detachImage(img: HTMLImageElement): void {\r\n const info = this.managedImages.get(img);\r\n if (info) {\r\n img.removeEventListener('contextmenu', info.ctxHandler);\r\n img.style.removeProperty('outline');\r\n img.style.cursor = '';\r\n this.managedImages.delete(img);\r\n }\r\n }\r\n\r\n private cleanupManagedImages(): void {\r\n for (const [img] of this.managedImages) this.detachImage(img);\r\n this.managedImages.clear();\r\n this.dismissImageCtxMenu();\r\n }\r\n\r\n private applyImageEditMode(editMode: boolean): void {\r\n for (const [img, info] of this.managedImages) {\r\n if (editMode) this.enableImageEdit(img, info.ctxHandler);\r\n else this.disableImageEdit(img, info.ctxHandler);\r\n }\r\n if (!editMode) {\r\n this.dismissImageCtxMenu();\r\n this.dismissFloatingEditDialog();\r\n }\r\n }\r\n\r\n private enableImageEdit(img: HTMLImageElement, ctxHandler: (e: MouseEvent) => void): void {\r\n if (!img.dataset.origTitle) img.dataset.origTitle = img.title || '';\r\n img.title = 'Right-click to change image';\r\n img.style.setProperty('outline', `2px dashed ${this.highlightColor}`, 'important');\r\n img.style.cursor = 'context-menu';\r\n img.addEventListener('contextmenu', ctxHandler);\r\n }\r\n\r\n private disableImageEdit(img: HTMLImageElement, ctxHandler: (e: MouseEvent) => void): void {\r\n img.title = img.dataset.origTitle || '';\r\n delete img.dataset.origTitle;\r\n img.style.removeProperty('outline');\r\n img.style.cursor = '';\r\n img.removeEventListener('contextmenu', ctxHandler);\r\n }\r\n\r\n private showImageContextMenu(x: number, y: number, img: HTMLImageElement): void {\r\n this.dismissImageCtxMenu();\r\n const menu = document.createElement('div');\r\n Object.assign(menu.style, {\r\n position: 'fixed', zIndex: '10005', minWidth: '160px',\r\n background: 'rgba(30,15,60,0.85)', backdropFilter: 'blur(16px)', webkitBackdropFilter: 'blur(16px)',\r\n border: '1px solid rgba(139,92,246,0.3)', borderRadius: '10px', padding: '4px',\r\n boxShadow: '0 8px 32px rgba(0,0,0,0.4)', fontFamily: 'system-ui, -apple-system, sans-serif',\r\n left: Math.min(x, window.innerWidth - 180) + 'px',\r\n top: Math.min(y, window.innerHeight - 50) + 'px',\r\n });\r\n const btn = document.createElement('button');\r\n Object.assign(btn.style, {\r\n width: '100%', padding: '8px 12px', border: 'none', borderRadius: '7px',\r\n background: 'transparent', color: 'white', fontSize: '12px', fontWeight: '500',\r\n cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px',\r\n });\r\n btn.innerHTML = `${ICON.image} Upload Image`;\r\n btn.addEventListener('mouseenter', () => btn.style.background = 'rgba(103,34,251,0.3)');\r\n btn.addEventListener('mouseleave', () => btn.style.background = 'transparent');\r\n btn.addEventListener('click', () => {\r\n this.activeImageEl = img;\r\n if (this.fileInput) { this.fileInput.value = ''; this.fileInput.click(); }\r\n this.dismissImageCtxMenu();\r\n });\r\n menu.appendChild(btn);\r\n (this.rootEl || document.body).appendChild(menu);\r\n this.imageCtxMenu = menu;\r\n\r\n const closeHandler = (e: MouseEvent) => {\r\n if (!menu.contains(e.target as Node)) {\r\n this.dismissImageCtxMenu();\r\n document.removeEventListener('mousedown', closeHandler);\r\n }\r\n };\r\n setTimeout(() => document.addEventListener('mousedown', closeHandler), 0);\r\n }\r\n\r\n private dismissImageCtxMenu(): void {\r\n if (this.imageCtxMenu) {\r\n this.imageCtxMenu.remove();\r\n this.imageCtxMenu = null;\r\n }\r\n }\r\n\r\n private showFloatingEditDialog(el: HTMLElement, key: string): void {\r\n this.dismissFloatingEditDialog();\r\n\r\n const currentText = el.textContent || '';\r\n const rect = el.getBoundingClientRect();\r\n\r\n const dialog = document.createElement('div');\r\n Object.assign(dialog.style, {\r\n position: 'fixed',\r\n zIndex: '99999',\r\n left: `${Math.max(20, rect.left)}px`,\r\n top: `${Math.max(20, rect.top - 120)}px`,\r\n background: 'rgba(15, 10, 40, 0.95)',\r\n backdropFilter: 'blur(20px)',\r\n webkitBackdropFilter: 'blur(20px)',\r\n border: '2px solid rgba(139, 92, 246, 0.5)',\r\n borderRadius: '12px',\r\n padding: '16px',\r\n boxShadow: '0 12px 48px rgba(0, 0, 0, 0.6)',\r\n minWidth: '320px',\r\n maxWidth: '500px',\r\n });\r\n\r\n const title = document.createElement('div');\r\n title.textContent = 'Edit Text';\r\n Object.assign(title.style, {\r\n color: 'rgba(255, 255, 255, 0.9)',\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n marginBottom: '12px',\r\n fontFamily: 'system-ui, sans-serif',\r\n });\r\n\r\n const textarea = document.createElement('textarea');\r\n textarea.value = currentText;\r\n Object.assign(textarea.style, {\r\n width: '100%',\r\n minHeight: '80px',\r\n background: 'rgba(255, 255, 255, 0.08)',\r\n border: '1px solid rgba(139, 92, 246, 0.3)',\r\n borderRadius: '8px',\r\n color: 'white',\r\n padding: '10px',\r\n fontSize: '14px',\r\n fontFamily: 'system-ui, sans-serif',\r\n resize: 'vertical',\r\n outline: 'none',\r\n });\r\n textarea.addEventListener('focus', () => {\r\n textarea.style.borderColor = this.highlightColor;\r\n });\r\n textarea.addEventListener('blur', () => {\r\n textarea.style.borderColor = 'rgba(139, 92, 246, 0.3)';\r\n });\r\n\r\n const buttons = document.createElement('div');\r\n Object.assign(buttons.style, {\r\n display: 'flex',\r\n gap: '8px',\r\n marginTop: '12px',\r\n justifyContent: 'flex-end',\r\n });\r\n\r\n const cancelBtn = document.createElement('button');\r\n cancelBtn.textContent = 'Cancel';\r\n Object.assign(cancelBtn.style, {\r\n padding: '8px 16px',\r\n background: 'rgba(255, 255, 255, 0.1)',\r\n border: 'none',\r\n borderRadius: '6px',\r\n color: 'rgba(255, 255, 255, 0.7)',\r\n fontSize: '13px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n fontFamily: 'system-ui, sans-serif',\r\n });\r\n cancelBtn.addEventListener('click', () => this.dismissFloatingEditDialog());\r\n cancelBtn.addEventListener('mouseenter', () => cancelBtn.style.background = 'rgba(255, 255, 255, 0.15)');\r\n cancelBtn.addEventListener('mouseleave', () => cancelBtn.style.background = 'rgba(255, 255, 255, 0.1)');\r\n\r\n const saveBtn = document.createElement('button');\r\n saveBtn.textContent = 'Save';\r\n Object.assign(saveBtn.style, {\r\n padding: '8px 16px',\r\n background: this.highlightColor,\r\n border: 'none',\r\n borderRadius: '6px',\r\n color: 'white',\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n cursor: 'pointer',\r\n fontFamily: 'system-ui, sans-serif',\r\n });\r\n saveBtn.addEventListener('click', () => {\r\n const newText = textarea.value;\r\n this.setElementContent(el, newText);\r\n this.onTextChanged(key, newText);\r\n this.dismissFloatingEditDialog();\r\n });\r\n saveBtn.addEventListener('mouseenter', () => saveBtn.style.opacity = '0.9');\r\n saveBtn.addEventListener('mouseleave', () => saveBtn.style.opacity = '1');\r\n\r\n buttons.appendChild(cancelBtn);\r\n buttons.appendChild(saveBtn);\r\n\r\n dialog.appendChild(title);\r\n dialog.appendChild(textarea);\r\n dialog.appendChild(buttons);\r\n\r\n (this.rootEl || document.body).appendChild(dialog);\r\n this.floatingEditDialog = dialog;\r\n\r\n textarea.focus();\r\n textarea.select();\r\n\r\n const closeHandler = (e: MouseEvent) => {\r\n if (!dialog.contains(e.target as Node)) {\r\n this.dismissFloatingEditDialog();\r\n document.removeEventListener('mousedown', closeHandler);\r\n }\r\n };\r\n setTimeout(() => document.addEventListener('mousedown', closeHandler), 0);\r\n }\r\n\r\n private dismissFloatingEditDialog(): void {\r\n if (this.floatingEditDialog) {\r\n this.floatingEditDialog.remove();\r\n this.floatingEditDialog = null;\r\n }\r\n }\r\n\r\n private onImageFileSelected(event: Event): void {\r\n const input = event.target as HTMLInputElement;\r\n const file = input.files?.[0];\r\n if (!file || !this.activeImageEl) return;\r\n\r\n this.imageUploading = true;\r\n this.updateUI();\r\n\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n const dataUrl = reader.result as string;\r\n this.uploadImageToApi(dataUrl);\r\n };\r\n reader.readAsDataURL(file);\r\n }\r\n\r\n private async uploadImageToApi(dataUrl: string): Promise<void> {\r\n try {\r\n // If image_url is set (from company detail), resolve it; otherwise use default\r\n const storedImageUrl = XtroedgeCMS.secureGet('xtroedge_image_url');\r\n const clientBase = this.config.clientApi || this.config.apiBase;\r\n const uploadUrl = storedImageUrl ? this.resolveClientUrl(storedImageUrl) : `${clientBase}/web/upload-image`;\r\n\r\n const res = await this.apiFetch(uploadUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ url: dataUrl }),\r\n });\r\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\r\n const data = await res.json();\r\n // Use apiBase origin as base for the returned image path\r\n const imgOriginBase = this.config.clientApi || this.config.apiBase || '';\r\n const baseUrl = this.config.imageBaseUrl || (imgOriginBase ? new URL(imgOriginBase).origin : '');\r\n const fullUrl = baseUrl + data.path;\r\n if (this.activeImageEl) {\r\n const key = this.managedImages.get(this.activeImageEl)?.key || '';\r\n this.activeImageEl.src = fullUrl;\r\n this.onImageChanged(key, fullUrl);\r\n }\r\n this.imageUploading = false;\r\n this.activeImageEl = null;\r\n this.updateUI();\r\n this.showToast('Image updated!', 'success');\r\n } catch (err) {\r\n this.imageUploading = false;\r\n this.activeImageEl = null;\r\n this.updateUI();\r\n this.showToast('Image upload failed.', 'error');\r\n this.config.onError?.('upload-image', err);\r\n }\r\n }\r\n\r\n private applyPageImages(): void {\r\n for (const [img, info] of this.managedImages) {\r\n const url = this.pageImages[info.key];\r\n if (url && img.src !== url) img.src = url;\r\n }\r\n }\r\n\r\n // ===============================================\r\n // TEXT STATE\r\n // ===============================================\r\n\r\n private getPageText(key: string): string {\r\n return this.pageTexts[key]?.[this.currentLang] || '';\r\n }\r\n\r\n private onTextChanged(key: string, newValue: string): void {\r\n this.undoStack.push(this.createSnapshot());\r\n this.redoStack = [];\r\n this.canUndo = true;\r\n this.canRedo = false;\r\n\r\n if (!this.pageTexts[key]) this.pageTexts[key] = {};\r\n // Store original DOM text on first edit (for structure-change resilience)\r\n const origKey = `_orig_${this.currentLang}`;\r\n if (!this.pageTexts[key][origKey]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key] || '';\r\n }\r\n this.pageTexts[key] = { ...this.pageTexts[key], [this.currentLang]: newValue };\r\n this.dirtyKeys.add(key);\r\n this.unsavedChanges = this.dirtyKeys.size + this.dirtyImageKeys.size;\r\n this.pushHistory(key, this.currentLang);\r\n this.updateUI();\r\n }\r\n\r\n private onImageChanged(key: string, url: string): void {\r\n this.undoStack.push(this.createSnapshot());\r\n this.redoStack = [];\r\n this.canUndo = true;\r\n this.canRedo = false;\r\n\r\n this.pageImages = { ...this.pageImages, [key]: url };\r\n this.dirtyImageKeys.add(key);\r\n this.unsavedChanges = this.dirtyKeys.size + this.dirtyImageKeys.size;\r\n this.pushHistory(key, 'img');\r\n this.updateUI();\r\n }\r\n\r\n private createSnapshot(): string {\r\n return JSON.stringify({ texts: this.pageTexts, images: this.pageImages });\r\n }\r\n\r\n private applySnapshot(raw: string): void {\r\n const data = JSON.parse(raw);\r\n if (data.texts) {\r\n this.pageTexts = data.texts;\r\n if (data.images) this.pageImages = data.images;\r\n } else {\r\n this.pageTexts = data;\r\n }\r\n }\r\n\r\n // ===============================================\r\n // RICH TEXT TOOLBAR\r\n // ===============================================\r\n\r\n private get richTextEnabled(): boolean {\r\n return this.config.richText !== false; // default true\r\n }\r\n\r\n // Tags where Enter should be blocked (single-line elements)\r\n private static readonly SINGLE_LINE_TAGS = new Set([\r\n 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BUTTON', 'LABEL', 'SPAN', 'A', 'SMALL', 'B', 'STRONG', 'I', 'EM',\r\n ]);\r\n\r\n // Allowed HTML tags for sanitization\r\n private static readonly ALLOWED_TAGS = new Set([\r\n 'B', 'STRONG', 'I', 'EM', 'U', 'S', 'STRIKE', 'A', 'BR', 'UL', 'OL', 'LI', 'SUB', 'SUP',\r\n ]);\r\n\r\n // Allowed attributes per tag\r\n private static readonly ALLOWED_ATTRS: Record<string, Set<string>> = {\r\n A: new Set(['href', 'target', 'rel']),\r\n };\r\n\r\n private sanitizeHTML(html: string): string {\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n const clean = (node: Node): void => {\r\n const children = Array.from(node.childNodes);\r\n for (const child of children) {\r\n if (child.nodeType === Node.TEXT_NODE) continue;\r\n if (child.nodeType === Node.ELEMENT_NODE) {\r\n const el = child as HTMLElement;\r\n if (!XtroedgeCMS.ALLOWED_TAGS.has(el.tagName)) {\r\n // Unwrap: keep children, remove the tag\r\n while (el.firstChild) el.parentNode?.insertBefore(el.firstChild, el);\r\n el.remove();\r\n } else {\r\n // Remove disallowed attributes\r\n const allowedAttrs = XtroedgeCMS.ALLOWED_ATTRS[el.tagName] || new Set();\r\n for (const attr of Array.from(el.attributes)) {\r\n if (!allowedAttrs.has(attr.name)) el.removeAttribute(attr.name);\r\n }\r\n // Sanitize href to prevent javascript: URLs\r\n if (el.tagName === 'A') {\r\n const href = el.getAttribute('href') || '';\r\n if (href.trim().toLowerCase().startsWith('javascript:')) {\r\n el.setAttribute('href', '#');\r\n }\r\n }\r\n clean(el);\r\n }\r\n } else {\r\n child.remove(); // Remove comments, etc.\r\n }\r\n }\r\n };\r\n clean(doc.body);\r\n return doc.body.innerHTML;\r\n }\r\n\r\n private createRichToolbar(): void {\r\n if (!this.richTextEnabled || this.richToolbarEl) return;\r\n\r\n const toolbar = document.createElement('div');\r\n toolbar.className = 'lcms-rich-toolbar';\r\n\r\n const buttons: { cmd: string; label: string; title: string }[] = [\r\n { cmd: 'bold', label: 'B', title: 'Bold' },\r\n { cmd: 'italic', label: '<i>I</i>', title: 'Italic' },\r\n { cmd: 'underline', label: '<u>U</u>', title: 'Underline' },\r\n { cmd: 'strikeThrough', label: '<s>S</s>', title: 'Strikethrough' },\r\n ];\r\n\r\n const linkButtons: { cmd: string; label: string; title: string }[] = [\r\n { cmd: 'createLink', label: '🔗', title: 'Insert Link' },\r\n { cmd: 'unlink', label: '⊘', title: 'Remove Link' },\r\n ];\r\n\r\n const utilButtons: { cmd: string; label: string; title: string }[] = [\r\n { cmd: 'removeFormat', label: '✕', title: 'Clear Formatting' },\r\n ];\r\n\r\n const makeBtn = (item: { cmd: string; label: string; title: string }) => {\r\n const btn = document.createElement('button');\r\n btn.innerHTML = item.label;\r\n btn.title = item.title;\r\n btn.dataset.cmd = item.cmd;\r\n btn.addEventListener('mousedown', (e) => {\r\n e.preventDefault(); // Prevent blur on the editable element\r\n this.execToolbarCommand(item.cmd);\r\n });\r\n return btn;\r\n };\r\n\r\n const addSep = () => {\r\n const sep = document.createElement('div');\r\n sep.className = 'lcms-tb-sep';\r\n toolbar.appendChild(sep);\r\n };\r\n\r\n buttons.forEach(b => toolbar.appendChild(makeBtn(b)));\r\n addSep();\r\n linkButtons.forEach(b => toolbar.appendChild(makeBtn(b)));\r\n addSep();\r\n utilButtons.forEach(b => toolbar.appendChild(makeBtn(b)));\r\n\r\n this.rootEl?.appendChild(toolbar);\r\n this.richToolbarEl = toolbar;\r\n\r\n // Listen for selection changes to update active states\r\n this.selectionChangeHandler = () => this.updateToolbarState();\r\n document.addEventListener('selectionchange', this.selectionChangeHandler);\r\n }\r\n\r\n private destroyRichToolbar(): void {\r\n if (this.richToolbarEl) {\r\n this.richToolbarEl.remove();\r\n this.richToolbarEl = null;\r\n }\r\n if (this.selectionChangeHandler) {\r\n document.removeEventListener('selectionchange', this.selectionChangeHandler);\r\n this.selectionChangeHandler = null;\r\n }\r\n this.activeEditableEl = null;\r\n }\r\n\r\n private execToolbarCommand(cmd: string): void {\r\n // Pause MutationObserver so DOM changes from execCommand don't trigger rescan\r\n this.observer?.disconnect();\r\n if (this.scanTimeout) { clearTimeout(this.scanTimeout); this.scanTimeout = null; }\r\n\r\n if (cmd === 'createLink') {\r\n const url = prompt('Enter URL:', 'https://');\r\n if (url) document.execCommand('createLink', false, url);\r\n } else {\r\n document.execCommand(cmd, false);\r\n }\r\n this.updateToolbarState();\r\n // Trigger input to capture the change\r\n if (this.activeEditableEl) {\r\n this.activeEditableEl.dispatchEvent(new Event('input', { bubbles: true }));\r\n }\r\n\r\n // Re-enable observer after a short delay\r\n setTimeout(() => {\r\n this.observer?.observe(document.body, { childList: true, subtree: true });\r\n }, 50);\r\n }\r\n\r\n private showRichToolbar(el: HTMLElement): void {\r\n if (!this.richTextEnabled || !this.richToolbarEl) return;\r\n if (this.toolbarHideTimeout) { clearTimeout(this.toolbarHideTimeout); this.toolbarHideTimeout = null; }\r\n\r\n this.activeEditableEl = el;\r\n this.positionToolbar(el);\r\n this.richToolbarEl.classList.add('visible');\r\n this.updateToolbarState();\r\n }\r\n\r\n private positionToolbar(el: HTMLElement): void {\r\n if (!this.richToolbarEl) return;\r\n const rect = el.getBoundingClientRect();\r\n const tbRect = this.richToolbarEl.getBoundingClientRect();\r\n let top = rect.top - tbRect.height - 8;\r\n let left = rect.left + (rect.width / 2) - (tbRect.width / 2);\r\n\r\n // If above viewport, show below element\r\n if (top < 4) top = rect.bottom + 8;\r\n // Keep within horizontal bounds\r\n if (left < 4) left = 4;\r\n if (left + tbRect.width > window.innerWidth - 4) left = window.innerWidth - tbRect.width - 4;\r\n\r\n this.richToolbarEl.style.top = `${top}px`;\r\n this.richToolbarEl.style.left = `${left}px`;\r\n }\r\n\r\n private hideRichToolbar(): void {\r\n if (!this.richToolbarEl) return;\r\n // Small delay so user can click toolbar buttons without it hiding\r\n this.toolbarHideTimeout = setTimeout(() => {\r\n this.richToolbarEl?.classList.remove('visible');\r\n this.activeEditableEl = null;\r\n this.toolbarHideTimeout = null;\r\n }, 150);\r\n }\r\n\r\n private updateToolbarState(): void {\r\n if (!this.richToolbarEl) return;\r\n const cmds = ['bold', 'italic', 'underline', 'strikeThrough'];\r\n for (const btn of Array.from(this.richToolbarEl.querySelectorAll('button'))) {\r\n const cmd = (btn as HTMLElement).dataset.cmd;\r\n if (cmd && cmds.includes(cmd)) {\r\n try {\r\n (btn as HTMLElement).classList.toggle('active', document.queryCommandState(cmd));\r\n } catch { /* ignore */ }\r\n }\r\n }\r\n }\r\n\r\n // ===============================================\r\n // UNDO / REDO\r\n // ===============================================\r\n\r\n private onUndo(): void {\r\n if (this.undoStack.length === 0) return;\r\n this.redoStack.push(this.createSnapshot());\r\n this.applySnapshot(this.undoStack.pop()!);\r\n this.canUndo = this.undoStack.length > 0;\r\n this.canRedo = true;\r\n this.recalcDirtyKeys();\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n }\r\n\r\n private onRedo(): void {\r\n if (this.redoStack.length === 0) return;\r\n this.undoStack.push(this.createSnapshot());\r\n this.applySnapshot(this.redoStack.pop()!);\r\n this.canUndo = true;\r\n this.canRedo = this.redoStack.length > 0;\r\n this.recalcDirtyKeys();\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n }\r\n\r\n private recalcDirtyKeys(): void {\r\n this.dirtyKeys.clear();\r\n for (const key of this.registeredKeys) {\r\n if (JSON.stringify(this.pageTexts[key]) !== JSON.stringify(this.originalTexts[key])) {\r\n this.dirtyKeys.add(key);\r\n }\r\n }\r\n this.unsavedChanges = this.dirtyKeys.size + this.dirtyImageKeys.size;\r\n }\r\n\r\n private resetAll(): void {\r\n this.dirtyKeys.clear();\r\n this.dirtyImageKeys.clear();\r\n this.unsavedChanges = 0;\r\n this.undoStack = [];\r\n this.redoStack = [];\r\n this.canUndo = false;\r\n this.canRedo = false;\r\n this.updateUI();\r\n }\r\n\r\n private resetAfterSave(): void {\r\n this.dirtyKeys.clear();\r\n this.dirtyImageKeys.clear();\r\n this.unsavedChanges = 0;\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n }\r\n\r\n private cancelEditing(): void {\r\n this.pageTexts = JSON.parse(JSON.stringify(this.originalTexts));\r\n this.pageImages = JSON.parse(JSON.stringify(this.originalImages));\r\n this.dirtyKeys.clear();\r\n this.dirtyImageKeys.clear();\r\n this.unsavedChanges = 0;\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n }\r\n\r\n private logout(): void {\r\n XtroedgeCMS.secureClear();\r\n sessionStorage.removeItem('builder_edit_mode');\r\n this.editMode = false;\r\n this.isEditAllowed = false;\r\n this.applyEditMode(false);\r\n this.isOpen = false;\r\n this.updateUI();\r\n this.showToast('Logged out', 'success');\r\n }\r\n\r\n // ===============================================\r\n // API\r\n // ===============================================\r\n\r\n private async loadTranslationsAndInit(loadDraft: boolean): Promise<void> {\r\n if (this.config.i18nBasePath) {\r\n try {\r\n const lang = this.currentLang;\r\n const res = await fetch(`${this.config.i18nBasePath}/${lang}.json`);\r\n if (res.ok) {\r\n const translations = await res.json();\r\n this.translationCache.clear();\r\n this.flattenTranslations(translations, '', this.getPageSection());\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n\r\n this.autoDetectAndScan();\r\n this.captureDomOriginals();\r\n if (this.editMode) this.applyEditMode(true);\r\n if (this.config.apiBase) {\r\n if (loadDraft) this.loadPageContent('draft');\r\n else this.loadPublishedContent();\r\n } else {\r\n this.buildDefaultTexts();\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n this.setLoading(false);\r\n }\r\n this.updateUI();\r\n }\r\n\r\n private flattenTranslations(obj: any, prefix: string, pageSection: string): void {\r\n for (const k of Object.keys(obj)) {\r\n const fullKey = prefix ? `${prefix}.${k}` : k;\r\n if (typeof obj[k] === 'string') {\r\n const text = obj[k].trim();\r\n if (text.length >= 2) {\r\n const existing = this.translationCache.get(text);\r\n if (!existing || fullKey.toUpperCase().startsWith(pageSection)) {\r\n this.translationCache.set(text, fullKey);\r\n }\r\n }\r\n } else if (typeof obj[k] === 'object' && obj[k] !== null && !Array.isArray(obj[k])) {\r\n this.flattenTranslations(obj[k], fullKey, pageSection);\r\n }\r\n }\r\n }\r\n\r\n private getPageSection(): string {\r\n return this.currentSlug.replace(/^\\//, '').replace(/-/g, '_').toUpperCase();\r\n }\r\n\r\n /** Resolve a stored URL against our server (apiBase) */\r\n private resolveServerUrl(storedUrl: string): string {\r\n if (storedUrl.startsWith('/')) return `${this.config.apiBase}${storedUrl}`;\r\n return storedUrl;\r\n }\r\n\r\n /** Resolve a stored URL against client's server (clientApi, falls back to apiBase) */\r\n private resolveClientUrl(storedUrl: string): string {\r\n const base = this.config.clientApi || this.config.apiBase;\r\n if (storedUrl.startsWith('/')) return `${base}${storedUrl}`;\r\n return storedUrl;\r\n }\r\n\r\n private apiFetch(url: string, opts?: RequestInit): Promise<Response> {\r\n const token = XtroedgeCMS.secureGet('builder_token') || '';\r\n const licenseKey = this.config.licenseKey || '';\r\n const headers: Record<string, string> = { ...(opts?.headers as Record<string, string> || {}) };\r\n if (token) headers['Authorization'] = `Bearer ${token}`;\r\n if (licenseKey) headers['X-License-Key'] = licenseKey;\r\n\r\n // Merge client headers only for requests going to client's server (not our apiBase)\r\n const isOurServer = this.config.apiBase && url.startsWith(this.config.apiBase);\r\n if (!isOurServer && this.config.clientHeaders) {\r\n for (const [k, v] of Object.entries(this.config.clientHeaders)) {\r\n if (!headers[k]) headers[k] = v;\r\n }\r\n }\r\n\r\n return fetch(url, { ...opts, headers });\r\n }\r\n\r\n // Fetch page by slug — if get_url exists in localStorage, call it directly (bypass our server)\r\n private async fetchSection(slug: string, status?: string): Promise<WebPageContent | null> {\r\n try {\r\n const storedGetUrl = XtroedgeCMS.secureGet('xtroedge_get_url');\r\n const clientBase = this.config.clientApi || this.config.apiBase;\r\n const getBase = storedGetUrl ? this.resolveClientUrl(storedGetUrl) : `${clientBase}/web-page/get`;\r\n let getUrl = `${getBase}?slug=${encodeURIComponent(slug)}`;\r\n if (status) getUrl += `&status=${encodeURIComponent(status)}`;\r\n const res = await this.apiFetch(getUrl);\r\n if (!res.ok) return null;\r\n return await res.json();\r\n } catch { return null; }\r\n }\r\n\r\n private hasSection(type: 'header' | 'footer'): boolean {\r\n const slug = type === 'header' ? '/header' : '/footer';\r\n for (const [, info] of this.managedElements) {\r\n if (info.sectionSlug === slug) return true;\r\n }\r\n return false;\r\n }\r\n\r\n private async loadPageContent(status: 'draft' | 'published'): Promise<void> {\r\n this.setLoading(true);\r\n this.cleanOldHistory();\r\n\r\n try {\r\n // Only fetch sections that exist in the DOM\r\n const requests: Promise<WebPageContent | null>[] = [this.fetchSection(this.currentSlug, status)];\r\n const hasHeader = this.hasSection('header');\r\n const hasFooter = this.hasSection('footer');\r\n if (hasHeader) requests.push(this.fetchSection('/header', status));\r\n if (hasFooter) requests.push(this.fetchSection('/footer', status));\r\n\r\n const results = await Promise.all(requests);\r\n const pageSec = results[0];\r\n const headerSec = hasHeader ? results[1] : null;\r\n const footerSec = hasFooter ? results[hasHeader ? 2 : 1] : null;\r\n\r\n const getTexts = (sec: WebPageContent | null) => sec?.content?.texts || sec?.published_content?.texts || null;\r\n const pageTexts = getTexts(pageSec);\r\n const headerTexts = getTexts(headerSec);\r\n const footerTexts = getTexts(footerSec);\r\n\r\n if (pageTexts || headerTexts || footerTexts) {\r\n this.pageTexts = { ...(pageTexts || {}), ...(headerTexts || {}), ...(footerTexts || {}) };\r\n } else {\r\n this.buildDefaultTexts();\r\n }\r\n\r\n // Extract images from the page response (no extra API call)\r\n const images = pageSec?.content?.images || pageSec?.published_content?.images;\r\n if (images) {\r\n this.pageImages = JSON.parse(JSON.stringify(images));\r\n this.applyPageImages();\r\n }\r\n\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n this.resetAll();\r\n this.updateElementTexts();\r\n } catch {\r\n this.buildDefaultTexts();\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n this.resetAll();\r\n } finally {\r\n this.setLoading(false);\r\n }\r\n }\r\n\r\n private async loadPublishedContent(): Promise<void> {\r\n this.setLoading(true);\r\n\r\n try {\r\n // Only fetch sections that exist in the DOM\r\n const requests: Promise<WebPageContent | null>[] = [this.fetchSection(this.currentSlug, 'published')];\r\n const hasHeader = this.hasSection('header');\r\n const hasFooter = this.hasSection('footer');\r\n if (hasHeader) requests.push(this.fetchSection('/header', 'published'));\r\n if (hasFooter) requests.push(this.fetchSection('/footer', 'published'));\r\n\r\n const results = await Promise.all(requests);\r\n const pageSec = results[0];\r\n const headerSec = hasHeader ? results[1] : null;\r\n const footerSec = hasFooter ? results[hasHeader ? 2 : 1] : null;\r\n\r\n const getTexts = (sec: WebPageContent | null) => sec?.published_content?.texts || null;\r\n const merged = { ...(getTexts(pageSec) || {}), ...(getTexts(headerSec) || {}), ...(getTexts(footerSec) || {}) };\r\n if (Object.keys(merged).length > 0) {\r\n this.pageTexts = JSON.parse(JSON.stringify(merged));\r\n this.updateElementTexts();\r\n }\r\n\r\n // Extract images from page response (no extra API call)\r\n const images = pageSec?.published_content?.images;\r\n if (images && Object.keys(images).length > 0) {\r\n this.pageImages = JSON.parse(JSON.stringify(images));\r\n this.applyPageImages();\r\n }\r\n } catch { /* ignore - use current DOM text */ }\r\n finally { this.setLoading(false); }\r\n }\r\n\r\n private buildDefaultTexts(): void {\r\n const texts: { [key: string]: PageTextEntry } = {};\r\n for (const key of this.registeredKeys) {\r\n const el = document.querySelector(`[data-cms=\"${key}\"]`);\r\n const val = el?.textContent?.trim() || '';\r\n // Only store DOM text under the default language — other languages start empty\r\n // so users must translate them explicitly\r\n const entry: PageTextEntry = { [this.defaultLanguage]: val };\r\n texts[key] = entry;\r\n }\r\n this.pageTexts = texts;\r\n\r\n // Load other languages from i18n files if available\r\n if (this.config.i18nBasePath) {\r\n const otherLangs = this.languages.filter(l => l !== this.currentLang);\r\n for (const lang of otherLangs) {\r\n fetch(`${this.config.i18nBasePath}/${lang}.json`)\r\n .then(r => r.json())\r\n .then(translations => {\r\n const updated = { ...this.pageTexts };\r\n for (const key of this.registeredKeys) {\r\n // Try to resolve key path in translations\r\n const parts = key.split('.');\r\n let val: any = translations;\r\n for (const part of parts) { val = val?.[part]; }\r\n if (val && typeof val === 'string') {\r\n updated[key] = { ...updated[key], [lang]: val };\r\n }\r\n }\r\n this.pageTexts = updated;\r\n this.originalTexts = JSON.parse(JSON.stringify(updated));\r\n this.updateElementTexts();\r\n })\r\n .catch(() => { /* ignore */ });\r\n }\r\n }\r\n }\r\n\r\n // Group pageTexts by section slug based on managedElements info\r\n private groupTextsBySection(): { [sectionSlug: string]: { [key: string]: PageTextEntry } } {\r\n const sections: { [sectionSlug: string]: { [key: string]: PageTextEntry } } = {};\r\n for (const [, info] of this.managedElements) {\r\n const slug = info.sectionSlug;\r\n if (!sections[slug]) sections[slug] = {};\r\n if (this.pageTexts[info.key] !== undefined) {\r\n sections[slug][info.key] = this.pageTexts[info.key];\r\n }\r\n }\r\n return sections;\r\n }\r\n\r\n private async saveChanges(): Promise<void> {\r\n if (!this.licenseValid) {\r\n this.showLicenseExpiredToast();\r\n return;\r\n }\r\n if (!this.config.apiBase) {\r\n this.showToast('No API configured. Set apiBase to enable save.', 'error');\r\n return;\r\n }\r\n this.isSaving = true;\r\n this.updateUI();\r\n\r\n // Ensure _orig for current language is stored for ALL entries before saving\r\n const origKey = `_orig_${this.currentLang}`;\r\n for (const key of Object.keys(this.pageTexts)) {\r\n if (!this.pageTexts[key][origKey] && this.domOriginals[key]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key];\r\n }\r\n }\r\n\r\n try {\r\n const sections = this.groupTextsBySection();\r\n const requests = Object.entries(sections).map(([slug, texts]) =>\r\n this.apiFetch(`${this.config.apiBase}/web_page/save`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n slug,\r\n title: slug === this.currentSlug ? this.currentTitle : slug.replace('/', ''),\r\n content: { texts, ...(slug === this.currentSlug ? { images: this.pageImages } : {}) }\r\n }),\r\n })\r\n );\r\n const responses = await Promise.all(requests);\r\n const saveResults: any[] = [];\r\n for (const res of responses) {\r\n const data = await res.json();\r\n saveResults.push({ ok: res.ok, status: res.status, data });\r\n }\r\n if (saveResults.some(r => !r.ok)) throw new Error('One or more sections failed to save');\r\n console.info('[XtroEdge] Save responses:', saveResults.map(r => r.data));\r\n this.isSaving = false;\r\n this.resetAfterSave();\r\n this.updateUI();\r\n this.showToast('Draft saved successfully!', 'success');\r\n this.config.onSaved?.();\r\n } catch (err) {\r\n this.isSaving = false;\r\n this.updateUI();\r\n this.showToast('Save failed. Please try again.', 'error');\r\n this.config.onError?.('save', err);\r\n }\r\n }\r\n\r\n private async publishChanges(): Promise<void> {\r\n if (!this.licenseValid) {\r\n this.showLicenseExpiredToast();\r\n return;\r\n }\r\n if (!this.config.apiBase) {\r\n this.showToast('No API configured. Set apiBase to enable publish.', 'error');\r\n return;\r\n }\r\n this.isPublishing = true;\r\n this.updateUI();\r\n\r\n // Ensure _orig for current language is stored for ALL entries before publishing\r\n const origKey = `_orig_${this.currentLang}`;\r\n for (const key of Object.keys(this.pageTexts)) {\r\n if (!this.pageTexts[key][origKey] && this.domOriginals[key]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key];\r\n }\r\n }\r\n\r\n try {\r\n const sections = this.groupTextsBySection();\r\n\r\n const requests = Object.entries(sections).map(([slug, texts]) =>\r\n this.apiFetch(`${this.config.apiBase}/web_page/publish`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n slug,\r\n title: slug === this.currentSlug ? this.currentTitle : slug.replace('/', ''),\r\n published_content: { texts, ...(slug === this.currentSlug ? { images: this.pageImages } : {}) },\r\n }),\r\n })\r\n );\r\n\r\n const results = await Promise.all(requests);\r\n const publishResults: any[] = [];\r\n for (const res of results) {\r\n const data = await res.json();\r\n publishResults.push({ ok: res.ok, status: res.status, data });\r\n }\r\n if (publishResults.some(r => !r.ok)) throw new Error('One or more sections failed to publish');\r\n console.info('[XtroEdge] Publish responses:', publishResults.map(r => r.data));\r\n this.isPublishing = false;\r\n this.resetAfterSave();\r\n this.updateUI();\r\n this.showToast('Published successfully!', 'success');\r\n this.config.onPublished?.();\r\n } catch (err) {\r\n this.isPublishing = false;\r\n this.updateUI();\r\n this.showToast('Publish failed. Please try again.', 'error');\r\n this.config.onError?.('publish', err);\r\n }\r\n }\r\n\r\n // ===============================================\r\n // HISTORY (IndexedDB)\r\n // ===============================================\r\n\r\n private async toggleHistory(): Promise<void> {\r\n this.showHistory = !this.showHistory;\r\n if (this.showHistory) await this.loadHistory();\r\n this.updateUI();\r\n }\r\n\r\n private async loadHistory(): Promise<void> {\r\n try {\r\n const db = await this.openDB();\r\n const entries = await new Promise<EditHistoryEntry[]>((resolve, reject) => {\r\n const tx = db.transaction(STORE_NAME, 'readonly');\r\n const store = tx.objectStore(STORE_NAME);\r\n const index = store.index('slug');\r\n const req = index.getAll(this.currentSlug);\r\n req.onsuccess = () => resolve((req.result as EditHistoryEntry[]).sort((a, b) => b.timestamp - a.timestamp).slice(0, 30));\r\n req.onerror = () => reject(req.error);\r\n });\r\n this.historyList = entries;\r\n this.renderHistoryList();\r\n } catch { /* ignore */ }\r\n }\r\n\r\n private renderHistoryList(): void {\r\n if (!this.historyListEl) return;\r\n this.historyListEl.innerHTML = '';\r\n if (this.historyList.length === 0) {\r\n const empty = this.createElement('div', 'lcms-history-empty');\r\n empty.textContent = 'No history yet';\r\n this.historyListEl.appendChild(empty);\r\n return;\r\n }\r\n for (const entry of this.historyList) {\r\n const item = document.createElement('button');\r\n item.className = 'lcms-history-item';\r\n const labelEl = this.createElement('div', 'lcms-history-label');\r\n labelEl.textContent = entry.label;\r\n const metaEl = this.createElement('div', 'lcms-history-meta');\r\n const langEl = this.createElement('span', 'lcms-history-lang');\r\n langEl.textContent = entry.lang.toUpperCase();\r\n const dateText = document.createTextNode(' ' + this.formatDate(entry.timestamp));\r\n metaEl.appendChild(langEl);\r\n metaEl.appendChild(dateText);\r\n item.appendChild(labelEl);\r\n item.appendChild(metaEl);\r\n item.addEventListener('click', (e) => { e.stopPropagation(); this.restoreHistory(entry); });\r\n this.historyListEl.appendChild(item);\r\n }\r\n }\r\n\r\n private restoreHistory(entry: EditHistoryEntry): void {\r\n this.undoStack.push(this.createSnapshot());\r\n this.canUndo = true;\r\n this.applySnapshot(entry.snapshot);\r\n this.recalcDirtyKeys();\r\n this.showHistory = false;\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n this.showToast('Restored from history', 'success');\r\n }\r\n\r\n private pushHistory(key: string, lang: string): void {\r\n const isImage = lang === 'img';\r\n const shortKey = isImage ? key.split('/').pop() || 'image' : (key.split('_').pop() || key);\r\n const label = isImage ? `Changed ${shortKey}` : `Edited ${shortKey}`;\r\n this.openDB().then(db => {\r\n const tx = db.transaction(STORE_NAME, 'readwrite');\r\n tx.objectStore(STORE_NAME).add({\r\n slug: this.currentSlug, timestamp: Date.now(),\r\n label, lang,\r\n snapshot: JSON.stringify({ texts: this.pageTexts, images: this.pageImages })\r\n });\r\n }).catch(() => { /* ignore */ });\r\n }\r\n\r\n private async cleanOldHistory(): Promise<void> {\r\n try {\r\n const db = await this.openDB();\r\n const cutoff = Date.now() - this.historyRetentionMs;\r\n const tx = db.transaction(STORE_NAME, 'readwrite');\r\n const index = tx.objectStore(STORE_NAME).index('timestamp');\r\n const req = index.openCursor(IDBKeyRange.upperBound(cutoff));\r\n req.onsuccess = () => { const c = req.result; if (c) { c.delete(); c.continue(); } };\r\n } catch { /* ignore */ }\r\n }\r\n\r\n private openDB(): Promise<IDBDatabase> {\r\n if (this.db) return Promise.resolve(this.db);\r\n return new Promise((resolve, reject) => {\r\n const req = indexedDB.open(DB_NAME, 1);\r\n req.onupgradeneeded = () => {\r\n const db = req.result;\r\n if (!db.objectStoreNames.contains(STORE_NAME)) {\r\n const store = db.createObjectStore(STORE_NAME, { keyPath: 'id', autoIncrement: true });\r\n store.createIndex('slug', 'slug', { unique: false });\r\n store.createIndex('timestamp', 'timestamp', { unique: false });\r\n }\r\n };\r\n req.onsuccess = () => { this.db = req.result; resolve(this.db); };\r\n req.onerror = () => reject(req.error);\r\n });\r\n }\r\n\r\n // ===============================================\r\n // TOAST\r\n // ===============================================\r\n\r\n private showToast(message: string, type: 'success' | 'error'): void {\r\n if (!this.toastEl) return;\r\n this.toastMessage = message;\r\n this.toastType = type;\r\n\r\n const icon = type === 'success' ? ICON.check : ICON.error;\r\n this.toastEl.className = `lcms-toast lcms-toast-${type}`;\r\n this.toastEl.innerHTML = `${icon} ${message}`;\r\n\r\n if (this.toastTimer) clearTimeout(this.toastTimer);\r\n this.toastTimer = setTimeout(() => {\r\n if (this.toastEl) this.toastEl.classList.add('lcms-hidden');\r\n }, 3000);\r\n }\r\n\r\n // ===============================================\r\n // FAB & PANEL\r\n // ===============================================\r\n\r\n private onFabClick(e: Event): void {\r\n e.stopPropagation();\r\n if (this.hasMoved) return;\r\n this.isOpen = !this.isOpen;\r\n this.updateUI();\r\n }\r\n\r\n private togglePanel(): void {\r\n if (!this.hasMoved) {\r\n this.isOpen = !this.isOpen;\r\n this.updateUI();\r\n }\r\n }\r\n\r\n private toggleEditMode(e: Event): void {\r\n e.stopPropagation();\r\n const checked = (e.target as HTMLInputElement).checked;\r\n\r\n // Gate: block edit mode if license is not valid\r\n if (checked && !this.licenseValid) {\r\n (e.target as HTMLInputElement).checked = false;\r\n this.showLicenseExpiredToast();\r\n return;\r\n }\r\n\r\n if (checked) {\r\n sessionStorage.setItem('builder_edit_mode', 'true');\r\n this.editMode = true;\r\n this.currentLang = this.detectCurrentLanguage();\r\n this.applyEditMode(true);\r\n this.loadPageContent('draft');\r\n } else {\r\n sessionStorage.removeItem('builder_edit_mode');\r\n this.editMode = false;\r\n this.applyEditMode(false);\r\n }\r\n this.updateUI();\r\n this.config.onEditModeChanged?.(this.editMode);\r\n }\r\n\r\n private switchLang(lang: string): void {\r\n this.currentLang = lang;\r\n\r\n // 1. Persist language so framework picks it up after reload\r\n localStorage.setItem('selectedLanguage', lang);\r\n document.documentElement.setAttribute('lang', lang);\r\n document.documentElement.setAttribute('dir', lang === 'ar' ? 'rtl' : 'ltr');\r\n\r\n // 2. Notify (fires before reload so any sync listener can catch it)\r\n this.config.onLangChanged?.(lang);\r\n window.dispatchEvent(new CustomEvent('cms:langChanged', { detail: { lang } }));\r\n\r\n // 3. Reload so the framework re-initializes with the new language\r\n window.location.reload();\r\n }\r\n\r\n // ===============================================\r\n // FAB DRAG\r\n // ===============================================\r\n\r\n private onDragStart(e: MouseEvent): void {\r\n if ((e.target as HTMLElement).closest('button:not(.lcms-fab-btn)') || (e.target as HTMLElement).closest('.lcms-panel')) return;\r\n this.isDragging = true;\r\n this.hasMoved = false;\r\n this.dragStartX = e.clientX;\r\n this.dragStartY = e.clientY;\r\n this.startPosX = this.posX;\r\n this.startPosY = this.posY;\r\n document.addEventListener('mousemove', this.boundMouseMove);\r\n document.addEventListener('mouseup', this.boundMouseUp);\r\n }\r\n\r\n private onDragMove(e: MouseEvent): void {\r\n if (!this.isDragging || !this.fabEl) return;\r\n const dx = e.clientX - this.dragStartX, dy = e.clientY - this.dragStartY;\r\n if (Math.abs(dx) > 3 || Math.abs(dy) > 3) this.hasMoved = true;\r\n this.posX = Math.max(0, Math.min(window.innerWidth - 60, this.startPosX + dx));\r\n this.posY = Math.max(0, Math.min(window.innerHeight - 60, this.startPosY + dy));\r\n this.fabEl.style.left = this.posX + 'px';\r\n this.fabEl.style.top = this.posY + 'px';\r\n }\r\n\r\n private onDragEnd(): void {\r\n this.isDragging = false;\r\n document.removeEventListener('mousemove', this.boundMouseMove);\r\n document.removeEventListener('mouseup', this.boundMouseUp);\r\n }\r\n\r\n private onTouchStart(e: TouchEvent): void {\r\n if ((e.target as HTMLElement).closest('button:not(.lcms-fab-btn)') || (e.target as HTMLElement).closest('.lcms-panel')) return;\r\n const t = e.touches[0];\r\n this.isDragging = true;\r\n this.hasMoved = false;\r\n this.dragStartX = t.clientX;\r\n this.dragStartY = t.clientY;\r\n this.startPosX = this.posX;\r\n this.startPosY = this.posY;\r\n document.addEventListener('touchmove', this.boundTouchMove, { passive: false });\r\n document.addEventListener('touchend', this.boundTouchEnd);\r\n }\r\n\r\n private onTouchMove(e: TouchEvent): void {\r\n if (!this.isDragging || !this.fabEl) return;\r\n e.preventDefault();\r\n const t = e.touches[0];\r\n const dx = t.clientX - this.dragStartX, dy = t.clientY - this.dragStartY;\r\n if (Math.abs(dx) > 3 || Math.abs(dy) > 3) this.hasMoved = true;\r\n this.posX = Math.max(0, Math.min(window.innerWidth - 60, this.startPosX + dx));\r\n this.posY = Math.max(0, Math.min(window.innerHeight - 60, this.startPosY + dy));\r\n this.fabEl.style.left = this.posX + 'px';\r\n this.fabEl.style.top = this.posY + 'px';\r\n }\r\n\r\n private onTouchEnd(): void {\r\n this.isDragging = false;\r\n document.removeEventListener('touchmove', this.boundTouchMove);\r\n document.removeEventListener('touchend', this.boundTouchEnd);\r\n }\r\n\r\n // ===============================================\r\n // HELPERS\r\n // ===============================================\r\n\r\n private setLoading(val: boolean): void {\r\n this.loading = val;\r\n this.updateUI();\r\n }\r\n\r\n private detectCurrentLanguage(): string {\r\n // Check localStorage first — set by switchLang() before reload, always reliable\r\n const stored = localStorage.getItem('selectedLanguage');\r\n if (stored && this.languages.includes(stored)) return stored;\r\n const htmlLang = document.documentElement.getAttribute('lang');\r\n if (htmlLang && this.languages.includes(htmlLang)) return htmlLang;\r\n return this.defaultLanguage;\r\n }\r\n\r\n private createElement(tag: string, className: string): HTMLElement {\r\n const el = document.createElement(tag);\r\n el.className = className;\r\n return el;\r\n }\r\n\r\n private formatDate(timestamp: number): string {\r\n const d = new Date(timestamp);\r\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\r\n const h = d.getHours();\r\n const m = d.getMinutes().toString().padStart(2, '0');\r\n const ampm = h >= 12 ? 'PM' : 'AM';\r\n const h12 = h % 12 || 12;\r\n return `${months[d.getMonth()]} ${d.getDate()}, ${h12}:${m} ${ampm}`;\r\n }\r\n\r\n // ===============================================\r\n // LOGIN MODAL\r\n // ===============================================\r\n\r\n private showLoginModal(): void {\r\n if (this.loginModalEl) return;\r\n\r\n const overlay = document.createElement('div');\r\n overlay.className = 'lcms-login-overlay';\r\n overlay.id = 'lcms-login-modal';\r\n\r\n overlay.innerHTML = `\r\n <div class=\"lcms-login-box\">\r\n <div class=\"lcms-login-logo\">\r\n <div class=\"lcms-login-logo-icon\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2.5\" 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>\r\n </div>\r\n <span class=\"lcms-login-logo-text\">XtroEdge CMS</span>\r\n </div>\r\n <div class=\"lcms-login-title\">Builder Login</div>\r\n <div class=\"lcms-login-sub\">Sign in to access edit mode</div>\r\n <div class=\"lcms-login-field\">\r\n <label class=\"lcms-login-label\">Username</label>\r\n <input class=\"lcms-login-input\" id=\"lcms-login-email\" type=\"text\" placeholder=\"Enter your username\" autocomplete=\"username\" />\r\n </div>\r\n <div class=\"lcms-login-field\">\r\n <label class=\"lcms-login-label\">Password</label>\r\n <div class=\"lcms-password-wrapper\">\r\n <input class=\"lcms-login-input\" id=\"lcms-login-password\" type=\"password\" placeholder=\"Enter your password\" autocomplete=\"current-password\" />\r\n <button type=\"button\" class=\"lcms-password-toggle\" id=\"lcms-password-toggle\" tabindex=\"-1\">\r\n <svg class=\"lcms-eye-open\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>\r\n <svg class=\"lcms-eye-closed lcms-hidden\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"/><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/></svg>\r\n </button>\r\n </div>\r\n </div>\r\n <button class=\"lcms-login-btn\" id=\"lcms-login-btn\">Sign In</button>\r\n <div class=\"lcms-login-error\" id=\"lcms-login-error\"></div>\r\n </div>\r\n `;\r\n\r\n (this.rootEl || document.body).appendChild(overlay);\r\n this.loginModalEl = overlay;\r\n\r\n const btn = overlay.querySelector('#lcms-login-btn') as HTMLButtonElement;\r\n const emailInput = overlay.querySelector('#lcms-login-email') as HTMLInputElement;\r\n const passInput = overlay.querySelector('#lcms-login-password') as HTMLInputElement;\r\n\r\n const doLogin = () => this.attemptLogin(emailInput.value.trim(), passInput.value);\r\n btn.addEventListener('click', doLogin);\r\n passInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') doLogin(); });\r\n\r\n // Password show/hide toggle\r\n const toggleBtn = overlay.querySelector('#lcms-password-toggle') as HTMLButtonElement;\r\n if (toggleBtn) {\r\n toggleBtn.addEventListener('click', () => {\r\n const isPassword = passInput.type === 'password';\r\n passInput.type = isPassword ? 'text' : 'password';\r\n toggleBtn.querySelector('.lcms-eye-open')!.classList.toggle('lcms-hidden', !isPassword);\r\n toggleBtn.querySelector('.lcms-eye-closed')!.classList.toggle('lcms-hidden', isPassword);\r\n passInput.focus();\r\n });\r\n }\r\n\r\n // Focus email field\r\n setTimeout(() => emailInput.focus(), 50);\r\n }\r\n\r\n private hideLoginModal(): void {\r\n this.loginModalEl?.remove();\r\n this.loginModalEl = null;\r\n }\r\n\r\n private async attemptLogin(email: string, password: string): Promise<void> {\r\n const btn = document.getElementById('lcms-login-btn') as HTMLButtonElement;\r\n const errorEl = document.getElementById('lcms-login-error') as HTMLElement;\r\n\r\n if (!email || !password) {\r\n errorEl.textContent = 'Please enter your username and password.';\r\n errorEl.classList.add('visible');\r\n return;\r\n }\r\n\r\n btn.disabled = true;\r\n btn.textContent = 'Signing in...';\r\n errorEl.classList.remove('visible');\r\n\r\n try {\r\n const loginUrl = this.config.loginUrl || `${this.config.apiBase}/auth/login`;\r\n const res = await fetch(loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ username: email, password }),\r\n });\r\n\r\n // Try to parse body regardless of status (API may return error details in body)\r\n let data: any = null;\r\n try { data = await res.json(); } catch { /* ignore parse error */ }\r\n\r\n if (!res.ok) {\r\n // Show API error message if available (e.g. Xano: { message: \"Invalid credentials.\" })\r\n const apiMsg = data?.message || data?.error || null;\r\n throw new Error(apiMsg || `HTTP ${res.status}`);\r\n }\r\n\r\n // Store token — support common response shapes: { token }, { authToken }, { data: { token } }\r\n const token = data?.token || data?.authToken || data?.auth_token || data?.data?.token;\r\n if (!token) throw new Error('Login successful but no token returned.');\r\n\r\n XtroedgeCMS.secureSet('builder_token', token);\r\n\r\n // Save company URLs for direct API calls (bypass our server)\r\n if (data?.get_url) XtroedgeCMS.secureSet('xtroedge_get_url', data.get_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_get_url');\r\n if (data?.published_url) XtroedgeCMS.secureSet('xtroedge_published_url', data.published_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_published_url');\r\n if (data?.image_url) XtroedgeCMS.secureSet('xtroedge_image_url', data.image_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_image_url');\r\n if (data?.client_api) {\r\n XtroedgeCMS.secureSet('xtroedge_client_api', data.client_api);\r\n this.config.clientApi = data.client_api; // Override config with server value\r\n } else {\r\n XtroedgeCMS.secureRemove('xtroedge_client_api');\r\n }\r\n if (data?.save_url) XtroedgeCMS.secureSet('xtroedge_save_url', data.save_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_save_url');\r\n\r\n this.hideLoginModal();\r\n\r\n // Now enable edit mode\r\n this.editMode = true;\r\n this.pendingEditMode = false;\r\n sessionStorage.setItem('builder_edit_mode', 'true');\r\n this.applyEditMode(true);\r\n this.updateUI();\r\n this.loadPageContent('draft');\r\n } catch (err: any) {\r\n btn.disabled = false;\r\n btn.textContent = 'Sign In';\r\n errorEl.textContent = err?.message || 'Login failed. Please try again.';\r\n errorEl.classList.add('visible');\r\n }\r\n }\r\n\r\n // ===============================================\r\n // SITE IDENTIFIER\r\n // ===============================================\r\n\r\n private resolveSiteIdentifier(): string {\r\n const hostname = window.location.hostname;\r\n if (hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.startsWith('192.168.')) {\r\n return hostname;\r\n }\r\n let id = localStorage.getItem('xtroedge_site_id');\r\n if (!id) {\r\n id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\r\n const r = Math.random() * 16 | 0;\r\n return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);\r\n });\r\n localStorage.setItem('xtroedge_site_id', id);\r\n }\r\n return id;\r\n }\r\n\r\n // ===============================================\r\n // THEME COLOR\r\n // ===============================================\r\n\r\n private hexToRgb(hex: string): string {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n if (!result) return '0,200,83';\r\n return `${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)}`;\r\n }\r\n\r\n private getDarkerColor(hex: string): string {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n if (!result) return '#2E7D32';\r\n const r = Math.max(0, Math.floor(parseInt(result[1], 16) * 0.6));\r\n const g = Math.max(0, Math.floor(parseInt(result[2], 16) * 0.6));\r\n const b = Math.max(0, Math.floor(parseInt(result[3], 16) * 0.6));\r\n return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;\r\n }\r\n\r\n private applyThemeColor(color: string): void {\r\n this.highlightColor = color;\r\n document.documentElement.style.setProperty('--lcms-primary', color);\r\n document.documentElement.style.setProperty('--lcms-primary-rgb', this.hexToRgb(color));\r\n document.documentElement.style.setProperty('--lcms-primary-dark', this.getDarkerColor(color));\r\n\r\n // Re-apply highlight to managed elements\r\n if (this.editMode) {\r\n for (const [el] of this.managedElements) {\r\n el.style.setProperty('outline', `2px dashed ${color}`, 'important');\r\n }\r\n for (const [img] of this.managedImages) {\r\n img.style.setProperty('outline', `2px dashed ${color}`, 'important');\r\n }\r\n }\r\n\r\n // Update swatch active states\r\n const swatches = this.panelEl?.querySelectorAll('.lcms-theme-swatch');\r\n swatches?.forEach(s => {\r\n (s as HTMLElement).classList.toggle('active', (s as HTMLElement).dataset.color === color);\r\n });\r\n\r\n // Persist to localStorage\r\n localStorage.setItem('xtroedge_theme_color', color);\r\n }\r\n\r\n // ===============================================\r\n // STATIC CONVENIENCE\r\n // ===============================================\r\n\r\n /** Quick init - create and start CMS in one call */\r\n static async create(config?: XtroedgeCmsConfig): Promise<XtroedgeCMS> {\r\n const cms = new XtroedgeCMS(config);\r\n await cms.init();\r\n return cms;\r\n }\r\n\r\n /** Auto-init: called automatically when package is loaded. No user code needed. */\r\n static async autoInit(): Promise<void> {\r\n // Prevent double init\r\n if ((window as any).__xtroedge_cms_instance__) return;\r\n\r\n const userConfig: XtroedgeCmsConfig = (window as any).__XTROEDGE_CMS_CONFIG__ || {};\r\n const cms = await XtroedgeCMS.create(userConfig);\r\n (window as any).__xtroedge_cms_instance__ = cms;\r\n }\r\n}\r\n\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/styles.ts","../src/xtroedge-cms.ts"],"sourcesContent":["export { XtroedgeCMS } from './xtroedge-cms';\r\nexport type {\r\n XtroedgeCmsConfig,\r\n PageTextEntry,\r\n WebPageContent,\r\n EditHistoryEntry,\r\n LicenseStatus,\r\n} from './types';\r\n\r\n// ===== AUTO-INIT =====\r\n// Automatically initializes CMS when the script loads.\r\n// No manual code needed - just install the package.\r\n// To pass config, set window.__XTROEDGE_CMS_CONFIG__ before loading.\r\nimport { XtroedgeCMS } from './xtroedge-cms';\r\n\r\nasync function boot() {\r\n await XtroedgeCMS.autoInit();\r\n}\r\n\r\nif (typeof window !== 'undefined') {\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', boot);\r\n } else {\r\n // DOM already ready (script loaded async/defer or after DOMContentLoaded)\r\n boot();\r\n }\r\n}\r\n","export const CMS_STYLES = `\r\n/* ===== XTROEDGE CMS ===== */\r\n\r\n/* LOADER */\r\n.lcms-loader-overlay {\r\n position: fixed; inset: 0; z-index: 10003;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.45);\r\n backdrop-filter: blur(12px) saturate(1.4);\r\n -webkit-backdrop-filter: blur(12px) saturate(1.4);\r\n}\r\n.lcms-loader-content { display: flex; flex-direction: column; align-items: center; gap: 28px; }\r\n.lcms-orbit-loader { position: relative; width: 90px; height: 90px; }\r\n.lcms-orbit { position: absolute; inset: 0; border-radius: 50%; border: 1px solid transparent; }\r\n.lcms-orbit-1 { border-top-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.5); animation: lcmsSpin 2.4s linear infinite; }\r\n.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; }\r\n.lcms-orbit-3 { inset: 20px; border-bottom-color: rgba(var(--lcms-primary-rgb, 0,200,83),0.35); animation: lcmsSpin 4.2s linear infinite; }\r\n.lcms-particle {\r\n position: absolute; width: 8px; height: 8px; border-radius: 50%; top: -4px; left: 50%; margin-left: -4px;\r\n box-shadow: 0 0 12px 3px currentColor;\r\n}\r\n.lcms-orbit-1 .lcms-particle { background: var(--lcms-primary, #00C853); color: var(--lcms-primary, #00C853); }\r\n.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; }\r\n.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; }\r\n.lcms-core-glow {\r\n position: absolute; width: 30px; height: 30px; top: 50%; left: 50%; transform: translate(-50%,-50%);\r\n border-radius: 50%; background: radial-gradient(circle, rgba(var(--lcms-primary-rgb, 0,200,83),0.4), transparent 70%);\r\n animation: lcmsPulse 2s ease-in-out infinite;\r\n}\r\n.lcms-core {\r\n position: absolute; width: 12px; height: 12px; top: 50%; left: 50%; transform: translate(-50%,-50%);\r\n border-radius: 50%; background: linear-gradient(135deg, var(--lcms-primary, #00C853), rgba(var(--lcms-primary-rgb, 0,200,83),0.6));\r\n box-shadow: 0 0 20px rgba(var(--lcms-primary-rgb, 0,200,83),0.6);\r\n}\r\n.lcms-loader-text {\r\n font-family: system-ui, -apple-system, sans-serif; font-size: 12px; font-weight: 600;\r\n color: rgba(255,255,255,0.5); letter-spacing: 4px; text-transform: uppercase;\r\n animation: lcmsBreath 2.5s ease-in-out infinite;\r\n}\r\n@keyframes lcmsSpin { to { transform: rotate(360deg); } }\r\n@keyframes lcmsPulse { 0%,100% { transform: translate(-50%,-50%) scale(1); opacity: 0.5; } 50% { transform: translate(-50%,-50%) scale(1.8); opacity: 0.2; } }\r\n@keyframes lcmsBreath { 0%,100% { letter-spacing: 4px; opacity: 0.5; } 50% { letter-spacing: 6px; opacity: 0.8; } }\r\n\r\n/* TOAST */\r\n.lcms-toast {\r\n position: fixed; top: 24px; left: 50%; transform: translateX(-50%); z-index: 10004;\r\n padding: 10px 20px; border-radius: 10px; font-size: 13px; font-weight: 600;\r\n font-family: system-ui, -apple-system, sans-serif; color: white;\r\n display: flex; align-items: center; gap: 8px;\r\n box-shadow: 0 8px 32px rgba(var(--lcms-primary-rgb, 0,200,83),0.25);\r\n animation: lcmsToastIn 0.3s ease, lcmsToastOut 0.3s ease 2.7s forwards; white-space: nowrap;\r\n}\r\n.lcms-toast-success { background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32)); }\r\n.lcms-toast-error { background: linear-gradient(135deg, #dc2626, #ef4444); }\r\n@keyframes lcmsToastIn { from { opacity: 0; transform: translateX(-50%) translateY(-12px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }\r\n@keyframes lcmsToastOut { from { opacity: 1; transform: translateX(-50%) translateY(0); } to { opacity: 0; transform: translateX(-50%) translateY(-12px); } }\r\n\r\n/* FAB */\r\n.lcms-fab { position: fixed; z-index: 10001; user-select: none; touch-action: none; }\r\n.lcms-fab-btn {\r\n width: 52px; height: 52px; border-radius: 50%; border: 1px solid rgba(255,255,255,0.2);\r\n background: rgba(var(--lcms-primary-rgb, 0,200,83),0.35); color: white;\r\n backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);\r\n cursor: grab; display: flex; align-items: center; justify-content: center;\r\n 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);\r\n transition: transform 0.2s, box-shadow 0.2s, background 0.2s; position: relative;\r\n}\r\n.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); }\r\n.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); }\r\n.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); }\r\n.lcms-badge {\r\n position: absolute; top: -4px; right: -4px; background: #ef4444; color: white;\r\n font-size: 11px; font-weight: 700; width: 20px; height: 20px; border-radius: 50%;\r\n display: flex; align-items: center; justify-content: center; border: 2px solid white;\r\n}\r\n\r\n/* PANEL */\r\n.lcms-panel {\r\n background: rgba(12,12,18,0.55); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);\r\n border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.25); border-radius: 16px; padding: 16px; min-width: 230px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.25), inset 0 1px 0 rgba(255,255,255,0.06);\r\n color: white; font-family: system-ui, -apple-system, sans-serif;\r\n animation: lcmsPanelIn 0.25s ease; position: absolute;\r\n}\r\n@keyframes lcmsPanelIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }\r\n\r\n/* SITE IDENTIFIER */\r\n.lcms-site-id {\r\n display: flex; align-items: center; gap: 5px;\r\n font-size: 10px; color: rgba(255,255,255,0.4);\r\n padding: 0 0 8px; margin-bottom: 8px;\r\n border-bottom: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.12);\r\n font-family: system-ui, -apple-system, sans-serif;\r\n letter-spacing: 0.3px;\r\n}\r\n.lcms-site-id-icon { font-size: 12px; opacity: 0.7; }\r\n.lcms-site-id-text {\r\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 180px;\r\n font-weight: 500;\r\n}\r\n\r\n/* BRANDING */\r\n.lcms-branding {\r\n display: flex; align-items: center; gap: 6px; padding: 8px 0 4px;\r\n border-top: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.15); margin-top: 10px;\r\n cursor: pointer; transition: opacity 0.2s; user-select: none;\r\n}\r\n.lcms-branding:hover { opacity: 0.8; }\r\n.lcms-branding-logo {\r\n width: 18px; height: 18px; border-radius: 4px; background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n display: flex; align-items: center; justify-content: center;\r\n}\r\n.lcms-branding-text {\r\n font-size: 10px; font-weight: 600; color: rgba(255,255,255,0.35); letter-spacing: 0.5px;\r\n}\r\n.lcms-branding-text span { color: var(--lcms-primary, #00C853); font-weight: 700; }\r\n\r\n.lcms-panel-header { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }\r\n.lcms-toggle { display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }\r\n.lcms-toggle input { display: none; }\r\n.lcms-toggle-slider {\r\n width: 36px; height: 20px; border-radius: 10px; position: relative;\r\n background: rgba(255,255,255,0.15); transition: background 0.25s;\r\n}\r\n.lcms-toggle-slider::after {\r\n content: ''; position: absolute; width: 16px; height: 16px; border-radius: 50%;\r\n top: 2px; left: 2px; background: rgba(255,255,255,0.6); transition: transform 0.25s, background 0.25s;\r\n}\r\n.lcms-toggle input:checked + .lcms-toggle-slider { background: var(--lcms-primary, #00C853); }\r\n.lcms-toggle input:checked + .lcms-toggle-slider::after { transform: translateX(16px); background: white; }\r\n.lcms-toggle-label { font-size: 12px; font-weight: 700; color: rgba(255,255,255,0.5); letter-spacing: 0.5px; transition: color 0.25s; }\r\n.lcms-toggle input:checked ~ .lcms-toggle-label { color: rgba(var(--lcms-primary-rgb, 0,200,83),0.75); }\r\n.lcms-lang-switch { margin-left: auto; position: relative; }\r\n.lcms-lang-select { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.15); border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.4); border-radius: 6px; color: white; padding: 3px 24px 3px 8px; font-size: 11px; font-weight: 600; cursor: pointer; appearance: none; -webkit-appearance: none; outline: none; transition: all 0.2s; }\r\n.lcms-lang-select:hover { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.3); }\r\n.lcms-lang-select:focus { border-color: var(--lcms-primary, #00C853); }\r\n.lcms-lang-select option { background: #1a1a2e; color: white; }\r\n.lcms-lang-arrow { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); pointer-events: none; color: rgba(255,255,255,0.6); font-size: 10px; }\r\n.lcms-close-btn { background: transparent; border: none; color: rgba(255,255,255,0.4); cursor: pointer; padding: 2px; display: flex; transition: color 0.2s; }\r\n.lcms-close-btn:hover { color: white; }\r\n.lcms-changes-info { font-size: 12px; color: rgba(var(--lcms-primary-rgb, 0,200,83),0.75); margin-bottom: 10px; padding-left: 2px; }\r\n\r\n.lcms-undo-row { display: flex; gap: 6px; margin-bottom: 12px; }\r\n.lcms-icon-btn {\r\n width: 36px; height: 32px; border-radius: 8px; border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.3);\r\n background: rgba(var(--lcms-primary-rgb, 0,200,83),0.1); color: rgba(255,255,255,0.8); cursor: pointer;\r\n display: flex; align-items: center; justify-content: center; transition: all 0.2s;\r\n}\r\n.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; }\r\n.lcms-icon-btn:disabled { opacity: 0.25; cursor: not-allowed; }\r\n\r\n/* COLOR THEME PICKER */\r\n.lcms-theme-row {\r\n display: flex; align-items: center; gap: 8px; margin-bottom: 12px;\r\n padding: 6px 0;\r\n}\r\n.lcms-theme-label {\r\n font-size: 10px; font-weight: 700; color: rgba(255,255,255,0.45);\r\n text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap;\r\n}\r\n.lcms-theme-colors {\r\n display: flex; align-items: center; gap: 5px; flex-wrap: wrap;\r\n}\r\n.lcms-theme-swatch {\r\n width: 20px; height: 20px; border-radius: 50%; border: 2px solid transparent;\r\n cursor: pointer; transition: all 0.2s; position: relative;\r\n}\r\n.lcms-theme-swatch:hover { transform: scale(1.15); }\r\n.lcms-theme-swatch.active { border-color: white; box-shadow: 0 0 8px rgba(255,255,255,0.3); }\r\n.lcms-theme-custom {\r\n width: 20px; height: 20px; border-radius: 50%; border: 1px dashed rgba(255,255,255,0.3);\r\n cursor: pointer; overflow: hidden; position: relative;\r\n}\r\n.lcms-theme-custom input {\r\n position: absolute; inset: -4px; width: 28px; height: 28px; border: none;\r\n background: transparent; cursor: pointer; opacity: 0;\r\n}\r\n.lcms-theme-custom-preview {\r\n width: 100%; height: 100%; border-radius: 50%;\r\n background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);\r\n}\r\n\r\n.lcms-history-btn {\r\n width: 100%; padding: 7px 12px; border-radius: 8px;\r\n border: 1px dashed rgba(var(--lcms-primary-rgb, 0,200,83),0.35); background: rgba(var(--lcms-primary-rgb, 0,200,83),0.08);\r\n color: rgba(255,255,255,0.6); font-size: 12px; font-weight: 500; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center; gap: 6px;\r\n transition: all 0.2s; margin-bottom: 12px; font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.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; }\r\n.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; }\r\n\r\n.lcms-history-panel { margin-top: 8px; border-top: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.15); padding-top: 10px; }\r\n.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; }\r\n.lcms-history-empty { font-size: 12px; color: rgba(255,255,255,0.3); text-align: center; padding: 12px 0; }\r\n.lcms-history-list { max-height: 200px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }\r\n.lcms-history-list::-webkit-scrollbar { width: 4px; }\r\n.lcms-history-list::-webkit-scrollbar-track { background: transparent; }\r\n.lcms-history-list::-webkit-scrollbar-thumb { background: rgba(var(--lcms-primary-rgb, 0,200,83),0.3); border-radius: 4px; }\r\n.lcms-history-item {\r\n width: 100%; text-align: left; background: rgba(var(--lcms-primary-rgb, 0,200,83),0.06);\r\n border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83),0.12); border-radius: 8px; padding: 8px 10px;\r\n cursor: pointer; transition: all 0.2s; color: white; font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.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); }\r\n.lcms-history-label { font-size: 12px; font-weight: 500; margin-bottom: 2px; }\r\n.lcms-history-meta { font-size: 10px; color: rgba(255,255,255,0.4); display: flex; align-items: center; gap: 6px; }\r\n.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); }\r\n\r\n.lcms-actions { display: flex; flex-direction: column; gap: 6px; }\r\n.lcms-actions button {\r\n width: 100%; padding: 9px 14px; border-radius: 8px; font-size: 12px; font-weight: 600;\r\n cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; gap: 6px; border: none;\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-btn-save { background: var(--lcms-primary, #00C853); color: white; }\r\n.lcms-btn-save:hover { background: var(--lcms-primary, #00C853); filter: brightness(1.15); }\r\n.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; }\r\n.lcms-btn-publish { background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32)); color: white; }\r\n.lcms-btn-publish:hover { background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32)); filter: brightness(1.1); }\r\n.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; filter: none; }\r\n.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; }\r\n.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); }\r\n.lcms-btn-cancel:disabled { opacity: 0.3; cursor: not-allowed; }\r\n.lcms-btn-logout { background: rgba(244,67,54,0.12); color: rgba(244,67,54,0.85); border: 1px solid rgba(244,67,54,0.25) !important; margin-top: 4px; }\r\n.lcms-btn-logout:hover { background: rgba(244,67,54,0.2); color: #f44336; border-color: rgba(244,67,54,0.5) !important; }\r\n\r\n.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; }\r\n\r\n/* IMAGE UPLOAD OVERLAY */\r\n.lcms-img-upload-overlay {\r\n position: fixed; inset: 0; z-index: 10005;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.5); backdrop-filter: blur(8px);\r\n}\r\n.lcms-img-upload-content {\r\n display: flex; flex-direction: column; align-items: center; gap: 16px;\r\n color: white; font-family: system-ui, -apple-system, sans-serif;\r\n font-size: 13px; font-weight: 600;\r\n}\r\n.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; }\r\n\r\n/* LOGIN MODAL */\r\n.lcms-login-overlay {\r\n position: fixed; inset: 0; z-index: 10010;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.75);\r\n backdrop-filter: blur(16px) saturate(1.4);\r\n -webkit-backdrop-filter: blur(16px) saturate(1.4);\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-login-box {\r\n background: #13151a; border: 1px solid rgba(255,255,255,0.1);\r\n border-radius: 16px; padding: 36px 32px; width: 340px;\r\n box-shadow: 0 24px 60px rgba(0,0,0,0.6);\r\n}\r\n.lcms-login-logo {\r\n display: flex; align-items: center; justify-content: center;\r\n gap: 8px; margin-bottom: 24px;\r\n}\r\n.lcms-login-logo-icon {\r\n width: 32px; height: 32px; border-radius: 8px;\r\n background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n display: flex; align-items: center; justify-content: center;\r\n}\r\n.lcms-login-logo-text { color: white; font-size: 15px; font-weight: 700; letter-spacing: 0.5px; }\r\n.lcms-login-title { color: white; font-size: 18px; font-weight: 700; text-align: center; margin-bottom: 6px; }\r\n.lcms-login-sub { color: rgba(255,255,255,0.4); font-size: 12px; text-align: center; margin-bottom: 24px; }\r\n.lcms-login-field { margin-bottom: 14px; }\r\n.lcms-login-label { display: block; color: rgba(255,255,255,0.6); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 6px; }\r\n.lcms-login-input {\r\n width: 100%; box-sizing: border-box;\r\n background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12);\r\n border-radius: 8px; padding: 10px 12px;\r\n color: white; font-size: 13px; font-family: inherit; outline: none;\r\n transition: border-color 0.2s;\r\n}\r\n.lcms-login-input:focus { border-color: var(--lcms-primary, #00C853); }\r\n.lcms-login-input::placeholder { color: rgba(255,255,255,0.25); }\r\n.lcms-password-wrapper { position: relative; display: flex; align-items: center; }\r\n.lcms-password-wrapper .lcms-login-input { padding-right: 40px; width: 100%; }\r\n.lcms-password-toggle {\r\n position: absolute; right: 10px; top: 50%; transform: translateY(-50%);\r\n background: none; border: none !important; outline: none !important; cursor: pointer; padding: 4px;\r\n color: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center;\r\n transition: color 0.2s; line-height: 0; z-index: 1;\r\n}\r\n.lcms-password-toggle:hover { color: rgba(0,0,0,0.8); }\r\n.lcms-password-toggle svg { display: block; }\r\n.lcms-login-btn {\r\n width: 100%; padding: 11px; margin-top: 6px; border: none; border-radius: 8px; cursor: pointer;\r\n background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n color: white; font-size: 13px; font-weight: 700; font-family: inherit;\r\n letter-spacing: 0.3px; transition: filter 0.2s;\r\n}\r\n.lcms-login-btn:hover { filter: brightness(1.1); }\r\n.lcms-login-btn:disabled { opacity: 0.6; cursor: not-allowed; }\r\n.lcms-login-error {\r\n background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.3);\r\n border-radius: 8px; padding: 9px 12px; color: #f87171;\r\n font-size: 12px; text-align: center; margin-top: 12px; display: none;\r\n}\r\n.lcms-login-error.visible { display: block; }\r\n\r\n/* LICENSE OVERLAY */\r\n.lcms-license-overlay {\r\n position: fixed; inset: 0; z-index: 10020;\r\n display: flex; align-items: center; justify-content: center;\r\n background: rgba(8, 8, 15, 0.85);\r\n backdrop-filter: blur(20px) saturate(1.4);\r\n -webkit-backdrop-filter: blur(20px) saturate(1.4);\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-license-box {\r\n background: #13151a; border: 1px solid rgba(255,255,255,0.1);\r\n border-radius: 20px; padding: 40px 36px; width: 380px; text-align: center;\r\n box-shadow: 0 24px 60px rgba(0,0,0,0.6);\r\n}\r\n.lcms-license-icon {\r\n width: 56px; height: 56px; border-radius: 16px; margin: 0 auto 20px;\r\n background: linear-gradient(135deg, rgba(239,68,68,0.2), rgba(239,68,68,0.1));\r\n border: 1px solid rgba(239,68,68,0.3);\r\n display: flex; align-items: center; justify-content: center;\r\n}\r\n.lcms-license-icon.trial {\r\n background: linear-gradient(135deg, rgba(251,191,36,0.2), rgba(251,191,36,0.1));\r\n border-color: rgba(251,191,36,0.3);\r\n}\r\n.lcms-license-title {\r\n color: white; font-size: 20px; font-weight: 700; margin-bottom: 8px;\r\n}\r\n.lcms-license-msg {\r\n color: rgba(255,255,255,0.5); font-size: 13px; line-height: 1.6; margin-bottom: 24px;\r\n}\r\n.lcms-license-btn {\r\n display: inline-block; padding: 11px 28px; border: none; border-radius: 8px; cursor: pointer;\r\n background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));\r\n color: white; font-size: 13px; font-weight: 700; font-family: inherit;\r\n letter-spacing: 0.3px; transition: filter 0.2s; text-decoration: none;\r\n}\r\n.lcms-license-btn:hover { filter: brightness(1.1); }\r\n.lcms-license-sub {\r\n color: rgba(255,255,255,0.3); font-size: 11px; margin-top: 16px;\r\n}\r\n.lcms-license-sub a { color: rgba(var(--lcms-primary-rgb, 0,200,83),0.7); text-decoration: none; }\r\n.lcms-license-sub a:hover { text-decoration: underline; }\r\n\r\n/* TRIAL BANNER */\r\n.lcms-trial-banner {\r\n display: flex; align-items: center; gap: 6px;\r\n background: rgba(251,191,36,0.12); border: 1px solid rgba(251,191,36,0.3);\r\n border-radius: 8px; padding: 6px 10px; margin-bottom: 10px;\r\n font-size: 11px; font-weight: 600; color: #fbbf24;\r\n}\r\n.lcms-trial-banner-icon { font-size: 14px; }\r\n.lcms-trial-banner-text { flex: 1; }\r\n.lcms-trial-banner-dismiss {\r\n background: none; border: none; color: rgba(251,191,36,0.5); cursor: pointer;\r\n padding: 0; font-size: 14px; line-height: 1; transition: color 0.2s;\r\n}\r\n.lcms-trial-banner-dismiss:hover { color: #fbbf24; }\r\n\r\n/* RICH TEXT TOOLBAR */\r\n.lcms-rich-toolbar {\r\n position: fixed; z-index: 10010;\r\n display: flex; align-items: center; gap: 2px;\r\n padding: 4px 6px;\r\n background: rgba(30, 15, 60, 0.92);\r\n backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);\r\n border: 1px solid rgba(var(--lcms-primary-rgb, 0,200,83), 0.3);\r\n border-radius: 8px;\r\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\r\n opacity: 0; transform: translateY(8px);\r\n transition: opacity 0.15s, transform 0.15s;\r\n pointer-events: none;\r\n font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n.lcms-rich-toolbar.visible { opacity: 1; transform: translateY(0); pointer-events: auto; }\r\n.lcms-rich-toolbar button {\r\n width: 28px; height: 28px; border: none; border-radius: 4px;\r\n background: transparent; color: #d0d0d0; cursor: pointer;\r\n display: flex; align-items: center; justify-content: center;\r\n font-size: 13px; font-weight: 700; padding: 0;\r\n transition: background 0.15s, color 0.15s;\r\n}\r\n.lcms-rich-toolbar button:hover { background: rgba(var(--lcms-primary-rgb, 0,200,83), 0.3); color: #fff; }\r\n.lcms-rich-toolbar button.active { background: rgba(var(--lcms-primary-rgb, 0,200,83), 0.5); color: #fff; }\r\n.lcms-rich-toolbar .lcms-tb-sep { width: 1px; height: 18px; background: rgba(255,255,255,0.12); margin: 0 3px; flex-shrink: 0; }\r\n\r\n/* HIDDEN ELEMENTS */\r\n.lcms-hidden { display: none !important; }\r\n\r\n/* EDIT MODE — keep animations running, just make CMS elements editable */\r\nbody.lcms-editing [data-cms] {\r\n user-select: text !important;\r\n -webkit-user-select: text !important;\r\n cursor: text !important;\r\n}\r\n`;\r\n","import { CMS_STYLES } from './styles';\r\nimport type {\r\n XtroedgeCmsConfig, PageTextEntry, WebPageContent,\r\n EditHistoryEntry, ManagedElementInfo, ManagedImageInfo, LicenseStatus\r\n} from './types';\r\n\r\n// ===== SVG Icons =====\r\nconst ICON = {\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n 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>',\r\n logout: '<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=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/><polyline points=\"16 17 21 12 16 7\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/></svg>',\r\n};\r\n\r\n// ===== IndexedDB constants =====\r\nconst DB_NAME = 'xtroedge_cms_history';\r\nconst STORE_NAME = 'history';\r\n\r\n// ===== Default editable tags =====\r\nconst DEFAULT_EDITABLE_TAGS = [\r\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\r\n 'p', 'span', 'b', 'strong', 'i', 'em',\r\n 'a', 'button', 'li', 'label', 'small', 'blockquote', 'td', 'th',\r\n 'div', 'header', 'footer',\r\n];\r\n\r\nexport class XtroedgeCMS {\r\n // ===== Encrypted vault (single key stores all sensitive data) =====\r\n private static readonly _SK = 'xTr0EdG3_s3cUr3_k3y!@#2024';\r\n private static readonly _VAULT_KEY = '_xtd';\r\n\r\n private static _enc(value: string): string {\r\n const k = XtroedgeCMS._SK;\r\n let result = '';\r\n for (let i = 0; i < value.length; i++) {\r\n result += String.fromCharCode(value.charCodeAt(i) ^ k.charCodeAt(i % k.length));\r\n }\r\n return btoa(result);\r\n }\r\n\r\n private static _dec(encoded: string): string {\r\n try {\r\n const k = XtroedgeCMS._SK;\r\n const decoded = atob(encoded);\r\n let result = '';\r\n for (let i = 0; i < decoded.length; i++) {\r\n result += String.fromCharCode(decoded.charCodeAt(i) ^ k.charCodeAt(i % k.length));\r\n }\r\n return result;\r\n } catch { return ''; }\r\n }\r\n\r\n private static _readVault(): Record<string, string> {\r\n try {\r\n const raw = localStorage.getItem(XtroedgeCMS._VAULT_KEY);\r\n if (!raw) return {};\r\n return JSON.parse(XtroedgeCMS._dec(raw));\r\n } catch { return {}; }\r\n }\r\n\r\n private static _writeVault(vault: Record<string, string>): void {\r\n try { localStorage.setItem(XtroedgeCMS._VAULT_KEY, XtroedgeCMS._enc(JSON.stringify(vault))); } catch { /* storage full */ }\r\n }\r\n\r\n private static secureSet(key: string, value: string): void {\r\n const v = XtroedgeCMS._readVault();\r\n v[key] = value;\r\n XtroedgeCMS._writeVault(v);\r\n }\r\n\r\n private static secureGet(key: string): string {\r\n return XtroedgeCMS._readVault()[key] || '';\r\n }\r\n\r\n private static secureRemove(key: string): void {\r\n const v = XtroedgeCMS._readVault();\r\n delete v[key];\r\n XtroedgeCMS._writeVault(v);\r\n }\r\n\r\n private static secureClear(): void {\r\n try { localStorage.removeItem(XtroedgeCMS._VAULT_KEY); } catch { /* ignore */ }\r\n }\r\n\r\n // ===== Config =====\r\n private config: XtroedgeCmsConfig;\r\n private containerSelector: string;\r\n private editableTags: string[];\r\n private languages: string[];\r\n private defaultLanguage: string;\r\n private highlightColor: string;\r\n private brandingEl: HTMLElement | null = null;\r\n private historyRetentionMs: number;\r\n private siteIdentifier = '';\r\n private siteIdEl: HTMLElement | null = null;\r\n private loginModalEl: HTMLElement | null = null;\r\n private pendingEditMode = false; // edit=true was requested but token missing\r\n\r\n // ===== State =====\r\n private editMode = false;\r\n private currentLang = 'en';\r\n private pageTexts: { [key: string]: PageTextEntry } = {};\r\n private pageImages: { [key: string]: string } = {};\r\n private originalTexts: { [key: string]: PageTextEntry } = {};\r\n private originalImages: { [key: string]: string } = {};\r\n private unsavedChanges = 0;\r\n private isSaving = false;\r\n private isPublishing = false;\r\n private loading = false;\r\n private canUndo = false;\r\n private canRedo = false;\r\n private showHistory = false;\r\n private historyList: EditHistoryEntry[] = [];\r\n private isOpen = false;\r\n private isEditAllowed = false;\r\n private imageUploading = false;\r\n private toastMessage = '';\r\n private toastType: 'success' | 'error' = 'success';\r\n\r\n // ===== Undo/Redo =====\r\n private undoStack: string[] = [];\r\n private redoStack: string[] = [];\r\n private dirtyKeys = new Set<string>();\r\n private dirtyImageKeys = new Set<string>();\r\n private registeredKeys = new Set<string>();\r\n\r\n // ===== DOM =====\r\n private domOriginals: { [key: string]: string } = {};\r\n private managedElements = new Map<HTMLElement, ManagedElementInfo>();\r\n private managedImages = new Map<HTMLImageElement, ManagedImageInfo>();\r\n private autoDetectedElements = new Set<HTMLElement>();\r\n private observer: MutationObserver | null = null;\r\n private scanTimeout: ReturnType<typeof setTimeout> | null = null;\r\n private activeImageEl: HTMLImageElement | null = null;\r\n private imageCtxMenu: HTMLElement | null = null;\r\n private floatingEditDialog: HTMLElement | null = null;\r\n\r\n // ===== Rich Text Toolbar =====\r\n private richToolbarEl: HTMLElement | null = null;\r\n private activeEditableEl: HTMLElement | null = null;\r\n private toolbarHideTimeout: ReturnType<typeof setTimeout> | null = null;\r\n private selectionChangeHandler: (() => void) | null = null;\r\n\r\n // ===== Navigation =====\r\n private currentSlug = '';\r\n private currentTitle = '';\r\n private initialized = false;\r\n private origPushState: typeof history.pushState | null = null;\r\n private origReplaceState: typeof history.replaceState | null = null;\r\n\r\n // ===== UI Elements =====\r\n private styleEl: HTMLStyleElement | null = null;\r\n private rootEl: HTMLElement | null = null;\r\n private loaderEl: HTMLElement | null = null;\r\n private toastEl: HTMLElement | null = null;\r\n private fabEl: HTMLElement | null = null;\r\n private fabBtn: HTMLButtonElement | null = null;\r\n private badgeEl: HTMLElement | null = null;\r\n private panelEl: HTMLElement | null = null;\r\n private editToggle: HTMLInputElement | null = null;\r\n private langSwitchEl: HTMLElement | null = null;\r\n private changesInfoEl: HTMLElement | null = null;\r\n private undoBtn: HTMLButtonElement | null = null;\r\n private redoBtn: HTMLButtonElement | null = null;\r\n private historyBtnEl: HTMLButtonElement | null = null;\r\n private historyPanelEl: HTMLElement | null = null;\r\n private historyListEl: HTMLElement | null = null;\r\n private saveBtn: HTMLButtonElement | null = null;\r\n private publishBtn: HTMLButtonElement | null = null;\r\n\r\n private actionsEl: HTMLElement | null = null;\r\n private editModeContent: HTMLElement | null = null;\r\n private fileInput: HTMLInputElement | null = null;\r\n private imgOverlay: HTMLElement | null = null;\r\n\r\n // ===== Edit-mode visibility tracking =====\r\n private editScrollHandler: (() => void) | null = null;\r\n private editScrollRAF: number | null = null;\r\n private editClickCaptureHandler: ((e: Event) => void) | null = null;\r\n\r\n // ===== FAB Drag =====\r\n private posX = 20;\r\n private posY = 20;\r\n private isDragging = false;\r\n private dragStartX = 0;\r\n private dragStartY = 0;\r\n private startPosX = 0;\r\n private startPosY = 0;\r\n private hasMoved = false;\r\n\r\n // ===== Timers =====\r\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // ===== License =====\r\n private licenseValid = false;\r\n private licenseStatus: LicenseStatus | null = null;\r\n private licenseOverlayEl: HTMLElement | null = null;\r\n private trialBannerDismissed = false;\r\n\r\n // ===== IndexedDB =====\r\n private db: IDBDatabase | null = null;\r\n\r\n // ===== Bound handlers =====\r\n private boundMouseMove: (e: MouseEvent) => void;\r\n private boundMouseUp: () => void;\r\n private boundTouchMove: (e: TouchEvent) => void;\r\n private boundTouchEnd: () => void;\r\n private boundPopState: () => void;\r\n private boundHashChange: () => void;\r\n\r\n // ===== i18n cache =====\r\n private translationCache = new Map<string, string>();\r\n\r\n constructor(config?: XtroedgeCmsConfig) {\r\n this.config = config || {};\r\n if (!this.config.apiBase) this.config.apiBase = 'https://backend-xi-lime-d90e4p1ysf.vercel.app/api';\r\n this.containerSelector = this.config.containerSelector || '';\r\n this.editableTags = (this.config.editableTags || DEFAULT_EDITABLE_TAGS).map(t => t.toLowerCase());\r\n this.languages = this.config.languages || ['en'];\r\n this.defaultLanguage = this.config.defaultLanguage || this.languages[0] || 'en';\r\n this.highlightColor = this.config.highlightColor || '#00C853';\r\n this.historyRetentionMs = (this.config.historyRetentionDays || 7) * 24 * 60 * 60 * 1000;\r\n this.currentLang = this.detectCurrentLanguage();\r\n this.siteIdentifier = this.resolveSiteIdentifier();\r\n\r\n // Restore client API base from vault (saved during login)\r\n const savedClientApi = XtroedgeCMS.secureGet('xtroedge_client_api');\r\n if (savedClientApi) this.config.clientApi = savedClientApi;\r\n\r\n // Load persisted theme color from localStorage\r\n const savedColor = localStorage.getItem('xtroedge_theme_color');\r\n if (savedColor) this.highlightColor = savedColor;\r\n\r\n // Bind handlers\r\n this.boundMouseMove = (e) => this.onDragMove(e);\r\n this.boundMouseUp = () => this.onDragEnd();\r\n this.boundTouchMove = (e) => this.onTouchMove(e);\r\n this.boundTouchEnd = () => this.onTouchEnd();\r\n this.boundPopState = () => this.handleNavigation();\r\n this.boundHashChange = () => this.handleNavigation();\r\n }\r\n\r\n // ===============================================\r\n // PUBLIC API\r\n // ===============================================\r\n\r\n async init(): Promise<void> {\r\n this.injectStyles();\r\n this.applyThemeColor(this.highlightColor);\r\n\r\n // Validate license (non-blocking — CMS always loads, only editing is gated)\r\n await this.validateLicense();\r\n\r\n this.posY = window.innerHeight - 72;\r\n this.buildUI();\r\n this.interceptNavigation();\r\n\r\n // MutationObserver for auto-scanning\r\n this.observer = new MutationObserver(() => {\r\n // Re-append CMS UI if removed by framework hydration (Next.js, React, etc.)\r\n if (this.rootEl && !document.contains(this.rootEl)) {\r\n document.body.appendChild(this.rootEl);\r\n }\r\n if (this.styleEl && !document.contains(this.styleEl)) {\r\n document.head.appendChild(this.styleEl);\r\n }\r\n if (this.scanTimeout) clearTimeout(this.scanTimeout);\r\n this.scanTimeout = setTimeout(() => {\r\n this.autoDetectAndScan();\r\n // Re-apply texts to any newly detected elements\r\n if (Object.keys(this.pageTexts).length > 0) {\r\n this.updateElementTexts();\r\n }\r\n }, 150);\r\n });\r\n this.observer.observe(document.body, { childList: true, subtree: true });\r\n\r\n // Listen for navigation events\r\n window.addEventListener('popstate', this.boundPopState);\r\n window.addEventListener('hashchange', this.boundHashChange);\r\n\r\n // Initial navigation\r\n this.handleNavigation();\r\n }\r\n\r\n destroy(): void {\r\n this.cleanupManagedElements();\r\n\r\n // Remove UI\r\n this.styleEl?.remove();\r\n this.rootEl?.remove();\r\n this.licenseOverlayEl?.remove();\r\n\r\n // Remove listeners\r\n window.removeEventListener('popstate', this.boundPopState);\r\n window.removeEventListener('hashchange', this.boundHashChange);\r\n document.removeEventListener('mousemove', this.boundMouseMove);\r\n document.removeEventListener('mouseup', this.boundMouseUp);\r\n document.removeEventListener('touchmove', this.boundTouchMove);\r\n document.removeEventListener('touchend', this.boundTouchEnd);\r\n\r\n // Restore navigation\r\n if (this.origPushState) history.pushState = this.origPushState;\r\n if (this.origReplaceState) history.replaceState = this.origReplaceState;\r\n\r\n // Disconnect observer\r\n this.observer?.disconnect();\r\n if (this.scanTimeout) clearTimeout(this.scanTimeout);\r\n if (this.toastTimer) clearTimeout(this.toastTimer);\r\n\r\n this.db?.close();\r\n }\r\n\r\n // ===============================================\r\n // LICENSE VALIDATION\r\n // ===============================================\r\n\r\n private static readonly LICENSE_CACHE_KEY = 'xtroedge_license_cache';\r\n private static readonly LICENSE_CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours\r\n\r\n private async validateLicense(): Promise<void> {\r\n const licenseKey = this.config.licenseKey || XtroedgeCMS.secureGet('builder_token') || '';\r\n\r\n if (!licenseKey) {\r\n // No license key — editing disabled, but CMS still loads published content\r\n this.licenseStatus = { valid: false, plan: 'invalid', message: 'No license key provided.' };\r\n this.licenseValid = false;\r\n return;\r\n }\r\n\r\n // Check cache first (avoid hitting API on every page load)\r\n const cached = this.getLicenseCache();\r\n if (cached) {\r\n this.licenseStatus = cached;\r\n this.licenseValid = cached.valid;\r\n return;\r\n }\r\n\r\n // Call license validation API\r\n const validateUrl = this.config.licenseValidateUrl\r\n || (this.config.apiBase ? `${this.config.apiBase}/license/validate` : '');\r\n\r\n if (!validateUrl) {\r\n // No validation URL configured — allow (graceful: don't block if no API is set up)\r\n this.licenseValid = true;\r\n this.licenseStatus = { valid: true, plan: 'trial', message: 'No license API configured.' };\r\n return;\r\n }\r\n\r\n try {\r\n const builderToken = XtroedgeCMS.secureGet('builder_token') || '';\r\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\r\n if (builderToken) headers['Authorization'] = `Bearer ${builderToken}`;\r\n\r\n const res = await fetch(validateUrl, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify({\r\n licenseKey,\r\n domain: window.location.hostname,\r\n }),\r\n });\r\n\r\n let data: LicenseStatus;\r\n try {\r\n data = await res.json();\r\n } catch {\r\n throw new Error('Invalid response from license server');\r\n }\r\n\r\n this.licenseStatus = data;\r\n this.setLicenseCache(data);\r\n this.licenseValid = data.valid;\r\n } catch {\r\n // Network error — check if we have any previous valid cache (even expired)\r\n const fallback = this.getLicenseCache(true); // ignore TTL\r\n if (fallback && fallback.valid) {\r\n // Grace period: allow editing with stale cache\r\n this.licenseValid = true;\r\n this.licenseStatus = fallback;\r\n } else {\r\n // No cache + network failed — content still loads, editing blocked\r\n this.licenseStatus = { valid: false, plan: 'invalid', message: 'Unable to verify license. Please check your internet connection.' };\r\n this.licenseValid = false;\r\n }\r\n }\r\n }\r\n\r\n private getLicenseCache(ignoreTTL = false): LicenseStatus | null {\r\n try {\r\n const raw = XtroedgeCMS.secureGet(XtroedgeCMS.LICENSE_CACHE_KEY);\r\n if (!raw) return null;\r\n const { status, timestamp, key } = JSON.parse(raw);\r\n // Invalidate cache if license key changed\r\n const currentKey = this.config.licenseKey || XtroedgeCMS.secureGet('builder_token') || '';\r\n if (key !== currentKey) return null;\r\n if (!ignoreTTL && (Date.now() - timestamp > XtroedgeCMS.LICENSE_CACHE_TTL)) return null;\r\n return status as LicenseStatus;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private setLicenseCache(status: LicenseStatus): void {\r\n try {\r\n const currentKey = this.config.licenseKey || XtroedgeCMS.secureGet('builder_token') || '';\r\n XtroedgeCMS.secureSet(XtroedgeCMS.LICENSE_CACHE_KEY, JSON.stringify({\r\n status,\r\n timestamp: Date.now(),\r\n key: currentKey,\r\n }));\r\n } catch { /* localStorage full or blocked — ignore */ }\r\n }\r\n\r\n /** Shows toast when user tries to edit with expired/invalid license */\r\n private showLicenseExpiredToast(): void {\r\n const isExpired = this.licenseStatus?.plan === 'expired';\r\n const msg = isExpired\r\n ? 'Your free trial has expired. Subscribe to enable editing.'\r\n : (this.licenseStatus?.message || 'License validation failed. Editing is disabled.');\r\n this.showToast(msg, 'error');\r\n }\r\n\r\n /** Returns trial/expired banner HTML if applicable, or empty string */\r\n private getTrialBannerHTML(): string {\r\n if (this.trialBannerDismissed || !this.licenseStatus) return '';\r\n\r\n // Expired or invalid license — show red banner\r\n if (!this.licenseValid) {\r\n const msg = this.licenseStatus.plan === 'expired'\r\n ? 'Trial expired — editing disabled. Subscribe to continue.'\r\n : 'License invalid — editing disabled.';\r\n return `\r\n <div class=\"lcms-trial-banner\" id=\"lcms-trial-banner\" style=\"background:rgba(239,68,68,0.12);border-color:rgba(239,68,68,0.3);color:#f87171;\">\r\n <span class=\"lcms-trial-banner-icon\">🔒</span>\r\n <span class=\"lcms-trial-banner-text\">${msg}</span>\r\n <button class=\"lcms-trial-banner-dismiss\" id=\"lcms-trial-dismiss\" title=\"Dismiss\" style=\"color:rgba(239,68,68,0.5);\">✕</button>\r\n </div>\r\n `;\r\n }\r\n\r\n // Active trial — show yellow banner with days remaining\r\n if (this.licenseStatus.plan === 'trial') {\r\n const days = this.licenseStatus.daysLeft ?? 0;\r\n return `\r\n <div class=\"lcms-trial-banner\" id=\"lcms-trial-banner\">\r\n <span class=\"lcms-trial-banner-icon\">⏳</span>\r\n <span class=\"lcms-trial-banner-text\">Free Trial: ${days} day${days !== 1 ? 's' : ''} remaining</span>\r\n <button class=\"lcms-trial-banner-dismiss\" id=\"lcms-trial-dismiss\" title=\"Dismiss\">✕</button>\r\n </div>\r\n `;\r\n }\r\n\r\n return '';\r\n }\r\n\r\n // ===============================================\r\n // STYLES INJECTION\r\n // ===============================================\r\n\r\n private injectStyles(): void {\r\n if (document.getElementById('xtroedge-cms-styles')) return;\r\n this.styleEl = document.createElement('style');\r\n this.styleEl.id = 'xtroedge-cms-styles';\r\n this.styleEl.textContent = CMS_STYLES;\r\n document.head.appendChild(this.styleEl);\r\n }\r\n\r\n // ===============================================\r\n // NAVIGATION INTERCEPTION\r\n // ===============================================\r\n\r\n private interceptNavigation(): void {\r\n this.origPushState = history.pushState.bind(history);\r\n this.origReplaceState = history.replaceState.bind(history);\r\n const self = this;\r\n history.pushState = function (...args) {\r\n self.origPushState!(...args);\r\n setTimeout(() => self.handleNavigation(), 0);\r\n };\r\n history.replaceState = function (...args) {\r\n self.origReplaceState!(...args);\r\n setTimeout(() => self.handleNavigation(), 0);\r\n };\r\n }\r\n\r\n private handleNavigation(): void {\r\n const url = window.location.href;\r\n const pathname = window.location.pathname || '/';\r\n const hash = window.location.hash || '';\r\n\r\n // Support hash routing: #/page?edit=true\r\n let path: string;\r\n let searchStr: string;\r\n if (hash.startsWith('#/') || hash.startsWith('#!')) {\r\n const hashPath = hash.replace(/^#[!/]*/, '');\r\n const qIdx = hashPath.indexOf('?');\r\n path = qIdx >= 0 ? hashPath.substring(0, qIdx) : hashPath;\r\n searchStr = qIdx >= 0 ? hashPath.substring(qIdx) : '';\r\n } else {\r\n path = pathname.replace(/^\\//, '') || 'home';\r\n searchStr = window.location.search;\r\n }\r\n\r\n const slug = '/' + (path.replace(/^\\//, '') || 'home');\r\n const params = new URLSearchParams(searchStr);\r\n const editViaParam = params.get('edit') === 'true';\r\n\r\n this.isEditAllowed = editViaParam || sessionStorage.getItem('builder_edit_mode') === 'true';\r\n\r\n const slugChanged = slug !== this.currentSlug;\r\n if (slugChanged) {\r\n this.cleanupManagedElements();\r\n this.currentSlug = slug;\r\n this.currentTitle = (path.replace(/^\\//, '') || 'home').replace(/-/g, ' ').replace(/\\b\\w/g, c => c.toUpperCase()) + ' Page';\r\n this.resetAll();\r\n }\r\n\r\n // Restore edit mode — check builder_token first\r\n const editFromSession = sessionStorage.getItem('builder_edit_mode') === 'true';\r\n const wantsEdit = editViaParam || editFromSession;\r\n\r\n if (wantsEdit) {\r\n const token = XtroedgeCMS.secureGet('builder_token');\r\n if (!token) {\r\n // No token → show login modal, do NOT enable edit mode yet\r\n if (!this.pendingEditMode) {\r\n this.pendingEditMode = true;\r\n this.currentLang = this.detectCurrentLanguage();\r\n this.setLoading(true);\r\n setTimeout(() => {\r\n this.loadTranslationsAndInit(false);\r\n this.showLoginModal();\r\n }, 300);\r\n }\r\n return;\r\n }\r\n\r\n // Block edit mode if license is not valid\r\n if (!this.licenseValid) {\r\n this.showLicenseExpiredToast();\r\n this.editMode = false;\r\n } else {\r\n this.editMode = true;\r\n }\r\n }\r\n\r\n // Skip reload if same slug and already initialized\r\n if (!slugChanged && this.initialized) {\r\n this.updateUI();\r\n return;\r\n }\r\n\r\n this.currentLang = this.detectCurrentLanguage();\r\n\r\n // Show loader\r\n this.setLoading(true);\r\n\r\n // Auto-detect after DOM settles, then load content\r\n this.initialized = true;\r\n const loadDraft = wantsEdit;\r\n setTimeout(() => {\r\n this.loadTranslationsAndInit(loadDraft);\r\n }, 300);\r\n }\r\n\r\n // ===============================================\r\n // BUILD UI\r\n // ===============================================\r\n\r\n private buildUI(): void {\r\n this.rootEl = document.createElement('div');\r\n this.rootEl.id = 'xtroedge-cms-root';\r\n\r\n // Loader\r\n this.loaderEl = this.createElement('div', 'lcms-loader-overlay lcms-hidden');\r\n this.loaderEl.innerHTML = `<div class=\"lcms-loader-content\">\r\n <div class=\"lcms-orbit-loader\">\r\n <div class=\"lcms-orbit lcms-orbit-1\"><span class=\"lcms-particle\"></span></div>\r\n <div class=\"lcms-orbit lcms-orbit-2\"><span class=\"lcms-particle\"></span></div>\r\n <div class=\"lcms-orbit lcms-orbit-3\"><span class=\"lcms-particle\"></span></div>\r\n <div class=\"lcms-core-glow\"></div>\r\n <div class=\"lcms-core\"></div>\r\n </div>\r\n <span class=\"lcms-loader-text\">Loading</span>\r\n </div>`;\r\n this.rootEl.appendChild(this.loaderEl);\r\n\r\n // Toast\r\n this.toastEl = this.createElement('div', 'lcms-toast lcms-hidden');\r\n this.rootEl.appendChild(this.toastEl);\r\n\r\n // FAB\r\n this.fabEl = this.createElement('div', 'lcms-fab');\r\n this.fabEl.style.left = this.posX + 'px';\r\n this.fabEl.style.top = this.posY + 'px';\r\n this.fabEl.addEventListener('mousedown', (e) => this.onDragStart(e));\r\n this.fabEl.addEventListener('touchstart', (e) => this.onTouchStart(e), { passive: true });\r\n\r\n // FAB button\r\n this.fabBtn = document.createElement('button');\r\n this.fabBtn.className = 'lcms-fab-btn';\r\n this.fabBtn.innerHTML = ICON.edit;\r\n this.fabBtn.addEventListener('click', (e) => this.onFabClick(e));\r\n this.badgeEl = this.createElement('span', 'lcms-badge lcms-hidden');\r\n this.fabBtn.appendChild(this.badgeEl);\r\n this.fabEl.appendChild(this.fabBtn);\r\n\r\n // Panel\r\n this.panelEl = this.createElement('div', 'lcms-panel lcms-hidden');\r\n this.buildPanel();\r\n this.fabEl.appendChild(this.panelEl);\r\n\r\n this.rootEl.appendChild(this.fabEl);\r\n\r\n // Hidden file input\r\n this.fileInput = document.createElement('input');\r\n this.fileInput.type = 'file';\r\n this.fileInput.accept = 'image/*';\r\n this.fileInput.style.display = 'none';\r\n this.fileInput.addEventListener('change', (e) => this.onImageFileSelected(e));\r\n this.rootEl.appendChild(this.fileInput);\r\n\r\n // Image upload overlay\r\n this.imgOverlay = this.createElement('div', 'lcms-img-upload-overlay lcms-hidden');\r\n this.imgOverlay.innerHTML = `<div class=\"lcms-img-upload-content\"><div class=\"lcms-spinner-lg\"></div><span>Uploading image...</span></div>`;\r\n this.rootEl.appendChild(this.imgOverlay);\r\n\r\n document.body.appendChild(this.rootEl);\r\n }\r\n\r\n private buildPanel(): void {\r\n if (!this.panelEl) return;\r\n\r\n // Header\r\n const header = this.createElement('div', 'lcms-panel-header');\r\n\r\n // Edit toggle\r\n const toggleLabel = this.createElement('label', 'lcms-toggle');\r\n toggleLabel.addEventListener('click', (e) => e.stopPropagation());\r\n this.editToggle = document.createElement('input');\r\n this.editToggle.type = 'checkbox';\r\n this.editToggle.checked = this.editMode;\r\n this.editToggle.addEventListener('change', (e) => this.toggleEditMode(e));\r\n const slider = this.createElement('span', 'lcms-toggle-slider');\r\n const labelText = this.createElement('span', 'lcms-toggle-label');\r\n labelText.textContent = 'Edit';\r\n toggleLabel.appendChild(this.editToggle);\r\n toggleLabel.appendChild(slider);\r\n toggleLabel.appendChild(labelText);\r\n header.appendChild(toggleLabel);\r\n\r\n // Language switch\r\n this.langSwitchEl = this.createElement('div', 'lcms-lang-switch lcms-hidden');\r\n this.buildLangButtons();\r\n header.appendChild(this.langSwitchEl);\r\n\r\n // Close button\r\n const closeBtn = document.createElement('button');\r\n closeBtn.className = 'lcms-close-btn';\r\n closeBtn.innerHTML = ICON.close;\r\n closeBtn.addEventListener('click', (e) => { e.stopPropagation(); this.togglePanel(); });\r\n header.appendChild(closeBtn);\r\n\r\n this.panelEl.appendChild(header);\r\n\r\n // Site identifier\r\n this.siteIdEl = this.createElement('div', 'lcms-site-id');\r\n const isDomain = this.siteIdentifier.includes('.');\r\n this.siteIdEl.innerHTML = `<span class=\"lcms-site-id-icon\">${isDomain ? '\\u{1F310}' : '\\u{1F511}'}</span><span class=\"lcms-site-id-text\">${isDomain ? this.siteIdentifier : this.siteIdentifier.substring(0, 8)}</span>`;\r\n this.panelEl.appendChild(this.siteIdEl);\r\n\r\n // Trial banner (shown only during free trial)\r\n const trialHTML = this.getTrialBannerHTML();\r\n if (trialHTML) {\r\n const trialWrap = this.createElement('div', '');\r\n trialWrap.innerHTML = trialHTML;\r\n this.panelEl.appendChild(trialWrap);\r\n // Attach dismiss handler after DOM insertion\r\n setTimeout(() => {\r\n const dismissBtn = document.getElementById('lcms-trial-dismiss');\r\n dismissBtn?.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.trialBannerDismissed = true;\r\n const banner = document.getElementById('lcms-trial-banner');\r\n banner?.remove();\r\n });\r\n }, 0);\r\n }\r\n\r\n // Edit mode content (hidden when edit mode off)\r\n this.editModeContent = this.createElement('div', 'lcms-hidden');\r\n\r\n // Changes info\r\n this.changesInfoEl = this.createElement('div', 'lcms-changes-info lcms-hidden');\r\n this.editModeContent.appendChild(this.changesInfoEl);\r\n\r\n // Undo/Redo row\r\n const undoRow = this.createElement('div', 'lcms-undo-row');\r\n this.undoBtn = document.createElement('button');\r\n this.undoBtn.className = 'lcms-icon-btn';\r\n this.undoBtn.innerHTML = ICON.undo;\r\n this.undoBtn.disabled = true;\r\n this.undoBtn.addEventListener('click', (e) => { e.stopPropagation(); this.onUndo(); });\r\n this.redoBtn = document.createElement('button');\r\n this.redoBtn.className = 'lcms-icon-btn';\r\n this.redoBtn.innerHTML = ICON.redo;\r\n this.redoBtn.disabled = true;\r\n this.redoBtn.addEventListener('click', (e) => { e.stopPropagation(); this.onRedo(); });\r\n undoRow.appendChild(this.undoBtn);\r\n undoRow.appendChild(this.redoBtn);\r\n this.editModeContent.appendChild(undoRow);\r\n\r\n // Color theme picker\r\n const themeRow = this.createElement('div', 'lcms-theme-row');\r\n const themeLabel = this.createElement('span', 'lcms-theme-label');\r\n themeLabel.textContent = 'Theme';\r\n themeRow.appendChild(themeLabel);\r\n const themeColors = this.createElement('div', 'lcms-theme-colors');\r\n const presetColors = ['#00C853', '#6722FB', '#2196F3', '#FF5722', '#E91E63', '#FFD600'];\r\n for (const color of presetColors) {\r\n const swatch = this.createElement('div', 'lcms-theme-swatch');\r\n swatch.style.background = color;\r\n swatch.dataset.color = color;\r\n if (color === this.highlightColor) swatch.classList.add('active');\r\n swatch.addEventListener('click', (e) => { e.stopPropagation(); this.applyThemeColor(color); });\r\n themeColors.appendChild(swatch);\r\n }\r\n // Custom color input\r\n const customSwatch = this.createElement('div', 'lcms-theme-custom');\r\n const customPreview = this.createElement('div', 'lcms-theme-custom-preview');\r\n const customInput = document.createElement('input');\r\n customInput.type = 'color';\r\n customInput.value = this.highlightColor;\r\n customInput.addEventListener('input', (e) => { e.stopPropagation(); this.applyThemeColor((e.target as HTMLInputElement).value); });\r\n customSwatch.appendChild(customPreview);\r\n customSwatch.appendChild(customInput);\r\n themeColors.appendChild(customSwatch);\r\n themeRow.appendChild(themeColors);\r\n this.editModeContent.appendChild(themeRow);\r\n\r\n // History button\r\n this.historyBtnEl = document.createElement('button');\r\n this.historyBtnEl.className = 'lcms-history-btn';\r\n this.historyBtnEl.innerHTML = `${ICON.history} History (7 days)`;\r\n this.historyBtnEl.addEventListener('click', (e) => { e.stopPropagation(); this.toggleHistory(); });\r\n this.editModeContent.appendChild(this.historyBtnEl);\r\n\r\n // History panel\r\n this.historyPanelEl = this.createElement('div', 'lcms-history-panel lcms-hidden');\r\n const historyTitle = this.createElement('div', 'lcms-history-title');\r\n historyTitle.textContent = 'Edit History';\r\n this.historyPanelEl.appendChild(historyTitle);\r\n this.historyListEl = this.createElement('div', 'lcms-history-list');\r\n this.historyPanelEl.appendChild(this.historyListEl);\r\n this.editModeContent.appendChild(this.historyPanelEl);\r\n\r\n // Actions\r\n this.actionsEl = this.createElement('div', 'lcms-actions');\r\n this.saveBtn = document.createElement('button');\r\n this.saveBtn.className = 'lcms-btn-save';\r\n this.saveBtn.innerHTML = `${ICON.save} Save Draft`;\r\n this.saveBtn.addEventListener('click', (e) => { e.stopPropagation(); this.saveChanges(); });\r\n this.publishBtn = document.createElement('button');\r\n this.publishBtn.className = 'lcms-btn-publish';\r\n this.publishBtn.innerHTML = `${ICON.publish} Publish`;\r\n this.publishBtn.addEventListener('click', (e) => { e.stopPropagation(); this.publishChanges(); });\r\n const logoutBtn = document.createElement('button');\r\n logoutBtn.className = 'lcms-btn-logout';\r\n logoutBtn.innerHTML = `${ICON.logout} Logout`;\r\n logoutBtn.addEventListener('click', (e) => { e.stopPropagation(); this.logout(); });\r\n this.actionsEl.appendChild(this.saveBtn);\r\n this.actionsEl.appendChild(this.publishBtn);\r\n this.actionsEl.appendChild(logoutBtn);\r\n this.editModeContent.appendChild(this.actionsEl);\r\n\r\n this.panelEl.appendChild(this.editModeContent);\r\n\r\n // Branding\r\n this.brandingEl = this.createElement('div', 'lcms-branding');\r\n 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>`;\r\n this.brandingEl.addEventListener('click', (e) => { e.stopPropagation(); window.open('https://xtro.vercel.app/', '_blank'); });\r\n this.panelEl.appendChild(this.brandingEl);\r\n }\r\n\r\n private buildLangButtons(): void {\r\n if (!this.langSwitchEl) return;\r\n this.langSwitchEl.innerHTML = '';\r\n const select = document.createElement('select');\r\n select.className = 'lcms-lang-select';\r\n for (const lang of this.languages) {\r\n const opt = document.createElement('option');\r\n opt.value = lang;\r\n opt.textContent = lang.toUpperCase();\r\n if (lang === this.currentLang) opt.selected = true;\r\n select.appendChild(opt);\r\n }\r\n select.addEventListener('change', (e) => { e.stopPropagation(); this.switchLang((e.target as HTMLSelectElement).value); });\r\n this.langSwitchEl.appendChild(select);\r\n const arrow = document.createElement('span');\r\n arrow.className = 'lcms-lang-arrow';\r\n arrow.textContent = '\\u25BC';\r\n this.langSwitchEl.appendChild(arrow);\r\n }\r\n\r\n // ===============================================\r\n // UI UPDATE\r\n // ===============================================\r\n\r\n private updateUI(): void {\r\n // FAB visibility\r\n if (this.fabEl) {\r\n this.fabEl.style.display = this.isEditAllowed ? '' : 'none';\r\n }\r\n\r\n // FAB button vs panel\r\n if (this.fabBtn) {\r\n this.fabBtn.style.display = this.isOpen ? 'none' : '';\r\n this.fabBtn.classList.toggle('lcms-fab-active', this.editMode);\r\n }\r\n if (this.panelEl) {\r\n this.panelEl.classList.toggle('lcms-hidden', !this.isOpen);\r\n // Position panel\r\n if (this.isOpen) {\r\n const openUp = this.posY > window.innerHeight / 2;\r\n const openLeft = this.posX > window.innerWidth / 2;\r\n this.panelEl.style.bottom = openUp ? '0' : '';\r\n this.panelEl.style.top = openUp ? '' : '0';\r\n this.panelEl.style.right = openLeft ? '0' : '';\r\n this.panelEl.style.left = openLeft ? '' : '0';\r\n }\r\n }\r\n\r\n // Badge\r\n if (this.badgeEl) {\r\n this.badgeEl.classList.toggle('lcms-hidden', this.unsavedChanges === 0);\r\n this.badgeEl.textContent = String(this.unsavedChanges);\r\n }\r\n\r\n // Edit toggle\r\n if (this.editToggle) this.editToggle.checked = this.editMode;\r\n\r\n // Lang switch\r\n if (this.langSwitchEl) {\r\n this.langSwitchEl.classList.toggle('lcms-hidden', !this.editMode || this.languages.length <= 1);\r\n const sel = this.langSwitchEl.querySelector('.lcms-lang-select') as HTMLSelectElement | null;\r\n if (sel) sel.value = this.currentLang;\r\n }\r\n\r\n // Edit mode content\r\n if (this.editModeContent) {\r\n this.editModeContent.classList.toggle('lcms-hidden', !this.editMode);\r\n }\r\n\r\n // Changes info\r\n if (this.changesInfoEl) {\r\n this.changesInfoEl.classList.toggle('lcms-hidden', this.unsavedChanges === 0);\r\n this.changesInfoEl.textContent = `${this.unsavedChanges} unsaved change${this.unsavedChanges > 1 ? 's' : ''}`;\r\n }\r\n\r\n // Undo/Redo\r\n if (this.undoBtn) this.undoBtn.disabled = !this.canUndo;\r\n if (this.redoBtn) this.redoBtn.disabled = !this.canRedo;\r\n\r\n // History button\r\n if (this.historyBtnEl) this.historyBtnEl.classList.toggle('active', this.showHistory);\r\n if (this.historyPanelEl) this.historyPanelEl.classList.toggle('lcms-hidden', !this.showHistory);\r\n\r\n // Save/Publish buttons\r\n if (this.saveBtn) {\r\n this.saveBtn.disabled = this.isSaving || this.isPublishing || this.unsavedChanges === 0;\r\n this.saveBtn.innerHTML = this.isSaving ? '<span class=\"lcms-spinner\"></span> Saving...' : `${ICON.save} Save Draft`;\r\n }\r\n if (this.publishBtn) {\r\n this.publishBtn.disabled = this.isSaving || this.isPublishing;\r\n this.publishBtn.innerHTML = this.isPublishing ? '<span class=\"lcms-spinner\"></span> Publishing...' : `${ICON.publish} Publish`;\r\n }\r\n\r\n // Loader\r\n if (this.loaderEl) this.loaderEl.classList.toggle('lcms-hidden', !this.loading);\r\n\r\n // Image overlay\r\n if (this.imgOverlay) this.imgOverlay.classList.toggle('lcms-hidden', !this.imageUploading);\r\n }\r\n\r\n // ===============================================\r\n // DOM SCANNING\r\n // ===============================================\r\n\r\n private autoDetectAndScan(): void {\r\n this.autoDetectElements();\r\n this.scanDOM();\r\n this.scanImages();\r\n }\r\n\r\n private resolveContainer(): Element {\r\n if (this.containerSelector) {\r\n return document.querySelector(this.containerSelector) || document.body;\r\n }\r\n return document.body;\r\n }\r\n\r\n private autoDetectElements(): void {\r\n const container = this.resolveContainer();\r\n if (!container) return;\r\n\r\n // Clean up stale auto-detected elements\r\n for (const el of this.autoDetectedElements) {\r\n if (!document.contains(el)) this.autoDetectedElements.delete(el);\r\n }\r\n\r\n // Detect section slug based on ancestor tag name\r\n // Only custom component tags ending with '-header'/'-footer' (e.g. <app-header>, <app-footer>)\r\n // get separate section slugs. Native HTML <header>/<footer> tags are treated as page content.\r\n const getSectionSlug = (el: HTMLElement): string => {\r\n let parent: HTMLElement | null = el.parentElement;\r\n while (parent && parent !== document.body) {\r\n const tag = parent.tagName.toLowerCase();\r\n if (tag.endsWith('-header')) return '/header';\r\n if (tag.endsWith('-footer')) return '/footer';\r\n parent = parent.parentElement;\r\n }\r\n return this.currentSlug;\r\n };\r\n\r\n // Section-aware tag counters to avoid key collisions across sections\r\n const tagCounters: { [section: string]: { [tag: string]: number } } = {};\r\n\r\n const hasCmsKey = (candidate: string) => {\r\n return Array.from(document.querySelectorAll<HTMLElement>('[data-cms]'))\r\n .some(node => node.getAttribute('data-cms') === candidate);\r\n };\r\n\r\n const assignKey = (el: HTMLElement, sectionSlug: string) => {\r\n const sectionKey = sectionSlug === '/header' ? 'header'\r\n : sectionSlug === '/footer' ? 'footer' : 'page';\r\n if (!tagCounters[sectionKey]) tagCounters[sectionKey] = {};\r\n const tag = el.tagName.toLowerCase();\r\n if (!tagCounters[sectionKey][tag]) tagCounters[sectionKey][tag] = 0;\r\n const prefix = sectionKey !== 'page' ? `${sectionKey}_` : '';\r\n let key = `${prefix}xcms_${tag}_${tagCounters[sectionKey][tag]}`;\r\n while (hasCmsKey(key)) {\r\n tagCounters[sectionKey][tag]++;\r\n key = `${prefix}xcms_${tag}_${tagCounters[sectionKey][tag]}`;\r\n }\r\n tagCounters[sectionKey][tag]++;\r\n el.setAttribute('data-cms', key);\r\n el.setAttribute('data-cms-section', sectionSlug); // used during save/load\r\n this.autoDetectedElements.add(el);\r\n };\r\n\r\n // Inline formatting tags created by rich text (execCommand) — never auto-scan these\r\n const RICH_TEXT_INLINE = new Set(['B', 'STRONG', 'I', 'EM', 'U', 'S', 'STRIKE', 'DEL', 'SUB', 'SUP', 'MARK']);\r\n\r\n // Scan standard editable tags (h1, p, div, etc.)\r\n const selector = this.editableTags.join(',');\r\n const elements = container.querySelectorAll<HTMLElement>(selector);\r\n elements.forEach(el => {\r\n if (el.hasAttribute('data-cms')) return;\r\n if (el.closest('#xtroedge-cms-root, #lcms-login-modal, script, style, noscript')) return;\r\n // Skip inline formatting tags inside elements already managed by CMS\r\n if (RICH_TEXT_INLINE.has(el.tagName) && el.parentElement?.closest('[data-cms]')) return;\r\n if (el.children.length > 3) return;\r\n const text = this.getDirectTextContent(el).trim();\r\n if (text.length < 2) return;\r\n assignKey(el, getSectionSlug(el));\r\n });\r\n\r\n // Scan [data-editable] elements — works with ANY tag (app-header, app-footer, custom components)\r\n // No children/text restrictions since user explicitly marked them\r\n const dataEditables = container.querySelectorAll<HTMLElement>('[data-editable]');\r\n dataEditables.forEach(el => {\r\n if (el.hasAttribute('data-cms')) return;\r\n if (el.closest('#xtroedge-cms-root, #lcms-login-modal, script, style, noscript')) return;\r\n assignKey(el, getSectionSlug(el));\r\n });\r\n }\r\n\r\n private scanDOM(): void {\r\n const elements = document.querySelectorAll<HTMLElement>('[data-cms]');\r\n const seenKeys = new Set<string>();\r\n elements.forEach(el => {\r\n if (el.closest('#xtroedge-cms-root, #lcms-login-modal')) return;\r\n let key = el.getAttribute('data-cms')!;\r\n if (seenKeys.has(key)) {\r\n let idx = 1;\r\n let repaired = `${key}__${idx}`;\r\n while (document.querySelector(`[data-cms=\"${repaired}\"]`)) {\r\n idx++;\r\n repaired = `${key}__${idx}`;\r\n }\r\n el.setAttribute('data-cms', repaired);\r\n key = repaired;\r\n }\r\n seenKeys.add(key);\r\n this.registeredKeys.add(key);\r\n if (!this.managedElements.has(el)) {\r\n this.attachElement(el, key);\r\n }\r\n });\r\n // Cleanup removed elements\r\n for (const [el] of this.managedElements) {\r\n if (!document.contains(el)) this.detachElement(el);\r\n }\r\n }\r\n\r\n private scanImages(): void {\r\n const container = this.resolveContainer();\r\n if (!container) return;\r\n const currentImages = { ...this.pageImages };\r\n let hasNew = false;\r\n const images = container.querySelectorAll<HTMLImageElement>('img');\r\n images.forEach(img => {\r\n if (img.closest('#xtroedge-cms-root')) return;\r\n if (this.managedImages.has(img)) return;\r\n const src = img.getAttribute('src') || '';\r\n if (!src || src.startsWith('data:')) return;\r\n this.attachImage(img, src);\r\n if (!currentImages[src]) {\r\n currentImages[src] = src;\r\n hasNew = true;\r\n }\r\n });\r\n if (hasNew) {\r\n this.pageImages = currentImages;\r\n this.originalImages = JSON.parse(JSON.stringify(currentImages));\r\n }\r\n for (const [img] of this.managedImages) {\r\n if (!document.contains(img)) this.detachImage(img);\r\n }\r\n }\r\n\r\n private getDirectTextContent(el: HTMLElement): string {\r\n let text = '';\r\n for (let i = 0; i < el.childNodes.length; i++) {\r\n if (el.childNodes[i].nodeType === Node.TEXT_NODE) {\r\n text += el.childNodes[i].textContent || '';\r\n }\r\n }\r\n return text;\r\n }\r\n\r\n private hasEditableChildren(el: HTMLElement): boolean {\r\n return !!el.querySelector('[data-cms]');\r\n }\r\n\r\n private getElementContent(el: HTMLElement): string {\r\n if (this.richTextEnabled) return el.innerHTML?.trim() || '';\r\n if (this.hasEditableChildren(el)) return this.getDirectTextContent(el).trim();\r\n return el.textContent?.trim() || '';\r\n }\r\n\r\n private setElementContent(el: HTMLElement, val: string): void {\r\n if (this.richTextEnabled) {\r\n el.innerHTML = this.sanitizeHTML(val);\r\n } else if (this.hasEditableChildren(el)) {\r\n const textNodes: Text[] = [];\r\n for (let i = 0; i < el.childNodes.length; i++) {\r\n if (el.childNodes[i].nodeType === Node.TEXT_NODE) textNodes.push(el.childNodes[i] as Text);\r\n }\r\n if (textNodes.length > 0) textNodes[0].textContent = val;\r\n else el.prepend(document.createTextNode(val));\r\n } else {\r\n el.textContent = val;\r\n }\r\n }\r\n\r\n // Legacy alias for backward compat with internal calls\r\n private setDirectTextContent(el: HTMLElement, val: string): void {\r\n this.setElementContent(el, val);\r\n }\r\n\r\n // ===============================================\r\n // ELEMENT EDITING\r\n // ===============================================\r\n\r\n private attachElement(el: HTMLElement, key: string): void {\r\n const getContent = () => this.getElementContent(el);\r\n const blurHandler = () => {\r\n const text = getContent();\r\n const currentVal = this.getPageText(key);\r\n if (text !== currentVal) this.onTextChanged(key, text);\r\n this.hideRichToolbar();\r\n };\r\n const keydownHandler = (e: KeyboardEvent) => {\r\n if (e.key === 'Enter') {\r\n // Allow Enter for multi-line elements when rich text is enabled\r\n if (this.richTextEnabled && !XtroedgeCMS.SINGLE_LINE_TAGS.has(el.tagName)) {\r\n return; // Allow default Enter behavior (line break)\r\n }\r\n e.preventDefault();\r\n el.blur();\r\n }\r\n };\r\n const inputHandler = () => {\r\n const text = getContent();\r\n const currentVal = this.getPageText(key);\r\n if (text !== currentVal) this.onTextChanged(key, text);\r\n };\r\n const focusEditableEnd = () => {\r\n if (document.activeElement !== el) el.focus();\r\n const selection = window.getSelection();\r\n if (!selection) return;\r\n const range = document.createRange();\r\n range.selectNodeContents(el);\r\n range.collapse(false);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n };\r\n\r\n // In edit mode: stop propagation to prevent dropdown close.\r\n // If editable is inside an anchor, block navigation.\r\n const clickHandler = (e: Event) => {\r\n e.stopPropagation();\r\n const inAnchor = el.tagName === 'A' || !!(e.target as HTMLElement).closest('a');\r\n if (inAnchor) {\r\n e.preventDefault();\r\n // Don't call focusEditableEnd() - let browser handle cursor positioning naturally\r\n // Element will focus automatically, and cursor will be placed where user clicked\r\n }\r\n };\r\n const sectionSlug = el.getAttribute('data-cms-section') || this.currentSlug;\r\n this.managedElements.set(el, { key, sectionSlug, blurHandler, keydownHandler, inputHandler, clickHandler });\r\n if (this.editMode) this.enableElementEdit(el, key, blurHandler, keydownHandler, inputHandler, clickHandler);\r\n }\r\n\r\n private detachElement(el: HTMLElement): void {\r\n const info = this.managedElements.get(el);\r\n if (info) {\r\n el.removeEventListener('blur', info.blurHandler);\r\n el.removeEventListener('keydown', info.keydownHandler as EventListener);\r\n el.removeEventListener('input', info.inputHandler);\r\n el.removeEventListener('click', info.clickHandler, true);\r\n el.removeAttribute('contenteditable');\r\n this.managedElements.delete(el);\r\n }\r\n }\r\n\r\n /** Stop propagation so parent carousels (Swiper, Owl, etc.) don't hijack the event */\r\n private static stopProp(e: Event): void { e.stopPropagation(); }\r\n\r\n private focusEditableEnd(el: HTMLElement): void {\r\n if (document.activeElement !== el) el.focus();\r\n const selection = window.getSelection();\r\n if (!selection) return;\r\n const range = document.createRange();\r\n range.selectNodeContents(el);\r\n range.collapse(false);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n }\r\n\r\n private enableElementEdit(el: HTMLElement, _key: string, blurH: (e: Event) => void, keyH: (e: KeyboardEvent) => void, inputH: (e: Event) => void, clickH: (e: Event) => void): void {\r\n const val = this.getPageText(_key);\r\n // Only set content if element is NOT currently focused (preserve cursor position)\r\n if (val && document.activeElement !== el) {\r\n this.setElementContent(el, val);\r\n }\r\n el.setAttribute('contenteditable', 'true');\r\n el.style.setProperty('outline', `2px dashed ${this.highlightColor}`, 'important');\r\n el.style.setProperty('outline-offset', '-2px', 'important');\r\n el.style.cursor = 'text';\r\n el.style.transition = 'background 0.2s';\r\n el.style.minWidth = '20px';\r\n\r\n // COMMENTED OUT: Double-click to show floating edit dialog\r\n // const dblClickHandler = (e: Event) => {\r\n // e.preventDefault();\r\n // e.stopPropagation();\r\n // this.showFloatingEditDialog(el, _key);\r\n // };\r\n // el.addEventListener('dblclick', dblClickHandler);\r\n // el.dataset.cmsDblClickAdded = 'true';\r\n\r\n el.addEventListener('blur', blurH);\r\n el.addEventListener('keydown', keyH as EventListener);\r\n el.addEventListener('input', inputH);\r\n el.addEventListener('click', clickH, true);\r\n // Prevent parent carousels/sliders from capturing pointer events on editable elements\r\n el.addEventListener('mousedown', XtroedgeCMS.stopProp, true);\r\n el.addEventListener('touchstart', XtroedgeCMS.stopProp, true);\r\n // Show rich text toolbar on focus\r\n el.addEventListener('focus', () => this.showRichToolbar(el));\r\n }\r\n\r\n private disableElementEdit(el: HTMLElement, _key: string, blurH: (e: Event) => void, keyH: (e: KeyboardEvent) => void, inputH: (e: Event) => void, clickH: (e: Event) => void): void {\r\n el.removeAttribute('contenteditable');\r\n el.style.removeProperty('outline');\r\n el.style.removeProperty('outline-offset');\r\n el.style.cursor = '';\r\n el.style.transition = '';\r\n el.style.minWidth = '';\r\n const val = this.getPageText(_key);\r\n if (val) this.setElementContent(el, val);\r\n el.removeEventListener('blur', blurH);\r\n el.removeEventListener('keydown', keyH as EventListener);\r\n el.removeEventListener('input', inputH);\r\n el.removeEventListener('click', clickH, true);\r\n el.removeEventListener('mousedown', XtroedgeCMS.stopProp, true);\r\n el.removeEventListener('touchstart', XtroedgeCMS.stopProp, true);\r\n }\r\n\r\n private applyEditMode(editMode: boolean): void {\r\n // Add/remove body class for edit-mode CSS overrides\r\n document.body.classList.toggle('lcms-editing', editMode);\r\n\r\n if (editMode) {\r\n // Document-level capture handler: stop pointer/click propagation on CMS-managed targets\r\n // so dropdowns, modals, etc. stay open while user edits content.\r\n this.editClickCaptureHandler = (e: Event) => {\r\n const target = e.target as HTMLElement;\r\n if (!target) return;\r\n\r\n const editable = target.closest('[contenteditable=\"true\"]') as HTMLElement | null;\r\n const imageTarget = target.closest('[data-cms-image-key], img[data-cms-key], [data-cms-key]') as HTMLElement | null;\r\n const isManagedEditable = !!editable && this.managedElements.has(editable);\r\n const isManagedImage = !!imageTarget && this.managedImages.has(imageTarget as HTMLImageElement);\r\n const isManagedTarget = isManagedEditable || isManagedImage || !!editable || !!imageTarget;\r\n\r\n if (isManagedTarget) {\r\n // Don't call focusEditableEnd - let browser handle cursor positioning naturally\r\n // Element will focus automatically, and cursor will be placed where user clicked\r\n e.stopPropagation();\r\n const anchor = target.closest('a');\r\n if (anchor) e.preventDefault();\r\n }\r\n };\r\n document.addEventListener('click', this.editClickCaptureHandler, true);\r\n document.addEventListener('mousedown', this.editClickCaptureHandler, true);\r\n document.addEventListener('pointerdown', this.editClickCaptureHandler, true);\r\n document.addEventListener('touchstart', this.editClickCaptureHandler, true);\r\n\r\n // Track scroll to toggle pointer-events on visible/hidden animated elements\r\n this.editScrollHandler = () => {\r\n if (this.editScrollRAF) return;\r\n this.editScrollRAF = requestAnimationFrame(() => {\r\n this.syncEditablePointerEvents();\r\n this.editScrollRAF = null;\r\n });\r\n };\r\n window.addEventListener('scroll', this.editScrollHandler, { passive: true });\r\n this.syncEditablePointerEvents();\r\n } else {\r\n // Clean up document-level capture handler\r\n if (this.editClickCaptureHandler) {\r\n document.removeEventListener('click', this.editClickCaptureHandler, true);\r\n document.removeEventListener('mousedown', this.editClickCaptureHandler, true);\r\n document.removeEventListener('pointerdown', this.editClickCaptureHandler, true);\r\n document.removeEventListener('touchstart', this.editClickCaptureHandler, true);\r\n this.editClickCaptureHandler = null;\r\n }\r\n // Clean up scroll listener\r\n if (this.editScrollHandler) {\r\n window.removeEventListener('scroll', this.editScrollHandler);\r\n this.editScrollHandler = null;\r\n }\r\n if (this.editScrollRAF) { cancelAnimationFrame(this.editScrollRAF); this.editScrollRAF = null; }\r\n // Restore pointer-events on all elements we modified\r\n for (const [el] of this.managedElements) el.style.pointerEvents = '';\r\n this.modifiedAncestors.forEach(a => { a.style.pointerEvents = ''; });\r\n this.modifiedAncestors.clear();\r\n }\r\n\r\n for (const [el, info] of this.managedElements) {\r\n if (editMode) this.enableElementEdit(el, info.key, info.blurHandler, info.keydownHandler, info.inputHandler, info.clickHandler);\r\n else this.disableElementEdit(el, info.key, info.blurHandler, info.keydownHandler, info.inputHandler, info.clickHandler);\r\n }\r\n this.applyImageEditMode(editMode);\r\n // Rich text toolbar lifecycle\r\n if (editMode) this.createRichToolbar();\r\n else this.destroyRichToolbar();\r\n }\r\n\r\n /** Set of positioned ancestors we added pointer-events:none to (for cleanup) */\r\n private modifiedAncestors = new Set<HTMLElement>();\r\n\r\n /**\r\n * For each managed element, find the nearest position:absolute/fixed ancestor.\r\n * If that ancestor is invisible (opacity ≈ 0), set pointer-events:none on it\r\n * so clicks pass through to the visible element behind it.\r\n */\r\n private syncEditablePointerEvents(): void {\r\n const checked = new Map<HTMLElement, boolean>();\r\n\r\n for (const [el] of this.managedElements) {\r\n const ancestor = this.findPositionedAncestor(el);\r\n if (!ancestor) continue;\r\n\r\n // Only compute once per ancestor\r\n if (!checked.has(ancestor)) {\r\n const cs = window.getComputedStyle(ancestor);\r\n const visible = parseFloat(cs.opacity) >= 0.15\r\n && cs.visibility !== 'hidden'\r\n && cs.display !== 'none';\r\n checked.set(ancestor, visible);\r\n\r\n if (!visible) {\r\n ancestor.style.pointerEvents = 'none';\r\n this.modifiedAncestors.add(ancestor);\r\n } else {\r\n if (this.modifiedAncestors.has(ancestor)) {\r\n ancestor.style.pointerEvents = '';\r\n this.modifiedAncestors.delete(ancestor);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** Walk up from el to find the nearest position:absolute or position:fixed ancestor */\r\n private findPositionedAncestor(el: HTMLElement): HTMLElement | null {\r\n let cur = el.parentElement;\r\n while (cur && cur !== document.body) {\r\n if (cur.closest('#xtroedge-cms-root')) return null;\r\n const pos = window.getComputedStyle(cur).position;\r\n if (pos === 'absolute' || pos === 'fixed') return cur;\r\n cur = cur.parentElement;\r\n }\r\n return null;\r\n }\r\n\r\n private killAnimations(): void {\r\n const win = window as any;\r\n\r\n // Kill GSAP ScrollTrigger (CDN or global version)\r\n if (win.ScrollTrigger) {\r\n try { win.ScrollTrigger.getAll().forEach((t: any) => t.kill(true)); } catch { /* ignore */ }\r\n }\r\n // Kill all GSAP tweens\r\n if (win.gsap) {\r\n try {\r\n win.gsap.globalTimeline.clear();\r\n win.gsap.killTweensOf('*');\r\n } catch { /* ignore */ }\r\n }\r\n // Disable AOS\r\n if (win.AOS) {\r\n try { win.AOS.refreshHard?.(); } catch { /* ignore */ }\r\n }\r\n\r\n // Remove GSAP pin-spacer wrappers\r\n this.removePinSpacers();\r\n\r\n // Clear GSAP-set inline styles from elements (one-time cleanup)\r\n this.clearAnimationInlineStyles();\r\n\r\n // Re-run after delay for late-initialized animations\r\n setTimeout(() => { this.removePinSpacers(); this.clearAnimationInlineStyles(); }, 500);\r\n setTimeout(() => { this.removePinSpacers(); this.clearAnimationInlineStyles(); }, 1500);\r\n }\r\n\r\n /** Remove GSAP ScrollTrigger pin-spacer wrapper divs and restore original elements */\r\n private removePinSpacers(): void {\r\n document.querySelectorAll('.pin-spacer').forEach(spacer => {\r\n const child = spacer.firstElementChild as HTMLElement;\r\n if (child) {\r\n spacer.parentNode?.insertBefore(child, spacer);\r\n child.style.cssText = '';\r\n }\r\n spacer.remove();\r\n });\r\n }\r\n\r\n /** Clear only animation-related inline styles (set by GSAP/ScrollTrigger) without breaking layout */\r\n private clearAnimationInlineStyles(): void {\r\n const container = this.containerSelector\r\n ? document.querySelector(this.containerSelector) || document.body\r\n : document.body;\r\n container.querySelectorAll<HTMLElement>('*').forEach(el => {\r\n if (el.closest('#xtroedge-cms-root')) return;\r\n const s = el.style;\r\n // Only clear properties that GSAP typically sets for animations\r\n if (s.pointerEvents === 'none') s.pointerEvents = '';\r\n if (s.userSelect === 'none') s.userSelect = '';\r\n if (s.visibility === 'hidden') s.visibility = '';\r\n if (s.clipPath && s.clipPath !== 'none') s.clipPath = '';\r\n });\r\n }\r\n\r\n /** Capture each element's current DOM text before CMS applies saved edits */\r\n private captureDomOriginals(): void {\r\n this.domOriginals = {};\r\n for (const [el, info] of this.managedElements) {\r\n this.domOriginals[info.key] = this.getElementContent(el);\r\n }\r\n }\r\n\r\n /** Ensure every entry in pageTexts has _orig for current language (from domOriginals) */\r\n private ensureOriginals(): void {\r\n const origKey = `_orig_${this.currentLang}`;\r\n for (const key of Object.keys(this.pageTexts)) {\r\n if (!this.pageTexts[key][origKey] && this.domOriginals[key]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key];\r\n }\r\n }\r\n }\r\n\r\n /** Find a managed element whose current text matches the given original text */\r\n private findElementByOriginal(originalText: string, tagName: string): HTMLElement | null {\r\n for (const [el] of this.managedElements) {\r\n if (el.tagName !== tagName) continue;\r\n const current = this.getElementContent(el);\r\n if (current === originalText) return el;\r\n }\r\n return null;\r\n }\r\n\r\n private updateElementTexts(): void {\r\n this.observer?.disconnect();\r\n let orphanedCount = 0;\r\n\r\n for (const [el, info] of this.managedElements) {\r\n if (document.activeElement === el) continue;\r\n const entry = this.pageTexts[info.key];\r\n if (!entry) continue;\r\n\r\n const val = entry[this.currentLang];\r\n if (!val) continue;\r\n\r\n const orig = entry[`_orig_${this.currentLang}`];\r\n\r\n // No original stored (old data) → apply directly (backward compat)\r\n if (!orig) {\r\n const current = this.getElementContent(el);\r\n if (val !== current) this.setElementContent(el, val);\r\n continue;\r\n }\r\n\r\n // Verify: does this element's DOM text match the saved original?\r\n const domText = this.domOriginals[info.key] || this.getElementContent(el);\r\n if (domText === orig) {\r\n // Match → apply\r\n if (val !== this.getElementContent(el)) this.setElementContent(el, val);\r\n } else {\r\n // Mismatch → structure may have changed\r\n // findElementByOriginal disabled: same text can appear multiple times on page\r\n // const found = this.findElementByOriginal(orig, el.tagName);\r\n // if (found) {\r\n // this.setElementContent(found, val);\r\n // } else {\r\n // orphanedCount++;\r\n // }\r\n orphanedCount++;\r\n }\r\n }\r\n\r\n // if (orphanedCount > 0) {\r\n // this.showToast(`${orphanedCount} edit(s) couldn't be matched to elements`, 'error');\r\n // }\r\n\r\n this.observer?.observe(document.body, { childList: true, subtree: true });\r\n }\r\n\r\n private cleanupManagedElements(): void {\r\n for (const [el] of this.managedElements) this.detachElement(el);\r\n this.managedElements.clear();\r\n for (const el of this.autoDetectedElements) el.removeAttribute('data-cms');\r\n this.autoDetectedElements.clear();\r\n this.domOriginals = {};\r\n this.cleanupManagedImages();\r\n }\r\n\r\n // ===============================================\r\n // IMAGE MANAGEMENT\r\n // ===============================================\r\n\r\n private attachImage(img: HTMLImageElement, key: string): void {\r\n const ctxHandler = (e: MouseEvent) => {\r\n if (!this.editMode) return;\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.showImageContextMenu(e.clientX, e.clientY, img);\r\n };\r\n this.managedImages.set(img, { key, ctxHandler });\r\n if (this.editMode) this.enableImageEdit(img, ctxHandler);\r\n }\r\n\r\n private detachImage(img: HTMLImageElement): void {\r\n const info = this.managedImages.get(img);\r\n if (info) {\r\n img.removeEventListener('contextmenu', info.ctxHandler);\r\n img.style.removeProperty('outline');\r\n img.style.cursor = '';\r\n this.managedImages.delete(img);\r\n }\r\n }\r\n\r\n private cleanupManagedImages(): void {\r\n for (const [img] of this.managedImages) this.detachImage(img);\r\n this.managedImages.clear();\r\n this.dismissImageCtxMenu();\r\n }\r\n\r\n private applyImageEditMode(editMode: boolean): void {\r\n for (const [img, info] of this.managedImages) {\r\n if (editMode) this.enableImageEdit(img, info.ctxHandler);\r\n else this.disableImageEdit(img, info.ctxHandler);\r\n }\r\n if (!editMode) {\r\n this.dismissImageCtxMenu();\r\n this.dismissFloatingEditDialog();\r\n }\r\n }\r\n\r\n private enableImageEdit(img: HTMLImageElement, ctxHandler: (e: MouseEvent) => void): void {\r\n if (!img.dataset.origTitle) img.dataset.origTitle = img.title || '';\r\n img.title = 'Right-click to change image';\r\n img.style.setProperty('outline', `2px dashed ${this.highlightColor}`, 'important');\r\n img.style.cursor = 'context-menu';\r\n img.addEventListener('contextmenu', ctxHandler);\r\n }\r\n\r\n private disableImageEdit(img: HTMLImageElement, ctxHandler: (e: MouseEvent) => void): void {\r\n img.title = img.dataset.origTitle || '';\r\n delete img.dataset.origTitle;\r\n img.style.removeProperty('outline');\r\n img.style.cursor = '';\r\n img.removeEventListener('contextmenu', ctxHandler);\r\n }\r\n\r\n private showImageContextMenu(x: number, y: number, img: HTMLImageElement): void {\r\n this.dismissImageCtxMenu();\r\n const menu = document.createElement('div');\r\n Object.assign(menu.style, {\r\n position: 'fixed', zIndex: '10005', minWidth: '160px',\r\n background: 'rgba(30,15,60,0.85)', backdropFilter: 'blur(16px)', webkitBackdropFilter: 'blur(16px)',\r\n border: '1px solid rgba(139,92,246,0.3)', borderRadius: '10px', padding: '4px',\r\n boxShadow: '0 8px 32px rgba(0,0,0,0.4)', fontFamily: 'system-ui, -apple-system, sans-serif',\r\n left: Math.min(x, window.innerWidth - 180) + 'px',\r\n top: Math.min(y, window.innerHeight - 50) + 'px',\r\n });\r\n const btn = document.createElement('button');\r\n Object.assign(btn.style, {\r\n width: '100%', padding: '8px 12px', border: 'none', borderRadius: '7px',\r\n background: 'transparent', color: 'white', fontSize: '12px', fontWeight: '500',\r\n cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px',\r\n });\r\n btn.innerHTML = `${ICON.image} Upload Image`;\r\n btn.addEventListener('mouseenter', () => btn.style.background = 'rgba(103,34,251,0.3)');\r\n btn.addEventListener('mouseleave', () => btn.style.background = 'transparent');\r\n btn.addEventListener('click', () => {\r\n this.activeImageEl = img;\r\n if (this.fileInput) { this.fileInput.value = ''; this.fileInput.click(); }\r\n this.dismissImageCtxMenu();\r\n });\r\n menu.appendChild(btn);\r\n (this.rootEl || document.body).appendChild(menu);\r\n this.imageCtxMenu = menu;\r\n\r\n const closeHandler = (e: MouseEvent) => {\r\n if (!menu.contains(e.target as Node)) {\r\n this.dismissImageCtxMenu();\r\n document.removeEventListener('mousedown', closeHandler);\r\n }\r\n };\r\n setTimeout(() => document.addEventListener('mousedown', closeHandler), 0);\r\n }\r\n\r\n private dismissImageCtxMenu(): void {\r\n if (this.imageCtxMenu) {\r\n this.imageCtxMenu.remove();\r\n this.imageCtxMenu = null;\r\n }\r\n }\r\n\r\n private showFloatingEditDialog(el: HTMLElement, key: string): void {\r\n this.dismissFloatingEditDialog();\r\n\r\n const currentText = el.textContent || '';\r\n const rect = el.getBoundingClientRect();\r\n\r\n const dialog = document.createElement('div');\r\n Object.assign(dialog.style, {\r\n position: 'fixed',\r\n zIndex: '99999',\r\n left: `${Math.max(20, rect.left)}px`,\r\n top: `${Math.max(20, rect.top - 120)}px`,\r\n background: 'rgba(15, 10, 40, 0.95)',\r\n backdropFilter: 'blur(20px)',\r\n webkitBackdropFilter: 'blur(20px)',\r\n border: '2px solid rgba(139, 92, 246, 0.5)',\r\n borderRadius: '12px',\r\n padding: '16px',\r\n boxShadow: '0 12px 48px rgba(0, 0, 0, 0.6)',\r\n minWidth: '320px',\r\n maxWidth: '500px',\r\n });\r\n\r\n const title = document.createElement('div');\r\n title.textContent = 'Edit Text';\r\n Object.assign(title.style, {\r\n color: 'rgba(255, 255, 255, 0.9)',\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n marginBottom: '12px',\r\n fontFamily: 'system-ui, sans-serif',\r\n });\r\n\r\n const textarea = document.createElement('textarea');\r\n textarea.value = currentText;\r\n Object.assign(textarea.style, {\r\n width: '100%',\r\n minHeight: '80px',\r\n background: 'rgba(255, 255, 255, 0.08)',\r\n border: '1px solid rgba(139, 92, 246, 0.3)',\r\n borderRadius: '8px',\r\n color: 'white',\r\n padding: '10px',\r\n fontSize: '14px',\r\n fontFamily: 'system-ui, sans-serif',\r\n resize: 'vertical',\r\n outline: 'none',\r\n });\r\n textarea.addEventListener('focus', () => {\r\n textarea.style.borderColor = this.highlightColor;\r\n });\r\n textarea.addEventListener('blur', () => {\r\n textarea.style.borderColor = 'rgba(139, 92, 246, 0.3)';\r\n });\r\n\r\n const buttons = document.createElement('div');\r\n Object.assign(buttons.style, {\r\n display: 'flex',\r\n gap: '8px',\r\n marginTop: '12px',\r\n justifyContent: 'flex-end',\r\n });\r\n\r\n const cancelBtn = document.createElement('button');\r\n cancelBtn.textContent = 'Cancel';\r\n Object.assign(cancelBtn.style, {\r\n padding: '8px 16px',\r\n background: 'rgba(255, 255, 255, 0.1)',\r\n border: 'none',\r\n borderRadius: '6px',\r\n color: 'rgba(255, 255, 255, 0.7)',\r\n fontSize: '13px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n fontFamily: 'system-ui, sans-serif',\r\n });\r\n cancelBtn.addEventListener('click', () => this.dismissFloatingEditDialog());\r\n cancelBtn.addEventListener('mouseenter', () => cancelBtn.style.background = 'rgba(255, 255, 255, 0.15)');\r\n cancelBtn.addEventListener('mouseleave', () => cancelBtn.style.background = 'rgba(255, 255, 255, 0.1)');\r\n\r\n const saveBtn = document.createElement('button');\r\n saveBtn.textContent = 'Save';\r\n Object.assign(saveBtn.style, {\r\n padding: '8px 16px',\r\n background: this.highlightColor,\r\n border: 'none',\r\n borderRadius: '6px',\r\n color: 'white',\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n cursor: 'pointer',\r\n fontFamily: 'system-ui, sans-serif',\r\n });\r\n saveBtn.addEventListener('click', () => {\r\n const newText = textarea.value;\r\n this.setElementContent(el, newText);\r\n this.onTextChanged(key, newText);\r\n this.dismissFloatingEditDialog();\r\n });\r\n saveBtn.addEventListener('mouseenter', () => saveBtn.style.opacity = '0.9');\r\n saveBtn.addEventListener('mouseleave', () => saveBtn.style.opacity = '1');\r\n\r\n buttons.appendChild(cancelBtn);\r\n buttons.appendChild(saveBtn);\r\n\r\n dialog.appendChild(title);\r\n dialog.appendChild(textarea);\r\n dialog.appendChild(buttons);\r\n\r\n (this.rootEl || document.body).appendChild(dialog);\r\n this.floatingEditDialog = dialog;\r\n\r\n textarea.focus();\r\n textarea.select();\r\n\r\n const closeHandler = (e: MouseEvent) => {\r\n if (!dialog.contains(e.target as Node)) {\r\n this.dismissFloatingEditDialog();\r\n document.removeEventListener('mousedown', closeHandler);\r\n }\r\n };\r\n setTimeout(() => document.addEventListener('mousedown', closeHandler), 0);\r\n }\r\n\r\n private dismissFloatingEditDialog(): void {\r\n if (this.floatingEditDialog) {\r\n this.floatingEditDialog.remove();\r\n this.floatingEditDialog = null;\r\n }\r\n }\r\n\r\n private onImageFileSelected(event: Event): void {\r\n const input = event.target as HTMLInputElement;\r\n const file = input.files?.[0];\r\n if (!file || !this.activeImageEl) return;\r\n\r\n this.imageUploading = true;\r\n this.updateUI();\r\n\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n const dataUrl = reader.result as string;\r\n this.uploadImageToApi(dataUrl);\r\n };\r\n reader.readAsDataURL(file);\r\n }\r\n\r\n private async uploadImageToApi(dataUrl: string): Promise<void> {\r\n try {\r\n // If image_url is set (from company detail), resolve it; otherwise use default\r\n const storedImageUrl = XtroedgeCMS.secureGet('xtroedge_image_url');\r\n const clientBase = this.config.clientApi || this.config.apiBase;\r\n const uploadUrl = storedImageUrl ? this.resolveClientUrl(storedImageUrl) : `${clientBase}/web/upload-image`;\r\n\r\n const res = await this.apiFetch(uploadUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ url: dataUrl }),\r\n });\r\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\r\n const data = await res.json();\r\n // Use apiBase origin as base for the returned image path\r\n const imgOriginBase = this.config.clientApi || this.config.apiBase || '';\r\n const baseUrl = this.config.imageBaseUrl || (imgOriginBase ? new URL(imgOriginBase).origin : '');\r\n const fullUrl = baseUrl + data.path;\r\n if (this.activeImageEl) {\r\n const key = this.managedImages.get(this.activeImageEl)?.key || '';\r\n this.activeImageEl.src = fullUrl;\r\n this.onImageChanged(key, fullUrl);\r\n }\r\n this.imageUploading = false;\r\n this.activeImageEl = null;\r\n this.updateUI();\r\n this.showToast('Image updated!', 'success');\r\n } catch (err) {\r\n this.imageUploading = false;\r\n this.activeImageEl = null;\r\n this.updateUI();\r\n this.showToast('Image upload failed.', 'error');\r\n this.config.onError?.('upload-image', err);\r\n }\r\n }\r\n\r\n private applyPageImages(): void {\r\n for (const [img, info] of this.managedImages) {\r\n const url = this.pageImages[info.key];\r\n if (url && img.src !== url) img.src = url;\r\n }\r\n }\r\n\r\n // ===============================================\r\n // TEXT STATE\r\n // ===============================================\r\n\r\n private getPageText(key: string): string {\r\n return this.pageTexts[key]?.[this.currentLang] || '';\r\n }\r\n\r\n private onTextChanged(key: string, newValue: string): void {\r\n this.undoStack.push(this.createSnapshot());\r\n this.redoStack = [];\r\n this.canUndo = true;\r\n this.canRedo = false;\r\n\r\n if (!this.pageTexts[key]) this.pageTexts[key] = {};\r\n // Store original DOM text on first edit (for structure-change resilience)\r\n const origKey = `_orig_${this.currentLang}`;\r\n if (!this.pageTexts[key][origKey]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key] || '';\r\n }\r\n this.pageTexts[key] = { ...this.pageTexts[key], [this.currentLang]: newValue };\r\n this.dirtyKeys.add(key);\r\n this.unsavedChanges = this.dirtyKeys.size + this.dirtyImageKeys.size;\r\n this.pushHistory(key, this.currentLang);\r\n this.updateUI();\r\n }\r\n\r\n private onImageChanged(key: string, url: string): void {\r\n this.undoStack.push(this.createSnapshot());\r\n this.redoStack = [];\r\n this.canUndo = true;\r\n this.canRedo = false;\r\n\r\n this.pageImages = { ...this.pageImages, [key]: url };\r\n this.dirtyImageKeys.add(key);\r\n this.unsavedChanges = this.dirtyKeys.size + this.dirtyImageKeys.size;\r\n this.pushHistory(key, 'img');\r\n this.updateUI();\r\n }\r\n\r\n private createSnapshot(): string {\r\n return JSON.stringify({ texts: this.pageTexts, images: this.pageImages });\r\n }\r\n\r\n private applySnapshot(raw: string): void {\r\n const data = JSON.parse(raw);\r\n if (data.texts) {\r\n this.pageTexts = data.texts;\r\n if (data.images) this.pageImages = data.images;\r\n } else {\r\n this.pageTexts = data;\r\n }\r\n }\r\n\r\n // ===============================================\r\n // RICH TEXT TOOLBAR\r\n // ===============================================\r\n\r\n private get richTextEnabled(): boolean {\r\n return this.config.richText !== false; // default true\r\n }\r\n\r\n // Tags where Enter should be blocked (single-line elements)\r\n private static readonly SINGLE_LINE_TAGS = new Set([\r\n 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BUTTON', 'LABEL', 'SPAN', 'A', 'SMALL', 'B', 'STRONG', 'I', 'EM',\r\n ]);\r\n\r\n // Allowed HTML tags for sanitization\r\n private static readonly ALLOWED_TAGS = new Set([\r\n 'B', 'STRONG', 'I', 'EM', 'U', 'S', 'STRIKE', 'A', 'BR', 'UL', 'OL', 'LI', 'SUB', 'SUP',\r\n ]);\r\n\r\n // Allowed attributes per tag\r\n private static readonly ALLOWED_ATTRS: Record<string, Set<string>> = {\r\n A: new Set(['href', 'target', 'rel']),\r\n };\r\n\r\n private sanitizeHTML(html: string): string {\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n const clean = (node: Node): void => {\r\n const children = Array.from(node.childNodes);\r\n for (const child of children) {\r\n if (child.nodeType === Node.TEXT_NODE) continue;\r\n if (child.nodeType === Node.ELEMENT_NODE) {\r\n const el = child as HTMLElement;\r\n if (!XtroedgeCMS.ALLOWED_TAGS.has(el.tagName)) {\r\n // Unwrap: keep children, remove the tag\r\n while (el.firstChild) el.parentNode?.insertBefore(el.firstChild, el);\r\n el.remove();\r\n } else {\r\n // Remove disallowed attributes\r\n const allowedAttrs = XtroedgeCMS.ALLOWED_ATTRS[el.tagName] || new Set();\r\n for (const attr of Array.from(el.attributes)) {\r\n if (!allowedAttrs.has(attr.name)) el.removeAttribute(attr.name);\r\n }\r\n // Sanitize href to prevent javascript: URLs\r\n if (el.tagName === 'A') {\r\n const href = el.getAttribute('href') || '';\r\n if (href.trim().toLowerCase().startsWith('javascript:')) {\r\n el.setAttribute('href', '#');\r\n }\r\n }\r\n clean(el);\r\n }\r\n } else {\r\n child.remove(); // Remove comments, etc.\r\n }\r\n }\r\n };\r\n clean(doc.body);\r\n return doc.body.innerHTML;\r\n }\r\n\r\n private createRichToolbar(): void {\r\n if (!this.richTextEnabled || this.richToolbarEl) return;\r\n\r\n const toolbar = document.createElement('div');\r\n toolbar.className = 'lcms-rich-toolbar';\r\n\r\n const buttons: { cmd: string; label: string; title: string }[] = [\r\n { cmd: 'bold', label: 'B', title: 'Bold' },\r\n { cmd: 'italic', label: '<i>I</i>', title: 'Italic' },\r\n { cmd: 'underline', label: '<u>U</u>', title: 'Underline' },\r\n { cmd: 'strikeThrough', label: '<s>S</s>', title: 'Strikethrough' },\r\n ];\r\n\r\n const linkButtons: { cmd: string; label: string; title: string }[] = [\r\n { cmd: 'createLink', label: '🔗', title: 'Insert Link' },\r\n { cmd: 'unlink', label: '⊘', title: 'Remove Link' },\r\n ];\r\n\r\n const utilButtons: { cmd: string; label: string; title: string }[] = [\r\n { cmd: 'removeFormat', label: '✕', title: 'Clear Formatting' },\r\n ];\r\n\r\n const makeBtn = (item: { cmd: string; label: string; title: string }) => {\r\n const btn = document.createElement('button');\r\n btn.innerHTML = item.label;\r\n btn.title = item.title;\r\n btn.dataset.cmd = item.cmd;\r\n btn.addEventListener('mousedown', (e) => {\r\n e.preventDefault(); // Prevent blur on the editable element\r\n this.execToolbarCommand(item.cmd);\r\n });\r\n return btn;\r\n };\r\n\r\n const addSep = () => {\r\n const sep = document.createElement('div');\r\n sep.className = 'lcms-tb-sep';\r\n toolbar.appendChild(sep);\r\n };\r\n\r\n buttons.forEach(b => toolbar.appendChild(makeBtn(b)));\r\n addSep();\r\n linkButtons.forEach(b => toolbar.appendChild(makeBtn(b)));\r\n addSep();\r\n utilButtons.forEach(b => toolbar.appendChild(makeBtn(b)));\r\n\r\n this.rootEl?.appendChild(toolbar);\r\n this.richToolbarEl = toolbar;\r\n\r\n // Listen for selection changes to update active states\r\n this.selectionChangeHandler = () => this.updateToolbarState();\r\n document.addEventListener('selectionchange', this.selectionChangeHandler);\r\n }\r\n\r\n private destroyRichToolbar(): void {\r\n if (this.richToolbarEl) {\r\n this.richToolbarEl.remove();\r\n this.richToolbarEl = null;\r\n }\r\n if (this.selectionChangeHandler) {\r\n document.removeEventListener('selectionchange', this.selectionChangeHandler);\r\n this.selectionChangeHandler = null;\r\n }\r\n this.activeEditableEl = null;\r\n }\r\n\r\n private execToolbarCommand(cmd: string): void {\r\n // Pause MutationObserver so DOM changes from execCommand don't trigger rescan\r\n this.observer?.disconnect();\r\n if (this.scanTimeout) { clearTimeout(this.scanTimeout); this.scanTimeout = null; }\r\n\r\n if (cmd === 'createLink') {\r\n const url = prompt('Enter URL:', 'https://');\r\n if (url) document.execCommand('createLink', false, url);\r\n } else {\r\n document.execCommand(cmd, false);\r\n }\r\n this.updateToolbarState();\r\n // Trigger input to capture the change\r\n if (this.activeEditableEl) {\r\n this.activeEditableEl.dispatchEvent(new Event('input', { bubbles: true }));\r\n }\r\n\r\n // Re-enable observer after a short delay\r\n setTimeout(() => {\r\n this.observer?.observe(document.body, { childList: true, subtree: true });\r\n }, 50);\r\n }\r\n\r\n private showRichToolbar(el: HTMLElement): void {\r\n if (!this.richTextEnabled || !this.richToolbarEl) return;\r\n if (this.toolbarHideTimeout) { clearTimeout(this.toolbarHideTimeout); this.toolbarHideTimeout = null; }\r\n\r\n this.activeEditableEl = el;\r\n this.positionToolbar(el);\r\n this.richToolbarEl.classList.add('visible');\r\n this.updateToolbarState();\r\n }\r\n\r\n private positionToolbar(el: HTMLElement): void {\r\n if (!this.richToolbarEl) return;\r\n const rect = el.getBoundingClientRect();\r\n const tbRect = this.richToolbarEl.getBoundingClientRect();\r\n let top = rect.top - tbRect.height - 8;\r\n let left = rect.left + (rect.width / 2) - (tbRect.width / 2);\r\n\r\n // If above viewport, show below element\r\n if (top < 4) top = rect.bottom + 8;\r\n // Keep within horizontal bounds\r\n if (left < 4) left = 4;\r\n if (left + tbRect.width > window.innerWidth - 4) left = window.innerWidth - tbRect.width - 4;\r\n\r\n this.richToolbarEl.style.top = `${top}px`;\r\n this.richToolbarEl.style.left = `${left}px`;\r\n }\r\n\r\n private hideRichToolbar(): void {\r\n if (!this.richToolbarEl) return;\r\n // Small delay so user can click toolbar buttons without it hiding\r\n this.toolbarHideTimeout = setTimeout(() => {\r\n this.richToolbarEl?.classList.remove('visible');\r\n this.activeEditableEl = null;\r\n this.toolbarHideTimeout = null;\r\n }, 150);\r\n }\r\n\r\n private updateToolbarState(): void {\r\n if (!this.richToolbarEl) return;\r\n const cmds = ['bold', 'italic', 'underline', 'strikeThrough'];\r\n for (const btn of Array.from(this.richToolbarEl.querySelectorAll('button'))) {\r\n const cmd = (btn as HTMLElement).dataset.cmd;\r\n if (cmd && cmds.includes(cmd)) {\r\n try {\r\n (btn as HTMLElement).classList.toggle('active', document.queryCommandState(cmd));\r\n } catch { /* ignore */ }\r\n }\r\n }\r\n }\r\n\r\n // ===============================================\r\n // UNDO / REDO\r\n // ===============================================\r\n\r\n private onUndo(): void {\r\n if (this.undoStack.length === 0) return;\r\n this.redoStack.push(this.createSnapshot());\r\n this.applySnapshot(this.undoStack.pop()!);\r\n this.canUndo = this.undoStack.length > 0;\r\n this.canRedo = true;\r\n this.recalcDirtyKeys();\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n }\r\n\r\n private onRedo(): void {\r\n if (this.redoStack.length === 0) return;\r\n this.undoStack.push(this.createSnapshot());\r\n this.applySnapshot(this.redoStack.pop()!);\r\n this.canUndo = true;\r\n this.canRedo = this.redoStack.length > 0;\r\n this.recalcDirtyKeys();\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n }\r\n\r\n private recalcDirtyKeys(): void {\r\n this.dirtyKeys.clear();\r\n for (const key of this.registeredKeys) {\r\n if (JSON.stringify(this.pageTexts[key]) !== JSON.stringify(this.originalTexts[key])) {\r\n this.dirtyKeys.add(key);\r\n }\r\n }\r\n this.unsavedChanges = this.dirtyKeys.size + this.dirtyImageKeys.size;\r\n }\r\n\r\n private resetAll(): void {\r\n this.dirtyKeys.clear();\r\n this.dirtyImageKeys.clear();\r\n this.unsavedChanges = 0;\r\n this.undoStack = [];\r\n this.redoStack = [];\r\n this.canUndo = false;\r\n this.canRedo = false;\r\n this.updateUI();\r\n }\r\n\r\n private resetAfterSave(): void {\r\n this.dirtyKeys.clear();\r\n this.dirtyImageKeys.clear();\r\n this.unsavedChanges = 0;\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n }\r\n\r\n private cancelEditing(): void {\r\n this.pageTexts = JSON.parse(JSON.stringify(this.originalTexts));\r\n this.pageImages = JSON.parse(JSON.stringify(this.originalImages));\r\n this.dirtyKeys.clear();\r\n this.dirtyImageKeys.clear();\r\n this.unsavedChanges = 0;\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n }\r\n\r\n private logout(): void {\r\n XtroedgeCMS.secureClear();\r\n sessionStorage.removeItem('builder_edit_mode');\r\n this.editMode = false;\r\n this.isEditAllowed = false;\r\n this.applyEditMode(false);\r\n this.isOpen = false;\r\n this.updateUI();\r\n this.showToast('Logged out', 'success');\r\n }\r\n\r\n // ===============================================\r\n // API\r\n // ===============================================\r\n\r\n private async loadTranslationsAndInit(loadDraft: boolean): Promise<void> {\r\n if (this.config.i18nBasePath) {\r\n try {\r\n const lang = this.currentLang;\r\n const res = await fetch(`${this.config.i18nBasePath}/${lang}.json`);\r\n if (res.ok) {\r\n const translations = await res.json();\r\n this.translationCache.clear();\r\n this.flattenTranslations(translations, '', this.getPageSection());\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n\r\n this.autoDetectAndScan();\r\n this.captureDomOriginals();\r\n if (this.editMode) this.applyEditMode(true);\r\n if (this.config.apiBase) {\r\n if (loadDraft) this.loadPageContent('draft');\r\n else this.loadPublishedContent();\r\n } else {\r\n this.buildDefaultTexts();\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n this.setLoading(false);\r\n }\r\n this.updateUI();\r\n }\r\n\r\n private flattenTranslations(obj: any, prefix: string, pageSection: string): void {\r\n for (const k of Object.keys(obj)) {\r\n const fullKey = prefix ? `${prefix}.${k}` : k;\r\n if (typeof obj[k] === 'string') {\r\n const text = obj[k].trim();\r\n if (text.length >= 2) {\r\n const existing = this.translationCache.get(text);\r\n if (!existing || fullKey.toUpperCase().startsWith(pageSection)) {\r\n this.translationCache.set(text, fullKey);\r\n }\r\n }\r\n } else if (typeof obj[k] === 'object' && obj[k] !== null && !Array.isArray(obj[k])) {\r\n this.flattenTranslations(obj[k], fullKey, pageSection);\r\n }\r\n }\r\n }\r\n\r\n private getPageSection(): string {\r\n return this.currentSlug.replace(/^\\//, '').replace(/-/g, '_').toUpperCase();\r\n }\r\n\r\n /** Resolve a stored URL against our server (apiBase) */\r\n private resolveServerUrl(storedUrl: string): string {\r\n if (storedUrl.startsWith('/')) return `${this.config.apiBase}${storedUrl}`;\r\n return storedUrl;\r\n }\r\n\r\n /** Resolve a stored URL against client's server (clientApi, falls back to apiBase) */\r\n private resolveClientUrl(storedUrl: string): string {\r\n const base = this.config.clientApi || this.config.apiBase;\r\n if (storedUrl.startsWith('/')) return `${base}${storedUrl}`;\r\n return storedUrl;\r\n }\r\n\r\n private apiFetch(url: string, opts?: RequestInit): Promise<Response> {\r\n const token = XtroedgeCMS.secureGet('builder_token') || '';\r\n const licenseKey = this.config.licenseKey || '';\r\n const headers: Record<string, string> = { ...(opts?.headers as Record<string, string> || {}) };\r\n if (token) headers['Authorization'] = `Bearer ${token}`;\r\n if (licenseKey) headers['X-License-Key'] = licenseKey;\r\n\r\n // Merge client headers only for requests going to client's server (not our apiBase)\r\n const isOurServer = this.config.apiBase && url.startsWith(this.config.apiBase);\r\n if (!isOurServer && this.config.clientHeaders) {\r\n for (const [k, v] of Object.entries(this.config.clientHeaders)) {\r\n if (!headers[k]) headers[k] = v;\r\n }\r\n }\r\n\r\n return fetch(url, { ...opts, headers });\r\n }\r\n\r\n // Fetch page by slug — if get_url exists in localStorage, call it directly (bypass our server)\r\n private async fetchSection(slug: string, status?: string): Promise<WebPageContent | null> {\r\n try {\r\n const storedGetUrl = XtroedgeCMS.secureGet('xtroedge_get_url');\r\n const clientBase = this.config.clientApi || this.config.apiBase;\r\n const getBase = storedGetUrl ? this.resolveClientUrl(storedGetUrl) : `${clientBase}/web-page/get`;\r\n let getUrl = `${getBase}?slug=${encodeURIComponent(slug)}`;\r\n if (status) getUrl += `&status=${encodeURIComponent(status)}`;\r\n const res = await this.apiFetch(getUrl);\r\n if (!res.ok) return null;\r\n return await res.json();\r\n } catch { return null; }\r\n }\r\n\r\n private hasSection(type: 'header' | 'footer'): boolean {\r\n const slug = type === 'header' ? '/header' : '/footer';\r\n for (const [, info] of this.managedElements) {\r\n if (info.sectionSlug === slug) return true;\r\n }\r\n return false;\r\n }\r\n\r\n private async loadPageContent(status: 'draft' | 'published'): Promise<void> {\r\n this.setLoading(true);\r\n this.cleanOldHistory();\r\n\r\n try {\r\n // Only fetch sections that exist in the DOM\r\n const requests: Promise<WebPageContent | null>[] = [this.fetchSection(this.currentSlug, status)];\r\n const hasHeader = this.hasSection('header');\r\n const hasFooter = this.hasSection('footer');\r\n if (hasHeader) requests.push(this.fetchSection('/header', status));\r\n if (hasFooter) requests.push(this.fetchSection('/footer', status));\r\n\r\n const results = await Promise.all(requests);\r\n const pageSec = results[0];\r\n const headerSec = hasHeader ? results[1] : null;\r\n const footerSec = hasFooter ? results[hasHeader ? 2 : 1] : null;\r\n\r\n const getTexts = (sec: WebPageContent | null) => sec?.content?.texts || sec?.published_content?.texts || null;\r\n const pageTexts = getTexts(pageSec);\r\n const headerTexts = getTexts(headerSec);\r\n const footerTexts = getTexts(footerSec);\r\n\r\n if (pageTexts || headerTexts || footerTexts) {\r\n this.pageTexts = { ...(pageTexts || {}), ...(headerTexts || {}), ...(footerTexts || {}) };\r\n } else {\r\n this.buildDefaultTexts();\r\n }\r\n\r\n // Extract images from the page response (no extra API call)\r\n const images = pageSec?.content?.images || pageSec?.published_content?.images;\r\n if (images) {\r\n this.pageImages = JSON.parse(JSON.stringify(images));\r\n this.applyPageImages();\r\n }\r\n\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n this.resetAll();\r\n this.updateElementTexts();\r\n } catch {\r\n this.buildDefaultTexts();\r\n this.originalTexts = JSON.parse(JSON.stringify(this.pageTexts));\r\n this.originalImages = JSON.parse(JSON.stringify(this.pageImages));\r\n this.resetAll();\r\n } finally {\r\n this.setLoading(false);\r\n }\r\n }\r\n\r\n private async loadPublishedContent(): Promise<void> {\r\n this.setLoading(true);\r\n\r\n try {\r\n // Only fetch sections that exist in the DOM\r\n const requests: Promise<WebPageContent | null>[] = [this.fetchSection(this.currentSlug, 'published')];\r\n const hasHeader = this.hasSection('header');\r\n const hasFooter = this.hasSection('footer');\r\n if (hasHeader) requests.push(this.fetchSection('/header', 'published'));\r\n if (hasFooter) requests.push(this.fetchSection('/footer', 'published'));\r\n\r\n const results = await Promise.all(requests);\r\n const pageSec = results[0];\r\n const headerSec = hasHeader ? results[1] : null;\r\n const footerSec = hasFooter ? results[hasHeader ? 2 : 1] : null;\r\n\r\n const getTexts = (sec: WebPageContent | null) => sec?.published_content?.texts || null;\r\n const merged = { ...(getTexts(pageSec) || {}), ...(getTexts(headerSec) || {}), ...(getTexts(footerSec) || {}) };\r\n if (Object.keys(merged).length > 0) {\r\n this.pageTexts = JSON.parse(JSON.stringify(merged));\r\n this.updateElementTexts();\r\n }\r\n\r\n // Extract images from page response (no extra API call)\r\n const images = pageSec?.published_content?.images;\r\n if (images && Object.keys(images).length > 0) {\r\n this.pageImages = JSON.parse(JSON.stringify(images));\r\n this.applyPageImages();\r\n }\r\n } catch { /* ignore - use current DOM text */ }\r\n finally { this.setLoading(false); }\r\n }\r\n\r\n private buildDefaultTexts(): void {\r\n const texts: { [key: string]: PageTextEntry } = {};\r\n for (const key of this.registeredKeys) {\r\n const el = document.querySelector(`[data-cms=\"${key}\"]`);\r\n const val = el?.textContent?.trim() || '';\r\n // Only store DOM text under the default language — other languages start empty\r\n // so users must translate them explicitly\r\n const entry: PageTextEntry = { [this.defaultLanguage]: val };\r\n texts[key] = entry;\r\n }\r\n this.pageTexts = texts;\r\n\r\n // Load other languages from i18n files if available\r\n if (this.config.i18nBasePath) {\r\n const otherLangs = this.languages.filter(l => l !== this.currentLang);\r\n for (const lang of otherLangs) {\r\n fetch(`${this.config.i18nBasePath}/${lang}.json`)\r\n .then(r => r.json())\r\n .then(translations => {\r\n const updated = { ...this.pageTexts };\r\n for (const key of this.registeredKeys) {\r\n // Try to resolve key path in translations\r\n const parts = key.split('.');\r\n let val: any = translations;\r\n for (const part of parts) { val = val?.[part]; }\r\n if (val && typeof val === 'string') {\r\n updated[key] = { ...updated[key], [lang]: val };\r\n }\r\n }\r\n this.pageTexts = updated;\r\n this.originalTexts = JSON.parse(JSON.stringify(updated));\r\n this.updateElementTexts();\r\n })\r\n .catch(() => { /* ignore */ });\r\n }\r\n }\r\n }\r\n\r\n // Group pageTexts by section slug based on managedElements info\r\n private groupTextsBySection(): { [sectionSlug: string]: { [key: string]: PageTextEntry } } {\r\n const sections: { [sectionSlug: string]: { [key: string]: PageTextEntry } } = {};\r\n for (const [, info] of this.managedElements) {\r\n const slug = info.sectionSlug;\r\n if (!sections[slug]) sections[slug] = {};\r\n if (this.pageTexts[info.key] !== undefined) {\r\n sections[slug][info.key] = this.pageTexts[info.key];\r\n }\r\n }\r\n return sections;\r\n }\r\n\r\n private async saveChanges(): Promise<void> {\r\n if (!this.licenseValid) {\r\n this.showLicenseExpiredToast();\r\n return;\r\n }\r\n if (!this.config.apiBase) {\r\n this.showToast('No API configured. Set apiBase to enable save.', 'error');\r\n return;\r\n }\r\n this.isSaving = true;\r\n this.updateUI();\r\n\r\n // Ensure _orig for current language is stored for ALL entries before saving\r\n const origKey = `_orig_${this.currentLang}`;\r\n for (const key of Object.keys(this.pageTexts)) {\r\n if (!this.pageTexts[key][origKey] && this.domOriginals[key]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key];\r\n }\r\n }\r\n\r\n try {\r\n const sections = this.groupTextsBySection();\r\n const requests = Object.entries(sections).map(([slug, texts]) =>\r\n this.apiFetch(`${this.config.apiBase}/web_page/save`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n slug,\r\n title: slug === this.currentSlug ? this.currentTitle : slug.replace('/', ''),\r\n content: { texts, ...(slug === this.currentSlug ? { images: this.pageImages } : {}) }\r\n }),\r\n })\r\n );\r\n const responses = await Promise.all(requests);\r\n const saveResults: any[] = [];\r\n for (const res of responses) {\r\n const data = await res.json();\r\n saveResults.push({ ok: res.ok, status: res.status, data });\r\n }\r\n if (saveResults.some(r => !r.ok)) throw new Error('One or more sections failed to save');\r\n console.info('[XtroEdge] Save responses:', saveResults.map(r => r.data));\r\n this.isSaving = false;\r\n this.resetAfterSave();\r\n this.updateUI();\r\n this.showToast('Draft saved successfully!', 'success');\r\n this.config.onSaved?.();\r\n } catch (err) {\r\n this.isSaving = false;\r\n this.updateUI();\r\n this.showToast('Save failed. Please try again.', 'error');\r\n this.config.onError?.('save', err);\r\n }\r\n }\r\n\r\n private async publishChanges(): Promise<void> {\r\n if (!this.licenseValid) {\r\n this.showLicenseExpiredToast();\r\n return;\r\n }\r\n if (!this.config.apiBase) {\r\n this.showToast('No API configured. Set apiBase to enable publish.', 'error');\r\n return;\r\n }\r\n this.isPublishing = true;\r\n this.updateUI();\r\n\r\n // Ensure _orig for current language is stored for ALL entries before publishing\r\n const origKey = `_orig_${this.currentLang}`;\r\n for (const key of Object.keys(this.pageTexts)) {\r\n if (!this.pageTexts[key][origKey] && this.domOriginals[key]) {\r\n this.pageTexts[key][origKey] = this.domOriginals[key];\r\n }\r\n }\r\n\r\n try {\r\n const sections = this.groupTextsBySection();\r\n\r\n const requests = Object.entries(sections).map(([slug, texts]) =>\r\n this.apiFetch(`${this.config.apiBase}/web_page/publish`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n slug,\r\n title: slug === this.currentSlug ? this.currentTitle : slug.replace('/', ''),\r\n published_content: { texts, ...(slug === this.currentSlug ? { images: this.pageImages } : {}) },\r\n }),\r\n })\r\n );\r\n\r\n const results = await Promise.all(requests);\r\n const publishResults: any[] = [];\r\n for (const res of results) {\r\n const data = await res.json();\r\n publishResults.push({ ok: res.ok, status: res.status, data });\r\n }\r\n if (publishResults.some(r => !r.ok)) throw new Error('One or more sections failed to publish');\r\n console.info('[XtroEdge] Publish responses:', publishResults.map(r => r.data));\r\n this.isPublishing = false;\r\n this.resetAfterSave();\r\n this.updateUI();\r\n this.showToast('Published successfully!', 'success');\r\n this.config.onPublished?.();\r\n } catch (err) {\r\n this.isPublishing = false;\r\n this.updateUI();\r\n this.showToast('Publish failed. Please try again.', 'error');\r\n this.config.onError?.('publish', err);\r\n }\r\n }\r\n\r\n // ===============================================\r\n // HISTORY (IndexedDB)\r\n // ===============================================\r\n\r\n private async toggleHistory(): Promise<void> {\r\n this.showHistory = !this.showHistory;\r\n if (this.showHistory) await this.loadHistory();\r\n this.updateUI();\r\n }\r\n\r\n private async loadHistory(): Promise<void> {\r\n try {\r\n const db = await this.openDB();\r\n const entries = await new Promise<EditHistoryEntry[]>((resolve, reject) => {\r\n const tx = db.transaction(STORE_NAME, 'readonly');\r\n const store = tx.objectStore(STORE_NAME);\r\n const index = store.index('slug');\r\n const req = index.getAll(this.currentSlug);\r\n req.onsuccess = () => resolve((req.result as EditHistoryEntry[]).sort((a, b) => b.timestamp - a.timestamp).slice(0, 30));\r\n req.onerror = () => reject(req.error);\r\n });\r\n this.historyList = entries;\r\n this.renderHistoryList();\r\n } catch { /* ignore */ }\r\n }\r\n\r\n private renderHistoryList(): void {\r\n if (!this.historyListEl) return;\r\n this.historyListEl.innerHTML = '';\r\n if (this.historyList.length === 0) {\r\n const empty = this.createElement('div', 'lcms-history-empty');\r\n empty.textContent = 'No history yet';\r\n this.historyListEl.appendChild(empty);\r\n return;\r\n }\r\n for (const entry of this.historyList) {\r\n const item = document.createElement('button');\r\n item.className = 'lcms-history-item';\r\n const labelEl = this.createElement('div', 'lcms-history-label');\r\n labelEl.textContent = entry.label;\r\n const metaEl = this.createElement('div', 'lcms-history-meta');\r\n const langEl = this.createElement('span', 'lcms-history-lang');\r\n langEl.textContent = entry.lang.toUpperCase();\r\n const dateText = document.createTextNode(' ' + this.formatDate(entry.timestamp));\r\n metaEl.appendChild(langEl);\r\n metaEl.appendChild(dateText);\r\n item.appendChild(labelEl);\r\n item.appendChild(metaEl);\r\n item.addEventListener('click', (e) => { e.stopPropagation(); this.restoreHistory(entry); });\r\n this.historyListEl.appendChild(item);\r\n }\r\n }\r\n\r\n private restoreHistory(entry: EditHistoryEntry): void {\r\n this.undoStack.push(this.createSnapshot());\r\n this.canUndo = true;\r\n this.applySnapshot(entry.snapshot);\r\n this.recalcDirtyKeys();\r\n this.showHistory = false;\r\n this.updateElementTexts();\r\n this.applyPageImages();\r\n this.updateUI();\r\n this.showToast('Restored from history', 'success');\r\n }\r\n\r\n private pushHistory(key: string, lang: string): void {\r\n const isImage = lang === 'img';\r\n const shortKey = isImage ? key.split('/').pop() || 'image' : (key.split('_').pop() || key);\r\n const label = isImage ? `Changed ${shortKey}` : `Edited ${shortKey}`;\r\n this.openDB().then(db => {\r\n const tx = db.transaction(STORE_NAME, 'readwrite');\r\n tx.objectStore(STORE_NAME).add({\r\n slug: this.currentSlug, timestamp: Date.now(),\r\n label, lang,\r\n snapshot: JSON.stringify({ texts: this.pageTexts, images: this.pageImages })\r\n });\r\n }).catch(() => { /* ignore */ });\r\n }\r\n\r\n private async cleanOldHistory(): Promise<void> {\r\n try {\r\n const db = await this.openDB();\r\n const cutoff = Date.now() - this.historyRetentionMs;\r\n const tx = db.transaction(STORE_NAME, 'readwrite');\r\n const index = tx.objectStore(STORE_NAME).index('timestamp');\r\n const req = index.openCursor(IDBKeyRange.upperBound(cutoff));\r\n req.onsuccess = () => { const c = req.result; if (c) { c.delete(); c.continue(); } };\r\n } catch { /* ignore */ }\r\n }\r\n\r\n private openDB(): Promise<IDBDatabase> {\r\n if (this.db) return Promise.resolve(this.db);\r\n return new Promise((resolve, reject) => {\r\n const req = indexedDB.open(DB_NAME, 1);\r\n req.onupgradeneeded = () => {\r\n const db = req.result;\r\n if (!db.objectStoreNames.contains(STORE_NAME)) {\r\n const store = db.createObjectStore(STORE_NAME, { keyPath: 'id', autoIncrement: true });\r\n store.createIndex('slug', 'slug', { unique: false });\r\n store.createIndex('timestamp', 'timestamp', { unique: false });\r\n }\r\n };\r\n req.onsuccess = () => { this.db = req.result; resolve(this.db); };\r\n req.onerror = () => reject(req.error);\r\n });\r\n }\r\n\r\n // ===============================================\r\n // TOAST\r\n // ===============================================\r\n\r\n private showToast(message: string, type: 'success' | 'error'): void {\r\n if (!this.toastEl) return;\r\n this.toastMessage = message;\r\n this.toastType = type;\r\n\r\n const icon = type === 'success' ? ICON.check : ICON.error;\r\n this.toastEl.className = `lcms-toast lcms-toast-${type}`;\r\n this.toastEl.innerHTML = `${icon} ${message}`;\r\n\r\n if (this.toastTimer) clearTimeout(this.toastTimer);\r\n this.toastTimer = setTimeout(() => {\r\n if (this.toastEl) this.toastEl.classList.add('lcms-hidden');\r\n }, 3000);\r\n }\r\n\r\n // ===============================================\r\n // FAB & PANEL\r\n // ===============================================\r\n\r\n private onFabClick(e: Event): void {\r\n e.stopPropagation();\r\n if (this.hasMoved) return;\r\n this.isOpen = !this.isOpen;\r\n this.updateUI();\r\n }\r\n\r\n private togglePanel(): void {\r\n if (!this.hasMoved) {\r\n this.isOpen = !this.isOpen;\r\n this.updateUI();\r\n }\r\n }\r\n\r\n private toggleEditMode(e: Event): void {\r\n e.stopPropagation();\r\n const checked = (e.target as HTMLInputElement).checked;\r\n\r\n // Gate: block edit mode if license is not valid\r\n if (checked && !this.licenseValid) {\r\n (e.target as HTMLInputElement).checked = false;\r\n this.showLicenseExpiredToast();\r\n return;\r\n }\r\n\r\n if (checked) {\r\n sessionStorage.setItem('builder_edit_mode', 'true');\r\n this.editMode = true;\r\n this.currentLang = this.detectCurrentLanguage();\r\n this.applyEditMode(true);\r\n this.loadPageContent('draft');\r\n } else {\r\n sessionStorage.removeItem('builder_edit_mode');\r\n this.editMode = false;\r\n this.applyEditMode(false);\r\n }\r\n this.updateUI();\r\n this.config.onEditModeChanged?.(this.editMode);\r\n }\r\n\r\n private switchLang(lang: string): void {\r\n this.currentLang = lang;\r\n\r\n // 1. Persist language so framework picks it up after reload\r\n localStorage.setItem('selectedLanguage', lang);\r\n document.documentElement.setAttribute('lang', lang);\r\n document.documentElement.setAttribute('dir', lang === 'ar' ? 'rtl' : 'ltr');\r\n\r\n // 2. Notify (fires before reload so any sync listener can catch it)\r\n this.config.onLangChanged?.(lang);\r\n window.dispatchEvent(new CustomEvent('cms:langChanged', { detail: { lang } }));\r\n\r\n // 3. Reload so the framework re-initializes with the new language\r\n window.location.reload();\r\n }\r\n\r\n // ===============================================\r\n // FAB DRAG\r\n // ===============================================\r\n\r\n private onDragStart(e: MouseEvent): void {\r\n if ((e.target as HTMLElement).closest('button:not(.lcms-fab-btn)') || (e.target as HTMLElement).closest('.lcms-panel')) return;\r\n this.isDragging = true;\r\n this.hasMoved = false;\r\n this.dragStartX = e.clientX;\r\n this.dragStartY = e.clientY;\r\n this.startPosX = this.posX;\r\n this.startPosY = this.posY;\r\n document.addEventListener('mousemove', this.boundMouseMove);\r\n document.addEventListener('mouseup', this.boundMouseUp);\r\n }\r\n\r\n private onDragMove(e: MouseEvent): void {\r\n if (!this.isDragging || !this.fabEl) return;\r\n const dx = e.clientX - this.dragStartX, dy = e.clientY - this.dragStartY;\r\n if (Math.abs(dx) > 3 || Math.abs(dy) > 3) this.hasMoved = true;\r\n this.posX = Math.max(0, Math.min(window.innerWidth - 60, this.startPosX + dx));\r\n this.posY = Math.max(0, Math.min(window.innerHeight - 60, this.startPosY + dy));\r\n this.fabEl.style.left = this.posX + 'px';\r\n this.fabEl.style.top = this.posY + 'px';\r\n }\r\n\r\n private onDragEnd(): void {\r\n this.isDragging = false;\r\n document.removeEventListener('mousemove', this.boundMouseMove);\r\n document.removeEventListener('mouseup', this.boundMouseUp);\r\n }\r\n\r\n private onTouchStart(e: TouchEvent): void {\r\n if ((e.target as HTMLElement).closest('button:not(.lcms-fab-btn)') || (e.target as HTMLElement).closest('.lcms-panel')) return;\r\n const t = e.touches[0];\r\n this.isDragging = true;\r\n this.hasMoved = false;\r\n this.dragStartX = t.clientX;\r\n this.dragStartY = t.clientY;\r\n this.startPosX = this.posX;\r\n this.startPosY = this.posY;\r\n document.addEventListener('touchmove', this.boundTouchMove, { passive: false });\r\n document.addEventListener('touchend', this.boundTouchEnd);\r\n }\r\n\r\n private onTouchMove(e: TouchEvent): void {\r\n if (!this.isDragging || !this.fabEl) return;\r\n e.preventDefault();\r\n const t = e.touches[0];\r\n const dx = t.clientX - this.dragStartX, dy = t.clientY - this.dragStartY;\r\n if (Math.abs(dx) > 3 || Math.abs(dy) > 3) this.hasMoved = true;\r\n this.posX = Math.max(0, Math.min(window.innerWidth - 60, this.startPosX + dx));\r\n this.posY = Math.max(0, Math.min(window.innerHeight - 60, this.startPosY + dy));\r\n this.fabEl.style.left = this.posX + 'px';\r\n this.fabEl.style.top = this.posY + 'px';\r\n }\r\n\r\n private onTouchEnd(): void {\r\n this.isDragging = false;\r\n document.removeEventListener('touchmove', this.boundTouchMove);\r\n document.removeEventListener('touchend', this.boundTouchEnd);\r\n }\r\n\r\n // ===============================================\r\n // HELPERS\r\n // ===============================================\r\n\r\n private setLoading(val: boolean): void {\r\n this.loading = val;\r\n this.updateUI();\r\n }\r\n\r\n private detectCurrentLanguage(): string {\r\n // Check localStorage first — set by switchLang() before reload, always reliable\r\n const stored = localStorage.getItem('selectedLanguage');\r\n if (stored && this.languages.includes(stored)) return stored;\r\n const htmlLang = document.documentElement.getAttribute('lang');\r\n if (htmlLang && this.languages.includes(htmlLang)) return htmlLang;\r\n return this.defaultLanguage;\r\n }\r\n\r\n private createElement(tag: string, className: string): HTMLElement {\r\n const el = document.createElement(tag);\r\n el.className = className;\r\n return el;\r\n }\r\n\r\n private formatDate(timestamp: number): string {\r\n const d = new Date(timestamp);\r\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\r\n const h = d.getHours();\r\n const m = d.getMinutes().toString().padStart(2, '0');\r\n const ampm = h >= 12 ? 'PM' : 'AM';\r\n const h12 = h % 12 || 12;\r\n return `${months[d.getMonth()]} ${d.getDate()}, ${h12}:${m} ${ampm}`;\r\n }\r\n\r\n // ===============================================\r\n // LOGIN MODAL\r\n // ===============================================\r\n\r\n private showLoginModal(): void {\r\n if (this.loginModalEl) return;\r\n\r\n const overlay = document.createElement('div');\r\n overlay.className = 'lcms-login-overlay';\r\n overlay.id = 'lcms-login-modal';\r\n\r\n overlay.innerHTML = `\r\n <div class=\"lcms-login-box\">\r\n <div class=\"lcms-login-logo\">\r\n <div class=\"lcms-login-logo-icon\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2.5\" 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>\r\n </div>\r\n <span class=\"lcms-login-logo-text\">XtroEdge CMS</span>\r\n </div>\r\n <div class=\"lcms-login-title\">Builder Login</div>\r\n <div class=\"lcms-login-sub\">Sign in to access edit mode</div>\r\n <div class=\"lcms-login-field\">\r\n <label class=\"lcms-login-label\">Username</label>\r\n <input class=\"lcms-login-input\" id=\"lcms-login-email\" type=\"text\" placeholder=\"Enter your username\" autocomplete=\"username\" />\r\n </div>\r\n <div class=\"lcms-login-field\">\r\n <label class=\"lcms-login-label\">Password</label>\r\n <div class=\"lcms-password-wrapper\">\r\n <input class=\"lcms-login-input\" id=\"lcms-login-password\" type=\"password\" placeholder=\"Enter your password\" autocomplete=\"current-password\" />\r\n <button type=\"button\" class=\"lcms-password-toggle\" id=\"lcms-password-toggle\" tabindex=\"-1\">\r\n <svg class=\"lcms-eye-open\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>\r\n <svg class=\"lcms-eye-closed lcms-hidden\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"/><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/></svg>\r\n </button>\r\n </div>\r\n </div>\r\n <button class=\"lcms-login-btn\" id=\"lcms-login-btn\">Sign In</button>\r\n <div class=\"lcms-login-error\" id=\"lcms-login-error\"></div>\r\n </div>\r\n `;\r\n\r\n (this.rootEl || document.body).appendChild(overlay);\r\n this.loginModalEl = overlay;\r\n\r\n const btn = overlay.querySelector('#lcms-login-btn') as HTMLButtonElement;\r\n const emailInput = overlay.querySelector('#lcms-login-email') as HTMLInputElement;\r\n const passInput = overlay.querySelector('#lcms-login-password') as HTMLInputElement;\r\n\r\n const doLogin = () => this.attemptLogin(emailInput.value.trim(), passInput.value);\r\n btn.addEventListener('click', doLogin);\r\n passInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') doLogin(); });\r\n\r\n // Password show/hide toggle\r\n const toggleBtn = overlay.querySelector('#lcms-password-toggle') as HTMLButtonElement;\r\n if (toggleBtn) {\r\n toggleBtn.addEventListener('click', () => {\r\n const isPassword = passInput.type === 'password';\r\n passInput.type = isPassword ? 'text' : 'password';\r\n toggleBtn.querySelector('.lcms-eye-open')!.classList.toggle('lcms-hidden', !isPassword);\r\n toggleBtn.querySelector('.lcms-eye-closed')!.classList.toggle('lcms-hidden', isPassword);\r\n passInput.focus();\r\n });\r\n }\r\n\r\n // Focus email field\r\n setTimeout(() => emailInput.focus(), 50);\r\n }\r\n\r\n private hideLoginModal(): void {\r\n this.loginModalEl?.remove();\r\n this.loginModalEl = null;\r\n }\r\n\r\n private async attemptLogin(email: string, password: string): Promise<void> {\r\n const btn = document.getElementById('lcms-login-btn') as HTMLButtonElement;\r\n const errorEl = document.getElementById('lcms-login-error') as HTMLElement;\r\n\r\n if (!email || !password) {\r\n errorEl.textContent = 'Please enter your username and password.';\r\n errorEl.classList.add('visible');\r\n return;\r\n }\r\n\r\n btn.disabled = true;\r\n btn.textContent = 'Signing in...';\r\n errorEl.classList.remove('visible');\r\n\r\n try {\r\n const loginUrl = this.config.loginUrl || `${this.config.apiBase}/auth/login`;\r\n const res = await fetch(loginUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ username: email, password }),\r\n });\r\n\r\n // Try to parse body regardless of status (API may return error details in body)\r\n let data: any = null;\r\n try { data = await res.json(); } catch { /* ignore parse error */ }\r\n\r\n if (!res.ok) {\r\n // Show API error message if available (e.g. Xano: { message: \"Invalid credentials.\" })\r\n const apiMsg = data?.message || data?.error || null;\r\n throw new Error(apiMsg || `HTTP ${res.status}`);\r\n }\r\n\r\n // Store token — support common response shapes: { token }, { authToken }, { data: { token } }\r\n const token = data?.token || data?.authToken || data?.auth_token || data?.data?.token;\r\n if (!token) throw new Error('Login successful but no token returned.');\r\n\r\n XtroedgeCMS.secureSet('builder_token', token);\r\n\r\n // Save company URLs for direct API calls (bypass our server)\r\n if (data?.get_url) XtroedgeCMS.secureSet('xtroedge_get_url', data.get_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_get_url');\r\n if (data?.published_url) XtroedgeCMS.secureSet('xtroedge_published_url', data.published_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_published_url');\r\n if (data?.image_url) XtroedgeCMS.secureSet('xtroedge_image_url', data.image_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_image_url');\r\n if (data?.client_api) {\r\n XtroedgeCMS.secureSet('xtroedge_client_api', data.client_api);\r\n this.config.clientApi = data.client_api; // Override config with server value\r\n } else {\r\n XtroedgeCMS.secureRemove('xtroedge_client_api');\r\n }\r\n if (data?.save_url) XtroedgeCMS.secureSet('xtroedge_save_url', data.save_url);\r\n else XtroedgeCMS.secureRemove('xtroedge_save_url');\r\n\r\n this.hideLoginModal();\r\n\r\n // Now enable edit mode\r\n this.editMode = true;\r\n this.pendingEditMode = false;\r\n sessionStorage.setItem('builder_edit_mode', 'true');\r\n this.applyEditMode(true);\r\n this.updateUI();\r\n this.loadPageContent('draft');\r\n } catch (err: any) {\r\n btn.disabled = false;\r\n btn.textContent = 'Sign In';\r\n errorEl.textContent = err?.message || 'Login failed. Please try again.';\r\n errorEl.classList.add('visible');\r\n }\r\n }\r\n\r\n // ===============================================\r\n // SITE IDENTIFIER\r\n // ===============================================\r\n\r\n private resolveSiteIdentifier(): string {\r\n const hostname = window.location.hostname;\r\n if (hostname && hostname !== 'localhost' && hostname !== '127.0.0.1' && !hostname.startsWith('192.168.')) {\r\n return hostname;\r\n }\r\n let id = localStorage.getItem('xtroedge_site_id');\r\n if (!id) {\r\n id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\r\n const r = Math.random() * 16 | 0;\r\n return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);\r\n });\r\n localStorage.setItem('xtroedge_site_id', id);\r\n }\r\n return id;\r\n }\r\n\r\n // ===============================================\r\n // THEME COLOR\r\n // ===============================================\r\n\r\n private hexToRgb(hex: string): string {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n if (!result) return '0,200,83';\r\n return `${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)}`;\r\n }\r\n\r\n private getDarkerColor(hex: string): string {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n if (!result) return '#2E7D32';\r\n const r = Math.max(0, Math.floor(parseInt(result[1], 16) * 0.6));\r\n const g = Math.max(0, Math.floor(parseInt(result[2], 16) * 0.6));\r\n const b = Math.max(0, Math.floor(parseInt(result[3], 16) * 0.6));\r\n return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;\r\n }\r\n\r\n private applyThemeColor(color: string): void {\r\n this.highlightColor = color;\r\n document.documentElement.style.setProperty('--lcms-primary', color);\r\n document.documentElement.style.setProperty('--lcms-primary-rgb', this.hexToRgb(color));\r\n document.documentElement.style.setProperty('--lcms-primary-dark', this.getDarkerColor(color));\r\n\r\n // Re-apply highlight to managed elements\r\n if (this.editMode) {\r\n for (const [el] of this.managedElements) {\r\n el.style.setProperty('outline', `2px dashed ${color}`, 'important');\r\n }\r\n for (const [img] of this.managedImages) {\r\n img.style.setProperty('outline', `2px dashed ${color}`, 'important');\r\n }\r\n }\r\n\r\n // Update swatch active states\r\n const swatches = this.panelEl?.querySelectorAll('.lcms-theme-swatch');\r\n swatches?.forEach(s => {\r\n (s as HTMLElement).classList.toggle('active', (s as HTMLElement).dataset.color === color);\r\n });\r\n\r\n // Persist to localStorage\r\n localStorage.setItem('xtroedge_theme_color', color);\r\n }\r\n\r\n // ===============================================\r\n // STATIC CONVENIENCE\r\n // ===============================================\r\n\r\n /** Quick init - create and start CMS in one call */\r\n static async create(config?: XtroedgeCmsConfig): Promise<XtroedgeCMS> {\r\n const cms = new XtroedgeCMS(config);\r\n await cms.init();\r\n return cms;\r\n }\r\n\r\n /** Auto-init: called automatically when package is loaded. No user code needed. */\r\n static async autoInit(): Promise<void> {\r\n // Prevent double init\r\n if ((window as any).__xtroedge_cms_instance__) return;\r\n\r\n const userConfig: XtroedgeCmsConfig = (window as any).__XTROEDGE_CMS_CONFIG__ || {};\r\n const cms = await XtroedgeCMS.create(userConfig);\r\n (window as any).__xtroedge_cms_instance__ = cms;\r\n }\r\n}\r\n\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACO1B,IAAM,OAAO;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AACV;AAGA,IAAM,UAAU;AAChB,IAAM,aAAa;AAGnB,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC9B;AAAA,EAAK;AAAA,EAAQ;AAAA,EAAK;AAAA,EAAU;AAAA,EAAK;AAAA,EACjC;AAAA,EAAK;AAAA,EAAU;AAAA,EAAM;AAAA,EAAS;AAAA,EAAS;AAAA,EAAc;AAAA,EAAM;AAAA,EAC3D;AAAA,EAAO;AAAA,EAAU;AACnB;AAEO,IAAM,eAAN,MAAM,aAAY;AAAA,EA2LvB,YAAY,QAA4B;AA1HxC,SAAQ,aAAiC;AAEzC,SAAQ,iBAAiB;AACzB,SAAQ,WAA+B;AACvC,SAAQ,eAAmC;AAC3C,SAAQ,kBAAkB;AAG1B;AAAA;AAAA,SAAQ,WAAW;AACnB,SAAQ,cAAc;AACtB,SAAQ,YAA8C,CAAC;AACvD,SAAQ,aAAwC,CAAC;AACjD,SAAQ,gBAAkD,CAAC;AAC3D,SAAQ,iBAA4C,CAAC;AACrD,SAAQ,iBAAiB;AACzB,SAAQ,WAAW;AACnB,SAAQ,eAAe;AACvB,SAAQ,UAAU;AAClB,SAAQ,UAAU;AAClB,SAAQ,UAAU;AAClB,SAAQ,cAAc;AACtB,SAAQ,cAAkC,CAAC;AAC3C,SAAQ,SAAS;AACjB,SAAQ,gBAAgB;AACxB,SAAQ,iBAAiB;AACzB,SAAQ,eAAe;AACvB,SAAQ,YAAiC;AAGzC;AAAA,SAAQ,YAAsB,CAAC;AAC/B,SAAQ,YAAsB,CAAC;AAC/B,SAAQ,YAAY,oBAAI,IAAY;AACpC,SAAQ,iBAAiB,oBAAI,IAAY;AACzC,SAAQ,iBAAiB,oBAAI,IAAY;AAGzC;AAAA,SAAQ,eAA0C,CAAC;AACnD,SAAQ,kBAAkB,oBAAI,IAAqC;AACnE,SAAQ,gBAAgB,oBAAI,IAAwC;AACpE,SAAQ,uBAAuB,oBAAI,IAAiB;AACpD,SAAQ,WAAoC;AAC5C,SAAQ,cAAoD;AAC5D,SAAQ,gBAAyC;AACjD,SAAQ,eAAmC;AAC3C,SAAQ,qBAAyC;AAGjD;AAAA,SAAQ,gBAAoC;AAC5C,SAAQ,mBAAuC;AAC/C,SAAQ,qBAA2D;AACnE,SAAQ,yBAA8C;AAGtD;AAAA,SAAQ,cAAc;AACtB,SAAQ,eAAe;AACvB,SAAQ,cAAc;AACtB,SAAQ,gBAAiD;AACzD,SAAQ,mBAAuD;AAG/D;AAAA,SAAQ,UAAmC;AAC3C,SAAQ,SAA6B;AACrC,SAAQ,WAA+B;AACvC,SAAQ,UAA8B;AACtC,SAAQ,QAA4B;AACpC,SAAQ,SAAmC;AAC3C,SAAQ,UAA8B;AACtC,SAAQ,UAA8B;AACtC,SAAQ,aAAsC;AAC9C,SAAQ,eAAmC;AAC3C,SAAQ,gBAAoC;AAC5C,SAAQ,UAAoC;AAC5C,SAAQ,UAAoC;AAC5C,SAAQ,eAAyC;AACjD,SAAQ,iBAAqC;AAC7C,SAAQ,gBAAoC;AAC5C,SAAQ,UAAoC;AAC5C,SAAQ,aAAuC;AAE/C,SAAQ,YAAgC;AACxC,SAAQ,kBAAsC;AAC9C,SAAQ,YAAqC;AAC7C,SAAQ,aAAiC;AAGzC;AAAA,SAAQ,oBAAyC;AACjD,SAAQ,gBAA+B;AACvC,SAAQ,0BAAuD;AAG/D;AAAA,SAAQ,OAAO;AACf,SAAQ,OAAO;AACf,SAAQ,aAAa;AACrB,SAAQ,aAAa;AACrB,SAAQ,aAAa;AACrB,SAAQ,YAAY;AACpB,SAAQ,YAAY;AACpB,SAAQ,WAAW;AAGnB;AAAA,SAAQ,aAAmD;AAG3D;AAAA,SAAQ,eAAe;AACvB,SAAQ,gBAAsC;AAC9C,SAAQ,mBAAuC;AAC/C,SAAQ,uBAAuB;AAG/B;AAAA,SAAQ,KAAyB;AAWjC;AAAA,SAAQ,mBAAmB,oBAAI,IAAoB;AAuiCnD;AAAA,SAAQ,oBAAoB,oBAAI,IAAiB;AApiC/C,SAAK,SAAS,UAAU,CAAC;AACzB,QAAI,CAAC,KAAK,OAAO,QAAS,MAAK,OAAO,UAAU;AAChD,SAAK,oBAAoB,KAAK,OAAO,qBAAqB;AAC1D,SAAK,gBAAgB,KAAK,OAAO,gBAAgB,uBAAuB,IAAI,OAAK,EAAE,YAAY,CAAC;AAChG,SAAK,YAAY,KAAK,OAAO,aAAa,CAAC,IAAI;AAC/C,SAAK,kBAAkB,KAAK,OAAO,mBAAmB,KAAK,UAAU,CAAC,KAAK;AAC3E,SAAK,iBAAiB,KAAK,OAAO,kBAAkB;AACpD,SAAK,sBAAsB,KAAK,OAAO,wBAAwB,KAAK,KAAK,KAAK,KAAK;AACnF,SAAK,cAAc,KAAK,sBAAsB;AAC9C,SAAK,iBAAiB,KAAK,sBAAsB;AAGjD,UAAM,iBAAiB,aAAY,UAAU,qBAAqB;AAClE,QAAI,eAAgB,MAAK,OAAO,YAAY;AAG5C,UAAM,aAAa,aAAa,QAAQ,sBAAsB;AAC9D,QAAI,WAAY,MAAK,iBAAiB;AAGtC,SAAK,iBAAiB,CAAC,MAAM,KAAK,WAAW,CAAC;AAC9C,SAAK,eAAe,MAAM,KAAK,UAAU;AACzC,SAAK,iBAAiB,CAAC,MAAM,KAAK,YAAY,CAAC;AAC/C,SAAK,gBAAgB,MAAM,KAAK,WAAW;AAC3C,SAAK,gBAAgB,MAAM,KAAK,iBAAiB;AACjD,SAAK,kBAAkB,MAAM,KAAK,iBAAiB;AAAA,EACrD;AAAA,EAjNA,OAAe,KAAK,OAAuB;AACzC,UAAM,IAAI,aAAY;AACtB,QAAI,SAAS;AACb,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gBAAU,OAAO,aAAa,MAAM,WAAW,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,MAAM,CAAC;AAAA,IAChF;AACA,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,OAAe,KAAK,SAAyB;AAC3C,QAAI;AACF,YAAM,IAAI,aAAY;AACtB,YAAM,UAAU,KAAK,OAAO;AAC5B,UAAI,SAAS;AACb,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,kBAAU,OAAO,aAAa,QAAQ,WAAW,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,MAAM,CAAC;AAAA,MAClF;AACA,aAAO;AAAA,IACT,QAAQ;AAAE,aAAO;AAAA,IAAI;AAAA,EACvB;AAAA,EAEA,OAAe,aAAqC;AAClD,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,aAAY,UAAU;AACvD,UAAI,CAAC,IAAK,QAAO,CAAC;AAClB,aAAO,KAAK,MAAM,aAAY,KAAK,GAAG,CAAC;AAAA,IACzC,QAAQ;AAAE,aAAO,CAAC;AAAA,IAAG;AAAA,EACvB;AAAA,EAEA,OAAe,YAAY,OAAqC;AAC9D,QAAI;AAAE,mBAAa,QAAQ,aAAY,YAAY,aAAY,KAAK,KAAK,UAAU,KAAK,CAAC,CAAC;AAAA,IAAG,QAAQ;AAAA,IAAqB;AAAA,EAC5H;AAAA,EAEA,OAAe,UAAU,KAAa,OAAqB;AACzD,UAAM,IAAI,aAAY,WAAW;AACjC,MAAE,GAAG,IAAI;AACT,iBAAY,YAAY,CAAC;AAAA,EAC3B;AAAA,EAEA,OAAe,UAAU,KAAqB;AAC5C,WAAO,aAAY,WAAW,EAAE,GAAG,KAAK;AAAA,EAC1C;AAAA,EAEA,OAAe,aAAa,KAAmB;AAC7C,UAAM,IAAI,aAAY,WAAW;AACjC,WAAO,EAAE,GAAG;AACZ,iBAAY,YAAY,CAAC;AAAA,EAC3B;AAAA,EAEA,OAAe,cAAoB;AACjC,QAAI;AAAE,mBAAa,WAAW,aAAY,UAAU;AAAA,IAAG,QAAQ;AAAA,IAAe;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA,EAoKA,MAAM,OAAsB;AAC1B,SAAK,aAAa;AAClB,SAAK,gBAAgB,KAAK,cAAc;AAGxC,UAAM,KAAK,gBAAgB;AAE3B,SAAK,OAAO,OAAO,cAAc;AACjC,SAAK,QAAQ;AACb,SAAK,oBAAoB;AAGzB,SAAK,WAAW,IAAI,iBAAiB,MAAM;AAEzC,UAAI,KAAK,UAAU,CAAC,SAAS,SAAS,KAAK,MAAM,GAAG;AAClD,iBAAS,KAAK,YAAY,KAAK,MAAM;AAAA,MACvC;AACA,UAAI,KAAK,WAAW,CAAC,SAAS,SAAS,KAAK,OAAO,GAAG;AACpD,iBAAS,KAAK,YAAY,KAAK,OAAO;AAAA,MACxC;AACA,UAAI,KAAK,YAAa,cAAa,KAAK,WAAW;AACnD,WAAK,cAAc,WAAW,MAAM;AAClC,aAAK,kBAAkB;AAEvB,YAAI,OAAO,KAAK,KAAK,SAAS,EAAE,SAAS,GAAG;AAC1C,eAAK,mBAAmB;AAAA,QAC1B;AAAA,MACF,GAAG,GAAG;AAAA,IACR,CAAC;AACD,SAAK,SAAS,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAGvE,WAAO,iBAAiB,YAAY,KAAK,aAAa;AACtD,WAAO,iBAAiB,cAAc,KAAK,eAAe;AAG1D,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,UAAgB;AACd,SAAK,uBAAuB;AAG5B,SAAK,SAAS,OAAO;AACrB,SAAK,QAAQ,OAAO;AACpB,SAAK,kBAAkB,OAAO;AAG9B,WAAO,oBAAoB,YAAY,KAAK,aAAa;AACzD,WAAO,oBAAoB,cAAc,KAAK,eAAe;AAC7D,aAAS,oBAAoB,aAAa,KAAK,cAAc;AAC7D,aAAS,oBAAoB,WAAW,KAAK,YAAY;AACzD,aAAS,oBAAoB,aAAa,KAAK,cAAc;AAC7D,aAAS,oBAAoB,YAAY,KAAK,aAAa;AAG3D,QAAI,KAAK,cAAe,SAAQ,YAAY,KAAK;AACjD,QAAI,KAAK,iBAAkB,SAAQ,eAAe,KAAK;AAGvD,SAAK,UAAU,WAAW;AAC1B,QAAI,KAAK,YAAa,cAAa,KAAK,WAAW;AACnD,QAAI,KAAK,WAAY,cAAa,KAAK,UAAU;AAEjD,SAAK,IAAI,MAAM;AAAA,EACjB;AAAA;AAAA,EASA,MAAc,kBAAiC;AAC7C,UAAM,aAAa,KAAK,OAAO,cAAc,aAAY,UAAU,eAAe,KAAK;AAEvF,QAAI,CAAC,YAAY;AAEf,WAAK,gBAAgB,EAAE,OAAO,OAAO,MAAM,WAAW,SAAS,2BAA2B;AAC1F,WAAK,eAAe;AACpB;AAAA,IACF;AAGA,UAAM,SAAS,KAAK,gBAAgB;AACpC,QAAI,QAAQ;AACV,WAAK,gBAAgB;AACrB,WAAK,eAAe,OAAO;AAC3B;AAAA,IACF;AAGA,UAAM,cAAc,KAAK,OAAO,uBAC1B,KAAK,OAAO,UAAU,GAAG,KAAK,OAAO,OAAO,sBAAsB;AAExE,QAAI,CAAC,aAAa;AAEhB,WAAK,eAAe;AACpB,WAAK,gBAAgB,EAAE,OAAO,MAAM,MAAM,SAAS,SAAS,6BAA6B;AACzF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,eAAe,aAAY,UAAU,eAAe,KAAK;AAC/D,YAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAC7E,UAAI,aAAc,SAAQ,eAAe,IAAI,UAAU,YAAY;AAEnE,YAAM,MAAM,MAAM,MAAM,aAAa;AAAA,QACnC,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA,QAAQ,OAAO,SAAS;AAAA,QAC1B,CAAC;AAAA,MACH,CAAC;AAED,UAAI;AACJ,UAAI;AACF,eAAO,MAAM,IAAI,KAAK;AAAA,MACxB,QAAQ;AACN,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AAEA,WAAK,gBAAgB;AACrB,WAAK,gBAAgB,IAAI;AACzB,WAAK,eAAe,KAAK;AAAA,IAC3B,QAAQ;AAEN,YAAM,WAAW,KAAK,gBAAgB,IAAI;AAC1C,UAAI,YAAY,SAAS,OAAO;AAE9B,aAAK,eAAe;AACpB,aAAK,gBAAgB;AAAA,MACvB,OAAO;AAEL,aAAK,gBAAgB,EAAE,OAAO,OAAO,MAAM,WAAW,SAAS,mEAAmE;AAClI,aAAK,eAAe;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAgB,YAAY,OAA6B;AAC/D,QAAI;AACF,YAAM,MAAM,aAAY,UAAU,aAAY,iBAAiB;AAC/D,UAAI,CAAC,IAAK,QAAO;AACjB,YAAM,EAAE,QAAQ,WAAW,IAAI,IAAI,KAAK,MAAM,GAAG;AAEjD,YAAM,aAAa,KAAK,OAAO,cAAc,aAAY,UAAU,eAAe,KAAK;AACvF,UAAI,QAAQ,WAAY,QAAO;AAC/B,UAAI,CAAC,aAAc,KAAK,IAAI,IAAI,YAAY,aAAY,kBAAoB,QAAO;AACnF,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,gBAAgB,QAA6B;AACnD,QAAI;AACF,YAAM,aAAa,KAAK,OAAO,cAAc,aAAY,UAAU,eAAe,KAAK;AACvF,mBAAY,UAAU,aAAY,mBAAmB,KAAK,UAAU;AAAA,QAClE;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,QACpB,KAAK;AAAA,MACP,CAAC,CAAC;AAAA,IACJ,QAAQ;AAAA,IAA8C;AAAA,EACxD;AAAA;AAAA,EAGQ,0BAAgC;AACtC,UAAM,YAAY,KAAK,eAAe,SAAS;AAC/C,UAAM,MAAM,YACR,8DACC,KAAK,eAAe,WAAW;AACpC,SAAK,UAAU,KAAK,OAAO;AAAA,EAC7B;AAAA;AAAA,EAGQ,qBAA6B;AACnC,QAAI,KAAK,wBAAwB,CAAC,KAAK,cAAe,QAAO;AAG7D,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,MAAM,KAAK,cAAc,SAAS,YACpC,kEACA;AACJ,aAAO;AAAA;AAAA;AAAA,iDAGoC,GAAG;AAAA;AAAA;AAAA;AAAA,IAIhD;AAGA,QAAI,KAAK,cAAc,SAAS,SAAS;AACvC,YAAM,OAAO,KAAK,cAAc,YAAY;AAC5C,aAAO;AAAA;AAAA;AAAA,6DAGgD,IAAI,OAAO,SAAS,IAAI,MAAM,EAAE;AAAA;AAAA;AAAA;AAAA,IAIzF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAqB;AAC3B,QAAI,SAAS,eAAe,qBAAqB,EAAG;AACpD,SAAK,UAAU,SAAS,cAAc,OAAO;AAC7C,SAAK,QAAQ,KAAK;AAClB,SAAK,QAAQ,cAAc;AAC3B,aAAS,KAAK,YAAY,KAAK,OAAO;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAMQ,sBAA4B;AAClC,SAAK,gBAAgB,QAAQ,UAAU,KAAK,OAAO;AACnD,SAAK,mBAAmB,QAAQ,aAAa,KAAK,OAAO;AACzD,UAAM,OAAO;AACb,YAAQ,YAAY,YAAa,MAAM;AACrC,WAAK,cAAe,GAAG,IAAI;AAC3B,iBAAW,MAAM,KAAK,iBAAiB,GAAG,CAAC;AAAA,IAC7C;AACA,YAAQ,eAAe,YAAa,MAAM;AACxC,WAAK,iBAAkB,GAAG,IAAI;AAC9B,iBAAW,MAAM,KAAK,iBAAiB,GAAG,CAAC;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,mBAAyB;AAC/B,UAAM,MAAM,OAAO,SAAS;AAC5B,UAAM,WAAW,OAAO,SAAS,YAAY;AAC7C,UAAM,OAAO,OAAO,SAAS,QAAQ;AAGrC,QAAI;AACJ,QAAI;AACJ,QAAI,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,IAAI,GAAG;AAClD,YAAM,WAAW,KAAK,QAAQ,WAAW,EAAE;AAC3C,YAAM,OAAO,SAAS,QAAQ,GAAG;AACjC,aAAO,QAAQ,IAAI,SAAS,UAAU,GAAG,IAAI,IAAI;AACjD,kBAAY,QAAQ,IAAI,SAAS,UAAU,IAAI,IAAI;AAAA,IACrD,OAAO;AACL,aAAO,SAAS,QAAQ,OAAO,EAAE,KAAK;AACtC,kBAAY,OAAO,SAAS;AAAA,IAC9B;AAEA,UAAM,OAAO,OAAO,KAAK,QAAQ,OAAO,EAAE,KAAK;AAC/C,UAAM,SAAS,IAAI,gBAAgB,SAAS;AAC5C,UAAM,eAAe,OAAO,IAAI,MAAM,MAAM;AAE5C,SAAK,gBAAgB,gBAAgB,eAAe,QAAQ,mBAAmB,MAAM;AAErF,UAAM,cAAc,SAAS,KAAK;AAClC,QAAI,aAAa;AACf,WAAK,uBAAuB;AAC5B,WAAK,cAAc;AACnB,WAAK,gBAAgB,KAAK,QAAQ,OAAO,EAAE,KAAK,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,SAAS,OAAK,EAAE,YAAY,CAAC,IAAI;AACpH,WAAK,SAAS;AAAA,IAChB;AAGA,UAAM,kBAAkB,eAAe,QAAQ,mBAAmB,MAAM;AACxE,UAAM,YAAY,gBAAgB;AAElC,QAAI,WAAW;AACb,YAAM,QAAQ,aAAY,UAAU,eAAe;AACnD,UAAI,CAAC,OAAO;AAEV,YAAI,CAAC,KAAK,iBAAiB;AACzB,eAAK,kBAAkB;AACvB,eAAK,cAAc,KAAK,sBAAsB;AAC9C,eAAK,WAAW,IAAI;AACpB,qBAAW,MAAM;AACf,iBAAK,wBAAwB,KAAK;AAClC,iBAAK,eAAe;AAAA,UACtB,GAAG,GAAG;AAAA,QACR;AACA;AAAA,MACF;AAGA,UAAI,CAAC,KAAK,cAAc;AACtB,aAAK,wBAAwB;AAC7B,aAAK,WAAW;AAAA,MAClB,OAAO;AACL,aAAK,WAAW;AAAA,MAClB;AAAA,IACF;AAGA,QAAI,CAAC,eAAe,KAAK,aAAa;AACpC,WAAK,SAAS;AACd;AAAA,IACF;AAEA,SAAK,cAAc,KAAK,sBAAsB;AAG9C,SAAK,WAAW,IAAI;AAGpB,SAAK,cAAc;AACnB,UAAM,YAAY;AAClB,eAAW,MAAM;AACf,WAAK,wBAAwB,SAAS;AAAA,IACxC,GAAG,GAAG;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAgB;AACtB,SAAK,SAAS,SAAS,cAAc,KAAK;AAC1C,SAAK,OAAO,KAAK;AAGjB,SAAK,WAAW,KAAK,cAAc,OAAO,iCAAiC;AAC3E,SAAK,SAAS,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAU1B,SAAK,OAAO,YAAY,KAAK,QAAQ;AAGrC,SAAK,UAAU,KAAK,cAAc,OAAO,wBAAwB;AACjE,SAAK,OAAO,YAAY,KAAK,OAAO;AAGpC,SAAK,QAAQ,KAAK,cAAc,OAAO,UAAU;AACjD,SAAK,MAAM,MAAM,OAAO,KAAK,OAAO;AACpC,SAAK,MAAM,MAAM,MAAM,KAAK,OAAO;AACnC,SAAK,MAAM,iBAAiB,aAAa,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AACnE,SAAK,MAAM,iBAAiB,cAAc,CAAC,MAAM,KAAK,aAAa,CAAC,GAAG,EAAE,SAAS,KAAK,CAAC;AAGxF,SAAK,SAAS,SAAS,cAAc,QAAQ;AAC7C,SAAK,OAAO,YAAY;AACxB,SAAK,OAAO,YAAY,KAAK;AAC7B,SAAK,OAAO,iBAAiB,SAAS,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;AAC/D,SAAK,UAAU,KAAK,cAAc,QAAQ,wBAAwB;AAClE,SAAK,OAAO,YAAY,KAAK,OAAO;AACpC,SAAK,MAAM,YAAY,KAAK,MAAM;AAGlC,SAAK,UAAU,KAAK,cAAc,OAAO,wBAAwB;AACjE,SAAK,WAAW;AAChB,SAAK,MAAM,YAAY,KAAK,OAAO;AAEnC,SAAK,OAAO,YAAY,KAAK,KAAK;AAGlC,SAAK,YAAY,SAAS,cAAc,OAAO;AAC/C,SAAK,UAAU,OAAO;AACtB,SAAK,UAAU,SAAS;AACxB,SAAK,UAAU,MAAM,UAAU;AAC/B,SAAK,UAAU,iBAAiB,UAAU,CAAC,MAAM,KAAK,oBAAoB,CAAC,CAAC;AAC5E,SAAK,OAAO,YAAY,KAAK,SAAS;AAGtC,SAAK,aAAa,KAAK,cAAc,OAAO,qCAAqC;AACjF,SAAK,WAAW,YAAY;AAC5B,SAAK,OAAO,YAAY,KAAK,UAAU;AAEvC,aAAS,KAAK,YAAY,KAAK,MAAM;AAAA,EACvC;AAAA,EAEQ,aAAmB;AACzB,QAAI,CAAC,KAAK,QAAS;AAGnB,UAAM,SAAS,KAAK,cAAc,OAAO,mBAAmB;AAG5D,UAAM,cAAc,KAAK,cAAc,SAAS,aAAa;AAC7D,gBAAY,iBAAiB,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC;AAChE,SAAK,aAAa,SAAS,cAAc,OAAO;AAChD,SAAK,WAAW,OAAO;AACvB,SAAK,WAAW,UAAU,KAAK;AAC/B,SAAK,WAAW,iBAAiB,UAAU,CAAC,MAAM,KAAK,eAAe,CAAC,CAAC;AACxE,UAAM,SAAS,KAAK,cAAc,QAAQ,oBAAoB;AAC9D,UAAM,YAAY,KAAK,cAAc,QAAQ,mBAAmB;AAChE,cAAU,cAAc;AACxB,gBAAY,YAAY,KAAK,UAAU;AACvC,gBAAY,YAAY,MAAM;AAC9B,gBAAY,YAAY,SAAS;AACjC,WAAO,YAAY,WAAW;AAG9B,SAAK,eAAe,KAAK,cAAc,OAAO,8BAA8B;AAC5E,SAAK,iBAAiB;AACtB,WAAO,YAAY,KAAK,YAAY;AAGpC,UAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,aAAS,YAAY;AACrB,aAAS,YAAY,KAAK;AAC1B,aAAS,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,YAAY;AAAA,IAAG,CAAC;AACtF,WAAO,YAAY,QAAQ;AAE3B,SAAK,QAAQ,YAAY,MAAM;AAG/B,SAAK,WAAW,KAAK,cAAc,OAAO,cAAc;AACxD,UAAM,WAAW,KAAK,eAAe,SAAS,GAAG;AACjD,SAAK,SAAS,YAAY,mCAAmC,WAAW,cAAc,WAAW,0CAA0C,WAAW,KAAK,iBAAiB,KAAK,eAAe,UAAU,GAAG,CAAC,CAAC;AAC/M,SAAK,QAAQ,YAAY,KAAK,QAAQ;AAGtC,UAAM,YAAY,KAAK,mBAAmB;AAC1C,QAAI,WAAW;AACb,YAAM,YAAY,KAAK,cAAc,OAAO,EAAE;AAC9C,gBAAU,YAAY;AACtB,WAAK,QAAQ,YAAY,SAAS;AAElC,iBAAW,MAAM;AACf,cAAM,aAAa,SAAS,eAAe,oBAAoB;AAC/D,oBAAY,iBAAiB,SAAS,CAAC,MAAM;AAC3C,YAAE,gBAAgB;AAClB,eAAK,uBAAuB;AAC5B,gBAAM,SAAS,SAAS,eAAe,mBAAmB;AAC1D,kBAAQ,OAAO;AAAA,QACjB,CAAC;AAAA,MACH,GAAG,CAAC;AAAA,IACN;AAGA,SAAK,kBAAkB,KAAK,cAAc,OAAO,aAAa;AAG9D,SAAK,gBAAgB,KAAK,cAAc,OAAO,+BAA+B;AAC9E,SAAK,gBAAgB,YAAY,KAAK,aAAa;AAGnD,UAAM,UAAU,KAAK,cAAc,OAAO,eAAe;AACzD,SAAK,UAAU,SAAS,cAAc,QAAQ;AAC9C,SAAK,QAAQ,YAAY;AACzB,SAAK,QAAQ,YAAY,KAAK;AAC9B,SAAK,QAAQ,WAAW;AACxB,SAAK,QAAQ,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,OAAO;AAAA,IAAG,CAAC;AACrF,SAAK,UAAU,SAAS,cAAc,QAAQ;AAC9C,SAAK,QAAQ,YAAY;AACzB,SAAK,QAAQ,YAAY,KAAK;AAC9B,SAAK,QAAQ,WAAW;AACxB,SAAK,QAAQ,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,OAAO;AAAA,IAAG,CAAC;AACrF,YAAQ,YAAY,KAAK,OAAO;AAChC,YAAQ,YAAY,KAAK,OAAO;AAChC,SAAK,gBAAgB,YAAY,OAAO;AAGxC,UAAM,WAAW,KAAK,cAAc,OAAO,gBAAgB;AAC3D,UAAM,aAAa,KAAK,cAAc,QAAQ,kBAAkB;AAChE,eAAW,cAAc;AACzB,aAAS,YAAY,UAAU;AAC/B,UAAM,cAAc,KAAK,cAAc,OAAO,mBAAmB;AACjE,UAAM,eAAe,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AACtF,eAAW,SAAS,cAAc;AAChC,YAAM,SAAS,KAAK,cAAc,OAAO,mBAAmB;AAC5D,aAAO,MAAM,aAAa;AAC1B,aAAO,QAAQ,QAAQ;AACvB,UAAI,UAAU,KAAK,eAAgB,QAAO,UAAU,IAAI,QAAQ;AAChE,aAAO,iBAAiB,SAAS,CAAC,MAAM;AAAE,UAAE,gBAAgB;AAAG,aAAK,gBAAgB,KAAK;AAAA,MAAG,CAAC;AAC7F,kBAAY,YAAY,MAAM;AAAA,IAChC;AAEA,UAAM,eAAe,KAAK,cAAc,OAAO,mBAAmB;AAClE,UAAM,gBAAgB,KAAK,cAAc,OAAO,2BAA2B;AAC3E,UAAM,cAAc,SAAS,cAAc,OAAO;AAClD,gBAAY,OAAO;AACnB,gBAAY,QAAQ,KAAK;AACzB,gBAAY,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,gBAAiB,EAAE,OAA4B,KAAK;AAAA,IAAG,CAAC;AACjI,iBAAa,YAAY,aAAa;AACtC,iBAAa,YAAY,WAAW;AACpC,gBAAY,YAAY,YAAY;AACpC,aAAS,YAAY,WAAW;AAChC,SAAK,gBAAgB,YAAY,QAAQ;AAGzC,SAAK,eAAe,SAAS,cAAc,QAAQ;AACnD,SAAK,aAAa,YAAY;AAC9B,SAAK,aAAa,YAAY,GAAG,KAAK,OAAO;AAC7C,SAAK,aAAa,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,cAAc;AAAA,IAAG,CAAC;AACjG,SAAK,gBAAgB,YAAY,KAAK,YAAY;AAGlD,SAAK,iBAAiB,KAAK,cAAc,OAAO,gCAAgC;AAChF,UAAM,eAAe,KAAK,cAAc,OAAO,oBAAoB;AACnE,iBAAa,cAAc;AAC3B,SAAK,eAAe,YAAY,YAAY;AAC5C,SAAK,gBAAgB,KAAK,cAAc,OAAO,mBAAmB;AAClE,SAAK,eAAe,YAAY,KAAK,aAAa;AAClD,SAAK,gBAAgB,YAAY,KAAK,cAAc;AAGpD,SAAK,YAAY,KAAK,cAAc,OAAO,cAAc;AACzD,SAAK,UAAU,SAAS,cAAc,QAAQ;AAC9C,SAAK,QAAQ,YAAY;AACzB,SAAK,QAAQ,YAAY,GAAG,KAAK,IAAI;AACrC,SAAK,QAAQ,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,YAAY;AAAA,IAAG,CAAC;AAC1F,SAAK,aAAa,SAAS,cAAc,QAAQ;AACjD,SAAK,WAAW,YAAY;AAC5B,SAAK,WAAW,YAAY,GAAG,KAAK,OAAO;AAC3C,SAAK,WAAW,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,eAAe;AAAA,IAAG,CAAC;AAChG,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,YAAY;AACtB,cAAU,YAAY,GAAG,KAAK,MAAM;AACpC,cAAU,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,OAAO;AAAA,IAAG,CAAC;AAClF,SAAK,UAAU,YAAY,KAAK,OAAO;AACvC,SAAK,UAAU,YAAY,KAAK,UAAU;AAC1C,SAAK,UAAU,YAAY,SAAS;AACpC,SAAK,gBAAgB,YAAY,KAAK,SAAS;AAE/C,SAAK,QAAQ,YAAY,KAAK,eAAe;AAG7C,SAAK,aAAa,KAAK,cAAc,OAAO,eAAe;AAC3D,SAAK,WAAW,YAAY;AAC5B,SAAK,WAAW,iBAAiB,SAAS,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,aAAO,KAAK,4BAA4B,QAAQ;AAAA,IAAG,CAAC;AAC5H,SAAK,QAAQ,YAAY,KAAK,UAAU;AAAA,EAC1C;AAAA,EAEQ,mBAAyB;AAC/B,QAAI,CAAC,KAAK,aAAc;AACxB,SAAK,aAAa,YAAY;AAC9B,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,YAAY;AACnB,eAAW,QAAQ,KAAK,WAAW;AACjC,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,QAAQ;AACZ,UAAI,cAAc,KAAK,YAAY;AACnC,UAAI,SAAS,KAAK,YAAa,KAAI,WAAW;AAC9C,aAAO,YAAY,GAAG;AAAA,IACxB;AACA,WAAO,iBAAiB,UAAU,CAAC,MAAM;AAAE,QAAE,gBAAgB;AAAG,WAAK,WAAY,EAAE,OAA6B,KAAK;AAAA,IAAG,CAAC;AACzH,SAAK,aAAa,YAAY,MAAM;AACpC,UAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,UAAM,YAAY;AAClB,UAAM,cAAc;AACpB,SAAK,aAAa,YAAY,KAAK;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAiB;AAEvB,QAAI,KAAK,OAAO;AACd,WAAK,MAAM,MAAM,UAAU,KAAK,gBAAgB,KAAK;AAAA,IACvD;AAGA,QAAI,KAAK,QAAQ;AACf,WAAK,OAAO,MAAM,UAAU,KAAK,SAAS,SAAS;AACnD,WAAK,OAAO,UAAU,OAAO,mBAAmB,KAAK,QAAQ;AAAA,IAC/D;AACA,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,UAAU,OAAO,eAAe,CAAC,KAAK,MAAM;AAEzD,UAAI,KAAK,QAAQ;AACf,cAAM,SAAS,KAAK,OAAO,OAAO,cAAc;AAChD,cAAM,WAAW,KAAK,OAAO,OAAO,aAAa;AACjD,aAAK,QAAQ,MAAM,SAAS,SAAS,MAAM;AAC3C,aAAK,QAAQ,MAAM,MAAM,SAAS,KAAK;AACvC,aAAK,QAAQ,MAAM,QAAQ,WAAW,MAAM;AAC5C,aAAK,QAAQ,MAAM,OAAO,WAAW,KAAK;AAAA,MAC5C;AAAA,IACF;AAGA,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,UAAU,OAAO,eAAe,KAAK,mBAAmB,CAAC;AACtE,WAAK,QAAQ,cAAc,OAAO,KAAK,cAAc;AAAA,IACvD;AAGA,QAAI,KAAK,WAAY,MAAK,WAAW,UAAU,KAAK;AAGpD,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,UAAU,OAAO,eAAe,CAAC,KAAK,YAAY,KAAK,UAAU,UAAU,CAAC;AAC9F,YAAM,MAAM,KAAK,aAAa,cAAc,mBAAmB;AAC/D,UAAI,IAAK,KAAI,QAAQ,KAAK;AAAA,IAC5B;AAGA,QAAI,KAAK,iBAAiB;AACxB,WAAK,gBAAgB,UAAU,OAAO,eAAe,CAAC,KAAK,QAAQ;AAAA,IACrE;AAGA,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,UAAU,OAAO,eAAe,KAAK,mBAAmB,CAAC;AAC5E,WAAK,cAAc,cAAc,GAAG,KAAK,cAAc,kBAAkB,KAAK,iBAAiB,IAAI,MAAM,EAAE;AAAA,IAC7G;AAGA,QAAI,KAAK,QAAS,MAAK,QAAQ,WAAW,CAAC,KAAK;AAChD,QAAI,KAAK,QAAS,MAAK,QAAQ,WAAW,CAAC,KAAK;AAGhD,QAAI,KAAK,aAAc,MAAK,aAAa,UAAU,OAAO,UAAU,KAAK,WAAW;AACpF,QAAI,KAAK,eAAgB,MAAK,eAAe,UAAU,OAAO,eAAe,CAAC,KAAK,WAAW;AAG9F,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,WAAW,KAAK,YAAY,KAAK,gBAAgB,KAAK,mBAAmB;AACtF,WAAK,QAAQ,YAAY,KAAK,WAAW,iDAAiD,GAAG,KAAK,IAAI;AAAA,IACxG;AACA,QAAI,KAAK,YAAY;AACnB,WAAK,WAAW,WAAW,KAAK,YAAY,KAAK;AACjD,WAAK,WAAW,YAAY,KAAK,eAAe,qDAAqD,GAAG,KAAK,OAAO;AAAA,IACtH;AAGA,QAAI,KAAK,SAAU,MAAK,SAAS,UAAU,OAAO,eAAe,CAAC,KAAK,OAAO;AAG9E,QAAI,KAAK,WAAY,MAAK,WAAW,UAAU,OAAO,eAAe,CAAC,KAAK,cAAc;AAAA,EAC3F;AAAA;AAAA;AAAA;AAAA,EAMQ,oBAA0B;AAChC,SAAK,mBAAmB;AACxB,SAAK,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,mBAA4B;AAClC,QAAI,KAAK,mBAAmB;AAC1B,aAAO,SAAS,cAAc,KAAK,iBAAiB,KAAK,SAAS;AAAA,IACpE;AACA,WAAO,SAAS;AAAA,EAClB;AAAA,EAEQ,qBAA2B;AACjC,UAAM,YAAY,KAAK,iBAAiB;AACxC,QAAI,CAAC,UAAW;AAGhB,eAAW,MAAM,KAAK,sBAAsB;AAC1C,UAAI,CAAC,SAAS,SAAS,EAAE,EAAG,MAAK,qBAAqB,OAAO,EAAE;AAAA,IACjE;AAKA,UAAM,iBAAiB,CAAC,OAA4B;AAClD,UAAI,SAA6B,GAAG;AACpC,aAAO,UAAU,WAAW,SAAS,MAAM;AACzC,cAAM,MAAM,OAAO,QAAQ,YAAY;AACvC,YAAI,IAAI,SAAS,SAAS,EAAG,QAAO;AACpC,YAAI,IAAI,SAAS,SAAS,EAAG,QAAO;AACpC,iBAAS,OAAO;AAAA,MAClB;AACA,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,cAAgE,CAAC;AAEvE,UAAM,YAAY,CAAC,cAAsB;AACvC,aAAO,MAAM,KAAK,SAAS,iBAA8B,YAAY,CAAC,EACnE,KAAK,UAAQ,KAAK,aAAa,UAAU,MAAM,SAAS;AAAA,IAC7D;AAEA,UAAM,YAAY,CAAC,IAAiB,gBAAwB;AAC1D,YAAM,aAAa,gBAAgB,YAAY,WAC5B,gBAAgB,YAAY,WAAW;AAC1D,UAAI,CAAC,YAAY,UAAU,EAAG,aAAY,UAAU,IAAI,CAAC;AACzD,YAAM,MAAM,GAAG,QAAQ,YAAY;AACnC,UAAI,CAAC,YAAY,UAAU,EAAE,GAAG,EAAG,aAAY,UAAU,EAAE,GAAG,IAAI;AAClE,YAAM,SAAS,eAAe,SAAS,GAAG,UAAU,MAAM;AAC1D,UAAI,MAAM,GAAG,MAAM,QAAQ,GAAG,IAAI,YAAY,UAAU,EAAE,GAAG,CAAC;AAC9D,aAAO,UAAU,GAAG,GAAG;AACrB,oBAAY,UAAU,EAAE,GAAG;AAC3B,cAAM,GAAG,MAAM,QAAQ,GAAG,IAAI,YAAY,UAAU,EAAE,GAAG,CAAC;AAAA,MAC5D;AACA,kBAAY,UAAU,EAAE,GAAG;AAC3B,SAAG,aAAa,YAAY,GAAG;AAC/B,SAAG,aAAa,oBAAoB,WAAW;AAC/C,WAAK,qBAAqB,IAAI,EAAE;AAAA,IAClC;AAGA,UAAM,mBAAmB,oBAAI,IAAI,CAAC,KAAK,UAAU,KAAK,MAAM,KAAK,KAAK,UAAU,OAAO,OAAO,OAAO,MAAM,CAAC;AAG5G,UAAM,WAAW,KAAK,aAAa,KAAK,GAAG;AAC3C,UAAM,WAAW,UAAU,iBAA8B,QAAQ;AACjE,aAAS,QAAQ,QAAM;AACrB,UAAI,GAAG,aAAa,UAAU,EAAG;AACjC,UAAI,GAAG,QAAQ,gEAAgE,EAAG;AAElF,UAAI,iBAAiB,IAAI,GAAG,OAAO,KAAK,GAAG,eAAe,QAAQ,YAAY,EAAG;AACjF,UAAI,GAAG,SAAS,SAAS,EAAG;AAC5B,YAAM,OAAO,KAAK,qBAAqB,EAAE,EAAE,KAAK;AAChD,UAAI,KAAK,SAAS,EAAG;AACrB,gBAAU,IAAI,eAAe,EAAE,CAAC;AAAA,IAClC,CAAC;AAID,UAAM,gBAAgB,UAAU,iBAA8B,iBAAiB;AAC/E,kBAAc,QAAQ,QAAM;AAC1B,UAAI,GAAG,aAAa,UAAU,EAAG;AACjC,UAAI,GAAG,QAAQ,gEAAgE,EAAG;AAClF,gBAAU,IAAI,eAAe,EAAE,CAAC;AAAA,IAClC,CAAC;AAAA,EACH;AAAA,EAEQ,UAAgB;AACtB,UAAM,WAAW,SAAS,iBAA8B,YAAY;AACpE,UAAM,WAAW,oBAAI,IAAY;AACjC,aAAS,QAAQ,QAAM;AACrB,UAAI,GAAG,QAAQ,uCAAuC,EAAG;AACzD,UAAI,MAAM,GAAG,aAAa,UAAU;AACpC,UAAI,SAAS,IAAI,GAAG,GAAG;AACrB,YAAI,MAAM;AACV,YAAI,WAAW,GAAG,GAAG,KAAK,GAAG;AAC7B,eAAO,SAAS,cAAc,cAAc,QAAQ,IAAI,GAAG;AACzD;AACA,qBAAW,GAAG,GAAG,KAAK,GAAG;AAAA,QAC3B;AACA,WAAG,aAAa,YAAY,QAAQ;AACpC,cAAM;AAAA,MACR;AACA,eAAS,IAAI,GAAG;AAChB,WAAK,eAAe,IAAI,GAAG;AAC3B,UAAI,CAAC,KAAK,gBAAgB,IAAI,EAAE,GAAG;AACjC,aAAK,cAAc,IAAI,GAAG;AAAA,MAC5B;AAAA,IACF,CAAC;AAED,eAAW,CAAC,EAAE,KAAK,KAAK,iBAAiB;AACvC,UAAI,CAAC,SAAS,SAAS,EAAE,EAAG,MAAK,cAAc,EAAE;AAAA,IACnD;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,UAAM,YAAY,KAAK,iBAAiB;AACxC,QAAI,CAAC,UAAW;AAChB,UAAM,gBAAgB,EAAE,GAAG,KAAK,WAAW;AAC3C,QAAI,SAAS;AACb,UAAM,SAAS,UAAU,iBAAmC,KAAK;AACjE,WAAO,QAAQ,SAAO;AACpB,UAAI,IAAI,QAAQ,oBAAoB,EAAG;AACvC,UAAI,KAAK,cAAc,IAAI,GAAG,EAAG;AACjC,YAAM,MAAM,IAAI,aAAa,KAAK,KAAK;AACvC,UAAI,CAAC,OAAO,IAAI,WAAW,OAAO,EAAG;AACrC,WAAK,YAAY,KAAK,GAAG;AACzB,UAAI,CAAC,cAAc,GAAG,GAAG;AACvB,sBAAc,GAAG,IAAI;AACrB,iBAAS;AAAA,MACX;AAAA,IACF,CAAC;AACD,QAAI,QAAQ;AACV,WAAK,aAAa;AAClB,WAAK,iBAAiB,KAAK,MAAM,KAAK,UAAU,aAAa,CAAC;AAAA,IAChE;AACA,eAAW,CAAC,GAAG,KAAK,KAAK,eAAe;AACtC,UAAI,CAAC,SAAS,SAAS,GAAG,EAAG,MAAK,YAAY,GAAG;AAAA,IACnD;AAAA,EACF;AAAA,EAEQ,qBAAqB,IAAyB;AACpD,QAAI,OAAO;AACX,aAAS,IAAI,GAAG,IAAI,GAAG,WAAW,QAAQ,KAAK;AAC7C,UAAI,GAAG,WAAW,CAAC,EAAE,aAAa,KAAK,WAAW;AAChD,gBAAQ,GAAG,WAAW,CAAC,EAAE,eAAe;AAAA,MAC1C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,IAA0B;AACpD,WAAO,CAAC,CAAC,GAAG,cAAc,YAAY;AAAA,EACxC;AAAA,EAEQ,kBAAkB,IAAyB;AACjD,QAAI,KAAK,gBAAiB,QAAO,GAAG,WAAW,KAAK,KAAK;AACzD,QAAI,KAAK,oBAAoB,EAAE,EAAG,QAAO,KAAK,qBAAqB,EAAE,EAAE,KAAK;AAC5E,WAAO,GAAG,aAAa,KAAK,KAAK;AAAA,EACnC;AAAA,EAEQ,kBAAkB,IAAiB,KAAmB;AAC5D,QAAI,KAAK,iBAAiB;AACxB,SAAG,YAAY,KAAK,aAAa,GAAG;AAAA,IACtC,WAAW,KAAK,oBAAoB,EAAE,GAAG;AACvC,YAAM,YAAoB,CAAC;AAC3B,eAAS,IAAI,GAAG,IAAI,GAAG,WAAW,QAAQ,KAAK;AAC7C,YAAI,GAAG,WAAW,CAAC,EAAE,aAAa,KAAK,UAAW,WAAU,KAAK,GAAG,WAAW,CAAC,CAAS;AAAA,MAC3F;AACA,UAAI,UAAU,SAAS,EAAG,WAAU,CAAC,EAAE,cAAc;AAAA,UAChD,IAAG,QAAQ,SAAS,eAAe,GAAG,CAAC;AAAA,IAC9C,OAAO;AACL,SAAG,cAAc;AAAA,IACnB;AAAA,EACF;AAAA;AAAA,EAGQ,qBAAqB,IAAiB,KAAmB;AAC/D,SAAK,kBAAkB,IAAI,GAAG;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,IAAiB,KAAmB;AACxD,UAAM,aAAa,MAAM,KAAK,kBAAkB,EAAE;AAClD,UAAM,cAAc,MAAM;AACxB,YAAM,OAAO,WAAW;AACxB,YAAM,aAAa,KAAK,YAAY,GAAG;AACvC,UAAI,SAAS,WAAY,MAAK,cAAc,KAAK,IAAI;AACrD,WAAK,gBAAgB;AAAA,IACvB;AACA,UAAM,iBAAiB,CAAC,MAAqB;AAC3C,UAAI,EAAE,QAAQ,SAAS;AAErB,YAAI,KAAK,mBAAmB,CAAC,aAAY,iBAAiB,IAAI,GAAG,OAAO,GAAG;AACzE;AAAA,QACF;AACA,UAAE,eAAe;AACjB,WAAG,KAAK;AAAA,MACV;AAAA,IACF;AACA,UAAM,eAAe,MAAM;AACzB,YAAM,OAAO,WAAW;AACxB,YAAM,aAAa,KAAK,YAAY,GAAG;AACvC,UAAI,SAAS,WAAY,MAAK,cAAc,KAAK,IAAI;AAAA,IACvD;AACA,UAAM,mBAAmB,MAAM;AAC7B,UAAI,SAAS,kBAAkB,GAAI,IAAG,MAAM;AAC5C,YAAM,YAAY,OAAO,aAAa;AACtC,UAAI,CAAC,UAAW;AAChB,YAAM,QAAQ,SAAS,YAAY;AACnC,YAAM,mBAAmB,EAAE;AAC3B,YAAM,SAAS,KAAK;AACpB,gBAAU,gBAAgB;AAC1B,gBAAU,SAAS,KAAK;AAAA,IAC1B;AAIA,UAAM,eAAe,CAAC,MAAa;AACjC,QAAE,gBAAgB;AAClB,YAAM,WAAW,GAAG,YAAY,OAAO,CAAC,CAAE,EAAE,OAAuB,QAAQ,GAAG;AAC9E,UAAI,UAAU;AACZ,UAAE,eAAe;AAAA,MAGnB;AAAA,IACF;AACA,UAAM,cAAc,GAAG,aAAa,kBAAkB,KAAK,KAAK;AAChE,SAAK,gBAAgB,IAAI,IAAI,EAAE,KAAK,aAAa,aAAa,gBAAgB,cAAc,aAAa,CAAC;AAC1G,QAAI,KAAK,SAAU,MAAK,kBAAkB,IAAI,KAAK,aAAa,gBAAgB,cAAc,YAAY;AAAA,EAC5G;AAAA,EAEQ,cAAc,IAAuB;AAC3C,UAAM,OAAO,KAAK,gBAAgB,IAAI,EAAE;AACxC,QAAI,MAAM;AACR,SAAG,oBAAoB,QAAQ,KAAK,WAAW;AAC/C,SAAG,oBAAoB,WAAW,KAAK,cAA+B;AACtE,SAAG,oBAAoB,SAAS,KAAK,YAAY;AACjD,SAAG,oBAAoB,SAAS,KAAK,cAAc,IAAI;AACvD,SAAG,gBAAgB,iBAAiB;AACpC,WAAK,gBAAgB,OAAO,EAAE;AAAA,IAChC;AAAA,EACF;AAAA;AAAA,EAGA,OAAe,SAAS,GAAgB;AAAE,MAAE,gBAAgB;AAAA,EAAG;AAAA,EAEvD,iBAAiB,IAAuB;AAC9C,QAAI,SAAS,kBAAkB,GAAI,IAAG,MAAM;AAC5C,UAAM,YAAY,OAAO,aAAa;AACtC,QAAI,CAAC,UAAW;AAChB,UAAM,QAAQ,SAAS,YAAY;AACnC,UAAM,mBAAmB,EAAE;AAC3B,UAAM,SAAS,KAAK;AACpB,cAAU,gBAAgB;AAC1B,cAAU,SAAS,KAAK;AAAA,EAC1B;AAAA,EAEQ,kBAAkB,IAAiB,MAAc,OAA2B,MAAkC,QAA4B,QAAkC;AAClL,UAAM,MAAM,KAAK,YAAY,IAAI;AAEjC,QAAI,OAAO,SAAS,kBAAkB,IAAI;AACxC,WAAK,kBAAkB,IAAI,GAAG;AAAA,IAChC;AACA,OAAG,aAAa,mBAAmB,MAAM;AACzC,OAAG,MAAM,YAAY,WAAW,cAAc,KAAK,cAAc,IAAI,WAAW;AAChF,OAAG,MAAM,YAAY,kBAAkB,QAAQ,WAAW;AAC1D,OAAG,MAAM,SAAS;AAClB,OAAG,MAAM,aAAa;AACtB,OAAG,MAAM,WAAW;AAWpB,OAAG,iBAAiB,QAAQ,KAAK;AACjC,OAAG,iBAAiB,WAAW,IAAqB;AACpD,OAAG,iBAAiB,SAAS,MAAM;AACnC,OAAG,iBAAiB,SAAS,QAAQ,IAAI;AAEzC,OAAG,iBAAiB,aAAa,aAAY,UAAU,IAAI;AAC3D,OAAG,iBAAiB,cAAc,aAAY,UAAU,IAAI;AAE5D,OAAG,iBAAiB,SAAS,MAAM,KAAK,gBAAgB,EAAE,CAAC;AAAA,EAC7D;AAAA,EAEQ,mBAAmB,IAAiB,MAAc,OAA2B,MAAkC,QAA4B,QAAkC;AACnL,OAAG,gBAAgB,iBAAiB;AACpC,OAAG,MAAM,eAAe,SAAS;AACjC,OAAG,MAAM,eAAe,gBAAgB;AACxC,OAAG,MAAM,SAAS;AAClB,OAAG,MAAM,aAAa;AACtB,OAAG,MAAM,WAAW;AACpB,UAAM,MAAM,KAAK,YAAY,IAAI;AACjC,QAAI,IAAK,MAAK,kBAAkB,IAAI,GAAG;AACvC,OAAG,oBAAoB,QAAQ,KAAK;AACpC,OAAG,oBAAoB,WAAW,IAAqB;AACvD,OAAG,oBAAoB,SAAS,MAAM;AACtC,OAAG,oBAAoB,SAAS,QAAQ,IAAI;AAC5C,OAAG,oBAAoB,aAAa,aAAY,UAAU,IAAI;AAC9D,OAAG,oBAAoB,cAAc,aAAY,UAAU,IAAI;AAAA,EACjE;AAAA,EAEQ,cAAc,UAAyB;AAE7C,aAAS,KAAK,UAAU,OAAO,gBAAgB,QAAQ;AAEvD,QAAI,UAAU;AAGZ,WAAK,0BAA0B,CAAC,MAAa;AAC3C,cAAM,SAAS,EAAE;AACjB,YAAI,CAAC,OAAQ;AAEb,cAAM,WAAW,OAAO,QAAQ,0BAA0B;AAC1D,cAAM,cAAc,OAAO,QAAQ,yDAAyD;AAC5F,cAAM,oBAAoB,CAAC,CAAC,YAAY,KAAK,gBAAgB,IAAI,QAAQ;AACzE,cAAM,iBAAiB,CAAC,CAAC,eAAe,KAAK,cAAc,IAAI,WAA+B;AAC9F,cAAM,kBAAkB,qBAAqB,kBAAkB,CAAC,CAAC,YAAY,CAAC,CAAC;AAE/E,YAAI,iBAAiB;AAGnB,YAAE,gBAAgB;AAClB,gBAAM,SAAS,OAAO,QAAQ,GAAG;AACjC,cAAI,OAAQ,GAAE,eAAe;AAAA,QAC/B;AAAA,MACF;AACA,eAAS,iBAAiB,SAAS,KAAK,yBAAyB,IAAI;AACrE,eAAS,iBAAiB,aAAa,KAAK,yBAAyB,IAAI;AACzE,eAAS,iBAAiB,eAAe,KAAK,yBAAyB,IAAI;AAC3E,eAAS,iBAAiB,cAAc,KAAK,yBAAyB,IAAI;AAG1E,WAAK,oBAAoB,MAAM;AAC7B,YAAI,KAAK,cAAe;AACxB,aAAK,gBAAgB,sBAAsB,MAAM;AAC/C,eAAK,0BAA0B;AAC/B,eAAK,gBAAgB;AAAA,QACvB,CAAC;AAAA,MACH;AACA,aAAO,iBAAiB,UAAU,KAAK,mBAAmB,EAAE,SAAS,KAAK,CAAC;AAC3E,WAAK,0BAA0B;AAAA,IACjC,OAAO;AAEL,UAAI,KAAK,yBAAyB;AAChC,iBAAS,oBAAoB,SAAS,KAAK,yBAAyB,IAAI;AACxE,iBAAS,oBAAoB,aAAa,KAAK,yBAAyB,IAAI;AAC5E,iBAAS,oBAAoB,eAAe,KAAK,yBAAyB,IAAI;AAC9E,iBAAS,oBAAoB,cAAc,KAAK,yBAAyB,IAAI;AAC7E,aAAK,0BAA0B;AAAA,MACjC;AAEA,UAAI,KAAK,mBAAmB;AAC1B,eAAO,oBAAoB,UAAU,KAAK,iBAAiB;AAC3D,aAAK,oBAAoB;AAAA,MAC3B;AACA,UAAI,KAAK,eAAe;AAAE,6BAAqB,KAAK,aAAa;AAAG,aAAK,gBAAgB;AAAA,MAAM;AAE/F,iBAAW,CAAC,EAAE,KAAK,KAAK,gBAAiB,IAAG,MAAM,gBAAgB;AAClE,WAAK,kBAAkB,QAAQ,OAAK;AAAE,UAAE,MAAM,gBAAgB;AAAA,MAAI,CAAC;AACnE,WAAK,kBAAkB,MAAM;AAAA,IAC/B;AAEA,eAAW,CAAC,IAAI,IAAI,KAAK,KAAK,iBAAiB;AAC7C,UAAI,SAAU,MAAK,kBAAkB,IAAI,KAAK,KAAK,KAAK,aAAa,KAAK,gBAAgB,KAAK,cAAc,KAAK,YAAY;AAAA,UACzH,MAAK,mBAAmB,IAAI,KAAK,KAAK,KAAK,aAAa,KAAK,gBAAgB,KAAK,cAAc,KAAK,YAAY;AAAA,IACxH;AACA,SAAK,mBAAmB,QAAQ;AAEhC,QAAI,SAAU,MAAK,kBAAkB;AAAA,QAChC,MAAK,mBAAmB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,4BAAkC;AACxC,UAAM,UAAU,oBAAI,IAA0B;AAE9C,eAAW,CAAC,EAAE,KAAK,KAAK,iBAAiB;AACvC,YAAM,WAAW,KAAK,uBAAuB,EAAE;AAC/C,UAAI,CAAC,SAAU;AAGf,UAAI,CAAC,QAAQ,IAAI,QAAQ,GAAG;AAC1B,cAAM,KAAK,OAAO,iBAAiB,QAAQ;AAC3C,cAAM,UAAU,WAAW,GAAG,OAAO,KAAK,QACrC,GAAG,eAAe,YAClB,GAAG,YAAY;AACpB,gBAAQ,IAAI,UAAU,OAAO;AAE7B,YAAI,CAAC,SAAS;AACZ,mBAAS,MAAM,gBAAgB;AAC/B,eAAK,kBAAkB,IAAI,QAAQ;AAAA,QACrC,OAAO;AACL,cAAI,KAAK,kBAAkB,IAAI,QAAQ,GAAG;AACxC,qBAAS,MAAM,gBAAgB;AAC/B,iBAAK,kBAAkB,OAAO,QAAQ;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,uBAAuB,IAAqC;AAClE,QAAI,MAAM,GAAG;AACb,WAAO,OAAO,QAAQ,SAAS,MAAM;AACnC,UAAI,IAAI,QAAQ,oBAAoB,EAAG,QAAO;AAC9C,YAAM,MAAM,OAAO,iBAAiB,GAAG,EAAE;AACzC,UAAI,QAAQ,cAAc,QAAQ,QAAS,QAAO;AAClD,YAAM,IAAI;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,iBAAuB;AAC7B,UAAM,MAAM;AAGZ,QAAI,IAAI,eAAe;AACrB,UAAI;AAAE,YAAI,cAAc,OAAO,EAAE,QAAQ,CAAC,MAAW,EAAE,KAAK,IAAI,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAe;AAAA,IAC7F;AAEA,QAAI,IAAI,MAAM;AACZ,UAAI;AACF,YAAI,KAAK,eAAe,MAAM;AAC9B,YAAI,KAAK,aAAa,GAAG;AAAA,MAC3B,QAAQ;AAAA,MAAe;AAAA,IACzB;AAEA,QAAI,IAAI,KAAK;AACX,UAAI;AAAE,YAAI,IAAI,cAAc;AAAA,MAAG,QAAQ;AAAA,MAAe;AAAA,IACxD;AAGA,SAAK,iBAAiB;AAGtB,SAAK,2BAA2B;AAGhC,eAAW,MAAM;AAAE,WAAK,iBAAiB;AAAG,WAAK,2BAA2B;AAAA,IAAG,GAAG,GAAG;AACrF,eAAW,MAAM;AAAE,WAAK,iBAAiB;AAAG,WAAK,2BAA2B;AAAA,IAAG,GAAG,IAAI;AAAA,EACxF;AAAA;AAAA,EAGQ,mBAAyB;AAC/B,aAAS,iBAAiB,aAAa,EAAE,QAAQ,YAAU;AACzD,YAAM,QAAQ,OAAO;AACrB,UAAI,OAAO;AACT,eAAO,YAAY,aAAa,OAAO,MAAM;AAC7C,cAAM,MAAM,UAAU;AAAA,MACxB;AACA,aAAO,OAAO;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,6BAAmC;AACzC,UAAM,YAAY,KAAK,oBACnB,SAAS,cAAc,KAAK,iBAAiB,KAAK,SAAS,OAC3D,SAAS;AACb,cAAU,iBAA8B,GAAG,EAAE,QAAQ,QAAM;AACzD,UAAI,GAAG,QAAQ,oBAAoB,EAAG;AACtC,YAAM,IAAI,GAAG;AAEb,UAAI,EAAE,kBAAkB,OAAQ,GAAE,gBAAgB;AAClD,UAAI,EAAE,eAAe,OAAQ,GAAE,aAAa;AAC5C,UAAI,EAAE,eAAe,SAAU,GAAE,aAAa;AAC9C,UAAI,EAAE,YAAY,EAAE,aAAa,OAAQ,GAAE,WAAW;AAAA,IACxD,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,sBAA4B;AAClC,SAAK,eAAe,CAAC;AACrB,eAAW,CAAC,IAAI,IAAI,KAAK,KAAK,iBAAiB;AAC7C,WAAK,aAAa,KAAK,GAAG,IAAI,KAAK,kBAAkB,EAAE;AAAA,IACzD;AAAA,EACF;AAAA;AAAA,EAGQ,kBAAwB;AAC9B,UAAM,UAAU,SAAS,KAAK,WAAW;AACzC,eAAW,OAAO,OAAO,KAAK,KAAK,SAAS,GAAG;AAC7C,UAAI,CAAC,KAAK,UAAU,GAAG,EAAE,OAAO,KAAK,KAAK,aAAa,GAAG,GAAG;AAC3D,aAAK,UAAU,GAAG,EAAE,OAAO,IAAI,KAAK,aAAa,GAAG;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,sBAAsB,cAAsB,SAAqC;AACvF,eAAW,CAAC,EAAE,KAAK,KAAK,iBAAiB;AACvC,UAAI,GAAG,YAAY,QAAS;AAC5B,YAAM,UAAU,KAAK,kBAAkB,EAAE;AACzC,UAAI,YAAY,aAAc,QAAO;AAAA,IACvC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,qBAA2B;AACjC,SAAK,UAAU,WAAW;AAC1B,QAAI,gBAAgB;AAEpB,eAAW,CAAC,IAAI,IAAI,KAAK,KAAK,iBAAiB;AAC7C,UAAI,SAAS,kBAAkB,GAAI;AACnC,YAAM,QAAQ,KAAK,UAAU,KAAK,GAAG;AACrC,UAAI,CAAC,MAAO;AAEZ,YAAM,MAAM,MAAM,KAAK,WAAW;AAClC,UAAI,CAAC,IAAK;AAEV,YAAM,OAAO,MAAM,SAAS,KAAK,WAAW,EAAE;AAG9C,UAAI,CAAC,MAAM;AACT,cAAM,UAAU,KAAK,kBAAkB,EAAE;AACzC,YAAI,QAAQ,QAAS,MAAK,kBAAkB,IAAI,GAAG;AACnD;AAAA,MACF;AAGA,YAAM,UAAU,KAAK,aAAa,KAAK,GAAG,KAAK,KAAK,kBAAkB,EAAE;AACxE,UAAI,YAAY,MAAM;AAEpB,YAAI,QAAQ,KAAK,kBAAkB,EAAE,EAAG,MAAK,kBAAkB,IAAI,GAAG;AAAA,MACxE,OAAO;AASL;AAAA,MACF;AAAA,IACF;AAMA,SAAK,UAAU,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAAA,EAC1E;AAAA,EAEQ,yBAA+B;AACrC,eAAW,CAAC,EAAE,KAAK,KAAK,gBAAiB,MAAK,cAAc,EAAE;AAC9D,SAAK,gBAAgB,MAAM;AAC3B,eAAW,MAAM,KAAK,qBAAsB,IAAG,gBAAgB,UAAU;AACzE,SAAK,qBAAqB,MAAM;AAChC,SAAK,eAAe,CAAC;AACrB,SAAK,qBAAqB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,KAAuB,KAAmB;AAC5D,UAAM,aAAa,CAAC,MAAkB;AACpC,UAAI,CAAC,KAAK,SAAU;AACpB,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAClB,WAAK,qBAAqB,EAAE,SAAS,EAAE,SAAS,GAAG;AAAA,IACrD;AACA,SAAK,cAAc,IAAI,KAAK,EAAE,KAAK,WAAW,CAAC;AAC/C,QAAI,KAAK,SAAU,MAAK,gBAAgB,KAAK,UAAU;AAAA,EACzD;AAAA,EAEQ,YAAY,KAA6B;AAC/C,UAAM,OAAO,KAAK,cAAc,IAAI,GAAG;AACvC,QAAI,MAAM;AACR,UAAI,oBAAoB,eAAe,KAAK,UAAU;AACtD,UAAI,MAAM,eAAe,SAAS;AAClC,UAAI,MAAM,SAAS;AACnB,WAAK,cAAc,OAAO,GAAG;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,uBAA6B;AACnC,eAAW,CAAC,GAAG,KAAK,KAAK,cAAe,MAAK,YAAY,GAAG;AAC5D,SAAK,cAAc,MAAM;AACzB,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEQ,mBAAmB,UAAyB;AAClD,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,eAAe;AAC5C,UAAI,SAAU,MAAK,gBAAgB,KAAK,KAAK,UAAU;AAAA,UAClD,MAAK,iBAAiB,KAAK,KAAK,UAAU;AAAA,IACjD;AACA,QAAI,CAAC,UAAU;AACb,WAAK,oBAAoB;AACzB,WAAK,0BAA0B;AAAA,IACjC;AAAA,EACF;AAAA,EAEQ,gBAAgB,KAAuB,YAA2C;AACxF,QAAI,CAAC,IAAI,QAAQ,UAAW,KAAI,QAAQ,YAAY,IAAI,SAAS;AACjE,QAAI,QAAQ;AACZ,QAAI,MAAM,YAAY,WAAW,cAAc,KAAK,cAAc,IAAI,WAAW;AACjF,QAAI,MAAM,SAAS;AACnB,QAAI,iBAAiB,eAAe,UAAU;AAAA,EAChD;AAAA,EAEQ,iBAAiB,KAAuB,YAA2C;AACzF,QAAI,QAAQ,IAAI,QAAQ,aAAa;AACrC,WAAO,IAAI,QAAQ;AACnB,QAAI,MAAM,eAAe,SAAS;AAClC,QAAI,MAAM,SAAS;AACnB,QAAI,oBAAoB,eAAe,UAAU;AAAA,EACnD;AAAA,EAEQ,qBAAqB,GAAW,GAAW,KAA6B;AAC9E,SAAK,oBAAoB;AACzB,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,WAAO,OAAO,KAAK,OAAO;AAAA,MACxB,UAAU;AAAA,MAAS,QAAQ;AAAA,MAAS,UAAU;AAAA,MAC9C,YAAY;AAAA,MAAuB,gBAAgB;AAAA,MAAc,sBAAsB;AAAA,MACvF,QAAQ;AAAA,MAAkC,cAAc;AAAA,MAAQ,SAAS;AAAA,MACzE,WAAW;AAAA,MAA8B,YAAY;AAAA,MACrD,MAAM,KAAK,IAAI,GAAG,OAAO,aAAa,GAAG,IAAI;AAAA,MAC7C,KAAK,KAAK,IAAI,GAAG,OAAO,cAAc,EAAE,IAAI;AAAA,IAC9C,CAAC;AACD,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,WAAO,OAAO,IAAI,OAAO;AAAA,MACvB,OAAO;AAAA,MAAQ,SAAS;AAAA,MAAY,QAAQ;AAAA,MAAQ,cAAc;AAAA,MAClE,YAAY;AAAA,MAAe,OAAO;AAAA,MAAS,UAAU;AAAA,MAAQ,YAAY;AAAA,MACzE,QAAQ;AAAA,MAAW,SAAS;AAAA,MAAQ,YAAY;AAAA,MAAU,KAAK;AAAA,IACjE,CAAC;AACD,QAAI,YAAY,GAAG,KAAK,KAAK;AAC7B,QAAI,iBAAiB,cAAc,MAAM,IAAI,MAAM,aAAa,sBAAsB;AACtF,QAAI,iBAAiB,cAAc,MAAM,IAAI,MAAM,aAAa,aAAa;AAC7E,QAAI,iBAAiB,SAAS,MAAM;AAClC,WAAK,gBAAgB;AACrB,UAAI,KAAK,WAAW;AAAE,aAAK,UAAU,QAAQ;AAAI,aAAK,UAAU,MAAM;AAAA,MAAG;AACzE,WAAK,oBAAoB;AAAA,IAC3B,CAAC;AACD,SAAK,YAAY,GAAG;AACpB,KAAC,KAAK,UAAU,SAAS,MAAM,YAAY,IAAI;AAC/C,SAAK,eAAe;AAEpB,UAAM,eAAe,CAAC,MAAkB;AACtC,UAAI,CAAC,KAAK,SAAS,EAAE,MAAc,GAAG;AACpC,aAAK,oBAAoB;AACzB,iBAAS,oBAAoB,aAAa,YAAY;AAAA,MACxD;AAAA,IACF;AACA,eAAW,MAAM,SAAS,iBAAiB,aAAa,YAAY,GAAG,CAAC;AAAA,EAC1E;AAAA,EAEQ,sBAA4B;AAClC,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,OAAO;AACzB,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEQ,uBAAuB,IAAiB,KAAmB;AACjE,SAAK,0BAA0B;AAE/B,UAAM,cAAc,GAAG,eAAe;AACtC,UAAM,OAAO,GAAG,sBAAsB;AAEtC,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,OAAO,OAAO,OAAO;AAAA,MAC1B,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,CAAC;AAAA,MAChC,KAAK,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,GAAG,CAAC;AAAA,MACpC,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,sBAAsB;AAAA,MACtB,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,SAAS;AAAA,MACT,WAAW;AAAA,MACX,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAED,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,UAAM,cAAc;AACpB,WAAO,OAAO,MAAM,OAAO;AAAA,MACzB,OAAO;AAAA,MACP,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,YAAY;AAAA,IACd,CAAC;AAED,UAAM,WAAW,SAAS,cAAc,UAAU;AAClD,aAAS,QAAQ;AACjB,WAAO,OAAO,SAAS,OAAO;AAAA,MAC5B,OAAO;AAAA,MACP,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AACD,aAAS,iBAAiB,SAAS,MAAM;AACvC,eAAS,MAAM,cAAc,KAAK;AAAA,IACpC,CAAC;AACD,aAAS,iBAAiB,QAAQ,MAAM;AACtC,eAAS,MAAM,cAAc;AAAA,IAC/B,CAAC;AAED,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,WAAO,OAAO,QAAQ,OAAO;AAAA,MAC3B,SAAS;AAAA,MACT,KAAK;AAAA,MACL,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAED,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,cAAc;AACxB,WAAO,OAAO,UAAU,OAAO;AAAA,MAC7B,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,OAAO;AAAA,MACP,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,YAAY;AAAA,IACd,CAAC;AACD,cAAU,iBAAiB,SAAS,MAAM,KAAK,0BAA0B,CAAC;AAC1E,cAAU,iBAAiB,cAAc,MAAM,UAAU,MAAM,aAAa,2BAA2B;AACvG,cAAU,iBAAiB,cAAc,MAAM,UAAU,MAAM,aAAa,0BAA0B;AAEtG,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,cAAc;AACtB,WAAO,OAAO,QAAQ,OAAO;AAAA,MAC3B,SAAS;AAAA,MACT,YAAY,KAAK;AAAA,MACjB,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,OAAO;AAAA,MACP,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,YAAY;AAAA,IACd,CAAC;AACD,YAAQ,iBAAiB,SAAS,MAAM;AACtC,YAAM,UAAU,SAAS;AACzB,WAAK,kBAAkB,IAAI,OAAO;AAClC,WAAK,cAAc,KAAK,OAAO;AAC/B,WAAK,0BAA0B;AAAA,IACjC,CAAC;AACD,YAAQ,iBAAiB,cAAc,MAAM,QAAQ,MAAM,UAAU,KAAK;AAC1E,YAAQ,iBAAiB,cAAc,MAAM,QAAQ,MAAM,UAAU,GAAG;AAExE,YAAQ,YAAY,SAAS;AAC7B,YAAQ,YAAY,OAAO;AAE3B,WAAO,YAAY,KAAK;AACxB,WAAO,YAAY,QAAQ;AAC3B,WAAO,YAAY,OAAO;AAE1B,KAAC,KAAK,UAAU,SAAS,MAAM,YAAY,MAAM;AACjD,SAAK,qBAAqB;AAE1B,aAAS,MAAM;AACf,aAAS,OAAO;AAEhB,UAAM,eAAe,CAAC,MAAkB;AACtC,UAAI,CAAC,OAAO,SAAS,EAAE,MAAc,GAAG;AACtC,aAAK,0BAA0B;AAC/B,iBAAS,oBAAoB,aAAa,YAAY;AAAA,MACxD;AAAA,IACF;AACA,eAAW,MAAM,SAAS,iBAAiB,aAAa,YAAY,GAAG,CAAC;AAAA,EAC1E;AAAA,EAEQ,4BAAkC;AACxC,QAAI,KAAK,oBAAoB;AAC3B,WAAK,mBAAmB,OAAO;AAC/B,WAAK,qBAAqB;AAAA,IAC5B;AAAA,EACF;AAAA,EAEQ,oBAAoB,OAAoB;AAC9C,UAAM,QAAQ,MAAM;AACpB,UAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,QAAI,CAAC,QAAQ,CAAC,KAAK,cAAe;AAElC,SAAK,iBAAiB;AACtB,SAAK,SAAS;AAEd,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,SAAS,MAAM;AACpB,YAAM,UAAU,OAAO;AACvB,WAAK,iBAAiB,OAAO;AAAA,IAC/B;AACA,WAAO,cAAc,IAAI;AAAA,EAC3B;AAAA,EAEA,MAAc,iBAAiB,SAAgC;AAC7D,QAAI;AAEF,YAAM,iBAAiB,aAAY,UAAU,oBAAoB;AACjE,YAAM,aAAa,KAAK,OAAO,aAAa,KAAK,OAAO;AACxD,YAAM,YAAY,iBAAiB,KAAK,iBAAiB,cAAc,IAAI,GAAG,UAAU;AAExF,YAAM,MAAM,MAAM,KAAK,SAAS,WAAW;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,KAAK,QAAQ,CAAC;AAAA,MACvC,CAAC;AACD,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,EAAE;AACjD,YAAM,OAAO,MAAM,IAAI,KAAK;AAE5B,YAAM,gBAAgB,KAAK,OAAO,aAAa,KAAK,OAAO,WAAW;AACtE,YAAM,UAAU,KAAK,OAAO,iBAAiB,gBAAgB,IAAI,IAAI,aAAa,EAAE,SAAS;AAC7F,YAAM,UAAU,UAAU,KAAK;AAC/B,UAAI,KAAK,eAAe;AACtB,cAAM,MAAM,KAAK,cAAc,IAAI,KAAK,aAAa,GAAG,OAAO;AAC/D,aAAK,cAAc,MAAM;AACzB,aAAK,eAAe,KAAK,OAAO;AAAA,MAClC;AACA,WAAK,iBAAiB;AACtB,WAAK,gBAAgB;AACrB,WAAK,SAAS;AACd,WAAK,UAAU,kBAAkB,SAAS;AAAA,IAC5C,SAAS,KAAK;AACZ,WAAK,iBAAiB;AACtB,WAAK,gBAAgB;AACrB,WAAK,SAAS;AACd,WAAK,UAAU,wBAAwB,OAAO;AAC9C,WAAK,OAAO,UAAU,gBAAgB,GAAG;AAAA,IAC3C;AAAA,EACF;AAAA,EAEQ,kBAAwB;AAC9B,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,eAAe;AAC5C,YAAM,MAAM,KAAK,WAAW,KAAK,GAAG;AACpC,UAAI,OAAO,IAAI,QAAQ,IAAK,KAAI,MAAM;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,KAAqB;AACvC,WAAO,KAAK,UAAU,GAAG,IAAI,KAAK,WAAW,KAAK;AAAA,EACpD;AAAA,EAEQ,cAAc,KAAa,UAAwB;AACzD,SAAK,UAAU,KAAK,KAAK,eAAe,CAAC;AACzC,SAAK,YAAY,CAAC;AAClB,SAAK,UAAU;AACf,SAAK,UAAU;AAEf,QAAI,CAAC,KAAK,UAAU,GAAG,EAAG,MAAK,UAAU,GAAG,IAAI,CAAC;AAEjD,UAAM,UAAU,SAAS,KAAK,WAAW;AACzC,QAAI,CAAC,KAAK,UAAU,GAAG,EAAE,OAAO,GAAG;AACjC,WAAK,UAAU,GAAG,EAAE,OAAO,IAAI,KAAK,aAAa,GAAG,KAAK;AAAA,IAC3D;AACA,SAAK,UAAU,GAAG,IAAI,EAAE,GAAG,KAAK,UAAU,GAAG,GAAG,CAAC,KAAK,WAAW,GAAG,SAAS;AAC7E,SAAK,UAAU,IAAI,GAAG;AACtB,SAAK,iBAAiB,KAAK,UAAU,OAAO,KAAK,eAAe;AAChE,SAAK,YAAY,KAAK,KAAK,WAAW;AACtC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,eAAe,KAAa,KAAmB;AACrD,SAAK,UAAU,KAAK,KAAK,eAAe,CAAC;AACzC,SAAK,YAAY,CAAC;AAClB,SAAK,UAAU;AACf,SAAK,UAAU;AAEf,SAAK,aAAa,EAAE,GAAG,KAAK,YAAY,CAAC,GAAG,GAAG,IAAI;AACnD,SAAK,eAAe,IAAI,GAAG;AAC3B,SAAK,iBAAiB,KAAK,UAAU,OAAO,KAAK,eAAe;AAChE,SAAK,YAAY,KAAK,KAAK;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,iBAAyB;AAC/B,WAAO,KAAK,UAAU,EAAE,OAAO,KAAK,WAAW,QAAQ,KAAK,WAAW,CAAC;AAAA,EAC1E;AAAA,EAEQ,cAAc,KAAmB;AACvC,UAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,QAAI,KAAK,OAAO;AACd,WAAK,YAAY,KAAK;AACtB,UAAI,KAAK,OAAQ,MAAK,aAAa,KAAK;AAAA,IAC1C,OAAO;AACL,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,IAAY,kBAA2B;AACrC,WAAO,KAAK,OAAO,aAAa;AAAA,EAClC;AAAA,EAiBQ,aAAa,MAAsB;AACzC,UAAM,MAAM,IAAI,UAAU,EAAE,gBAAgB,MAAM,WAAW;AAC7D,UAAM,QAAQ,CAAC,SAAqB;AAClC,YAAM,WAAW,MAAM,KAAK,KAAK,UAAU;AAC3C,iBAAW,SAAS,UAAU;AAC5B,YAAI,MAAM,aAAa,KAAK,UAAW;AACvC,YAAI,MAAM,aAAa,KAAK,cAAc;AACxC,gBAAM,KAAK;AACX,cAAI,CAAC,aAAY,aAAa,IAAI,GAAG,OAAO,GAAG;AAE7C,mBAAO,GAAG,WAAY,IAAG,YAAY,aAAa,GAAG,YAAY,EAAE;AACnE,eAAG,OAAO;AAAA,UACZ,OAAO;AAEL,kBAAM,eAAe,aAAY,cAAc,GAAG,OAAO,KAAK,oBAAI,IAAI;AACtE,uBAAW,QAAQ,MAAM,KAAK,GAAG,UAAU,GAAG;AAC5C,kBAAI,CAAC,aAAa,IAAI,KAAK,IAAI,EAAG,IAAG,gBAAgB,KAAK,IAAI;AAAA,YAChE;AAEA,gBAAI,GAAG,YAAY,KAAK;AACtB,oBAAM,OAAO,GAAG,aAAa,MAAM,KAAK;AACxC,kBAAI,KAAK,KAAK,EAAE,YAAY,EAAE,WAAW,aAAa,GAAG;AACvD,mBAAG,aAAa,QAAQ,GAAG;AAAA,cAC7B;AAAA,YACF;AACA,kBAAM,EAAE;AAAA,UACV;AAAA,QACF,OAAO;AACL,gBAAM,OAAO;AAAA,QACf;AAAA,MACF;AAAA,IACF;AACA,UAAM,IAAI,IAAI;AACd,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA,EAEQ,oBAA0B;AAChC,QAAI,CAAC,KAAK,mBAAmB,KAAK,cAAe;AAEjD,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AAEpB,UAAM,UAA2D;AAAA,MAC/D,EAAE,KAAK,QAAQ,OAAO,KAAK,OAAO,OAAO;AAAA,MACzC,EAAE,KAAK,UAAU,OAAO,YAAY,OAAO,SAAS;AAAA,MACpD,EAAE,KAAK,aAAa,OAAO,YAAY,OAAO,YAAY;AAAA,MAC1D,EAAE,KAAK,iBAAiB,OAAO,YAAY,OAAO,gBAAgB;AAAA,IACpE;AAEA,UAAM,cAA+D;AAAA,MACnE,EAAE,KAAK,cAAc,OAAO,aAAM,OAAO,cAAc;AAAA,MACvD,EAAE,KAAK,UAAU,OAAO,UAAK,OAAO,cAAc;AAAA,IACpD;AAEA,UAAM,cAA+D;AAAA,MACnE,EAAE,KAAK,gBAAgB,OAAO,UAAK,OAAO,mBAAmB;AAAA,IAC/D;AAEA,UAAM,UAAU,CAAC,SAAwD;AACvE,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,YAAY,KAAK;AACrB,UAAI,QAAQ,KAAK;AACjB,UAAI,QAAQ,MAAM,KAAK;AACvB,UAAI,iBAAiB,aAAa,CAAC,MAAM;AACvC,UAAE,eAAe;AACjB,aAAK,mBAAmB,KAAK,GAAG;AAAA,MAClC,CAAC;AACD,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,MAAM;AACnB,YAAM,MAAM,SAAS,cAAc,KAAK;AACxC,UAAI,YAAY;AAChB,cAAQ,YAAY,GAAG;AAAA,IACzB;AAEA,YAAQ,QAAQ,OAAK,QAAQ,YAAY,QAAQ,CAAC,CAAC,CAAC;AACpD,WAAO;AACP,gBAAY,QAAQ,OAAK,QAAQ,YAAY,QAAQ,CAAC,CAAC,CAAC;AACxD,WAAO;AACP,gBAAY,QAAQ,OAAK,QAAQ,YAAY,QAAQ,CAAC,CAAC,CAAC;AAExD,SAAK,QAAQ,YAAY,OAAO;AAChC,SAAK,gBAAgB;AAGrB,SAAK,yBAAyB,MAAM,KAAK,mBAAmB;AAC5D,aAAS,iBAAiB,mBAAmB,KAAK,sBAAsB;AAAA,EAC1E;AAAA,EAEQ,qBAA2B;AACjC,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,OAAO;AAC1B,WAAK,gBAAgB;AAAA,IACvB;AACA,QAAI,KAAK,wBAAwB;AAC/B,eAAS,oBAAoB,mBAAmB,KAAK,sBAAsB;AAC3E,WAAK,yBAAyB;AAAA,IAChC;AACA,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEQ,mBAAmB,KAAmB;AAE5C,SAAK,UAAU,WAAW;AAC1B,QAAI,KAAK,aAAa;AAAE,mBAAa,KAAK,WAAW;AAAG,WAAK,cAAc;AAAA,IAAM;AAEjF,QAAI,QAAQ,cAAc;AACxB,YAAM,MAAM,OAAO,cAAc,UAAU;AAC3C,UAAI,IAAK,UAAS,YAAY,cAAc,OAAO,GAAG;AAAA,IACxD,OAAO;AACL,eAAS,YAAY,KAAK,KAAK;AAAA,IACjC;AACA,SAAK,mBAAmB;AAExB,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC;AAAA,IAC3E;AAGA,eAAW,MAAM;AACf,WAAK,UAAU,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAAA,IAC1E,GAAG,EAAE;AAAA,EACP;AAAA,EAEQ,gBAAgB,IAAuB;AAC7C,QAAI,CAAC,KAAK,mBAAmB,CAAC,KAAK,cAAe;AAClD,QAAI,KAAK,oBAAoB;AAAE,mBAAa,KAAK,kBAAkB;AAAG,WAAK,qBAAqB;AAAA,IAAM;AAEtG,SAAK,mBAAmB;AACxB,SAAK,gBAAgB,EAAE;AACvB,SAAK,cAAc,UAAU,IAAI,SAAS;AAC1C,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEQ,gBAAgB,IAAuB;AAC7C,QAAI,CAAC,KAAK,cAAe;AACzB,UAAM,OAAO,GAAG,sBAAsB;AACtC,UAAM,SAAS,KAAK,cAAc,sBAAsB;AACxD,QAAI,MAAM,KAAK,MAAM,OAAO,SAAS;AACrC,QAAI,OAAO,KAAK,OAAQ,KAAK,QAAQ,IAAM,OAAO,QAAQ;AAG1D,QAAI,MAAM,EAAG,OAAM,KAAK,SAAS;AAEjC,QAAI,OAAO,EAAG,QAAO;AACrB,QAAI,OAAO,OAAO,QAAQ,OAAO,aAAa,EAAG,QAAO,OAAO,aAAa,OAAO,QAAQ;AAE3F,SAAK,cAAc,MAAM,MAAM,GAAG,GAAG;AACrC,SAAK,cAAc,MAAM,OAAO,GAAG,IAAI;AAAA,EACzC;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,CAAC,KAAK,cAAe;AAEzB,SAAK,qBAAqB,WAAW,MAAM;AACzC,WAAK,eAAe,UAAU,OAAO,SAAS;AAC9C,WAAK,mBAAmB;AACxB,WAAK,qBAAqB;AAAA,IAC5B,GAAG,GAAG;AAAA,EACR;AAAA,EAEQ,qBAA2B;AACjC,QAAI,CAAC,KAAK,cAAe;AACzB,UAAM,OAAO,CAAC,QAAQ,UAAU,aAAa,eAAe;AAC5D,eAAW,OAAO,MAAM,KAAK,KAAK,cAAc,iBAAiB,QAAQ,CAAC,GAAG;AAC3E,YAAM,MAAO,IAAoB,QAAQ;AACzC,UAAI,OAAO,KAAK,SAAS,GAAG,GAAG;AAC7B,YAAI;AACF,UAAC,IAAoB,UAAU,OAAO,UAAU,SAAS,kBAAkB,GAAG,CAAC;AAAA,QACjF,QAAQ;AAAA,QAAe;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAe;AACrB,QAAI,KAAK,UAAU,WAAW,EAAG;AACjC,SAAK,UAAU,KAAK,KAAK,eAAe,CAAC;AACzC,SAAK,cAAc,KAAK,UAAU,IAAI,CAAE;AACxC,SAAK,UAAU,KAAK,UAAU,SAAS;AACvC,SAAK,UAAU;AACf,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AACrB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,SAAe;AACrB,QAAI,KAAK,UAAU,WAAW,EAAG;AACjC,SAAK,UAAU,KAAK,KAAK,eAAe,CAAC;AACzC,SAAK,cAAc,KAAK,UAAU,IAAI,CAAE;AACxC,SAAK,UAAU;AACf,SAAK,UAAU,KAAK,UAAU,SAAS;AACvC,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AACrB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,kBAAwB;AAC9B,SAAK,UAAU,MAAM;AACrB,eAAW,OAAO,KAAK,gBAAgB;AACrC,UAAI,KAAK,UAAU,KAAK,UAAU,GAAG,CAAC,MAAM,KAAK,UAAU,KAAK,cAAc,GAAG,CAAC,GAAG;AACnF,aAAK,UAAU,IAAI,GAAG;AAAA,MACxB;AAAA,IACF;AACA,SAAK,iBAAiB,KAAK,UAAU,OAAO,KAAK,eAAe;AAAA,EAClE;AAAA,EAEQ,WAAiB;AACvB,SAAK,UAAU,MAAM;AACrB,SAAK,eAAe,MAAM;AAC1B,SAAK,iBAAiB;AACtB,SAAK,YAAY,CAAC;AAClB,SAAK,YAAY,CAAC;AAClB,SAAK,UAAU;AACf,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,UAAU,MAAM;AACrB,SAAK,eAAe,MAAM;AAC1B,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,KAAK,MAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AAC9D,SAAK,iBAAiB,KAAK,MAAM,KAAK,UAAU,KAAK,UAAU,CAAC;AAAA,EAClE;AAAA,EAEQ,gBAAsB;AAC5B,SAAK,YAAY,KAAK,MAAM,KAAK,UAAU,KAAK,aAAa,CAAC;AAC9D,SAAK,aAAa,KAAK,MAAM,KAAK,UAAU,KAAK,cAAc,CAAC;AAChE,SAAK,UAAU,MAAM;AACrB,SAAK,eAAe,MAAM;AAC1B,SAAK,iBAAiB;AACtB,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AACrB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,SAAe;AACrB,iBAAY,YAAY;AACxB,mBAAe,WAAW,mBAAmB;AAC7C,SAAK,WAAW;AAChB,SAAK,gBAAgB;AACrB,SAAK,cAAc,KAAK;AACxB,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,UAAU,cAAc,SAAS;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,wBAAwB,WAAmC;AACvE,QAAI,KAAK,OAAO,cAAc;AAC5B,UAAI;AACF,cAAM,OAAO,KAAK;AAClB,cAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,YAAY,IAAI,IAAI,OAAO;AAClE,YAAI,IAAI,IAAI;AACV,gBAAM,eAAe,MAAM,IAAI,KAAK;AACpC,eAAK,iBAAiB,MAAM;AAC5B,eAAK,oBAAoB,cAAc,IAAI,KAAK,eAAe,CAAC;AAAA,QAClE;AAAA,MACF,QAAQ;AAAA,MAAe;AAAA,IACzB;AAEA,SAAK,kBAAkB;AACvB,SAAK,oBAAoB;AACzB,QAAI,KAAK,SAAU,MAAK,cAAc,IAAI;AAC1C,QAAI,KAAK,OAAO,SAAS;AACvB,UAAI,UAAW,MAAK,gBAAgB,OAAO;AAAA,UACtC,MAAK,qBAAqB;AAAA,IACjC,OAAO;AACL,WAAK,kBAAkB;AACvB,WAAK,gBAAgB,KAAK,MAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AAC9D,WAAK,iBAAiB,KAAK,MAAM,KAAK,UAAU,KAAK,UAAU,CAAC;AAChE,WAAK,WAAW,KAAK;AAAA,IACvB;AACA,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,oBAAoB,KAAU,QAAgB,aAA2B;AAC/E,eAAW,KAAK,OAAO,KAAK,GAAG,GAAG;AAChC,YAAM,UAAU,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK;AAC5C,UAAI,OAAO,IAAI,CAAC,MAAM,UAAU;AAC9B,cAAM,OAAO,IAAI,CAAC,EAAE,KAAK;AACzB,YAAI,KAAK,UAAU,GAAG;AACpB,gBAAM,WAAW,KAAK,iBAAiB,IAAI,IAAI;AAC/C,cAAI,CAAC,YAAY,QAAQ,YAAY,EAAE,WAAW,WAAW,GAAG;AAC9D,iBAAK,iBAAiB,IAAI,MAAM,OAAO;AAAA,UACzC;AAAA,QACF;AAAA,MACF,WAAW,OAAO,IAAI,CAAC,MAAM,YAAY,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,QAAQ,IAAI,CAAC,CAAC,GAAG;AAClF,aAAK,oBAAoB,IAAI,CAAC,GAAG,SAAS,WAAW;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,iBAAyB;AAC/B,WAAO,KAAK,YAAY,QAAQ,OAAO,EAAE,EAAE,QAAQ,MAAM,GAAG,EAAE,YAAY;AAAA,EAC5E;AAAA;AAAA,EAGQ,iBAAiB,WAA2B;AAClD,QAAI,UAAU,WAAW,GAAG,EAAG,QAAO,GAAG,KAAK,OAAO,OAAO,GAAG,SAAS;AACxE,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,iBAAiB,WAA2B;AAClD,UAAM,OAAO,KAAK,OAAO,aAAa,KAAK,OAAO;AAClD,QAAI,UAAU,WAAW,GAAG,EAAG,QAAO,GAAG,IAAI,GAAG,SAAS;AACzD,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,KAAa,MAAuC;AACnE,UAAM,QAAQ,aAAY,UAAU,eAAe,KAAK;AACxD,UAAM,aAAa,KAAK,OAAO,cAAc;AAC7C,UAAM,UAAkC,EAAE,GAAI,MAAM,WAAqC,CAAC,EAAG;AAC7F,QAAI,MAAO,SAAQ,eAAe,IAAI,UAAU,KAAK;AACrD,QAAI,WAAY,SAAQ,eAAe,IAAI;AAG3C,UAAM,cAAc,KAAK,OAAO,WAAW,IAAI,WAAW,KAAK,OAAO,OAAO;AAC7E,QAAI,CAAC,eAAe,KAAK,OAAO,eAAe;AAC7C,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,OAAO,aAAa,GAAG;AAC9D,YAAI,CAAC,QAAQ,CAAC,EAAG,SAAQ,CAAC,IAAI;AAAA,MAChC;AAAA,IACF;AAEA,WAAO,MAAM,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC;AAAA,EACxC;AAAA;AAAA,EAGA,MAAc,aAAa,MAAc,QAAiD;AACxF,QAAI;AACF,YAAM,eAAe,aAAY,UAAU,kBAAkB;AAC7D,YAAM,aAAa,KAAK,OAAO,aAAa,KAAK,OAAO;AACxD,YAAM,UAAU,eAAe,KAAK,iBAAiB,YAAY,IAAI,GAAG,UAAU;AAClF,UAAI,SAAS,GAAG,OAAO,SAAS,mBAAmB,IAAI,CAAC;AACxD,UAAI,OAAQ,WAAU,WAAW,mBAAmB,MAAM,CAAC;AAC3D,YAAM,MAAM,MAAM,KAAK,SAAS,MAAM;AACtC,UAAI,CAAC,IAAI,GAAI,QAAO;AACpB,aAAO,MAAM,IAAI,KAAK;AAAA,IACxB,QAAQ;AAAE,aAAO;AAAA,IAAM;AAAA,EACzB;AAAA,EAEQ,WAAW,MAAoC;AACrD,UAAM,OAAO,SAAS,WAAW,YAAY;AAC7C,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,iBAAiB;AAC3C,UAAI,KAAK,gBAAgB,KAAM,QAAO;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,gBAAgB,QAA8C;AAC1E,SAAK,WAAW,IAAI;AACpB,SAAK,gBAAgB;AAErB,QAAI;AAEF,YAAM,WAA6C,CAAC,KAAK,aAAa,KAAK,aAAa,MAAM,CAAC;AAC/F,YAAM,YAAY,KAAK,WAAW,QAAQ;AAC1C,YAAM,YAAY,KAAK,WAAW,QAAQ;AAC1C,UAAI,UAAW,UAAS,KAAK,KAAK,aAAa,WAAW,MAAM,CAAC;AACjE,UAAI,UAAW,UAAS,KAAK,KAAK,aAAa,WAAW,MAAM,CAAC;AAEjE,YAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ;AAC1C,YAAM,UAAU,QAAQ,CAAC;AACzB,YAAM,YAAY,YAAY,QAAQ,CAAC,IAAI;AAC3C,YAAM,YAAY,YAAY,QAAQ,YAAY,IAAI,CAAC,IAAI;AAE3D,YAAM,WAAW,CAAC,QAA+B,KAAK,SAAS,SAAS,KAAK,mBAAmB,SAAS;AACzG,YAAM,YAAY,SAAS,OAAO;AAClC,YAAM,cAAc,SAAS,SAAS;AACtC,YAAM,cAAc,SAAS,SAAS;AAEtC,UAAI,aAAa,eAAe,aAAa;AAC3C,aAAK,YAAY,EAAE,GAAI,aAAa,CAAC,GAAI,GAAI,eAAe,CAAC,GAAI,GAAI,eAAe,CAAC,EAAG;AAAA,MAC1F,OAAO;AACL,aAAK,kBAAkB;AAAA,MACzB;AAGA,YAAM,SAAS,SAAS,SAAS,UAAU,SAAS,mBAAmB;AACvE,UAAI,QAAQ;AACV,aAAK,aAAa,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AACnD,aAAK,gBAAgB;AAAA,MACvB;AAEA,WAAK,gBAAgB,KAAK,MAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AAC9D,WAAK,iBAAiB,KAAK,MAAM,KAAK,UAAU,KAAK,UAAU,CAAC;AAChE,WAAK,SAAS;AACd,WAAK,mBAAmB;AAAA,IAC1B,QAAQ;AACN,WAAK,kBAAkB;AACvB,WAAK,gBAAgB,KAAK,MAAM,KAAK,UAAU,KAAK,SAAS,CAAC;AAC9D,WAAK,iBAAiB,KAAK,MAAM,KAAK,UAAU,KAAK,UAAU,CAAC;AAChE,WAAK,SAAS;AAAA,IAChB,UAAE;AACA,WAAK,WAAW,KAAK;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAc,uBAAsC;AAClD,SAAK,WAAW,IAAI;AAEpB,QAAI;AAEF,YAAM,WAA6C,CAAC,KAAK,aAAa,KAAK,aAAa,WAAW,CAAC;AACpG,YAAM,YAAY,KAAK,WAAW,QAAQ;AAC1C,YAAM,YAAY,KAAK,WAAW,QAAQ;AAC1C,UAAI,UAAW,UAAS,KAAK,KAAK,aAAa,WAAW,WAAW,CAAC;AACtE,UAAI,UAAW,UAAS,KAAK,KAAK,aAAa,WAAW,WAAW,CAAC;AAEtE,YAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ;AAC1C,YAAM,UAAU,QAAQ,CAAC;AACzB,YAAM,YAAY,YAAY,QAAQ,CAAC,IAAI;AAC3C,YAAM,YAAY,YAAY,QAAQ,YAAY,IAAI,CAAC,IAAI;AAE3D,YAAM,WAAW,CAAC,QAA+B,KAAK,mBAAmB,SAAS;AAClF,YAAM,SAAS,EAAE,GAAI,SAAS,OAAO,KAAK,CAAC,GAAI,GAAI,SAAS,SAAS,KAAK,CAAC,GAAI,GAAI,SAAS,SAAS,KAAK,CAAC,EAAG;AAC9G,UAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,aAAK,YAAY,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AAClD,aAAK,mBAAmB;AAAA,MAC1B;AAGA,YAAM,SAAS,SAAS,mBAAmB;AAC3C,UAAI,UAAU,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAC5C,aAAK,aAAa,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AACnD,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF,QAAQ;AAAA,IAAsC,UAC9C;AAAU,WAAK,WAAW,KAAK;AAAA,IAAG;AAAA,EACpC;AAAA,EAEQ,oBAA0B;AAChC,UAAM,QAA0C,CAAC;AACjD,eAAW,OAAO,KAAK,gBAAgB;AACrC,YAAM,KAAK,SAAS,cAAc,cAAc,GAAG,IAAI;AACvD,YAAM,MAAM,IAAI,aAAa,KAAK,KAAK;AAGvC,YAAM,QAAuB,EAAE,CAAC,KAAK,eAAe,GAAG,IAAI;AAC3D,YAAM,GAAG,IAAI;AAAA,IACf;AACA,SAAK,YAAY;AAGjB,QAAI,KAAK,OAAO,cAAc;AAC5B,YAAM,aAAa,KAAK,UAAU,OAAO,OAAK,MAAM,KAAK,WAAW;AACpE,iBAAW,QAAQ,YAAY;AAC7B,cAAM,GAAG,KAAK,OAAO,YAAY,IAAI,IAAI,OAAO,EAC7C,KAAK,OAAK,EAAE,KAAK,CAAC,EAClB,KAAK,kBAAgB;AACpB,gBAAM,UAAU,EAAE,GAAG,KAAK,UAAU;AACpC,qBAAW,OAAO,KAAK,gBAAgB;AAErC,kBAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,gBAAI,MAAW;AACf,uBAAW,QAAQ,OAAO;AAAE,oBAAM,MAAM,IAAI;AAAA,YAAG;AAC/C,gBAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,sBAAQ,GAAG,IAAI,EAAE,GAAG,QAAQ,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI;AAAA,YAChD;AAAA,UACF;AACA,eAAK,YAAY;AACjB,eAAK,gBAAgB,KAAK,MAAM,KAAK,UAAU,OAAO,CAAC;AACvD,eAAK,mBAAmB;AAAA,QAC1B,CAAC,EACA,MAAM,MAAM;AAAA,QAAe,CAAC;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,sBAAmF;AACzF,UAAM,WAAwE,CAAC;AAC/E,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,iBAAiB;AAC3C,YAAM,OAAO,KAAK;AAClB,UAAI,CAAC,SAAS,IAAI,EAAG,UAAS,IAAI,IAAI,CAAC;AACvC,UAAI,KAAK,UAAU,KAAK,GAAG,MAAM,QAAW;AAC1C,iBAAS,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,UAAU,KAAK,GAAG;AAAA,MACpD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,cAA6B;AACzC,QAAI,CAAC,KAAK,cAAc;AACtB,WAAK,wBAAwB;AAC7B;AAAA,IACF;AACA,QAAI,CAAC,KAAK,OAAO,SAAS;AACxB,WAAK,UAAU,kDAAkD,OAAO;AACxE;AAAA,IACF;AACA,SAAK,WAAW;AAChB,SAAK,SAAS;AAGd,UAAM,UAAU,SAAS,KAAK,WAAW;AACzC,eAAW,OAAO,OAAO,KAAK,KAAK,SAAS,GAAG;AAC7C,UAAI,CAAC,KAAK,UAAU,GAAG,EAAE,OAAO,KAAK,KAAK,aAAa,GAAG,GAAG;AAC3D,aAAK,UAAU,GAAG,EAAE,OAAO,IAAI,KAAK,aAAa,GAAG;AAAA,MACtD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,KAAK,oBAAoB;AAC1C,YAAM,WAAW,OAAO,QAAQ,QAAQ,EAAE;AAAA,QAAI,CAAC,CAAC,MAAM,KAAK,MACzD,KAAK,SAAS,GAAG,KAAK,OAAO,OAAO,kBAAkB;AAAA,UACpD,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA,OAAO,SAAS,KAAK,cAAc,KAAK,eAAe,KAAK,QAAQ,KAAK,EAAE;AAAA,YAC3E,SAAS,EAAE,OAAO,GAAI,SAAS,KAAK,cAAc,EAAE,QAAQ,KAAK,WAAW,IAAI,CAAC,EAAG;AAAA,UACtF,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AACA,YAAM,YAAY,MAAM,QAAQ,IAAI,QAAQ;AAC5C,YAAM,cAAqB,CAAC;AAC5B,iBAAW,OAAO,WAAW;AAC3B,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,oBAAY,KAAK,EAAE,IAAI,IAAI,IAAI,QAAQ,IAAI,QAAQ,KAAK,CAAC;AAAA,MAC3D;AACA,UAAI,YAAY,KAAK,OAAK,CAAC,EAAE,EAAE,EAAG,OAAM,IAAI,MAAM,qCAAqC;AACvF,cAAQ,KAAK,8BAA8B,YAAY,IAAI,OAAK,EAAE,IAAI,CAAC;AACvE,WAAK,WAAW;AAChB,WAAK,eAAe;AACpB,WAAK,SAAS;AACd,WAAK,UAAU,6BAA6B,SAAS;AACrD,WAAK,OAAO,UAAU;AAAA,IACxB,SAAS,KAAK;AACZ,WAAK,WAAW;AAChB,WAAK,SAAS;AACd,WAAK,UAAU,kCAAkC,OAAO;AACxD,WAAK,OAAO,UAAU,QAAQ,GAAG;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,MAAc,iBAAgC;AAC5C,QAAI,CAAC,KAAK,cAAc;AACtB,WAAK,wBAAwB;AAC7B;AAAA,IACF;AACA,QAAI,CAAC,KAAK,OAAO,SAAS;AACxB,WAAK,UAAU,qDAAqD,OAAO;AAC3E;AAAA,IACF;AACA,SAAK,eAAe;AACpB,SAAK,SAAS;AAGd,UAAM,UAAU,SAAS,KAAK,WAAW;AACzC,eAAW,OAAO,OAAO,KAAK,KAAK,SAAS,GAAG;AAC7C,UAAI,CAAC,KAAK,UAAU,GAAG,EAAE,OAAO,KAAK,KAAK,aAAa,GAAG,GAAG;AAC3D,aAAK,UAAU,GAAG,EAAE,OAAO,IAAI,KAAK,aAAa,GAAG;AAAA,MACtD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,KAAK,oBAAoB;AAE1C,YAAM,WAAW,OAAO,QAAQ,QAAQ,EAAE;AAAA,QAAI,CAAC,CAAC,MAAM,KAAK,MACzD,KAAK,SAAS,GAAG,KAAK,OAAO,OAAO,qBAAqB;AAAA,UACvD,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA,OAAO,SAAS,KAAK,cAAc,KAAK,eAAe,KAAK,QAAQ,KAAK,EAAE;AAAA,YAC3E,mBAAmB,EAAE,OAAO,GAAI,SAAS,KAAK,cAAc,EAAE,QAAQ,KAAK,WAAW,IAAI,CAAC,EAAG;AAAA,UAChG,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAEA,YAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ;AAC1C,YAAM,iBAAwB,CAAC;AAC/B,iBAAW,OAAO,SAAS;AACzB,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,uBAAe,KAAK,EAAE,IAAI,IAAI,IAAI,QAAQ,IAAI,QAAQ,KAAK,CAAC;AAAA,MAC9D;AACA,UAAI,eAAe,KAAK,OAAK,CAAC,EAAE,EAAE,EAAG,OAAM,IAAI,MAAM,wCAAwC;AAC7F,cAAQ,KAAK,iCAAiC,eAAe,IAAI,OAAK,EAAE,IAAI,CAAC;AAC7E,WAAK,eAAe;AACpB,WAAK,eAAe;AACpB,WAAK,SAAS;AACd,WAAK,UAAU,2BAA2B,SAAS;AACnD,WAAK,OAAO,cAAc;AAAA,IAC5B,SAAS,KAAK;AACZ,WAAK,eAAe;AACpB,WAAK,SAAS;AACd,WAAK,UAAU,qCAAqC,OAAO;AAC3D,WAAK,OAAO,UAAU,WAAW,GAAG;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAA+B;AAC3C,SAAK,cAAc,CAAC,KAAK;AACzB,QAAI,KAAK,YAAa,OAAM,KAAK,YAAY;AAC7C,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAc,cAA6B;AACzC,QAAI;AACF,YAAM,KAAK,MAAM,KAAK,OAAO;AAC7B,YAAM,UAAU,MAAM,IAAI,QAA4B,CAAC,SAAS,WAAW;AACzE,cAAM,KAAK,GAAG,YAAY,YAAY,UAAU;AAChD,cAAM,QAAQ,GAAG,YAAY,UAAU;AACvC,cAAM,QAAQ,MAAM,MAAM,MAAM;AAChC,cAAM,MAAM,MAAM,OAAO,KAAK,WAAW;AACzC,YAAI,YAAY,MAAM,QAAS,IAAI,OAA8B,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC;AACvH,YAAI,UAAU,MAAM,OAAO,IAAI,KAAK;AAAA,MACtC,CAAC;AACD,WAAK,cAAc;AACnB,WAAK,kBAAkB;AAAA,IACzB,QAAQ;AAAA,IAAe;AAAA,EACzB;AAAA,EAEQ,oBAA0B;AAChC,QAAI,CAAC,KAAK,cAAe;AACzB,SAAK,cAAc,YAAY;AAC/B,QAAI,KAAK,YAAY,WAAW,GAAG;AACjC,YAAM,QAAQ,KAAK,cAAc,OAAO,oBAAoB;AAC5D,YAAM,cAAc;AACpB,WAAK,cAAc,YAAY,KAAK;AACpC;AAAA,IACF;AACA,eAAW,SAAS,KAAK,aAAa;AACpC,YAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,WAAK,YAAY;AACjB,YAAM,UAAU,KAAK,cAAc,OAAO,oBAAoB;AAC9D,cAAQ,cAAc,MAAM;AAC5B,YAAM,SAAS,KAAK,cAAc,OAAO,mBAAmB;AAC5D,YAAM,SAAS,KAAK,cAAc,QAAQ,mBAAmB;AAC7D,aAAO,cAAc,MAAM,KAAK,YAAY;AAC5C,YAAM,WAAW,SAAS,eAAe,MAAM,KAAK,WAAW,MAAM,SAAS,CAAC;AAC/E,aAAO,YAAY,MAAM;AACzB,aAAO,YAAY,QAAQ;AAC3B,WAAK,YAAY,OAAO;AACxB,WAAK,YAAY,MAAM;AACvB,WAAK,iBAAiB,SAAS,CAAC,MAAM;AAAE,UAAE,gBAAgB;AAAG,aAAK,eAAe,KAAK;AAAA,MAAG,CAAC;AAC1F,WAAK,cAAc,YAAY,IAAI;AAAA,IACrC;AAAA,EACF;AAAA,EAEQ,eAAe,OAA+B;AACpD,SAAK,UAAU,KAAK,KAAK,eAAe,CAAC;AACzC,SAAK,UAAU;AACf,SAAK,cAAc,MAAM,QAAQ;AACjC,SAAK,gBAAgB;AACrB,SAAK,cAAc;AACnB,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AACrB,SAAK,SAAS;AACd,SAAK,UAAU,yBAAyB,SAAS;AAAA,EACnD;AAAA,EAEQ,YAAY,KAAa,MAAoB;AACnD,UAAM,UAAU,SAAS;AACzB,UAAM,WAAW,UAAU,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK,UAAW,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK;AACtF,UAAM,QAAQ,UAAU,WAAW,QAAQ,KAAK,UAAU,QAAQ;AAClE,SAAK,OAAO,EAAE,KAAK,QAAM;AACvB,YAAM,KAAK,GAAG,YAAY,YAAY,WAAW;AACjD,SAAG,YAAY,UAAU,EAAE,IAAI;AAAA,QAC7B,MAAM,KAAK;AAAA,QAAa,WAAW,KAAK,IAAI;AAAA,QAC5C;AAAA,QAAO;AAAA,QACP,UAAU,KAAK,UAAU,EAAE,OAAO,KAAK,WAAW,QAAQ,KAAK,WAAW,CAAC;AAAA,MAC7E,CAAC;AAAA,IACH,CAAC,EAAE,MAAM,MAAM;AAAA,IAAe,CAAC;AAAA,EACjC;AAAA,EAEA,MAAc,kBAAiC;AAC7C,QAAI;AACF,YAAM,KAAK,MAAM,KAAK,OAAO;AAC7B,YAAM,SAAS,KAAK,IAAI,IAAI,KAAK;AACjC,YAAM,KAAK,GAAG,YAAY,YAAY,WAAW;AACjD,YAAM,QAAQ,GAAG,YAAY,UAAU,EAAE,MAAM,WAAW;AAC1D,YAAM,MAAM,MAAM,WAAW,YAAY,WAAW,MAAM,CAAC;AAC3D,UAAI,YAAY,MAAM;AAAE,cAAM,IAAI,IAAI;AAAQ,YAAI,GAAG;AAAE,YAAE,OAAO;AAAG,YAAE,SAAS;AAAA,QAAG;AAAA,MAAE;AAAA,IACrF,QAAQ;AAAA,IAAe;AAAA,EACzB;AAAA,EAEQ,SAA+B;AACrC,QAAI,KAAK,GAAI,QAAO,QAAQ,QAAQ,KAAK,EAAE;AAC3C,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,MAAM,UAAU,KAAK,SAAS,CAAC;AACrC,UAAI,kBAAkB,MAAM;AAC1B,cAAM,KAAK,IAAI;AACf,YAAI,CAAC,GAAG,iBAAiB,SAAS,UAAU,GAAG;AAC7C,gBAAM,QAAQ,GAAG,kBAAkB,YAAY,EAAE,SAAS,MAAM,eAAe,KAAK,CAAC;AACrF,gBAAM,YAAY,QAAQ,QAAQ,EAAE,QAAQ,MAAM,CAAC;AACnD,gBAAM,YAAY,aAAa,aAAa,EAAE,QAAQ,MAAM,CAAC;AAAA,QAC/D;AAAA,MACF;AACA,UAAI,YAAY,MAAM;AAAE,aAAK,KAAK,IAAI;AAAQ,gBAAQ,KAAK,EAAE;AAAA,MAAG;AAChE,UAAI,UAAU,MAAM,OAAO,IAAI,KAAK;AAAA,IACtC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,SAAiB,MAAiC;AAClE,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,eAAe;AACpB,SAAK,YAAY;AAEjB,UAAM,OAAO,SAAS,YAAY,KAAK,QAAQ,KAAK;AACpD,SAAK,QAAQ,YAAY,yBAAyB,IAAI;AACtD,SAAK,QAAQ,YAAY,GAAG,IAAI,IAAI,OAAO;AAE3C,QAAI,KAAK,WAAY,cAAa,KAAK,UAAU;AACjD,SAAK,aAAa,WAAW,MAAM;AACjC,UAAI,KAAK,QAAS,MAAK,QAAQ,UAAU,IAAI,aAAa;AAAA,IAC5D,GAAG,GAAI;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAW,GAAgB;AACjC,MAAE,gBAAgB;AAClB,QAAI,KAAK,SAAU;AACnB,SAAK,SAAS,CAAC,KAAK;AACpB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,cAAoB;AAC1B,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,SAAS,CAAC,KAAK;AACpB,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,eAAe,GAAgB;AACrC,MAAE,gBAAgB;AAClB,UAAM,UAAW,EAAE,OAA4B;AAG/C,QAAI,WAAW,CAAC,KAAK,cAAc;AACjC,MAAC,EAAE,OAA4B,UAAU;AACzC,WAAK,wBAAwB;AAC7B;AAAA,IACF;AAEA,QAAI,SAAS;AACX,qBAAe,QAAQ,qBAAqB,MAAM;AAClD,WAAK,WAAW;AAChB,WAAK,cAAc,KAAK,sBAAsB;AAC9C,WAAK,cAAc,IAAI;AACvB,WAAK,gBAAgB,OAAO;AAAA,IAC9B,OAAO;AACL,qBAAe,WAAW,mBAAmB;AAC7C,WAAK,WAAW;AAChB,WAAK,cAAc,KAAK;AAAA,IAC1B;AACA,SAAK,SAAS;AACd,SAAK,OAAO,oBAAoB,KAAK,QAAQ;AAAA,EAC/C;AAAA,EAEQ,WAAW,MAAoB;AACrC,SAAK,cAAc;AAGnB,iBAAa,QAAQ,oBAAoB,IAAI;AAC7C,aAAS,gBAAgB,aAAa,QAAQ,IAAI;AAClD,aAAS,gBAAgB,aAAa,OAAO,SAAS,OAAO,QAAQ,KAAK;AAG1E,SAAK,OAAO,gBAAgB,IAAI;AAChC,WAAO,cAAc,IAAI,YAAY,mBAAmB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AAG7E,WAAO,SAAS,OAAO;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,GAAqB;AACvC,QAAK,EAAE,OAAuB,QAAQ,2BAA2B,KAAM,EAAE,OAAuB,QAAQ,aAAa,EAAG;AACxH,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,aAAa,EAAE;AACpB,SAAK,aAAa,EAAE;AACpB,SAAK,YAAY,KAAK;AACtB,SAAK,YAAY,KAAK;AACtB,aAAS,iBAAiB,aAAa,KAAK,cAAc;AAC1D,aAAS,iBAAiB,WAAW,KAAK,YAAY;AAAA,EACxD;AAAA,EAEQ,WAAW,GAAqB;AACtC,QAAI,CAAC,KAAK,cAAc,CAAC,KAAK,MAAO;AACrC,UAAM,KAAK,EAAE,UAAU,KAAK,YAAY,KAAK,EAAE,UAAU,KAAK;AAC9D,QAAI,KAAK,IAAI,EAAE,IAAI,KAAK,KAAK,IAAI,EAAE,IAAI,EAAG,MAAK,WAAW;AAC1D,SAAK,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,aAAa,IAAI,KAAK,YAAY,EAAE,CAAC;AAC7E,SAAK,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,cAAc,IAAI,KAAK,YAAY,EAAE,CAAC;AAC9E,SAAK,MAAM,MAAM,OAAO,KAAK,OAAO;AACpC,SAAK,MAAM,MAAM,MAAM,KAAK,OAAO;AAAA,EACrC;AAAA,EAEQ,YAAkB;AACxB,SAAK,aAAa;AAClB,aAAS,oBAAoB,aAAa,KAAK,cAAc;AAC7D,aAAS,oBAAoB,WAAW,KAAK,YAAY;AAAA,EAC3D;AAAA,EAEQ,aAAa,GAAqB;AACxC,QAAK,EAAE,OAAuB,QAAQ,2BAA2B,KAAM,EAAE,OAAuB,QAAQ,aAAa,EAAG;AACxH,UAAM,IAAI,EAAE,QAAQ,CAAC;AACrB,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,aAAa,EAAE;AACpB,SAAK,aAAa,EAAE;AACpB,SAAK,YAAY,KAAK;AACtB,SAAK,YAAY,KAAK;AACtB,aAAS,iBAAiB,aAAa,KAAK,gBAAgB,EAAE,SAAS,MAAM,CAAC;AAC9E,aAAS,iBAAiB,YAAY,KAAK,aAAa;AAAA,EAC1D;AAAA,EAEQ,YAAY,GAAqB;AACvC,QAAI,CAAC,KAAK,cAAc,CAAC,KAAK,MAAO;AACrC,MAAE,eAAe;AACjB,UAAM,IAAI,EAAE,QAAQ,CAAC;AACrB,UAAM,KAAK,EAAE,UAAU,KAAK,YAAY,KAAK,EAAE,UAAU,KAAK;AAC9D,QAAI,KAAK,IAAI,EAAE,IAAI,KAAK,KAAK,IAAI,EAAE,IAAI,EAAG,MAAK,WAAW;AAC1D,SAAK,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,aAAa,IAAI,KAAK,YAAY,EAAE,CAAC;AAC7E,SAAK,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,cAAc,IAAI,KAAK,YAAY,EAAE,CAAC;AAC9E,SAAK,MAAM,MAAM,OAAO,KAAK,OAAO;AACpC,SAAK,MAAM,MAAM,MAAM,KAAK,OAAO;AAAA,EACrC;AAAA,EAEQ,aAAmB;AACzB,SAAK,aAAa;AAClB,aAAS,oBAAoB,aAAa,KAAK,cAAc;AAC7D,aAAS,oBAAoB,YAAY,KAAK,aAAa;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAW,KAAoB;AACrC,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,wBAAgC;AAEtC,UAAM,SAAS,aAAa,QAAQ,kBAAkB;AACtD,QAAI,UAAU,KAAK,UAAU,SAAS,MAAM,EAAG,QAAO;AACtD,UAAM,WAAW,SAAS,gBAAgB,aAAa,MAAM;AAC7D,QAAI,YAAY,KAAK,UAAU,SAAS,QAAQ,EAAG,QAAO;AAC1D,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,cAAc,KAAa,WAAgC;AACjE,UAAM,KAAK,SAAS,cAAc,GAAG;AACrC,OAAG,YAAY;AACf,WAAO;AAAA,EACT;AAAA,EAEQ,WAAW,WAA2B;AAC5C,UAAM,IAAI,IAAI,KAAK,SAAS;AAC5B,UAAM,SAAS,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAClG,UAAM,IAAI,EAAE,SAAS;AACrB,UAAM,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACnD,UAAM,OAAO,KAAK,KAAK,OAAO;AAC9B,UAAM,MAAM,IAAI,MAAM;AACtB,WAAO,GAAG,OAAO,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,IAAI;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAuB;AAC7B,QAAI,KAAK,aAAc;AAEvB,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AACpB,YAAQ,KAAK;AAEb,YAAQ,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BpB,KAAC,KAAK,UAAU,SAAS,MAAM,YAAY,OAAO;AAClD,SAAK,eAAe;AAEpB,UAAM,MAAM,QAAQ,cAAc,iBAAiB;AACnD,UAAM,aAAa,QAAQ,cAAc,mBAAmB;AAC5D,UAAM,YAAY,QAAQ,cAAc,sBAAsB;AAE9D,UAAM,UAAU,MAAM,KAAK,aAAa,WAAW,MAAM,KAAK,GAAG,UAAU,KAAK;AAChF,QAAI,iBAAiB,SAAS,OAAO;AACrC,cAAU,iBAAiB,WAAW,CAAC,MAAM;AAAE,UAAI,EAAE,QAAQ,QAAS,SAAQ;AAAA,IAAG,CAAC;AAGlF,UAAM,YAAY,QAAQ,cAAc,uBAAuB;AAC/D,QAAI,WAAW;AACb,gBAAU,iBAAiB,SAAS,MAAM;AACxC,cAAM,aAAa,UAAU,SAAS;AACtC,kBAAU,OAAO,aAAa,SAAS;AACvC,kBAAU,cAAc,gBAAgB,EAAG,UAAU,OAAO,eAAe,CAAC,UAAU;AACtF,kBAAU,cAAc,kBAAkB,EAAG,UAAU,OAAO,eAAe,UAAU;AACvF,kBAAU,MAAM;AAAA,MAClB,CAAC;AAAA,IACH;AAGA,eAAW,MAAM,WAAW,MAAM,GAAG,EAAE;AAAA,EACzC;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,cAAc,OAAO;AAC1B,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,MAAc,aAAa,OAAe,UAAiC;AACzE,UAAM,MAAM,SAAS,eAAe,gBAAgB;AACpD,UAAM,UAAU,SAAS,eAAe,kBAAkB;AAE1D,QAAI,CAAC,SAAS,CAAC,UAAU;AACvB,cAAQ,cAAc;AACtB,cAAQ,UAAU,IAAI,SAAS;AAC/B;AAAA,IACF;AAEA,QAAI,WAAW;AACf,QAAI,cAAc;AAClB,YAAQ,UAAU,OAAO,SAAS;AAElC,QAAI;AACF,YAAM,WAAW,KAAK,OAAO,YAAY,GAAG,KAAK,OAAO,OAAO;AAC/D,YAAM,MAAM,MAAM,MAAM,UAAU;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,OAAO,SAAS,CAAC;AAAA,MACpD,CAAC;AAGD,UAAI,OAAY;AAChB,UAAI;AAAE,eAAO,MAAM,IAAI,KAAK;AAAA,MAAG,QAAQ;AAAA,MAA2B;AAElE,UAAI,CAAC,IAAI,IAAI;AAEX,cAAM,SAAS,MAAM,WAAW,MAAM,SAAS;AAC/C,cAAM,IAAI,MAAM,UAAU,QAAQ,IAAI,MAAM,EAAE;AAAA,MAChD;AAGA,YAAM,QAAQ,MAAM,SAAS,MAAM,aAAa,MAAM,cAAc,MAAM,MAAM;AAChF,UAAI,CAAC,MAAO,OAAM,IAAI,MAAM,yCAAyC;AAErE,mBAAY,UAAU,iBAAiB,KAAK;AAG5C,UAAI,MAAM,QAAS,cAAY,UAAU,oBAAoB,KAAK,OAAO;AAAA,UACpE,cAAY,aAAa,kBAAkB;AAChD,UAAI,MAAM,cAAe,cAAY,UAAU,0BAA0B,KAAK,aAAa;AAAA,UACtF,cAAY,aAAa,wBAAwB;AACtD,UAAI,MAAM,UAAW,cAAY,UAAU,sBAAsB,KAAK,SAAS;AAAA,UAC1E,cAAY,aAAa,oBAAoB;AAClD,UAAI,MAAM,YAAY;AACpB,qBAAY,UAAU,uBAAuB,KAAK,UAAU;AAC5D,aAAK,OAAO,YAAY,KAAK;AAAA,MAC/B,OAAO;AACL,qBAAY,aAAa,qBAAqB;AAAA,MAChD;AACA,UAAI,MAAM,SAAU,cAAY,UAAU,qBAAqB,KAAK,QAAQ;AAAA,UACvE,cAAY,aAAa,mBAAmB;AAEjD,WAAK,eAAe;AAGpB,WAAK,WAAW;AAChB,WAAK,kBAAkB;AACvB,qBAAe,QAAQ,qBAAqB,MAAM;AAClD,WAAK,cAAc,IAAI;AACvB,WAAK,SAAS;AACd,WAAK,gBAAgB,OAAO;AAAA,IAC9B,SAAS,KAAU;AACjB,UAAI,WAAW;AACf,UAAI,cAAc;AAClB,cAAQ,cAAc,KAAK,WAAW;AACtC,cAAQ,UAAU,IAAI,SAAS;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,wBAAgC;AACtC,UAAM,WAAW,OAAO,SAAS;AACjC,QAAI,YAAY,aAAa,eAAe,aAAa,eAAe,CAAC,SAAS,WAAW,UAAU,GAAG;AACxG,aAAO;AAAA,IACT;AACA,QAAI,KAAK,aAAa,QAAQ,kBAAkB;AAChD,QAAI,CAAC,IAAI;AACP,WAAK,uCAAuC,QAAQ,SAAS,OAAK;AAChE,cAAM,IAAI,KAAK,OAAO,IAAI,KAAK;AAC/B,gBAAQ,MAAM,MAAM,IAAK,IAAI,IAAM,GAAM,SAAS,EAAE;AAAA,MACtD,CAAC;AACD,mBAAa,QAAQ,oBAAoB,EAAE;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAS,KAAqB;AACpC,UAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO,GAAG,SAAS,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,SAAS,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,SAAS,OAAO,CAAC,GAAG,EAAE,CAAC;AAAA,EACzF;AAAA,EAEQ,eAAe,KAAqB;AAC1C,UAAM,SAAS,4CAA4C,KAAK,GAAG;AACnE,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC;AAC/D,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC;AAC/D,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC;AAC/D,WAAO,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,EAChH;AAAA,EAEQ,gBAAgB,OAAqB;AAC3C,SAAK,iBAAiB;AACtB,aAAS,gBAAgB,MAAM,YAAY,kBAAkB,KAAK;AAClE,aAAS,gBAAgB,MAAM,YAAY,sBAAsB,KAAK,SAAS,KAAK,CAAC;AACrF,aAAS,gBAAgB,MAAM,YAAY,uBAAuB,KAAK,eAAe,KAAK,CAAC;AAG5F,QAAI,KAAK,UAAU;AACjB,iBAAW,CAAC,EAAE,KAAK,KAAK,iBAAiB;AACvC,WAAG,MAAM,YAAY,WAAW,cAAc,KAAK,IAAI,WAAW;AAAA,MACpE;AACA,iBAAW,CAAC,GAAG,KAAK,KAAK,eAAe;AACtC,YAAI,MAAM,YAAY,WAAW,cAAc,KAAK,IAAI,WAAW;AAAA,MACrE;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,SAAS,iBAAiB,oBAAoB;AACpE,cAAU,QAAQ,OAAK;AACrB,MAAC,EAAkB,UAAU,OAAO,UAAW,EAAkB,QAAQ,UAAU,KAAK;AAAA,IAC1F,CAAC;AAGD,iBAAa,QAAQ,wBAAwB,KAAK;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,OAAO,QAAkD;AACpE,UAAM,MAAM,IAAI,aAAY,MAAM;AAClC,UAAM,IAAI,KAAK;AACf,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAa,WAA0B;AAErC,QAAK,OAAe,0BAA2B;AAE/C,UAAM,aAAiC,OAAe,2BAA2B,CAAC;AAClF,UAAM,MAAM,MAAM,aAAY,OAAO,UAAU;AAC/C,IAAC,OAAe,4BAA4B;AAAA,EAC9C;AACF;AAAA;AAx2Fa,aAEa,MAAM;AAFnB,aAGa,aAAa;AAAA;AAAA;AAAA;AAH1B,aAmSa,oBAAoB;AAnSjC,aAoSa,oBAAoB,KAAK,KAAK,KAAK;AAAA;AApShD,aAgwDa,mBAAmB,oBAAI,IAAI;AAAA,EACjD;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAU;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAK;AAAA,EAAS;AAAA,EAAK;AAAA,EAAU;AAAA,EAAK;AACnG,CAAC;AAAA;AAlwDU,aAqwDa,eAAe,oBAAI,IAAI;AAAA,EAC7C;AAAA,EAAK;AAAA,EAAU;AAAA,EAAK;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAU;AAAA,EAAK;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAO;AACpF,CAAC;AAAA;AAvwDU,aA0wDa,gBAA6C;AAAA,EACnE,GAAG,oBAAI,IAAI,CAAC,QAAQ,UAAU,KAAK,CAAC;AACtC;AA5wDK,IAAM,cAAN;;;AFlBP,eAAe,OAAO;AACpB,QAAM,YAAY,SAAS;AAC7B;AAEA,IAAI,OAAO,WAAW,aAAa;AACjC,MAAI,SAAS,eAAe,WAAW;AACrC,aAAS,iBAAiB,oBAAoB,IAAI;AAAA,EACpD,OAAO;AAEL,SAAK;AAAA,EACP;AACF;","names":[]}