Your IP : 216.73.216.79


Current Path : /var/www/html/brspace/www/admin/
Upload File :
Current File : /var/www/html/brspace/www/admin/web-page-editor.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Page Editor</title>

<link href="/admin/css/css2.css" rel="stylesheet">
<link href="/admin/css/bootstrap-icons.min.css" rel="stylesheet">
<!-- Ace editor for source code editing -->
<script src="/admin/js/ace.min.js"></script>
<script src="/admin/js/ext-language_tools.min.js"></script>
<script src="/admin/js/mode-html.min.js"></script>
<script src="/admin/js/mode-php.min.js"></script>
<script src="/admin/js/theme-tomorrow_night.min.js"></script>

<style>
:root {
  --bg-0:            #0a0e17;
  --bg-1:            #0f1623;
  --bg-2:            #1a2030;
  --bg-3:            #232a3d;
  --border:          rgba(255,255,255,0.07);
  --border-hl:       rgba(255,255,255,0.14);
  --text-0:          #ffffff;
  --text-1:          rgba(255,255,255,0.85);
  --text-2:          rgba(255,255,255,0.55);
  --text-3:          rgba(255,255,255,0.35);

  --accent:          #f59e0b;     /* edit mode amber */
  --accent-glow:     rgba(245,158,11,0.35);
  --brand:           #4f6ef7;
  --brand-glow:      rgba(79,110,247,0.35);
  --success:         #10b981;
  --danger:          #ef4444;
  --warning:         #f59e0b;
  --info:            #06b6d4;

  --radius:          8px;
  --radius-lg:       12px;
  --font:            'Plus Jakarta Sans', system-ui, sans-serif;
  --font-mono:       'JetBrains Mono', ui-monospace, monospace;
  --shadow:          0 4px 20px rgba(0,0,0,0.4);
  --shadow-lg:       0 10px 40px rgba(0,0,0,0.5);

  --sidebar-w:       280px;
  --props-w:         300px;
}

* , *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%; width: 100%;
  overflow: hidden;
  font-family: var(--font);
  background: var(--bg-0);
  color: var(--text-1);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

button { font-family: inherit; cursor: pointer; outline: none; border: none; }
input, textarea, select { font-family: inherit; outline: none; }

::selection { background: var(--brand-glow); color: #fff; }

/* ═══════════════════════════════════════════
   APP SHELL
═══════════════════════════════════════════ */
#app {
  display: grid;
  grid-template-rows: 56px 1fr;
  grid-template-columns: var(--sidebar-w) 1fr var(--props-w);
  grid-template-areas:
    "topbar topbar topbar"
    "sidebar main props";
  width: 100vw;
  height: 100vh;
  transition: grid-template-columns .2s ease;
}
#app.left-collapsed { grid-template-columns: 0 1fr var(--props-w); }
#app.right-collapsed { grid-template-columns: var(--sidebar-w) 1fr 0; }
#app.left-collapsed.right-collapsed { grid-template-columns: 0 1fr 0; }

/* ── Topbar ─────────────────────────────────── */
#topbar {
  grid-area: topbar;
  background: var(--bg-1);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 18px;
  gap: 14px;
  box-shadow: 0 2px 12px rgba(0,0,0,.3);
  z-index: 10;
}

.edit-badge {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 12px 6px 10px;
  background: rgba(245,158,11,.12);
  border: 1px solid rgba(245,158,11,.25);
  border-radius: 20px;
  flex-shrink: 0;
}
.edit-badge-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
  animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse {
  0%,100% { opacity: 1; transform: scale(1); }
  50% { opacity: .5; transform: scale(.75); }
}
.edit-badge-label {
  font-size: 10.5px; font-weight: 700;
  letter-spacing: 1.3px; text-transform: uppercase;
  color: var(--accent);
}

.tb-divider { width: 1px; height: 24px; background: var(--border); flex-shrink: 0; }

.tb-breadcrumb {
  display: flex; align-items: center; gap: 8px;
  min-width: 0; overflow: hidden;
}
.tb-crumb-portal {
  font-size: 12.5px; font-weight: 500;
  color: var(--text-2);
  white-space: nowrap;
}
.tb-crumb-sep { color: var(--text-3); font-size: 14px; }
.tb-crumb-page {
  font-size: 13.5px; font-weight: 700;
  color: var(--text-0);
  letter-spacing: -0.2px;
}
.tb-crumb-id {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--accent);
  background: rgba(245,158,11,.1);
  padding: 2px 7px;
  border-radius: 4px;
  margin-left: 2px;
}

.tb-spacer { margin-left: auto; }

.tb-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.tb-icon-btn {
  width: 34px; height: 34px;
  background: rgba(255,255,255,.05);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
  transition: all .15s;
  flex-shrink: 0;
}
.tb-icon-btn:hover {
  background: rgba(255,255,255,.1);
  color: var(--text-0);
  border-color: var(--border-hl);
}
.tb-icon-btn.active {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
}

.tb-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px;
  background: rgba(255,255,255,.05);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text-2);
  font-size: 12.5px; font-weight: 600;
  transition: all .15s;
  white-space: nowrap;
}
.tb-btn:hover {
  background: rgba(255,255,255,.1);
  border-color: var(--border-hl);
  color: var(--text-0);
}
.tb-btn i { font-size: 12px; }

.tb-btn.primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  box-shadow: 0 2px 10px var(--brand-glow);
}
.tb-btn.primary:hover {
  background: #3b55e0;
  border-color: #3b55e0;
  color: #fff;
}

.tb-btn.success {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
  box-shadow: 0 2px 10px rgba(16,185,129,.35);
}
.tb-btn.success:hover { background: #059669; }

.tb-save-indicator {
  display: none;
  align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--text-3);
  padding-right: 4px;
}
.tb-save-indicator i { color: var(--success); }
.tb-save-indicator.visible { display: inline-flex; }

/* ── Sidebar ────────────────────────────────── */
#sidebar {
  grid-area: sidebar;
  background: var(--bg-1);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

/* Sidebar tabs */
.sb-tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  background: var(--bg-0);
  flex-shrink: 0;
}
.sb-tab {
  flex: 1;
  padding: 10px 8px;
  background: transparent;
  color: var(--text-3);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  display: flex; align-items: center; justify-content: center;
  gap: 5px;
  border-bottom: 2px solid transparent;
  transition: all .15s;
}
.sb-tab i { font-size: 13px; }
.sb-tab:hover { color: var(--text-1); background: rgba(255,255,255,.03); }
.sb-tab.active {
  color: var(--text-0);
  border-bottom-color: var(--brand);
  background: var(--bg-1);
}

.sb-tab-panel { display: none; flex: 1; min-height: 0; overflow: hidden; flex-direction: column; }
.sb-tab-panel.active { display: flex; }

.sb-section {
  padding: 14px 14px 10px;
}
.sb-section-title {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 10px;
  padding: 0 6px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.sb-section-title .count {
  background: rgba(255,255,255,.08);
  color: var(--text-2);
  padding: 1px 6px;
  border-radius: 8px;
  font-size: 9.5px;
  letter-spacing: 0.5px;
}

.sb-scroll {
  flex: 1;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--bg-3) transparent;
}
.sb-scroll::-webkit-scrollbar { width: 6px; }
.sb-scroll::-webkit-scrollbar-thumb { background: var(--bg-3); border-radius: 3px; }

/* Library */
.lib-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 0 6px;
}
.lib-item {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 8px;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  cursor: grab;
  transition: all .15s;
  user-select: none;
  text-align: center;
}
.lib-item:hover {
  background: var(--bg-3);
  border-color: var(--border-hl);
  transform: translateY(-1px);
}
.lib-item:active { cursor: grabbing; }
.lib-item.dragging { opacity: 0.5; }
.lib-item-icon {
  width: 36px; height: 36px;
  background: linear-gradient(135deg, var(--brand), #7c5ef5);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 15px;
  flex-shrink: 0;
}
.lib-item-name {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-1);
  letter-spacing: 0.1px;
  line-height: 1.2;
}
.lib-item.cat-layout .lib-item-icon { background: linear-gradient(135deg, #3b82f6, #1e40af); }
.lib-item.cat-text .lib-item-icon { background: linear-gradient(135deg, #10b981, #059669); }
.lib-item.cat-media .lib-item-icon { background: linear-gradient(135deg, #a78bfa, #7c3aed); }
.lib-item.cat-form .lib-item-icon { background: linear-gradient(135deg, #f59e0b, #d97706); }
.lib-item.cat-ui .lib-item-icon { background: linear-gradient(135deg, #ec4899, #be185d); }

.lib-cat-title {
  font-size: 9.5px; font-weight: 700;
  letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--text-3);
  padding: 10px 6px 6px;
  grid-column: 1 / -1;
}

/* ── Right properties panel ───────────────── */
#propsPanel {
  grid-area: props;
  background: var(--bg-1);
  border-left: 1px solid var(--border);
  display: flex; flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

.props-tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  background: var(--bg-0);
  flex-shrink: 0;
}
.props-tab {
  flex: 1;
  padding: 10px 8px;
  background: transparent;
  color: var(--text-3);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  display: flex; align-items: center; justify-content: center;
  gap: 5px;
  border-bottom: 2px solid transparent;
  transition: all .15s;
}
.props-tab i { font-size: 13px; }
.props-tab:hover { color: var(--text-1); background: rgba(255,255,255,.03); }
.props-tab.active {
  color: var(--text-0);
  border-bottom-color: var(--brand);
  background: var(--bg-1);
}
.props-tab-panel { display: none; flex: 1; min-height: 0; overflow: hidden; flex-direction: column; }
.props-tab-panel.active { display: flex; }
.props-header {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  flex-shrink: 0;
}
.props-header-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 700;
  color: var(--text-0); letter-spacing: 0.2px;
}
.props-header-title i { color: var(--brand); font-size: 14px; }
.props-tag-chip {
  font-family: var(--font-mono);
  font-size: 10px; font-weight: 700;
  color: var(--brand);
  background: rgba(79,110,247,.12);
  padding: 2px 8px;
  border-radius: 4px;
}
.props-scroll {
  flex: 1; overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--bg-3) transparent;
}
.props-scroll::-webkit-scrollbar { width: 6px; }
.props-scroll::-webkit-scrollbar-thumb { background: var(--bg-3); border-radius: 3px; }

.props-empty {
  padding: 40px 20px;
  text-align: center;
  color: var(--text-3);
  font-size: 12px;
  line-height: 1.55;
}
.props-empty i { font-size: 36px; display: block; margin-bottom: 10px; color: var(--text-3); opacity: 0.5; }

.props-group {
  border-bottom: 1px solid var(--border);
}
.props-group > summary {
  padding: 10px 14px;
  cursor: pointer;
  list-style: none;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-2);
  display: flex; align-items: center; gap: 8px;
  background: rgba(255,255,255,.02);
  transition: all .12s;
}
.props-group > summary::-webkit-details-marker { display: none; }
.props-group > summary::before {
  content: "▸";
  font-size: 10px;
  color: var(--text-3);
  transition: transform .15s;
}
.props-group[open] > summary::before { transform: rotate(90deg); }
.props-group > summary:hover { background: rgba(255,255,255,.05); color: var(--text-1); }
.props-group > summary i { color: var(--brand); font-size: 13px; }

.props-fields {
  padding: 10px 14px 14px;
  display: flex; flex-direction: column;
  gap: 9px;
}
.props-lbl {
  display: block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 3px;
}
.props-in {
  width: 100%;
  padding: 6px 9px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-1);
  font-family: var(--font-mono);
  font-size: 11px;
  outline: none;
  transition: border-color .15s, background .15s;
}
.props-in:focus {
  border-color: var(--brand);
  background: var(--bg-0);
}
select.props-in { height: 28px; padding: 0 9px; cursor: pointer; }
.props-row-split { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.props-color-row { display: flex; gap: 6px; align-items: center; }
.props-color {
  width: 32px; height: 28px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--bg-2);
  cursor: pointer;
  flex-shrink: 0;
}
.props-color::-webkit-color-swatch-wrapper { padding: 2px; }
.props-color::-webkit-color-swatch { border: none; border-radius: 3px; }

/* ── Hierarchy tree ────────────────────────── */
.hierarchy-toolbar {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex-shrink: 0;
}
.hierarchy-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-size: 9.5px;
  color: var(--text-3);
  font-weight: 600;
  letter-spacing: 0.3px;
}
.hierarchy-legend i { font-size: 9px; margin-right: 2px; }

.hier-tree {
  padding: 6px 0;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
}
.hier-node {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px 2px 0;
  cursor: pointer;
  border-left: 2px solid transparent;
  position: relative;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background .12s, border-color .12s;
}
.hier-node:hover {
  background: rgba(255,255,255,.04);
  border-left-color: var(--brand);
}
.hier-node.is-selected {
  background: rgba(16,185,129,.12);
  border-left-color: #10b981;
}
.hier-node.is-comp-root {
  background: rgba(245,158,11,.08);
  border-left-color: var(--accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  font-size: 10px;
  padding: 5px 8px 5px 0;
  font-family: var(--font);
}
.hier-node.is-comp-root:hover { background: rgba(245,158,11,.15); }
.hier-node.hier-hidden { display: none; }

.hier-toggle {
  width: 12px;
  height: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  font-size: 9px;
  cursor: pointer;
  flex-shrink: 0;
  transition: transform .12s, color .12s;
}
.hier-toggle:hover { color: var(--text-1); }
.hier-toggle.collapsed { transform: rotate(-90deg); }
.hier-toggle.leaf { visibility: hidden; }

.hier-icon {
  width: 14px;
  font-size: 10px;
  flex-shrink: 0;
  text-align: center;
}
.hier-icon.kind-container { color: #4f6ef7; }
.hier-icon.kind-text      { color: #10b981; }
.hier-icon.kind-image     { color: #a78bfa; }
.hier-icon.kind-link      { color: #06b6d4; }
.hier-icon.kind-list      { color: #f59e0b; }

.hier-tag {
  color: var(--text-1);
  font-weight: 600;
}
.hier-node.is-selected .hier-tag { color: #10b981; }
.hier-id {
  color: var(--info);
  font-weight: 500;
}
.hier-cls {
  color: var(--text-3);
  font-weight: 400;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hier-txt {
  color: var(--accent);
  font-style: italic;
  font-weight: 400;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hier-children.collapsed { display: none; }

/* Component list */
.comp-list { display: flex; flex-direction: column; gap: 3px; }
.comp-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius);
  cursor: pointer;
  transition: all .15s;
  border: 1px solid transparent;
  position: relative;
}
.comp-item:hover {
  background: rgba(255,255,255,.04);
  border-color: var(--border);
}
.comp-item.dirty {
  background: rgba(245,158,11,.07);
  border-color: rgba(245,158,11,.2);
}
.comp-item.dirty::before {
  content: ''; position: absolute;
  left: 4px; top: 50%;
  transform: translateY(-50%);
  width: 3px; height: 20px;
  background: var(--accent);
  border-radius: 2px;
  box-shadow: 0 0 6px var(--accent);
}
.comp-item.new {
  background: rgba(16,185,129,.07);
  border-color: rgba(16,185,129,.25);
}
.comp-item.php {
  background: rgba(167,139,250,.06);
  border-color: rgba(167,139,250,.2);
}
.comp-item.php .comp-item-icon {
  background: linear-gradient(135deg, #a78bfa, #7c3aed);
  color: #fff;
  border-color: transparent;
}
.badge-new, .badge-php {
  display: inline-block;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.6px;
  padding: 1px 6px;
  border-radius: 3px;
  margin-left: 5px;
  vertical-align: middle;
  text-transform: uppercase;
}
.badge-new { background: rgba(16,185,129,.18); color: #10b981; }
.badge-php { background: rgba(167,139,250,.22); color: #a78bfa; }
.comp-item.dragging-item {
  opacity: 0.45;
}
.comp-item.drop-above { box-shadow: 0 -2px 0 0 var(--brand); }
.comp-item.drop-below { box-shadow: 0 2px 0 0 var(--brand); }

.comp-item-grip {
  cursor: grab;
  color: var(--text-3);
  font-size: 12px;
  padding: 2px 3px;
  display: flex;
  align-items: center;
  opacity: 0;
  transition: opacity .15s, color .15s;
  flex-shrink: 0;
  user-select: none;
}
.comp-item:hover .comp-item-grip { opacity: 1; }
.comp-item-grip:active { cursor: grabbing; color: var(--text-0); }

.sb-add-btn {
  background: var(--brand);
  color: #fff;
  padding: 3px 8px;
  border-radius: 5px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.3px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  text-transform: none;
  box-shadow: 0 1px 4px rgba(79,110,247,.3);
  transition: all .15s;
}
.sb-add-btn:hover { background: #3b55e0; box-shadow: 0 2px 8px rgba(79,110,247,.5); }
.sb-add-btn i { font-size: 10px; }
.comp-item-icon {
  width: 30px; height: 30px;
  border-radius: 7px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-2);
  font-size: 14px;
  flex-shrink: 0;
  transition: all .15s;
}
.comp-item.visual .comp-item-icon {
  background: rgba(79,110,247,.1);
  border-color: rgba(79,110,247,.25);
  color: var(--brand);
}
.comp-item.infra .comp-item-icon {
  background: rgba(139,92,246,.08);
  border-color: rgba(139,92,246,.2);
  color: #a78bfa;
}
.comp-item-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.comp-item-name {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: -0.1px;
}
.comp-item-sub {
  font-size: 10px;
  color: var(--text-3);
  letter-spacing: 0.3px;
  text-transform: uppercase;
  font-weight: 600;
}
.comp-item-edit {
  width: 26px; height: 26px;
  border-radius: 6px;
  background: transparent;
  color: var(--text-3);
  font-size: 11px;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  transition: all .15s;
}
.comp-item:hover .comp-item-edit { opacity: 1; }
.comp-item-edit:hover { background: var(--brand); color: #fff; }

/* Status box */
.sb-status {
  padding: 12px 14px;
  background: var(--bg-2);
  border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 8px;
}
.sb-status-row {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 11px;
  color: var(--text-2);
}
.sb-status-row .lbl {
  color: var(--text-3);
  font-size: 10px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  font-weight: 700;
}
.sb-status-row .val {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-1);
  font-weight: 500;
}
.sb-status-row .val.dirty { color: var(--accent); }

.sb-action-btn {
  width: 100%;
  padding: 9px;
  background: var(--brand);
  color: #fff;
  border-radius: 8px;
  font-size: 12px; font-weight: 700;
  letter-spacing: 0.3px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  transition: all .15s;
  box-shadow: 0 2px 10px var(--brand-glow);
}
.sb-action-btn:hover { background: #3b55e0; box-shadow: 0 4px 14px var(--brand-glow); }
.sb-action-btn:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }

/* API Settings form */
.api-form { display: flex; flex-direction: column; gap: 8px; }
.api-lbl {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--text-3);
}
.api-in {
  width: 100%;
  padding: 7px 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-1);
  font-family: var(--font-mono);
  font-size: 11px;
  transition: border-color .15s;
}
.api-in:focus {
  border-color: var(--brand);
  background: var(--bg-0);
}

/* ── Main area ──────────────────────────────── */
#main {
  grid-area: main;
  background: #2a2f3e;
  display: flex; flex-direction: column;
  position: relative;
  overflow: hidden;
}

#viewport-frame {
  width: 100%;
  height: 100%;
  border: none;
  background: #fff;
  display: block;
}

/* Empty state */
.empty-state {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 16px;
  padding: 40px;
  text-align: center;
  background: var(--bg-0);
}
.empty-state-icon {
  width: 80px; height: 80px;
  border-radius: 20px;
  background: linear-gradient(135deg, var(--brand), #7c5ef5);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 38px;
  box-shadow: 0 10px 40px var(--brand-glow);
}
.empty-state-title {
  font-size: 22px; font-weight: 800;
  color: var(--text-0);
  letter-spacing: -0.5px;
}
.empty-state-sub {
  font-size: 13px; color: var(--text-2);
  max-width: 420px; line-height: 1.55;
}
.empty-state-actions { display: flex; gap: 10px; margin-top: 6px; }
.empty-btn {
  padding: 10px 18px;
  background: var(--brand);
  color: #fff;
  border-radius: 8px;
  font-size: 13px; font-weight: 700;
  transition: all .15s;
  display: inline-flex; align-items: center; gap: 7px;
  box-shadow: 0 4px 14px var(--brand-glow);
}
.empty-btn:hover { background: #3b55e0; transform: translateY(-1px); }
.empty-btn.outline {
  background: transparent;
  border: 1.5px solid var(--border-hl);
  color: var(--text-1);
  box-shadow: none;
}
.empty-btn.outline:hover { background: rgba(255,255,255,.05); border-color: var(--text-2); }

/* ═══════════════════════════════════════════
   MODAL
═══════════════════════════════════════════ */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,.7);
  backdrop-filter: blur(8px);
  z-index: 1000;
  display: none;
  align-items: center; justify-content: center;
  animation: fadeIn .18s ease-out;
}
.modal-backdrop.visible { display: flex; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.modal {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 90vw;
  max-width: 1100px;
  height: 85vh;
  display: flex; flex-direction: column;
  overflow: hidden;
  animation: slideUp .2s ease-out;
}
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

.modal-header {
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 14px;
  flex-shrink: 0;
}
.modal-header-icon {
  width: 34px; height: 34px;
  background: linear-gradient(135deg, var(--brand), #7c5ef5);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 15px;
  flex-shrink: 0;
}
.modal-header-text {
  flex: 1;
  display: flex; flex-direction: column;
  min-width: 0;
}
.modal-header-eyebrow {
  font-size: 9.5px; font-weight: 700;
  letter-spacing: 1.3px; text-transform: uppercase;
  color: var(--text-3);
  line-height: 1;
  margin-bottom: 3px;
}
.modal-header-title {
  font-size: 15px; font-weight: 700;
  color: var(--text-0);
  letter-spacing: -0.3px;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.modal-close {
  width: 30px; height: 30px;
  background: transparent;
  color: var(--text-3);
  border-radius: 6px;
  font-size: 18px;
  display: flex; align-items: center; justify-content: center;
  transition: all .15s;
}
.modal-close:hover { background: rgba(255,255,255,.07); color: var(--text-0); }

.modal-body {
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
}
#srcEditor { width: 100%; height: 100%; }

.modal-tabs {
  padding: 0 20px;
  border-bottom: 1px solid var(--border);
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}
.modal-tab {
  padding: 11px 16px;
  background: transparent;
  color: var(--text-3);
  font-size: 12px; font-weight: 600;
  letter-spacing: 0.2px;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: all .15s;
  display: inline-flex; align-items: center; gap: 6px;
}
.modal-tab:hover { color: var(--text-1); }
.modal-tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.modal-tab-panel { display: none; flex: 1; overflow: hidden; }
.modal-tab-panel.active { display: flex; flex-direction: column; }

#previewPanel {
  flex: 1;
  overflow: auto;
  background: #fff;
  padding: 20px;
}

.modal-footer {
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  background: var(--bg-0);
}
.modal-footer-info {
  flex: 1;
  font-size: 11px;
  color: var(--text-3);
  display: flex; align-items: center; gap: 6px;
}
.modal-footer-info i { color: var(--accent); }
.modal-footer-info .kbd {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
}

.m-btn {
  padding: 8px 14px;
  border-radius: 7px;
  font-size: 12.5px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px;
  transition: all .15s;
  white-space: nowrap;
}
.m-btn.ghost {
  background: transparent;
  color: var(--text-2);
  border: 1px solid var(--border);
}
.m-btn.ghost:hover { background: rgba(255,255,255,.05); color: var(--text-0); border-color: var(--border-hl); }
.m-btn.primary {
  background: var(--brand);
  color: #fff;
  box-shadow: 0 2px 10px var(--brand-glow);
}
.m-btn.primary:hover { background: #3b55e0; }
.m-btn.success {
  background: var(--success);
  color: #fff;
  box-shadow: 0 2px 10px rgba(16,185,129,.35);
}
.m-btn.success:hover { background: #059669; }
.m-btn.danger {
  background: transparent;
  color: var(--danger);
  border: 1px solid rgba(239,68,68,.3);
}
.m-btn.danger:hover { background: rgba(239,68,68,.1); border-color: var(--danger); }

/* ── Save preview modal ────────────────────── */
.save-summary {
  padding: 16px 20px;
  display: flex; flex-direction: column; gap: 12px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}
.save-stat-row { display: flex; gap: 12px; flex-wrap: wrap; }
.save-stat {
  flex: 1;
  min-width: 140px;
  padding: 12px 14px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: flex; flex-direction: column; gap: 4px;
}
.save-stat-lbl {
  font-size: 10px; font-weight: 700;
  letter-spacing: 1px; text-transform: uppercase;
  color: var(--text-3);
}
.save-stat-val {
  font-size: 18px; font-weight: 800;
  color: var(--text-0);
  letter-spacing: -0.3px;
  font-family: var(--font-mono);
}
.save-stat-val.accent { color: var(--accent); }
.save-stat-val.success { color: var(--success); }

.save-list {
  max-height: 180px;
  overflow-y: auto;
  padding: 12px 20px 0;
}
.save-list-title {
  font-size: 10.5px; font-weight: 700;
  letter-spacing: 1px; text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 6px;
}
.save-list-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 0;
  border-bottom: 1px dashed var(--border);
  font-size: 12px;
}
.save-list-item:last-child { border-bottom: none; }
.save-list-status {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--text-3);
  flex-shrink: 0;
}
.save-list-status.dirty { background: var(--accent); box-shadow: 0 0 6px var(--accent); }
.save-list-name { color: var(--text-1); flex: 1; font-weight: 500; }
.save-list-size { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-3); }

/* ── Toast ───────────────────────────────── */
#toastWrap {
  position: fixed; bottom: 20px; right: 20px; z-index: 5000;
  display: flex; flex-direction: column-reverse; gap: 8px;
  pointer-events: none;
}
.toast {
  background: var(--bg-1);
  border: 1px solid var(--border-hl);
  border-left: 3px solid var(--brand);
  padding: 12px 16px;
  border-radius: 8px;
  box-shadow: var(--shadow);
  color: var(--text-1);
  font-size: 12.5px; font-weight: 500;
  max-width: 360px;
  display: flex; align-items: center; gap: 10px;
  animation: toastIn .25s cubic-bezier(.4,0,.2,1);
  pointer-events: auto;
}
.toast.success { border-left-color: var(--success); }
.toast.error { border-left-color: var(--danger); }
.toast.warning { border-left-color: var(--warning); }
.toast.info { border-left-color: var(--info); }
.toast i {
  font-size: 16px; flex-shrink: 0;
}
.toast.success i { color: var(--success); }
.toast.error i { color: var(--danger); }
.toast.warning i { color: var(--warning); }
.toast.info i { color: var(--info); }
@keyframes toastIn { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: translateX(0); } }

/* Loader */
.loader-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,.6);
  backdrop-filter: blur(4px);
  z-index: 9000;
  display: none;
  align-items: center; justify-content: center;
}
.loader-overlay.visible { display: flex; }
.loader-card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 28px 36px;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  box-shadow: var(--shadow-lg);
}
.spinner {
  width: 32px; height: 32px;
  border: 3px solid rgba(255,255,255,.08);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: spin .9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.loader-text { font-size: 13px; font-weight: 600; color: var(--text-1); }

/* File upload hidden */
.hidden-file { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }

/* Small copy/download buttons */
.mini-btn {
  padding: 5px 10px;
  background: rgba(255,255,255,.05);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text-2);
  font-size: 10.5px;
  font-weight: 600;
  display: inline-flex; align-items: center; gap: 4px;
  transition: all .15s;
}
.mini-btn:hover { background: rgba(255,255,255,.1); color: var(--text-0); }
</style>
</head>
<body>

<!-- ═══════════════════════════════════════════
     APP SHELL
══════════════════════════════════════════════ -->
<div id="app">

  <!-- TOPBAR -->
  <div id="topbar">
    <button class="tb-icon-btn" onclick="toggleLeftPanel()" title="Toggle left panel" id="btnToggleLeft">
      <svg width="16" height="16" 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"/><line x1="9" y1="3" x2="9" y2="21"/></svg>
    </button>
    <div class="edit-badge">
      <div class="edit-badge-dot"></div>
      <span class="edit-badge-label">Edit Mode</span>
    </div>
    <div class="tb-divider"></div>
    <div class="tb-breadcrumb">
      <span class="tb-crumb-portal" id="tbPortal"></span>
      <span class="tb-crumb-sep" id="tbPortalSep" style="display:none;">›</span>
      <span class="tb-crumb-page" id="tbPage"></span>
      <span class="tb-crumb-id" id="tbPageId" style="display:none;"></span>
    </div>
    <div class="tb-spacer"></div>
    <div class="tb-actions">
      <span class="tb-save-indicator" id="tbSaveInd">
        <i class="bi bi-check-circle-fill"></i><span id="tbSaveIndTxt">Saved</span>
      </span>
      <input type="file" id="loadJsonInput" accept=".json" class="hidden-file">
      <button class="tb-btn" onclick="document.getElementById('loadJsonInput').click()" title="Load components.json from local file">
        <i class="bi bi-folder2-open"></i> Load File
      </button>
      <button class="tb-btn" onclick="loadFromAPI()" title="Fetch components from the configured GET endpoint" id="btnLoadAPI">
        <i class="bi bi-cloud-download"></i> Load from API
      </button>
      <button class="tb-btn" onclick="refreshPreview()" title="Refresh the preview iframe (re-render from current components + asset base)" id="btnRefresh">
        <i class="bi bi-arrow-clockwise"></i> Refresh
      </button>
      <button class="tb-btn" onclick="openPreviewInNewTab()" title="Open preview in new tab">
        <i class="bi bi-box-arrow-up-right"></i> Preview
      </button>
      <button class="tb-btn success" onclick="openSaveDialog()" id="btnSave">
        <i class="bi bi-cloud-arrow-up"></i> Save Changes
      </button>
      <div class="tb-divider"></div>
      <button class="tb-icon-btn" onclick="toggleRightPanel()" title="Toggle properties panel" id="btnToggleRight">
        <svg width="16" height="16" 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"/><line x1="15" y1="3" x2="15" y2="21"/></svg>
      </button>
    </div>
  </div>

  <!-- SIDEBAR (LEFT) -->
  <aside id="sidebar">
    <div class="sb-tabs">
      <button class="sb-tab active" onclick="switchSidebarTab('components')" data-tab="components">
        <i class="bi bi-layers"></i><span>Pages</span>
      </button>
      <button class="sb-tab" onclick="switchSidebarTab('library')" data-tab="library">
        <i class="bi bi-plus-square"></i><span>Library</span>
      </button>
      <button class="sb-tab" onclick="switchSidebarTab('api')" data-tab="api">
        <i class="bi bi-cloud"></i><span>API</span>
      </button>
    </div>

    <!-- Tab: Components -->
    <div class="sb-tab-panel active" data-tab-panel="components">
      <div class="sb-scroll">
        <div class="sb-section">
          <div class="sb-section-title" style="display:flex;align-items:center;justify-content:space-between;">
            <span>Components <span class="count" id="compCount">0</span></span>
            <button onclick="openNewCompModal()" class="sb-add-btn" title="Add new component">
              <i class="bi bi-plus-lg"></i> New
            </button>
          </div>
          <div class="comp-list" id="compList"></div>
          <div class="comp-hint" style="font-size:10px;color:var(--text-3);line-height:1.5;padding:8px 6px 0;">
            <i class="bi bi-info-circle" style="color:var(--info);"></i>
            Drag the grip to reorder. Click any row to edit full source.
          </div>
        </div>
      </div>
    </div>

    <!-- Tab: Library (drag-and-drop components) -->
    <div class="sb-tab-panel" data-tab-panel="library">
      <div class="sb-scroll">
        <div class="sb-section">
          <div class="sb-section-title">Drag to insert</div>
          <div class="lib-hint" style="font-size:10.5px;color:var(--text-3);line-height:1.5;padding:0 6px 10px;">
            <i class="bi bi-info-circle" style="color:var(--info);"></i>
            Drag any block into the page. A blue indicator shows where it will land.
          </div>
          <div id="libList" class="lib-list"></div>
        </div>
      </div>
    </div>

    <!-- Tab: API -->
    <div class="sb-tab-panel" data-tab-panel="api">
      <div class="sb-scroll">
        <div class="sb-section">
          <div class="sb-section-title">API Endpoints</div>
          <div class="api-form">
            <div>
              <div class="api-lbl" style="margin-bottom:4px;">Page ID</div>
              <input type="text" class="api-in" id="apiPageId" placeholder="e.g. 264" value="">
            </div>
            <div>
              <div class="api-lbl" style="margin-bottom:4px;">Load URL (GET)</div>
              <input type="text" class="api-in" id="apiLoadUrl"
                placeholder="/api/index?code=getpagecontent&page_id={page_id}"
                value="/api/index?code=getpagecontent&page_id={page_id}">
            </div>
            <div>
              <div class="api-lbl" style="margin-bottom:4px;">Save URL (POST)</div>
              <input type="text" class="api-in" id="apiSaveUrl"
                placeholder="/api/index?code=savepagecontent&page_id={page_id}"
                value="/api/index?code=savepagecontent&page_id={page_id}">
            </div>
            <div>
              <div class="api-lbl" style="margin-bottom:4px;">Asset Base (iframe)</div>
              <input type="text" class="api-in" id="assetBase"
                placeholder="/  or  https://your-portal.example.com"
                value="/">
            </div>
            <div>
              <div class="api-lbl" style="margin-bottom:4px;display:flex;align-items:center;justify-content:space-between;">
                <span>Custom Headers</span>
                <a href="#" onclick="openAuthHelp(event)" style="color:var(--accent);text-decoration:none;font-size:9.5px;font-weight:700;letter-spacing:0.5px;">
                  <i class="bi bi-shield-lock"></i> AUTH HELP
                </a>
              </div>
              <textarea class="api-in" id="apiHeaders" rows="3"
                placeholder="Authorization: Bearer abc123&#10;X-CSRF-Token: xyz"
                style="resize:vertical;min-height:56px;font-size:10.5px;line-height:1.5;"></textarea>
            </div>
            <div style="font-size:10px;color:var(--text-3);line-height:1.45;margin-top:2px;">
              <i class="bi bi-info-circle"></i> Use <code style="font-family:var(--font-mono);color:var(--accent);">{page_id}</code> as placeholder.
              Asset Base <code style="font-family:var(--font-mono);color:var(--accent);">/</code> = current origin.
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- Footer status -->
    <div class="sb-status">
      <div class="sb-status-row">
        <span class="lbl">Status</span>
        <span class="val" id="statusText">Clean</span>
      </div>
      <div class="sb-status-row">
        <span class="lbl">Modified</span>
        <span class="val" id="dirtyCount">0 / 0</span>
      </div>
    </div>
  </aside>

  <!-- MAIN -->
  <main id="main">
    <iframe id="viewport-frame" title="Page preview"></iframe>
    <!-- Empty state (shown when no JSON loaded) -->
    <div class="empty-state" id="emptyState">
      <div class="empty-state-icon">
        <i class="bi bi-layers"></i>
      </div>
      <div class="empty-state-title">Web Page Editor</div>
      <div class="empty-state-sub">
        Load a page to begin editing. You can fetch from your API, open a local <code style="background:rgba(255,255,255,.08);padding:2px 6px;border-radius:4px;font-family:var(--font-mono);font-size:11.5px;color:var(--accent);">components.json</code>, or pass <code style="background:rgba(255,255,255,.08);padding:2px 6px;border-radius:4px;font-family:var(--font-mono);font-size:11.5px;color:var(--accent);">?page_id=N</code> in the URL to auto-load.
      </div>
      <div class="empty-state-actions">
        <button class="empty-btn" onclick="loadFromAPI()">
          <i class="bi bi-cloud-download"></i> Load from API
        </button>
        <button class="empty-btn outline" onclick="document.getElementById('loadJsonInput').click()">
          <i class="bi bi-upload"></i> Load from File
        </button>
      </div>
    </div>
  </main>

  <!-- PROPERTIES PANEL (RIGHT) -->
  <aside id="propsPanel">
    <div class="props-tabs">
      <button class="props-tab active" data-rtab="properties" onclick="switchRightTab('properties')">
        <i class="bi bi-sliders2"></i><span>Properties</span>
      </button>
      <button class="props-tab" data-rtab="hierarchy" onclick="switchRightTab('hierarchy')">
        <i class="bi bi-diagram-3"></i><span>Hierarchy</span>
      </button>
    </div>

    <!-- Tab: Properties -->
    <div class="props-tab-panel active" data-rtab-panel="properties">
      <div class="props-header">
        <div class="props-header-title">
          <i class="bi bi-sliders2"></i>
          <span>Selected element</span>
        </div>
        <span class="props-tag-chip" id="propsTagChip" style="display:none;"></span>
      </div>
      <div class="props-scroll" id="propsScroll">
        <div class="props-empty" id="propsEmpty">
          <i class="bi bi-cursor"></i>
          <div>Select an element to edit its properties</div>
        </div>

        <div class="props-content" id="propsContent" style="display:none;">
        <!-- Layout section -->
        <details class="props-group" open>
          <summary><i class="bi bi-border-all"></i> Layout &amp; Spacing</summary>
          <div class="props-fields">
            <div class="props-row">
              <label class="props-lbl">Display</label>
              <select class="props-in" id="pStyle_display" data-style="display">
                <option value="">— default —</option>
                <option value="block">block</option>
                <option value="inline-block">inline-block</option>
                <option value="inline">inline</option>
                <option value="flex">flex</option>
                <option value="inline-flex">inline-flex</option>
                <option value="grid">grid</option>
                <option value="none">none (hidden)</option>
              </select>
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Width</label>
                <input class="props-in" id="pStyle_width" data-style="width" placeholder="auto / 100px / 50%">
              </div>
              <div>
                <label class="props-lbl">Height</label>
                <input class="props-in" id="pStyle_height" data-style="height" placeholder="auto">
              </div>
            </div>
            <div>
              <label class="props-lbl">Padding</label>
              <input class="props-in" id="pStyle_padding" data-style="padding" placeholder="10px  or  10px 20px">
            </div>
            <div>
              <label class="props-lbl">Margin</label>
              <input class="props-in" id="pStyle_margin" data-style="margin" placeholder="0 auto">
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Text align</label>
                <select class="props-in" id="pStyle_textAlign" data-style="text-align">
                  <option value="">—</option>
                  <option value="left">left</option>
                  <option value="center">center</option>
                  <option value="right">right</option>
                  <option value="justify">justify</option>
                </select>
              </div>
              <div>
                <label class="props-lbl">Vertical align</label>
                <select class="props-in" id="pStyle_verticalAlign" data-style="vertical-align">
                  <option value="">—</option>
                  <option value="top">top</option>
                  <option value="middle">middle</option>
                  <option value="bottom">bottom</option>
                  <option value="baseline">baseline</option>
                </select>
              </div>
            </div>
          </div>
        </details>

        <!-- Typography -->
        <details class="props-group" open>
          <summary><i class="bi bi-fonts"></i> Typography</summary>
          <div class="props-fields">
            <div>
              <label class="props-lbl">Font family</label>
              <input class="props-in" id="pStyle_fontFamily" data-style="font-family" placeholder="Inter, sans-serif" list="fontFamilyList">
              <datalist id="fontFamilyList">
                <option value="Inter, sans-serif">
                <option value="'Plus Jakarta Sans', sans-serif">
                <option value="Roboto, sans-serif">
                <option value="Arial, sans-serif">
                <option value="Helvetica, sans-serif">
                <option value="Georgia, serif">
                <option value="'Times New Roman', serif">
                <option value="'Courier New', monospace">
                <option value="'JetBrains Mono', monospace">
              </datalist>
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Size</label>
                <input class="props-in" id="pStyle_fontSize" data-style="font-size" placeholder="16px">
              </div>
              <div>
                <label class="props-lbl">Weight</label>
                <select class="props-in" id="pStyle_fontWeight" data-style="font-weight">
                  <option value="">—</option>
                  <option value="300">300 · Light</option>
                  <option value="400">400 · Normal</option>
                  <option value="500">500 · Medium</option>
                  <option value="600">600 · Semibold</option>
                  <option value="700">700 · Bold</option>
                  <option value="800">800 · Extra bold</option>
                  <option value="900">900 · Black</option>
                </select>
              </div>
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Line height</label>
                <input class="props-in" id="pStyle_lineHeight" data-style="line-height" placeholder="1.5">
              </div>
              <div>
                <label class="props-lbl">Letter spacing</label>
                <input class="props-in" id="pStyle_letterSpacing" data-style="letter-spacing" placeholder="0.02em">
              </div>
            </div>
            <div>
              <label class="props-lbl">Text color</label>
              <div class="props-color-row">
                <input type="color" class="props-color" id="pStyleColor_color" data-style-color="color">
                <input type="text" class="props-in" id="pStyle_color" data-style="color" placeholder="#333333">
              </div>
            </div>
            <div>
              <label class="props-lbl">Text transform</label>
              <select class="props-in" id="pStyle_textTransform" data-style="text-transform">
                <option value="">—</option>
                <option value="none">none</option>
                <option value="uppercase">UPPERCASE</option>
                <option value="lowercase">lowercase</option>
                <option value="capitalize">Capitalize</option>
              </select>
            </div>
          </div>
        </details>

        <!-- Background -->
        <details class="props-group">
          <summary><i class="bi bi-palette"></i> Background</summary>
          <div class="props-fields">
            <div>
              <label class="props-lbl">Background color</label>
              <div class="props-color-row">
                <input type="color" class="props-color" id="pStyleColor_backgroundColor" data-style-color="background-color">
                <input type="text" class="props-in" id="pStyle_backgroundColor" data-style="background-color" placeholder="transparent / #fff">
              </div>
            </div>
            <div>
              <label class="props-lbl">Background image</label>
              <div style="display:flex;gap:6px;align-items:stretch;">
                <input class="props-in" id="pStyle_backgroundImage" data-style="background-image" placeholder="url(/bg.png) or url(data:...)" style="flex:1;min-width:0;">
                <input type="file" id="pBgImageFile" accept="image/*" style="display:none;">
                <button class="mini-btn" onclick="document.getElementById('pBgImageFile').click()" title="Upload image (stored as base64)" style="padding:0 10px;flex-shrink:0;">
                  <i class="bi bi-cloud-arrow-up"></i> Upload
                </button>
                <button class="mini-btn" onclick="clearBgImage()" title="Clear" style="padding:0 8px;flex-shrink:0;">
                  <i class="bi bi-x-lg"></i>
                </button>
              </div>
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Size</label>
                <select class="props-in" id="pStyle_backgroundSize" data-style="background-size">
                  <option value="">—</option>
                  <option value="cover">cover</option>
                  <option value="contain">contain</option>
                  <option value="auto">auto</option>
                  <option value="100% 100%">100% 100%</option>
                </select>
              </div>
              <div>
                <label class="props-lbl">Repeat</label>
                <select class="props-in" id="pStyle_backgroundRepeat" data-style="background-repeat">
                  <option value="">—</option>
                  <option value="no-repeat">no-repeat</option>
                  <option value="repeat">repeat</option>
                  <option value="repeat-x">repeat-x</option>
                  <option value="repeat-y">repeat-y</option>
                </select>
              </div>
            </div>
            <div>
              <label class="props-lbl">Position</label>
              <input class="props-in" id="pStyle_backgroundPosition" data-style="background-position" placeholder="center center">
            </div>
          </div>
        </details>

        <!-- Border & Shadow -->
        <details class="props-group">
          <summary><i class="bi bi-bounding-box"></i> Border &amp; Shadow</summary>
          <div class="props-fields">
            <div>
              <label class="props-lbl">Border</label>
              <input class="props-in" id="pStyle_border" data-style="border" placeholder="1px solid #ccc">
            </div>
            <div>
              <label class="props-lbl">Border radius</label>
              <input class="props-in" id="pStyle_borderRadius" data-style="border-radius" placeholder="8px / 50%">
            </div>
            <div>
              <label class="props-lbl">Box shadow</label>
              <input class="props-in" id="pStyle_boxShadow" data-style="box-shadow" placeholder="0 2px 8px rgba(0,0,0,.1)">
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Opacity</label>
                <input class="props-in" id="pStyle_opacity" data-style="opacity" placeholder="1">
              </div>
              <div>
                <label class="props-lbl">Cursor</label>
                <select class="props-in" id="pStyle_cursor" data-style="cursor">
                  <option value="">—</option>
                  <option value="pointer">pointer</option>
                  <option value="default">default</option>
                  <option value="text">text</option>
                  <option value="not-allowed">not-allowed</option>
                  <option value="grab">grab</option>
                </select>
              </div>
            </div>
          </div>
        </details>

        <!-- Flexbox -->
        <details class="props-group">
          <summary><i class="bi bi-distribute-horizontal"></i> Flex / Grid</summary>
          <div class="props-fields">
            <div>
              <label class="props-lbl">Flex direction</label>
              <select class="props-in" id="pStyle_flexDirection" data-style="flex-direction">
                <option value="">—</option>
                <option value="row">row</option>
                <option value="row-reverse">row-reverse</option>
                <option value="column">column</option>
                <option value="column-reverse">column-reverse</option>
              </select>
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Justify</label>
                <select class="props-in" id="pStyle_justifyContent" data-style="justify-content">
                  <option value="">—</option>
                  <option value="flex-start">start</option>
                  <option value="center">center</option>
                  <option value="flex-end">end</option>
                  <option value="space-between">between</option>
                  <option value="space-around">around</option>
                  <option value="space-evenly">evenly</option>
                </select>
              </div>
              <div>
                <label class="props-lbl">Align items</label>
                <select class="props-in" id="pStyle_alignItems" data-style="align-items">
                  <option value="">—</option>
                  <option value="flex-start">start</option>
                  <option value="center">center</option>
                  <option value="flex-end">end</option>
                  <option value="stretch">stretch</option>
                </select>
              </div>
            </div>
            <div class="props-row-split">
              <div>
                <label class="props-lbl">Gap</label>
                <input class="props-in" id="pStyle_gap" data-style="gap" placeholder="12px">
              </div>
              <div>
                <label class="props-lbl">Flex wrap</label>
                <select class="props-in" id="pStyle_flexWrap" data-style="flex-wrap">
                  <option value="">—</option>
                  <option value="nowrap">nowrap</option>
                  <option value="wrap">wrap</option>
                  <option value="wrap-reverse">wrap-reverse</option>
                </select>
              </div>
            </div>
          </div>
        </details>

        <!-- CSS Classes -->
        <details class="props-group">
          <summary><i class="bi bi-braces"></i> CSS Classes &amp; Raw</summary>
          <div class="props-fields">
            <div>
              <label class="props-lbl">class</label>
              <input class="props-in" id="pClassName" placeholder="my-class another-class">
            </div>
            <div>
              <label class="props-lbl">style (raw)</label>
              <textarea class="props-in" id="pRawStyle" rows="3" style="font-family:var(--font-mono);font-size:10.5px;" placeholder="color: red; padding: 10px;"></textarea>
              <div style="font-size:10px;color:var(--text-3);margin-top:4px;">
                Edit the full inline <code style="font-family:var(--font-mono);">style</code> attribute directly.
              </div>
            </div>
          </div>
        </details>
      </div>
      </div>
    </div>

    <!-- Tab: Hierarchy -->
    <div class="props-tab-panel" data-rtab-panel="hierarchy">
      <div class="props-header">
        <div class="props-header-title">
          <i class="bi bi-diagram-3"></i>
          <span>DOM tree</span>
        </div>
        <button class="mini-btn" onclick="refreshHierarchy()" title="Rebuild the tree from the current iframe">
          <i class="bi bi-arrow-clockwise"></i>
        </button>
      </div>
      <div class="hierarchy-toolbar">
        <input type="text" id="hierSearch" class="api-in" placeholder="Filter by tag or class..."
          style="font-size:11px;padding:5px 9px;" oninput="filterHierarchy(this.value)">
        <div class="hierarchy-legend">
          <span><i class="bi bi-square-fill" style="color:#4f6ef7;"></i> container</span>
          <span><i class="bi bi-fonts" style="color:#10b981;"></i> text</span>
          <span><i class="bi bi-image" style="color:#a78bfa;"></i> image</span>
          <span><i class="bi bi-link-45deg" style="color:#06b6d4;"></i> link</span>
        </div>
      </div>
      <div class="props-scroll" id="hierScroll">
        <div class="props-empty" id="hierEmpty">
          <i class="bi bi-diagram-3"></i>
          <div>Load components to see the DOM tree</div>
        </div>
        <div id="hierTree" class="hier-tree" style="display:none;"></div>
      </div>
    </div>
  </aside>
</div>

<!-- ═══════════════════════════════════════════
     SOURCE EDITOR MODAL
══════════════════════════════════════════════ -->
<div class="modal-backdrop" id="srcModalBackdrop">
  <div class="modal">
    <div class="modal-header">
      <div class="modal-header-icon"><i class="bi bi-code-slash"></i></div>
      <div class="modal-header-text">
        <span class="modal-header-eyebrow">Edit Component Source</span>
        <span class="modal-header-title" id="srcModalTitle">MARCOMM - HEADER</span>
      </div>
      <button class="modal-close" onclick="closeSourceModal()"><i class="bi bi-x-lg"></i></button>
    </div>

    <div class="modal-tabs">
      <button class="modal-tab active" onclick="showSrcTab('editor')"><i class="bi bi-braces"></i> HTML Source</button>
      <button class="modal-tab" onclick="showSrcTab('preview')"><i class="bi bi-eye"></i> Preview</button>
    </div>

    <div class="modal-body">
      <div class="modal-tab-panel active" id="srcTabEditor">
        <div id="srcEditor"></div>
      </div>
      <div class="modal-tab-panel" id="srcTabPreview">
        <iframe id="previewPanel" style="width:100%;height:100%;border:none;background:#fff;"></iframe>
      </div>
    </div>

    <div class="modal-footer">
      <div class="modal-footer-info">
        <i class="bi bi-info-circle-fill"></i>
        <span>Use <span class="kbd">Ctrl</span><span class="kbd">F</span> to search, <span class="kbd">Ctrl</span><span class="kbd">H</span> to replace.</span>
      </div>
      <button class="m-btn ghost" onclick="resetCurrentComponent()" title="Revert to original"><i class="bi bi-arrow-counterclockwise"></i> Revert</button>
      <button class="m-btn ghost" onclick="closeSourceModal()">Cancel</button>
      <button class="m-btn primary" onclick="applySourceEdit()"><i class="bi bi-check2"></i> Apply</button>
    </div>
  </div>
</div>

<!-- ═══════════════════════════════════════════
     SAVE PREVIEW MODAL
══════════════════════════════════════════════ -->
<div class="modal-backdrop" id="saveModalBackdrop">
  <div class="modal" style="max-width: 880px; height: auto; max-height: 88vh;">
    <div class="modal-header">
      <div class="modal-header-icon" style="background:linear-gradient(135deg,var(--success),#059669);"><i class="bi bi-cloud-arrow-up"></i></div>
      <div class="modal-header-text">
        <span class="modal-header-eyebrow">Review &amp; Send</span>
        <span class="modal-header-title">Save Component Changes</span>
      </div>
      <button class="modal-close" onclick="closeSaveModal()"><i class="bi bi-x-lg"></i></button>
    </div>

    <div class="save-summary">
      <div class="save-stat-row">
        <div class="save-stat">
          <span class="save-stat-lbl">Total components</span>
          <span class="save-stat-val" id="saveTotalComp">0</span>
        </div>
        <div class="save-stat">
          <span class="save-stat-lbl">Modified</span>
          <span class="save-stat-val accent" id="saveDirtyComp">0</span>
        </div>
        <div class="save-stat">
          <span class="save-stat-lbl">Payload size</span>
          <span class="save-stat-val" id="savePayloadSize">0 KB</span>
        </div>
      </div>
    </div>

    <div class="save-list">
      <div class="save-list-title">Components in payload</div>
      <div id="saveList"></div>
    </div>

    <div class="modal-body" style="padding: 12px 20px 0; display: flex; flex-direction: column; gap: 8px; overflow: hidden;">
      <div style="display:flex;align-items:center;justify-content:space-between;">
        <span class="save-list-title" style="margin:0;">JSON payload preview</span>
        <button class="mini-btn" onclick="copyPayload()"><i class="bi bi-clipboard"></i> Copy</button>
      </div>
      <pre id="savePayloadPreview" style="
        flex:1; overflow:auto; margin:0;
        background: var(--bg-0);
        border: 1px solid var(--border);
        border-radius: 8px;
        padding: 12px 14px;
        font-family: var(--font-mono);
        font-size: 10.5px;
        color: var(--text-1);
        line-height: 1.55;
        min-height: 140px;
        max-height: 220px;
      "></pre>
    </div>

    <div class="modal-footer">
      <div class="modal-footer-info">
        <i class="bi bi-shield-check"></i>
        <span>Payload will be sent as <strong style="color:var(--text-1);">POST</strong> to the configured API URL.</span>
      </div>
      <button class="m-btn ghost" onclick="downloadPayload()"><i class="bi bi-download"></i> Download JSON</button>
      <button class="m-btn ghost" onclick="closeSaveModal()">Cancel</button>
      <button class="m-btn success" onclick="sendToServer()"><i class="bi bi-send"></i> Send to Server</button>
    </div>
  </div>
</div>

<!-- ═══════════════════════════════════════════
     NEW COMPONENT MODAL
══════════════════════════════════════════════ -->
<div class="modal-backdrop" id="newCompBackdrop">
  <div class="modal" style="max-width: 540px; height: auto; max-height: 85vh;">
    <div class="modal-header">
      <div class="modal-header-icon" style="background:linear-gradient(135deg,#10b981,#059669);">
        <i class="bi bi-plus-square-dotted"></i>
      </div>
      <div class="modal-header-text">
        <span class="modal-header-eyebrow">Add New Component</span>
        <span class="modal-header-title">Create a new page section</span>
      </div>
      <button class="modal-close" onclick="closeNewCompModal()"><i class="bi bi-x-lg"></i></button>
    </div>

    <div class="modal-body" style="padding: 18px 22px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px;">
      <div>
        <div class="elem-lbl">Component name</div>
        <input type="text" id="newCompName" class="elem-in" placeholder="MARCOMM - MY NEW SECTION">
        <div style="font-size:10px;color:var(--text-3);margin-top:4px;">
          Conventionally uppercase with a portal prefix (e.g. <code style="font-family:var(--font-mono);color:var(--accent);">MARCOMM - </code>). Must be unique.
        </div>
      </div>

      <div>
        <div class="elem-lbl">Starter template</div>
        <select id="newCompTemplate" class="elem-in" style="height:34px;" onchange="onNewCompTemplateChange()">
          <option value="empty">Empty &lt;div&gt;</option>
          <option value="section">Section with heading + paragraph</option>
          <option value="banner">Banner with image &amp; button</option>
          <option value="grid2">Two-column grid</option>
          <option value="cards3">Three feature cards</option>
          <option value="custom">Custom (paste HTML below)</option>
        </select>
      </div>

      <div>
        <div class="elem-lbl" style="display:flex;justify-content:space-between;align-items:center;">
          <span>HTML content</span>
          <span style="font-family:var(--font-mono);font-size:10px;color:var(--text-3);" id="newCompCharCount">0 chars</span>
        </div>
        <textarea id="newCompHtml" class="elem-in" rows="8"
          style="resize:vertical;min-height:160px;font-family:var(--font-mono);font-size:11px;line-height:1.5;"
          oninput="updateNewCompCharCount()"
          placeholder="<div>Your HTML here</div>"></textarea>
      </div>

      <div>
        <div class="elem-lbl">Insert position</div>
        <select id="newCompInsertAt" class="elem-in" style="height:34px;">
          <option value="before-footer">Before FOOTER (end of main content)</option>
          <option value="after-home">After HOME</option>
          <option value="before-home">Before HOME</option>
          <option value="after-header">After HEADER</option>
          <option value="end">End of list</option>
        </select>
      </div>

      <div class="elem-hint">
        <i class="bi bi-info-circle"></i>
        The new component will be marked <strong style="color:#10b981;">NEW</strong> and sent to the save API with <code style="font-family:var(--font-mono);">_isNew: true</code> so your server inserts it.
      </div>
    </div>

    <div class="modal-footer">
      <button class="m-btn ghost" onclick="closeNewCompModal()">Cancel</button>
      <button class="m-btn success" onclick="createNewComponent()"><i class="bi bi-plus-lg"></i> Create</button>
    </div>
  </div>
</div>

<!-- ═══════════════════════════════════════════
     ELEMENT EDITOR MODAL (text / image / link)
══════════════════════════════════════════════ -->
<div class="modal-backdrop" id="elemModalBackdrop">
  <div class="modal" style="max-width: 560px; height: auto; max-height: 85vh;">
    <div class="modal-header">
      <div class="modal-header-icon" id="elemModalIcon" style="background:linear-gradient(135deg,#10b981,#059669);">
        <i class="bi bi-pencil-square"></i>
      </div>
      <div class="modal-header-text">
        <span class="modal-header-eyebrow" id="elemModalEyebrow">Edit Element</span>
        <span class="modal-header-title" id="elemModalTitle">Edit text</span>
      </div>
      <button class="modal-close" onclick="closeElemModal()"><i class="bi bi-x-lg"></i></button>
    </div>

    <div class="modal-body" style="padding: 18px 22px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px;">

      <!-- TEXT variant -->
      <div class="elem-variant" id="elemVariantText" style="display:none; flex-direction:column; gap:12px;">
        <div>
          <div class="elem-lbl">Text content</div>
          <textarea id="elemText" class="elem-in" rows="4" placeholder="Enter text…"
            style="resize:vertical; min-height:90px; font-family:var(--font); font-size:13px;"></textarea>
        </div>
        <div class="elem-hint">
          <i class="bi bi-info-circle"></i>
          Plain-text edit — tag <span id="elemTextTag" class="tag-chip"></span> is preserved.
        </div>
      </div>

      <!-- IMAGE variant -->
      <div class="elem-variant" id="elemVariantImage" style="display:none; flex-direction:column; gap:12px;">
        <div>
          <div class="elem-lbl" style="display:flex;align-items:center;justify-content:space-between;">
            <span>Preview</span>
            <span id="elemImgSize" style="font-size:10px;color:var(--text-3);font-family:var(--font-mono);"></span>
          </div>
          <div id="elemImgPreviewWrap" style="
            background: repeating-conic-gradient(#1a2030 0% 25%, #232a3d 0% 50%) 50% / 20px 20px;
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 12px;
            display: flex; align-items: center; justify-content: center;
            min-height: 140px;
          ">
            <img id="elemImgPreview" style="max-width:100%; max-height:220px; display:block;" alt="">
          </div>
        </div>

        <div>
          <div class="elem-lbl">Replace image</div>
          <label id="elemImgDrop" for="elemImgFile" style="
            display:block; cursor:pointer;
            border: 2px dashed var(--border-hl);
            border-radius: 8px;
            padding: 14px;
            text-align: center;
            color: var(--text-2); font-size: 12px;
            transition: all .15s;
            background: rgba(139,92,246,.04);
          ">
            <i class="bi bi-cloud-arrow-up" style="font-size:18px;color:#a78bfa;"></i>
            <div style="margin-top:4px;">Drop file or click to upload (saved as base64)</div>
          </label>
          <input type="file" id="elemImgFile" accept="image/*" style="display:none;">
        </div>

        <div>
          <div class="elem-lbl">Image URL (src)</div>
          <input type="text" id="elemImgSrc" class="elem-in" placeholder="/path/to/image.png or data:image/…">
        </div>

        <div style="display:flex;gap:10px;">
          <div style="flex:1;">
            <div class="elem-lbl">Alt text</div>
            <input type="text" id="elemImgAlt" class="elem-in" placeholder="Describe the image">
          </div>
          <div style="flex:1;">
            <div class="elem-lbl">Title (tooltip)</div>
            <input type="text" id="elemImgTitle" class="elem-in" placeholder="Optional">
          </div>
        </div>
      </div>

      <!-- LINK variant -->
      <div class="elem-variant" id="elemVariantLink" style="display:none; flex-direction:column; gap:12px;">
        <div id="elemLinkTextRow">
          <div class="elem-lbl">Link text</div>
          <input type="text" id="elemLinkText" class="elem-in" placeholder="Click here">
        </div>
        <div>
          <div class="elem-lbl">URL (href)</div>
          <input type="text" id="elemLinkHref" class="elem-in" placeholder="https://example.com or /relative/path or #anchor">
        </div>
        <div style="display:flex;gap:10px;">
          <div style="flex:1;">
            <div class="elem-lbl">Opens in</div>
            <select id="elemLinkTarget" class="elem-in" style="height:34px;">
              <option value="">Same tab (default)</option>
              <option value="_blank">New tab (_blank)</option>
              <option value="_self">Same tab (_self)</option>
              <option value="_parent">Parent frame</option>
              <option value="_top">Top frame</option>
            </select>
          </div>
          <div style="flex:1;">
            <div class="elem-lbl">Title (tooltip)</div>
            <input type="text" id="elemLinkTitle" class="elem-in" placeholder="Optional">
          </div>
        </div>
        <div class="elem-hint" id="elemLinkNonTextHint" style="display:none;">
          <i class="bi bi-info-circle"></i>
          This link wraps non-text content (e.g. an image) — text editing is disabled.
        </div>
      </div>

    </div>

    <div class="modal-footer">
      <div class="modal-footer-info">
        <i class="bi bi-lightbulb"></i>
        <span><span class="kbd">Esc</span> to cancel, <span class="kbd">Enter</span> to apply (single-line fields).</span>
      </div>
      <button class="m-btn ghost" onclick="closeElemModal()">Cancel</button>
      <button class="m-btn success" onclick="applyElemEdit()"><i class="bi bi-check2"></i> Apply</button>
    </div>
  </div>
</div>

<!-- Element-editor styles -->
<style>
.elem-lbl {
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.9px; text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 5px;
}
.elem-in {
  width: 100%;
  padding: 9px 11px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text-1);
  font-family: var(--font-mono);
  font-size: 12px;
  outline: none;
  transition: border-color .15s, background .15s;
}
.elem-in:focus {
  border-color: var(--brand);
  background: var(--bg-0);
}
.elem-hint {
  font-size: 11px;
  color: var(--text-3);
  line-height: 1.5;
  display: flex; align-items: center; gap: 6px;
}
.elem-hint i { color: var(--info); }
.tag-chip {
  font-family: var(--font-mono);
  font-size: 10px; font-weight: 700;
  background: rgba(16,185,129,.15);
  color: var(--success);
  padding: 1px 6px;
  border-radius: 4px;
  text-transform: lowercase;
}
#elemImgDrop:hover, #elemImgDrop.drag-over {
  border-color: #a78bfa;
  background: rgba(139,92,246,.1);
  color: var(--text-1);
}
</style>

<!-- ═══════════════════════════════════════════
     AUTH HELP MODAL
══════════════════════════════════════════════ -->
<div class="modal-backdrop" id="authHelpBackdrop">
  <div class="modal" style="max-width: 720px; height: auto; max-height: 88vh;">
    <div class="modal-header">
      <div class="modal-header-icon" style="background:linear-gradient(135deg,#a78bfa,#7c5ef5);"><i class="bi bi-shield-lock"></i></div>
      <div class="modal-header-text">
        <span class="modal-header-eyebrow">Authentication &amp; CORS</span>
        <span class="modal-header-title">Connecting to a JS-protected portal</span>
      </div>
      <button class="modal-close" onclick="closeAuthHelp()"><i class="bi bi-x-lg"></i></button>
    </div>

    <div class="modal-body" style="overflow-y:auto; padding: 18px 22px; gap: 16px;">
      <div style="display:flex;flex-direction:column;gap:18px;color:var(--text-1);font-size:13px;line-height:1.6;">

        <p style="color:var(--text-2);">
          If your portal requires login, the browser needs a way to send your session with API calls.
          Pick the option that fits how you host this editor:
        </p>

        <!-- Option A -->
        <div style="background:var(--bg-2);border:1px solid var(--border);border-left:3px solid var(--success);border-radius:8px;padding:14px 16px;">
          <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
            <span style="background:var(--success);color:#fff;font-size:10px;font-weight:800;padding:2px 8px;border-radius:10px;letter-spacing:0.8px;">RECOMMENDED</span>
            <strong style="font-size:14px;">A. Host the editor on the same origin as the API</strong>
          </div>
          <p style="margin-bottom:8px;color:var(--text-2);">
            Save this file inside your Yii2 app (e.g. <code style="font-family:var(--font-mono);color:var(--accent);background:var(--bg-0);padding:1px 6px;border-radius:3px;">/web/admin/editor.html</code>)
            so the URL is something like:
          </p>
          <pre style="background:var(--bg-0);border:1px solid var(--border);border-radius:6px;padding:8px 12px;font-family:var(--font-mono);font-size:11px;color:var(--accent);margin:0;overflow-x:auto;">https://brs.dynaweb4.work/admin/editor.html</pre>
          <p style="margin-top:8px;color:var(--text-2);">
            Log into the portal in the same browser first, then open the editor.
            The session cookie is automatically sent with every <code style="font-family:var(--font-mono);color:var(--accent);background:var(--bg-0);padding:1px 6px;border-radius:3px;">fetch</code> call
            because it's same-origin. No extra config needed.
          </p>
        </div>

        <!-- Option B -->
        <div style="background:var(--bg-2);border:1px solid var(--border);border-left:3px solid var(--brand);border-radius:8px;padding:14px 16px;">
          <strong style="font-size:14px;">B. Use a bearer token (if your API supports it)</strong>
          <p style="margin-top:8px;margin-bottom:8px;color:var(--text-2);">
            Put this in the <strong>Custom Headers</strong> field:
          </p>
          <pre style="background:var(--bg-0);border:1px solid var(--border);border-radius:6px;padding:8px 12px;font-family:var(--font-mono);font-size:11px;color:var(--text-1);margin:0;overflow-x:auto;">Authorization: Bearer YOUR_TOKEN_HERE</pre>
          <p style="margin-top:8px;color:var(--text-2);">
            Works cross-origin (including <code style="font-family:var(--font-mono);background:var(--bg-0);padding:1px 6px;border-radius:3px;">file://</code>)
            as long as your API's CORS settings allow the <code style="font-family:var(--font-mono);background:var(--bg-0);padding:1px 6px;border-radius:3px;">Authorization</code> header.
          </p>
        </div>

        <!-- Option C -->
        <div style="background:var(--bg-2);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:8px;padding:14px 16px;">
          <strong style="font-size:14px;">C. Paste your session cookie manually</strong>
          <p style="margin-top:8px;margin-bottom:8px;color:var(--text-2);">
            Log into the portal in your browser, open DevTools → Application → Cookies, copy the session cookie
            (e.g. <code style="font-family:var(--font-mono);color:var(--accent);background:var(--bg-0);padding:1px 6px;border-radius:3px;">PHPSESSID</code>),
            then add to Custom Headers:
          </p>
          <pre style="background:var(--bg-0);border:1px solid var(--border);border-radius:6px;padding:8px 12px;font-family:var(--font-mono);font-size:11px;color:var(--text-1);margin:0;overflow-x:auto;">Cookie: PHPSESSID=abc123xyz...</pre>
          <p style="margin-top:8px;color:var(--text-2);font-size:12px;">
            <i class="bi bi-exclamation-triangle-fill" style="color:var(--warning);"></i>
            Most browsers <strong>forbid scripts from setting the Cookie header</strong> for security, so this usually fails unless the
            editor is served from the same domain. If it doesn't work, use Option A or D instead.
          </p>
        </div>

        <!-- Option D -->
        <div style="background:var(--bg-2);border:1px solid var(--border);border-left:3px solid var(--text-3);border-radius:8px;padding:14px 16px;">
          <strong style="font-size:14px;">D. Download, edit, re-upload (always works)</strong>
          <p style="margin-top:8px;color:var(--text-2);">
            If your portal's API is served behind a login and you can't configure the above:
          </p>
          <ol style="margin-top:8px;margin-left:20px;color:var(--text-2);line-height:1.7;">
            <li>In your browser, log into the portal, then visit the API URL directly to download the JSON</li>
            <li>Save it as <code style="font-family:var(--font-mono);color:var(--accent);background:var(--bg-0);padding:1px 6px;border-radius:3px;">components.json</code></li>
            <li>Click <strong>Load File</strong> here and edit</li>
            <li>Click <strong>Save Changes</strong> → <strong>Download JSON</strong></li>
            <li>POST the saved file to your API using curl, Postman, or your own tool</li>
          </ol>
        </div>

        <!-- CORS note -->
        <div style="background:rgba(6,182,212,.08);border:1px solid rgba(6,182,212,.25);border-radius:8px;padding:12px 16px;">
          <strong style="font-size:13px;color:var(--info);"><i class="bi bi-info-circle-fill"></i> CORS reminder</strong>
          <p style="margin-top:6px;color:var(--text-2);font-size:12px;">
            For cross-origin API calls with credentials, your Yii2 response must include:
          </p>
          <pre style="background:var(--bg-0);border:1px solid var(--border);border-radius:6px;padding:8px 12px;font-family:var(--font-mono);font-size:10.5px;color:var(--text-1);margin-top:6px;overflow-x:auto;">Access-Control-Allow-Origin: &lt;exact editor origin, not *&gt;
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, OPTIONS</pre>
        </div>

      </div>
    </div>

    <div class="modal-footer">
      <div class="modal-footer-info">
        <i class="bi bi-lightbulb-fill"></i>
        <span>Option A (same-origin) is almost always the simplest path.</span>
      </div>
      <button class="m-btn primary" onclick="closeAuthHelp()">Got it</button>
    </div>
  </div>
</div>

<!-- ═══════════════════════════════════════════
     LOADER + TOASTS
══════════════════════════════════════════════ -->
<div class="loader-overlay" id="loaderOverlay">
  <div class="loader-card">
    <div class="spinner"></div>
    <div class="loader-text" id="loaderText">Loading…</div>
  </div>
</div>
<div id="toastWrap"></div>

<script>
/* ═══════════════════════════════════════════
   STATE
═══════════════════════════════════════════ */
const STATE = {
  components: [],         // array of { content_id, content_name, content_details, content_is_php, content_status, _originalDetails, _isNew }
  originalJson: null,     // the original parsed JSON (full object as received)
  header: null,           // { header_id, header_content, header_is_php, header_description, _originalContent }
  footer: null,           // { footer_id, footer_content, footer_is_php, footer_description, _originalContent }
  dirty: new Set(),       // indices of modified components
  dirtyHeader: false,     // true if the header has been edited
  dirtyFooter: false,     // true if the footer has been edited
  currentEditIdx: -1,     // index being edited in modal (-1 = header, -2 = footer)
  currentElemCodeMode: false,
  aceEditor: null,
  headTemplate: '',       // [legacy] <head> inner HTML extracted from page-source.html — used only when JSON lacks a header
  nextNewCompId: -1,      // counter for locally-assigned temporary IDs on new components (negative = new)
};

/* Component classification
   Infrastructure components wrap the visible content: they usually open DOM
   containers at the top of the page and close them at the bottom. Detected by
   a name suffix (e.g. "LEGAL - WRAPPER START", "MARCOMM - WRAPPER END").
   Visual components are the ones the user actually edits. */
const INFRA_SUFFIX_RE = /-\s*WRAPPER\s+(START|END)\s*$/i;
function isInfra(name) { return !!(name && INFRA_SUFFIX_RE.test(name)); }
function isVisual(name) { return VISUAL_NAMES.includes(name); }

/* ═══════════════════════════════════════════
   TOAST / LOADER
═══════════════════════════════════════════ */
function toast(msg, type = 'info', ms = 3200) {
  const wrap = document.getElementById('toastWrap');
  const el = document.createElement('div');
  el.className = 'toast ' + type;
  const icons = { success: 'check-circle-fill', error: 'x-circle-fill', warning: 'exclamation-triangle-fill', info: 'info-circle-fill' };
  el.innerHTML = `<i class="bi bi-${icons[type] || 'info-circle-fill'}"></i><span>${msg}</span>`;
  wrap.appendChild(el);
  setTimeout(() => {
    el.style.transition = 'opacity .25s, transform .25s';
    el.style.opacity = '0'; el.style.transform = 'translateX(40px)';
    setTimeout(() => el.remove(), 260);
  }, ms);
}
function showLoader(text = 'Loading…') {
  document.getElementById('loaderText').textContent = text;
  document.getElementById('loaderOverlay').classList.add('visible');
}
function hideLoader() { document.getElementById('loaderOverlay').classList.remove('visible'); }

/* ═══════════════════════════════════════════
   URL & SANITIZATION HELPERS
═══════════════════════════════════════════ */
// Build a concrete URL from a template containing {page_id}
function resolveUrl(template, pageId) {
  if (!template) return '';
  return template.replace(/\{page_id\}/gi, encodeURIComponent(pageId || ''));
}

// Parse the Custom Headers textarea into a plain object suitable for fetch().
// Format: one "Header-Name: value" per line. Blank lines and lines starting
// with # are ignored.
function parseCustomHeaders() {
  const raw = document.getElementById('apiHeaders')?.value || '';
  const out = {};
  raw.split(/\r?\n/).forEach(line => {
    line = line.trim();
    if (!line || line.startsWith('#')) return;
    const idx = line.indexOf(':');
    if (idx < 1) return;
    const name = line.substring(0, idx).trim();
    const value = line.substring(idx + 1).trim();
    if (name && value) out[name] = value;
  });
  return out;
}

// Domains to strip from loaded content to keep all paths relative.
// Add more here if you have additional portals.
const STRIP_DOMAINS = [
  'https://brspace.bankrakyat.com.my',
  'http://brspace.bankrakyat.com.my',
];

function stripAbsoluteUrlsFromString(s) {
  if (typeof s !== 'string') return { text: s, count: 0 };
  let count = 0;
  let out = s;
  STRIP_DOMAINS.forEach(d => {
    const re = new RegExp(d.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
    out = out.replace(re, () => { count++; return ''; });
  });
  return { text: out, count };
}

function stripAbsoluteUrlsFromComponents(components) {
  let total = 0;
  components.forEach(c => {
    const { text, count } = stripAbsoluteUrlsFromString(c.content_details);
    c.content_details = text;
    total += count;
  });
  return total;
}

/* ═══════════════════════════════════════════
   LOAD COMPONENTS (file / API / demo)
═══════════════════════════════════════════ */
document.getElementById('loadJsonInput').addEventListener('change', async (e) => {
  const f = e.target.files?.[0];
  if (!f) return;
  try {
    const text = await f.text();
    const parsed = JSON.parse(text);
    loadComponents(parsed, { source: 'file: ' + f.name });
  } catch (err) {
    toast('Could not parse file: ' + err.message, 'error');
  }
  e.target.value = '';
});

async function loadFromAPI() {
  const tmpl = document.getElementById('apiLoadUrl').value.trim();
  const pid  = document.getElementById('apiPageId').value.trim();
  if (!tmpl) { toast('Set the Load URL first', 'warning'); return; }
  if (!pid)  { toast('Set a Page ID first', 'warning'); return; }
  const url = resolveUrl(tmpl, pid);
  showLoader('Fetching components from API…');
  try {
    const res = await fetch(url, {
      method: 'GET',
      headers: { 'Accept': 'application/json', ...parseCustomHeaders() },
      credentials: 'include',
    });
    if (!res.ok) {
      hideLoader();
      let bodySnip = '';
      try { bodySnip = (await res.text()).substring(0, 200); } catch(_) {}
      toast(`API ${res.status} ${res.statusText}${bodySnip ? ' — ' + bodySnip : ''}`, 'error', 6000);
      // If we get a redirect or 401, it's almost certainly an auth problem
      if (res.status === 401 || res.status === 403 || res.status === 302) {
        setTimeout(() => toast('Tip: click "Auth Help" in the sidebar for options.', 'info', 5000), 500);
      }
      return;
    }
    const parsed = await res.json();
    hideLoader();
    // On successful API load, default the Asset Base to "/" — the content is
    // now relative and will resolve against whatever origin is serving the editor.
    // User can change it back to a specific host if they need to.
    const assetBaseEl = document.getElementById('assetBase');
    if (assetBaseEl && assetBaseEl.value.trim() !== '/') {
      assetBaseEl.value = '/';
    }
    loadComponents(parsed, { source: 'API page_id=' + pid });
    // Make the loaded state bookmarkable
    syncUrlWithPageId(pid);
  } catch (err) {
    hideLoader();
    toast('Network error: ' + (err.message || 'Could not reach API') + '. See Auth Help.', 'error', 7000);
    console.error(err);
  }
}

function loadComponents(parsed, opts = {}) {
  if (!parsed || !Array.isArray(parsed.data)) {
    toast('Invalid JSON: missing "data" array', 'error');
    return;
  }
  STATE.originalJson = parsed;

  // Map components and respect content_order. If order is missing or duplicated,
  // fall back to the array index the API sent.
  STATE.components = parsed.data.map((c, i) => ({
    ...c,
    content_order: (typeof c.content_order === 'number' && c.content_order > 0) ? c.content_order : (i + 1),
    _originalDetails: c.content_details,
    _isNew: false,
  }));

  // Sort by content_order so the editor displays the canonical page order,
  // regardless of how the API returned the rows.
  STATE.components.sort((a, b) => (a.content_order || 0) - (b.content_order || 0));
  // Re-number 1..N in case the incoming values were sparse (1, 5, 9, ...) so
  // subsequent reorders produce clean sequential values.
  STATE.components.forEach((c, i) => { c.content_order = i + 1; });

  // Header / footer
  if (parsed.header && typeof parsed.header.header_content === 'string') {
    STATE.header = { ...parsed.header, _originalContent: parsed.header.header_content };
  } else { STATE.header = null; }
  if (parsed.footer && typeof parsed.footer.footer_content === 'string') {
    STATE.footer = { ...parsed.footer, _originalContent: parsed.footer.footer_content };
  } else { STATE.footer = null; }

  // Auto-strip absolute URLs so paths stay portable
  const stripped = stripAbsoluteUrlsFromComponents(STATE.components);
  let stripHdr = 0, stripFtr = 0;
  if (STATE.header) {
    const r = stripAbsoluteUrlsFromString(STATE.header.header_content);
    STATE.header.header_content = r.text;
    STATE.header._originalContent = r.text;
    stripHdr = r.count;
  }
  if (STATE.footer) {
    const r = stripAbsoluteUrlsFromString(STATE.footer.footer_content);
    STATE.footer.footer_content = r.text;
    STATE.footer._originalContent = r.text;
    stripFtr = r.count;
  }
  STATE.components.forEach(c => { c._originalDetails = c.content_details; });

  STATE.dirty.clear();
  STATE.dirtyHeader = false;
  STATE.dirtyFooter = false;
  renderSidebar();
  renderIframe();
  document.getElementById('emptyState').style.display = 'none';
  updateStatus();

  const phpCount = STATE.components.filter(c => c.content_is_php).length;
  const src = opts.source ? ' from ' + opts.source : '';
  const totalStripped = stripped + stripHdr + stripFtr;
  const extra = totalStripped > 0 ? ` (stripped ${totalStripped} URL${totalStripped > 1 ? 's' : ''})` : '';
  const phpNote = phpCount > 0 ? `, ${phpCount} PHP` : '';
  const hdrNote = STATE.header ? ', +header' : '';
  const ftrNote = STATE.footer ? ', +footer' : '';
  toast(`Loaded ${STATE.components.length} components${phpNote}${hdrNote}${ftrNote}${src}${extra}`, 'success', 3500);

  // Update the topbar breadcrumb with portal / page / id
  updateBreadcrumb();
}

// Derive the portal name and page name from loaded components.
// Portal: the common prefix before " - " across canonical names (e.g. "MARCOMM").
// Page:  derived from the name of the most-specific visual component (e.g. "HOME" → "Home").
function updateBreadcrumb() {
  const portalEl = document.getElementById('tbPortal');
  const portalSepEl = document.getElementById('tbPortalSep');
  const pageEl = document.getElementById('tbPage');
  const idEl = document.getElementById('tbPageId');

  if (!STATE.components.length) {
    portalEl.textContent = '';
    portalSepEl.style.display = 'none';
    pageEl.textContent = '';
    idEl.style.display = 'none';
    return;
  }

  // Portal prefix: find first component that matches "PORTAL - NAME"
  let portal = '';
  for (const c of STATE.components) {
    const m = c.content_name && c.content_name.match(/^([A-Z][A-Z0-9\s]*?)\s*-\s*/);
    if (m) { portal = m[1].trim(); break; }
  }

  // Page name: prefer "HOME" if present, else first visual (non-infra, non-PHP) component
  let page = '';
  const home = STATE.components.find(c => /(^|-\s*)HOME\s*$/i.test(c.content_name || ''));
  if (home) {
    page = 'Home';
  } else {
    const visual = STATE.components.find(c => !isInfra(c.content_name) && !c.content_is_php);
    if (visual) {
      page = prettyName(visual.content_name);
    }
  }

  const pid = document.getElementById('apiPageId').value.trim();

  portalEl.textContent = portal;
  portalSepEl.style.display = portal ? '' : 'none';
  pageEl.textContent = page;
  if (pid) {
    idEl.textContent = 'ID ' + pid;
    idEl.style.display = '';
  } else {
    idEl.style.display = 'none';
  }
}

function loadDemoData() {
  const demoTag = document.getElementById('__demo_data__');
  if (!demoTag) { toast('No embedded demo data available', 'warning'); return; }
  const raw = demoTag.textContent.trim();
  if (!raw || !raw.startsWith('{')) { toast('No embedded demo data available', 'warning'); return; }
  try {
    const parsed = JSON.parse(raw);
    loadComponents(parsed, { source: 'embedded demo' });
  } catch (err) {
    toast('Could not load demo data: ' + err.message, 'error');
  }
}

/* ═══════════════════════════════════════════
   SIDEBAR
═══════════════════════════════════════════ */
function renderSidebar() {
  document.getElementById('compCount').textContent = STATE.components.length;
  const list = document.getElementById('compList');
  list.innerHTML = '';
  STATE.components.forEach((c, idx) => {
    const infra = isInfra(c.content_name);
    const isPhp = !!c.content_is_php;
    const item = document.createElement('div');
    const classes = ['comp-item', infra ? 'infra' : 'visual'];
    if (STATE.dirty.has(idx)) classes.push('dirty');
    if (c._isNew) classes.push('new');
    if (isPhp) classes.push('php');
    item.className = classes.join(' ');
    item.draggable = true;
    item.dataset.idx = String(idx);
    item.onclick = (e) => {
      if (e.target.closest('.comp-item-grip') || e.target.closest('.comp-item-remove')) return;
      openSourceModal(idx);
    };
    const icon = isPhp ? 'bi-filetype-php'
                : (infra ? 'bi-braces-asterisk'
                         : (c._isNew ? 'bi-plus-square-dotted' : 'bi-window-stack'));
    item.innerHTML = `
      <span class="comp-item-grip" title="Drag to reorder"><i class="bi bi-grip-vertical"></i></span>
      <div class="comp-item-icon"><i class="bi ${icon}"></i></div>
      <div class="comp-item-text">
        <div class="comp-item-name">${escapeHtml(prettyName(c.content_name))}${c._isNew ? ' <span class="badge-new">NEW</span>' : ''}${isPhp ? ' <span class="badge-php">PHP</span>' : ''}</div>
        <div class="comp-item-sub">${isPhp ? 'PHP template' : (infra ? 'Infrastructure' : 'Visual')} • ${formatBytes((c.content_details || '').length)}${c.content_id ? ' • #' + c.content_id : ''} • order ${c.content_order || '—'}</div>
      </div>
      <button class="comp-item-edit" title="Edit source"><i class="bi bi-code-slash"></i></button>
      ${c._isNew ? `<button class="comp-item-remove" title="Remove this new component" onclick="event.stopPropagation();removeNewComponent(${idx})" style="background:transparent;color:var(--danger);font-size:11px;padding:4px 6px;border-radius:4px;"><i class="bi bi-trash"></i></button>` : ''}
    `;
    wireCompItemDrag(item);
    list.appendChild(item);
  });
}

// Drag-to-reorder for component list items
let _dragIdx = -1;
function wireCompItemDrag(item) {
  item.addEventListener('dragstart', (e) => {
    _dragIdx = parseInt(item.dataset.idx, 10);
    item.classList.add('dragging-item');
    e.dataTransfer.effectAllowed = 'move';
    // Set some data so Firefox doesn't cancel the drag
    try { e.dataTransfer.setData('text/plain', String(_dragIdx)); } catch(_) {}
  });
  item.addEventListener('dragend', () => {
    item.classList.remove('dragging-item');
    document.querySelectorAll('.comp-item').forEach(x => {
      x.classList.remove('drop-above', 'drop-below');
    });
    _dragIdx = -1;
  });
  item.addEventListener('dragover', (e) => {
    if (_dragIdx < 0) return;
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    // Figure out whether we're in the top or bottom half
    const rect = item.getBoundingClientRect();
    const above = e.clientY < rect.top + rect.height / 2;
    document.querySelectorAll('.comp-item').forEach(x => {
      x.classList.remove('drop-above', 'drop-below');
    });
    item.classList.add(above ? 'drop-above' : 'drop-below');
  });
  item.addEventListener('drop', (e) => {
    if (_dragIdx < 0) return;
    e.preventDefault();
    const targetIdx = parseInt(item.dataset.idx, 10);
    const rect = item.getBoundingClientRect();
    const above = e.clientY < rect.top + rect.height / 2;
    let insertAt = above ? targetIdx : targetIdx + 1;
    if (_dragIdx === targetIdx) return;
    // Remove the dragged item, then insert at new position
    const [moved] = STATE.components.splice(_dragIdx, 1);
    // Adjust insertion index if the removed item was before the target
    if (_dragIdx < insertAt) insertAt--;
    STATE.components.splice(insertAt, 0, moved);
    // Renumber content_order 1..N
    STATE.components.forEach((c, i) => { c.content_order = i + 1; });
    // Mark everything as dirty since order changed
    STATE.components.forEach((_, i) => STATE.dirty.add(i));
    renderSidebar();
    renderIframe();
    updateStatus();
    flashSaveIndicator('Reordered');
    toast('Components reordered', 'success', 2500);
  });
}

function prettyName(n) {
  return n.replace(/^MARCOMM\s*-\s*/, '');
}

function formatBytes(b) {
  if (b < 1024) return b + ' B';
  if (b < 1024 * 1024) return (b / 1024).toFixed(1) + ' KB';
  return (b / 1024 / 1024).toFixed(2) + ' MB';
}

function escapeHtml(s) {
  return (s || '').replace(/[&<>"']/g, m => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
  }[m]));
}

function updateStatus() {
  const n = STATE.dirty.size;
  const total = STATE.components.length;
  document.getElementById('dirtyCount').textContent = `${n} / ${total}`;
  const statusTxt = document.getElementById('statusText');
  if (n === 0) {
    statusTxt.textContent = 'Clean';
    statusTxt.classList.remove('dirty');
  } else {
    statusTxt.textContent = `${n} unsaved`;
    statusTxt.classList.add('dirty');
  }
}

// Build a <base href="..."> tag from the Asset Base field.
// Returns empty string if base is empty or "/", so the iframe inherits the
// parent document's base URL (works for srcdoc iframes).
function getBaseTag() {
  let base = document.getElementById('assetBase').value.trim();
  if (!base || base === '/') return '';
  if (!base.endsWith('/')) base += '/';
  return `<base href="${base}">`;
}

// Variant for blob-URL previews (opened in a new tab). Blob URLs have their
// own synthetic origin, so we MUST include a base tag with an absolute URL.
// When Asset Base is empty or "/", fall back to the current page's origin.
function getBaseTagAbsolute() {
  let base = document.getElementById('assetBase').value.trim();
  if (!base || base === '/') {
    base = window.location.origin + '/';
  } else if (!base.endsWith('/')) {
    base += '/';
  }
  return `<base href="${base}">`;
}

/* ═══════════════════════════════════════════
   IFRAME RENDERING
═══════════════════════════════════════════ */
function getComp(name) { return STATE.components.find(c => c.content_name === name); }
function getCompIdx(name) { return STATE.components.findIndex(c => c.content_name === name); }

// For PHP components: produce a visible placeholder card shown inside the
// iframe. The user can't visually edit PHP source (it's not HTML) but they
// can still open the code editor from the top-right pencil (when forEdit).
function phpPlaceholderCard(comp, idx, forEdit) {
  const label = escapeHtml(prettyName(comp.content_name || 'PHP COMPONENT'));
  const size = formatBytes((comp.content_details || '').length);
  const id = comp.content_id ? '#' + comp.content_id : '';
  const hint = forEdit
    ? 'Click the toolbar pencil at the top-right of this card to edit the raw PHP source. This component is not visually editable because PHP must be interpreted on the server.'
    : 'This component renders server-side. Its output will appear when the page is served by your PHP runtime.';
  return `
<div class="ve-php-placeholder" style="
  position: relative;
  margin: 20px auto;
  max-width: 720px;
  padding: 28px 28px 24px;
  background: repeating-linear-gradient(45deg, #2a1f3d 0 14px, #1f1a2e 14px 28px);
  border: 2px dashed #a78bfa;
  border-radius: 10px;
  color: #e5e4f0;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  box-shadow: inset 0 0 40px rgba(167,139,250,.08);
">
  <div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;">
    <div style="
      width: 44px; height: 44px;
      background: linear-gradient(135deg,#a78bfa,#7c3aed);
      border-radius: 10px;
      display:flex;align-items:center;justify-content:center;
      font-family:'JetBrains Mono',monospace;
      font-weight:800;font-size:14px;color:#fff;
      box-shadow:0 4px 14px rgba(124,58,237,.5);
    ">PHP</div>
    <div style="flex:1;min-width:0;">
      <div style="font-size:10px;font-weight:800;letter-spacing:1.5px;color:#a78bfa;text-transform:uppercase;">Server-rendered component</div>
      <div style="font-size:18px;font-weight:700;color:#fff;letter-spacing:-0.3px;">${label}</div>
    </div>
    <div style="
      font-family:'JetBrains Mono',monospace;
      font-size:10.5px;color:#a78bfa;
      background:rgba(167,139,250,.12);
      padding:4px 10px;border-radius:5px;
      white-space:nowrap;
    ">${size}${id ? ' · ' + id : ''}</div>
  </div>
  <div style="font-size:12.5px;line-height:1.55;color:#c4c0d6;">${hint}</div>
</div>`.trim();
}

function buildFullHTML(opts) {
  opts = opts || {};
  const forEdit = opts.forEdit !== false; // default: true
  const absoluteBase = !!opts.absoluteBase;

  const baseTag = absoluteBase ? getBaseTagAbsolute() : getBaseTag();

  // Infrastructure components (page scaffolding with open/close tags) are emitted
  // as raw HTML so they can wrap the visible content. Everything else becomes an
  // editable ve-comp wrapper (or a PHP placeholder).
  // Detection uses the shared isInfra() helper which matches any "… - WRAPPER START/END".

  // Iterate components in STATE order so drag-reorder in the Pages tab actually
  // changes the page layout. Each component renders according to its own kind:
  //  - PHP -> placeholder card (in edit mode) or skipped (in preview mode)
  //  - Infrastructure -> raw HTML (no ve-comp wrapper)
  //  - Visual -> ve-comp wrapper (or raw HTML in preview mode)
  const bodyParts = [];
  STATE.components.forEach((c, i) => {
    if (c.content_is_php) {
      const placeholder = phpPlaceholderCard(c, i, forEdit);
      if (forEdit) {
        bodyParts.push(`<div class="ve-comp ve-comp-php" data-comp-idx="${i}" data-comp-name="${escapeHtml(c.content_name)}">${placeholder}</div>`);
      }
      // In non-edit preview, PHP components are server-rendered, so we output
      // the raw source and let the final renderer deal with it.
      else bodyParts.push(c.content_details || '');
      return;
    }
    if (isInfra(c.content_name)) {
      bodyParts.push(c.content_details || '');
      return;
    }
    if (forEdit) {
      bodyParts.push(`<div class="ve-comp" data-comp-idx="${i}" data-comp-name="${escapeHtml(c.content_name)}">${c.content_details || ''}</div>`);
    } else {
      bodyParts.push(c.content_details || '');
    }
  });
  const bodyInner = bodyParts.join('\n');

  // ── Path A: Use the page's real header + footer from the JSON ──
  if (STATE.header && STATE.footer) {
    let headerHtml = STATE.header.header_content;
    let footerHtml = STATE.footer.footer_content;

    if (baseTag && /<head[^>]*>/i.test(headerHtml)) {
      headerHtml = headerHtml.replace(/<head[^>]*>/i, (m) => m + baseTag);
    }
    if (forEdit) {
      if (/<\/head>/i.test(headerHtml)) headerHtml = headerHtml.replace(/<\/head>/i, VE_INJECT_CSS + '</head>');
      else headerHtml = headerHtml + VE_INJECT_CSS;
    }
    let finalFooter = footerHtml;
    if (forEdit) {
      if (/<\/body>/i.test(finalFooter)) finalFooter = finalFooter.replace(/<\/body>/i, VE_INJECT_SCRIPT + '</body>');
      else finalFooter = VE_INJECT_SCRIPT + finalFooter;
    }
    return headerHtml + '\n' + bodyInner + '\n' + finalFooter;
  }

  // ── Path B: Legacy fallback (no header/footer in JSON) ──
  const head = STATE.headTemplate || '';
  const editorCSS = forEdit ? VE_INJECT_CSS : '';
  const editorJS = forEdit ? VE_INJECT_SCRIPT : '';
  return `<!DOCTYPE html>
<html dir="ltr" lang="en-MY">
<head>
${baseTag}
${head}
${editorCSS}
</head>
<body class="bkrm-body ms-backgroundImage">
${bodyInner}
${editorJS}
</body>
</html>`;
}

// ─── Editor inject templates (extracted so Preview tab and main iframe share) ───
const VE_INJECT_CSS = `
<style id="__ve_style__">
  /* ── Component-level wrapper ── */
  .ve-comp { position: relative; transition: outline .15s, background .15s; }
  .ve-comp:hover { outline: 2px dashed rgba(245,158,11,.55); outline-offset: 2px; }
  .ve-comp:hover > .ve-comp-label { opacity: 1; transform: translateY(0); }
  .ve-comp:hover > .ve-comp-edit { opacity: 1; transform: translateY(0) scale(1); }
  .ve-comp-label {
    position: absolute; top: -12px; left: 10px; z-index: 99998;
    background: #f59e0b; color: #1a1a2e;
    font-size: 10px; font-weight: 800;
    padding: 2px 9px; border-radius: 4px;
    letter-spacing: 0.5px; text-transform: uppercase;
    pointer-events: none;
    font-family: 'JetBrains Mono', monospace;
    opacity: 0; transform: translateY(-3px);
    transition: all .18s;
    white-space: nowrap;
    box-shadow: 0 2px 6px rgba(0,0,0,.2);
  }
  .ve-comp-edit {
    position: absolute; top: 6px; right: 6px; z-index: 99999;
    width: 34px; height: 34px;
    background: #4f6ef7; color: #fff;
    border: none; border-radius: 8px;
    font-size: 14px;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    opacity: 0; transform: translateY(-3px) scale(.92);
    transition: all .18s;
    box-shadow: 0 4px 14px rgba(79,110,247,.5);
  }
  .ve-comp-edit:hover { background: #3b55e0; transform: translateY(0) scale(1.05) !important; }

  /* ── Element-level: hover, selected, edit pencil ── */
  .ve-comp [data-ve-editable] {
    transition: outline .12s;
  }
  .ve-comp [data-ve-editable]:hover {
    outline: 1.5px dashed rgba(79,110,247,.55);
    outline-offset: 2px;
    cursor: pointer;
  }
  .ve-comp [data-ve-editable][data-ve-kind="image"]:hover { cursor: zoom-in; }
  .ve-comp [data-ve-editable][data-ve-kind="link"]:hover  { cursor: pointer; }
  .ve-comp [data-ve-selected] {
    outline: 2px solid #10b981 !important;
    outline-offset: 2px;
    background: rgba(16,185,129,.05);
  }

  /* Floating toolbar (positioned via fixed coords set in JS) */
  .ve-elem-toolbar {
    position: fixed;
    z-index: 2147483647;
    display: flex;
    gap: 6px;
    pointer-events: auto;
  }
  .ve-elem-btn {
    width: 32px; height: 32px;
    min-width: 32px; min-height: 32px;
    max-width: 32px; max-height: 32px;
    padding: 0; margin: 0;
    border: 2px solid rgba(255,255,255,0.9);
    border-radius: 50%;
    font-size: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: #fff;
    box-sizing: border-box;
    flex-shrink: 0;
    font-family: inherit;
    line-height: 1;
    transition: transform .12s, background .12s, box-shadow .12s;
  }
  .ve-elem-btn:hover { transform: scale(1.12); }
  .ve-elem-btn svg { width: 14px; height: 14px; display: block; }

  /* Kind-specific colors */
  .ve-elem-btn.kind-text   { background: #10b981; box-shadow: 0 3px 10px rgba(16,185,129,.6); }
  .ve-elem-btn.kind-text:hover   { background: #059669; }
  .ve-elem-btn.kind-image  { background: #8b5cf6; box-shadow: 0 3px 10px rgba(139,92,246,.6); }
  .ve-elem-btn.kind-image:hover  { background: #7c3aed; }
  .ve-elem-btn.kind-link   { background: #06b6d4; box-shadow: 0 3px 10px rgba(6,182,212,.6); }
  .ve-elem-btn.kind-link:hover   { background: #0891b2; }
  .ve-elem-btn.kind-code   { background: #f59e0b; box-shadow: 0 3px 10px rgba(245,158,11,.6); }
  .ve-elem-btn.kind-code:hover   { background: #d97706; }
  .ve-elem-btn.kind-addchild { background: #10b981; box-shadow: 0 3px 10px rgba(16,185,129,.6); }
  .ve-elem-btn.kind-addchild:hover { background: #059669; }
  .ve-elem-btn.kind-dup    { background: #3b82f6; box-shadow: 0 3px 10px rgba(59,130,246,.6); }
  .ve-elem-btn.kind-dup:hover    { background: #2563eb; }
  .ve-elem-btn.kind-move   { background: #64748b; box-shadow: 0 3px 10px rgba(100,116,139,.5); }
  .ve-elem-btn.kind-move:hover   { background: #475569; }
  .ve-elem-btn.kind-delete { background: #ef4444; box-shadow: 0 3px 10px rgba(239,68,68,.6); }
  .ve-elem-btn.kind-delete:hover { background: #dc2626; }

  /* Drop zone indicators for drag-drop */
  .ve-drop-indicator {
    position: absolute;
    background: #4f6ef7;
    z-index: 99997;
    pointer-events: none;
    border-radius: 2px;
    box-shadow: 0 0 12px rgba(79,110,247,.8);
    animation: vePulse 1s ease-in-out infinite;
  }
  @keyframes vePulse {
    0%,100% { opacity: 1; }
    50% { opacity: .6; }
  }
  .ve-drop-target-hover {
    outline: 2px dashed #4f6ef7 !important;
    outline-offset: 2px;
    background: rgba(79,110,247,.05) !important;
  }
</style>
  `.trim();

const VE_INJECT_SCRIPT = `
<script>
(function(){
  var SELECTED = null;        // currently selected element
  var TOOLBAR = null;         // floating toolbar (fixed position)
  var ELEM_ID_COUNTER = 0;

  function post(msg){ try { parent.postMessage(msg, '*'); } catch(e){} }

  // Block form submissions & link navigation in editor
  document.addEventListener('submit', function(e){ e.preventDefault(); e.stopPropagation(); }, true);

  // Classify an element into: 'image', 'link', or 'text' (or null = not editable)
  function classifyElement(el){
    if (!el) return null;
    if (el.closest('.ve-comp-edit') || el.closest('.ve-comp-label') || el.closest('.ve-elem-toolbar')) return null;
    if (!el.closest('.ve-comp')) return null;
    var tag = el.tagName.toLowerCase();
    if (['script','style','meta','link','form','iframe','html','body','head'].indexOf(tag) !== -1) return null;
    if (tag === 'img') return 'image';
    if (tag === 'a') return 'link';
    // Text-only element (has exactly one text node child)
    if (el.childNodes.length === 1 && el.childNodes[0].nodeType === 3 && el.childNodes[0].nodeValue.trim()) {
      return 'text';
    }
    // Container-ish element with no text leaf — still editable as 'code' (for property panel)
    return 'container';
  }

  // Walk up from click target to find the first editable ancestor within a ve-comp.
  // For images, prefer the image itself. For links with child image, prefer the image
  // on click (user can drill up via the toolbar).
  function findEditableTarget(el){
    var cur = el;
    var depth = 0;
    while (cur && cur !== document.body && depth < 15) {
      var kind = classifyElement(cur);
      if (kind) return { el: cur, kind: kind };
      cur = cur.parentElement;
      depth++;
    }
    return null;
  }

  // Serialize a ve-comp to its innerHTML, stripping editor-only markup
  function serializeComp(comp){
    var clone = comp.cloneNode(true);
    // Remove editor UI (comp-level and any leftover toolbars)
    Array.prototype.slice.call(clone.querySelectorAll('.ve-comp-label, .ve-comp-edit, .ve-elem-toolbar, .ve-drop-indicator')).forEach(function(x){ x.remove(); });
    // Remove editor attributes
    Array.prototype.slice.call(clone.querySelectorAll('[data-ve-editable]')).forEach(function(x){ x.removeAttribute('data-ve-editable'); });
    Array.prototype.slice.call(clone.querySelectorAll('[data-ve-elem-id]')).forEach(function(x){ x.removeAttribute('data-ve-elem-id'); });
    Array.prototype.slice.call(clone.querySelectorAll('[data-ve-selected]')).forEach(function(x){ x.removeAttribute('data-ve-selected'); });
    Array.prototype.slice.call(clone.querySelectorAll('[data-ve-kind]')).forEach(function(x){ x.removeAttribute('data-ve-kind'); });
    Array.prototype.slice.call(clone.querySelectorAll('[data-ve-dropzone]')).forEach(function(x){ x.removeAttribute('data-ve-dropzone'); });
    Array.prototype.slice.call(clone.querySelectorAll('.ve-drop-target-hover')).forEach(function(x){ x.classList.remove('ve-drop-target-hover'); if (!x.className) x.removeAttribute('class'); });
    return clone.innerHTML;
  }

  // Notify parent that this component changed (after inline edit, paste, drop, etc.)
  function notifyCompChange(comp){
    if (!comp) return;
    var compIdx = parseInt(comp.getAttribute('data-comp-idx'), 10);
    post({ type: 'VE_UPDATE_COMP', idx: compIdx, innerHtml: serializeComp(comp) });
    // Also refresh hierarchy snapshot if the parent has opened the tab
    post({ type: 'VE_HIERARCHY_SNAPSHOT', tree: buildHierarchy() });
  }

  // SVG icon helpers
  function svgEdit(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" 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>'; }
  function svgCode(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>'; }
  function svgTrash(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-2 14a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"/></svg>'; }
  function svgFonts(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2"/><path d="M9 20h6"/><path d="M12 4v16"/></svg>'; }
  function svgImage(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>'; }
  function svgLink(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>'; }
  function svgPlus(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>'; }
  function svgDuplicate(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'; }
  function svgArrowUp(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>'; }
  function svgArrowDown(){ return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg>'; }

  // Position the toolbar next to a target element using FIXED positioning
  function positionToolbar(el){
    if (!TOOLBAR) return;
    var rect = el.getBoundingClientRect();
    var tbWidth = TOOLBAR.offsetWidth || 120;
    var tbHeight = TOOLBAR.offsetHeight || 36;
    // Prefer top-right corner
    var top = rect.top - tbHeight - 8;
    var left = rect.right - tbWidth;
    // If above viewport, put inside the element at top-right
    if (top < 4) top = rect.top + 4;
    // Clamp to viewport
    if (left < 4) left = 4;
    var vw = document.documentElement.clientWidth;
    if (left + tbWidth > vw - 4) left = vw - tbWidth - 4;
    TOOLBAR.style.top = top + 'px';
    TOOLBAR.style.left = left + 'px';
  }

  // Build the floating toolbar for an element
  function buildToolbar(el, kind){
    var tb = document.createElement('div');
    tb.className = 've-elem-toolbar';
    var tag = el.tagName.toLowerCase();

    // Main edit button (kind-specific)
    if (kind === 'text' || kind === 'image' || kind === 'link') {
      var editBtn = document.createElement('button');
      editBtn.className = 've-elem-btn kind-' + kind;
      editBtn.title = 'Edit ' + kind;
      editBtn.innerHTML = (kind === 'image' ? svgImage() : (kind === 'link' ? svgLink() : svgFonts()));
      editBtn.onclick = function(e){ e.preventDefault(); e.stopPropagation(); openElementEditor(el, kind); };
      tb.appendChild(editBtn);
    }

    // Wrap-in-link button for text/image/button elements not already a link.
    // If the element already sits inside an <a>, this opens the parent link's editor.
    if (kind === 'text' || kind === 'image' || tag === 'button') {
      var parentLink = el.closest('a');
      var linkBtn = document.createElement('button');
      linkBtn.className = 've-elem-btn kind-link';
      linkBtn.title = parentLink ? 'Edit parent link' : 'Wrap in a link';
      linkBtn.innerHTML = svgLink();
      linkBtn.onclick = function(e){
        e.preventDefault(); e.stopPropagation();
        if (parentLink) {
          // Open the link editor for the ancestor <a>
          ensureElemId(parentLink);
          openElementEditor(parentLink, 'link');
        } else {
          wrapInLink(el);
        }
      };
      tb.appendChild(linkBtn);
    }

    // Code edit (always present)
    var codeBtn = document.createElement('button');
    codeBtn.className = 've-elem-btn kind-code';
    codeBtn.title = 'Edit HTML source of this element';
    codeBtn.innerHTML = svgCode();
    codeBtn.onclick = function(e){ e.preventDefault(); e.stopPropagation(); openElementCodeEditor(el); };
    tb.appendChild(codeBtn);

    // Add child <li> for UL / OL
    if (tag === 'ul' || tag === 'ol') {
      var addBtn = document.createElement('button');
      addBtn.className = 've-elem-btn kind-addchild';
      addBtn.title = 'Add new <li> to this list';
      addBtn.innerHTML = svgPlus();
      addBtn.onclick = function(e){ e.preventDefault(); e.stopPropagation(); addChildListItem(el); };
      tb.appendChild(addBtn);
    }

    // Duplicate
    var dupBtn = document.createElement('button');
    dupBtn.className = 've-elem-btn kind-dup';
    dupBtn.title = 'Duplicate this element';
    dupBtn.innerHTML = svgDuplicate();
    dupBtn.onclick = function(e){ e.preventDefault(); e.stopPropagation(); duplicateElement(el); };
    tb.appendChild(dupBtn);

    // Move up
    var upBtn = document.createElement('button');
    upBtn.className = 've-elem-btn kind-move';
    upBtn.title = 'Move up';
    upBtn.innerHTML = svgArrowUp();
    upBtn.onclick = function(e){ e.preventDefault(); e.stopPropagation(); moveElement(el, 'up'); };
    tb.appendChild(upBtn);

    // Move down
    var downBtn = document.createElement('button');
    downBtn.className = 've-elem-btn kind-move';
    downBtn.title = 'Move down';
    downBtn.innerHTML = svgArrowDown();
    downBtn.onclick = function(e){ e.preventDefault(); e.stopPropagation(); moveElement(el, 'down'); };
    tb.appendChild(downBtn);

    // Delete
    var delBtn = document.createElement('button');
    delBtn.className = 've-elem-btn kind-delete';
    delBtn.title = 'Delete this element';
    delBtn.innerHTML = svgTrash();
    delBtn.onclick = function(e){ e.preventDefault(); e.stopPropagation(); deleteElement(el); };
    tb.appendChild(delBtn);

    return tb;
  }

  // Wrap the given element in a new <a> tag, then open the link editor immediately.
  function wrapInLink(el){
    if (!el || !el.parentNode) return;
    var comp = el.closest('.ve-comp'); if (!comp) return;
    var a = document.createElement('a');
    a.setAttribute('href', '#');
    el.parentNode.insertBefore(a, el);
    a.appendChild(el);
    // Give the new <a> an elem id, wire it, then open the editor
    ensureElemId(a);
    wireElements();
    notifyCompChange(comp);
    setTimeout(function(){
      selectElement(a, 'link');
      openElementEditor(a, 'link');
    }, 50);
  }

  function openElementCodeEditor(el){
    var comp = el.closest('.ve-comp');
    if (!comp) return;
    var compIdx = parseInt(comp.getAttribute('data-comp-idx'), 10);
    var elemId = el.getAttribute('data-ve-elem-id');
    // Serialize the element's outerHTML, stripping our editor attributes
    var clone = el.cloneNode(true);
    ['data-ve-editable','data-ve-elem-id','data-ve-selected','data-ve-kind','data-ve-dropzone'].forEach(function(attr){
      if (clone.hasAttribute(attr)) clone.removeAttribute(attr);
      Array.prototype.slice.call(clone.querySelectorAll('[' + attr + ']')).forEach(function(x){ x.removeAttribute(attr); });
    });
    post({
      type: 'VE_EDIT_ELEMENT_CODE',
      compIdx: compIdx,
      elemId: elemId,
      outerHtml: clone.outerHTML,
      tag: el.tagName.toLowerCase()
    });
  }

  function deleteElement(el){
    var comp = el.closest('.ve-comp');
    if (!comp) return;
    post({ type: 'VE_CONFIRM_DELETE', elemId: el.getAttribute('data-ve-elem-id'), tag: el.tagName.toLowerCase() });
  }

  function selectElement(el, kind){
    clearSelection();
    if (!el || !kind) return;
    if (!el.getAttribute('data-ve-elem-id')) {
      el.setAttribute('data-ve-elem-id', 'e' + (++ELEM_ID_COUNTER) + '-' + Date.now());
    }
    el.setAttribute('data-ve-selected', '');
    el.setAttribute('data-ve-kind', kind);
    TOOLBAR = buildToolbar(el, kind);
    document.body.appendChild(TOOLBAR);
    positionToolbar(el);
    SELECTED = el;
    // Notify parent so property panel can populate
    post({
      type: 'VE_SELECTION_CHANGED',
      compIdx: parseInt(el.closest('.ve-comp').getAttribute('data-comp-idx'), 10),
      elemId: el.getAttribute('data-ve-elem-id'),
      kind: kind,
      tag: el.tagName.toLowerCase(),
      style: el.getAttribute('style') || '',
      className: el.className || '',
      outerHtml: null
    });
  }

  function clearSelection(){
    if (SELECTED) {
      SELECTED.removeAttribute('data-ve-selected');
      SELECTED.removeAttribute('data-ve-kind');
    }
    if (TOOLBAR && TOOLBAR.parentNode) TOOLBAR.parentNode.removeChild(TOOLBAR);
    SELECTED = null; TOOLBAR = null;
    post({ type: 'VE_SELECTION_CHANGED', elemId: null });
  }

  function openElementEditor(el, kind){
    var comp = el.closest('.ve-comp');
    if (!comp) return;
    var compIdx = parseInt(comp.getAttribute('data-comp-idx'), 10);
    var elemId = el.getAttribute('data-ve-elem-id');
    var payload = { type: 'VE_EDIT_ELEMENT', kind: kind, compIdx: compIdx, elemId: elemId, tag: el.tagName.toLowerCase() };
    if (kind === 'text') payload.text = el.textContent;
    else if (kind === 'image') {
      payload.src = el.getAttribute('src') || '';
      payload.alt = el.getAttribute('alt') || '';
      payload.title = el.getAttribute('title') || '';
    } else if (kind === 'link') {
      payload.href = el.getAttribute('href') || '';
      payload.target = el.getAttribute('target') || '';
      payload.title = el.getAttribute('title') || '';
      var leafText = (el.childNodes.length === 1 && el.childNodes[0].nodeType === 3);
      payload.text = leafText ? el.textContent : null;
    }
    post(payload);
  }

  // ========== Element actions: duplicate, move, addChild ==========
  function ensureElemId(el){
    if (!el.getAttribute('data-ve-elem-id')) {
      el.setAttribute('data-ve-elem-id', 'e' + (++ELEM_ID_COUNTER) + '-' + Date.now());
    }
    return el.getAttribute('data-ve-elem-id');
  }

  function duplicateElement(el){
    if (!el || !el.parentNode) return;
    var comp = el.closest('.ve-comp'); if (!comp) return;
    var clone = el.cloneNode(true);
    // Strip editor attrs from clone (new copies get fresh ids on next click)
    clone.removeAttribute('data-ve-elem-id');
    clone.removeAttribute('data-ve-selected');
    clone.removeAttribute('data-ve-kind');
    clone.removeAttribute('data-ve-editable');
    Array.prototype.slice.call(clone.querySelectorAll('[data-ve-elem-id],[data-ve-selected],[data-ve-kind],[data-ve-editable]')).forEach(function(x){
      x.removeAttribute('data-ve-elem-id');
      x.removeAttribute('data-ve-selected');
      x.removeAttribute('data-ve-kind');
      x.removeAttribute('data-ve-editable');
    });
    el.parentNode.insertBefore(clone, el.nextSibling);
    wireElements();
    notifyCompChange(comp);
    // Select the new clone
    var kind = classifyElement(clone);
    if (kind) setTimeout(function(){ selectElement(clone, kind); }, 50);
  }

  function moveElement(el, direction){
    if (!el || !el.parentNode) return;

    // SPECIAL CASE: moving a ve-comp itself (the whole component wrapper).
    // This is a page-level reorder — tell the parent to swap components in STATE.
    if (el.classList && el.classList.contains('ve-comp')) {
      var compIdx = parseInt(el.getAttribute('data-comp-idx'), 10);
      if (!isNaN(compIdx)) {
        post({ type: 'VE_REORDER_COMP', fromIdx: compIdx, direction: direction });
        return;
      }
    }

    var comp = el.closest('.ve-comp'); if (!comp) return;
    var parent = el.parentNode;
    var moved = false;
    if (direction === 'up') {
      var prev = el.previousElementSibling;
      // Skip our own overlays (normally on document.body, but safe to skip)
      while (prev && (prev.classList.contains('ve-comp-label') || prev.classList.contains('ve-comp-edit') || prev.classList.contains('ve-elem-toolbar'))) {
        prev = prev.previousElementSibling;
      }
      if (prev) { parent.insertBefore(el, prev); moved = true; }
    } else {
      var next = el.nextElementSibling;
      while (next && (next.classList.contains('ve-comp-label') || next.classList.contains('ve-comp-edit') || next.classList.contains('ve-elem-toolbar'))) {
        next = next.nextElementSibling;
      }
      if (next) { parent.insertBefore(next, el); moved = true; }
    }
    if (!moved) {
      // Give a subtle shake so the user knows the button registered but the element
      // was already at the edge.
      el.animate([
        { transform: 'translateX(-3px)' }, { transform: 'translateX(3px)' },
        { transform: 'translateX(-2px)' }, { transform: 'translateX(2px)' },
        { transform: 'translateX(0)' },
      ], { duration: 200 });
      return;
    }

    // Visible flash so the user sees the movement register
    el.animate([
      { outline: '3px solid #10b981', outlineOffset: '3px', backgroundColor: 'rgba(16,185,129,.15)' },
      { outline: '2px solid #10b981', outlineOffset: '2px', backgroundColor: 'transparent' },
    ], { duration: 400 });

    // Make sure the moved element is still visible in the viewport
    el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });

    notifyCompChange(comp);
    if (TOOLBAR) {
      // Defer repositioning until after the scroll animation has settled
      setTimeout(function(){ if (SELECTED === el && TOOLBAR) positionToolbar(el); }, 350);
    }
  }

  // For <ul> or <ol>: insert a new <li>. If there's an existing <li> to copy
  // its styling/structure from, clone the last one; otherwise insert a plain item.
  function addChildListItem(el){
    if (!el || (el.tagName !== 'UL' && el.tagName !== 'OL')) return;
    var comp = el.closest('.ve-comp'); if (!comp) return;
    var existing = el.querySelectorAll(':scope > li');
    var newItem;
    if (existing.length > 0) {
      newItem = existing[existing.length - 1].cloneNode(true);
      // Strip editor attrs
      newItem.removeAttribute('data-ve-elem-id');
      newItem.removeAttribute('data-ve-selected');
      newItem.removeAttribute('data-ve-kind');
      newItem.removeAttribute('data-ve-editable');
      Array.prototype.slice.call(newItem.querySelectorAll('[data-ve-elem-id],[data-ve-selected],[data-ve-kind],[data-ve-editable]')).forEach(function(x){
        x.removeAttribute('data-ve-elem-id');
        x.removeAttribute('data-ve-selected');
        x.removeAttribute('data-ve-kind');
        x.removeAttribute('data-ve-editable');
      });
      // Tweak text so the user sees a fresh entry instead of a duplicate
      if (newItem.children.length === 0 && newItem.textContent) {
        newItem.textContent = 'New list item';
      }
    } else {
      newItem = document.createElement('li');
      newItem.textContent = 'New list item';
    }
    el.appendChild(newItem);
    wireElements();
    notifyCompChange(comp);
    setTimeout(function(){ selectElement(newItem, 'text'); }, 50);
  }

  // ========== Hierarchy snapshot ==========
  // Build a compact tree snapshot (kinds, tags, ids, classes, elemIds) that
  // the parent can render in the Hierarchy tab without needing the full DOM.
  function buildHierarchy(){
    var comps = document.querySelectorAll('.ve-comp');
    var tree = [];
    Array.prototype.slice.call(comps).forEach(function(comp){
      var compIdx = parseInt(comp.getAttribute('data-comp-idx'), 10);
      var compName = comp.getAttribute('data-comp-name') || '';
      tree.push({
        isCompRoot: true,
        compIdx: compIdx,
        name: compName,
        children: buildHierarchyChildren(comp)
      });
    });
    return tree;
  }
  function buildHierarchyChildren(root){
    var out = [];
    Array.prototype.slice.call(root.children).forEach(function(child){
      // Skip editor UI
      if (child.classList && (
        child.classList.contains('ve-comp-label') ||
        child.classList.contains('ve-comp-edit') ||
        child.classList.contains('ve-elem-toolbar') ||
        child.classList.contains('ve-drop-indicator')
      )) return;
      // Skip non-elements
      if (child.nodeType !== 1) return;
      var tag = child.tagName.toLowerCase();
      if (['script','style','meta','link'].indexOf(tag) !== -1) return;
      // Ensure it has an elem-id so we can target it from the parent
      ensureElemId(child);
      var kind = classifyElement(child) || 'container';
      var node = {
        elemId: child.getAttribute('data-ve-elem-id'),
        tag: tag,
        kind: (tag === 'ul' || tag === 'ol') ? 'list' : kind,
        id: child.id || '',
        classes: (child.className || '').toString().trim().split(/\s+/).filter(function(c){
          return c && !/^ve-|^data-ve/.test(c);
        }).slice(0, 3),
        // A short preview of inline text (if any)
        preview: '',
        children: []
      };
      // Leaf-ish text preview
      if (kind === 'text' && child.textContent) {
        node.preview = child.textContent.trim().substring(0, 40);
      }
      // Descend (cap recursion depth at 10 to avoid blowing up on huge trees)
      if (child.children.length > 0) {
        node.children = buildHierarchyChildren(child);
      }
      out.push(node);
    });
    return out;
  }

  function selectByElemId(elemId){
    var el = document.querySelector('[data-ve-elem-id="' + elemId + '"]');
    if (!el) return;
    var kind = classifyElement(el) || 'container';
    // Scroll into view first so the toolbar lands in a visible place
    el.scrollIntoView({ behavior: 'smooth', block: 'center' });
    selectElement(el, kind);
  }

  // Click handling — use capture + preventDefault to intercept native clicks on <a> and <img>
  document.addEventListener('click', function(e){
    // Skip clicks on our own controls
    if (e.target.closest('.ve-comp-edit') || e.target.closest('.ve-elem-toolbar') || e.target.closest('.ve-comp-label')) return;
    // If the user clicks an editable in ve-comp, select it
    var t = findEditableTarget(e.target);
    if (t) {
      e.preventDefault(); e.stopPropagation();
      selectElement(t.el, t.kind);
    } else {
      // Click elsewhere clears selection
      clearSelection();
    }
  }, true);

  // Prevent default actions (link nav, drag-start on images) in edit mode
  document.addEventListener('mousedown', function(e){
    var a = e.target.closest && e.target.closest('a');
    if (a && !e.target.closest('.ve-elem-toolbar')) e.preventDefault();
  }, true);
  document.addEventListener('dragstart', function(e){
    // Allow drag if initiated by our drag source; block native img/a drags inside ve-comp
    if (e.target.closest('.ve-comp') && !e.target.hasAttribute('data-ve-drag-source')) e.preventDefault();
  }, true);

  // Reposition toolbar on scroll/resize to keep it pinned to the selected element
  ['scroll','resize'].forEach(function(ev){
    window.addEventListener(ev, function(){ if (SELECTED && TOOLBAR) positionToolbar(SELECTED); }, true);
  });

  function markEditable(el){
    var kind = classifyElement(el);
    if (kind && kind !== 'container') el.setAttribute('data-ve-editable', '1');
    else if (kind === 'container') {
      // Containers get a lighter marker so they're clickable but don't dominate hover
      el.setAttribute('data-ve-editable', '1');
    }
  }
  function wireElements(){
    Array.prototype.slice.call(document.querySelectorAll('.ve-comp *')).forEach(markEditable);
  }

  function wireComp(el){
    var idx = el.getAttribute('data-comp-idx');
    var name = el.getAttribute('data-comp-name');
    var lbl = document.createElement('div');
    lbl.className = 've-comp-label';
    lbl.textContent = name;
    el.appendChild(lbl);
    var btn = document.createElement('button');
    btn.className = 've-comp-edit';
    btn.title = 'Edit ' + name + ' — full source';
    btn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 18 22 12 16 6"/><path d="m8 6-6 6 6 6"/></svg>';
    btn.onclick = function(e){
      e.stopPropagation(); e.preventDefault();
      post({ type: 'VE_EDIT_COMP', idx: parseInt(idx,10) });
    };
    el.appendChild(btn);
  }

  // ========== DRAG & DROP (from parent toolbar) ==========
  // Parent sends VE_DRAG_START (with html payload) when a library item starts
  // being dragged. We then listen natively inside the iframe for drag events.
  // On drop, we insert the payload at the computed position.
  var DROP_INDICATOR = null;
  var DRAG_PAYLOAD = null; // { html, name }

  function ensureIndicator(){
    if (!DROP_INDICATOR) {
      DROP_INDICATOR = document.createElement('div');
      DROP_INDICATOR.className = 've-drop-indicator';
      document.body.appendChild(DROP_INDICATOR);
    }
    return DROP_INDICATOR;
  }

  function clearDropUI(){
    if (DROP_INDICATOR && DROP_INDICATOR.parentNode) DROP_INDICATOR.parentNode.removeChild(DROP_INDICATOR);
    DROP_INDICATOR = null;
    Array.prototype.slice.call(document.querySelectorAll('.ve-drop-target-hover')).forEach(function(x){ x.classList.remove('ve-drop-target-hover'); });
  }

  // Given a client-x/y, find the best insertion point. Returns { target, position: 'before'|'after'|'inside' }
  function findDropPoint(x, y){
    // Temporarily hide our overlays so elementFromPoint doesn't hit them
    var hidden = [];
    Array.prototype.slice.call(document.querySelectorAll('.ve-elem-toolbar, .ve-comp-label, .ve-comp-edit, .ve-drop-indicator')).forEach(function(x){
      hidden.push({ el: x, vis: x.style.visibility });
      x.style.visibility = 'hidden';
    });
    var el = document.elementFromPoint(x, y);
    hidden.forEach(function(p){ p.el.style.visibility = p.vis; });
    if (!el) return null;
    var comp = el.closest('.ve-comp');
    if (!comp) return null;
    var rect = el.getBoundingClientRect();
    var mid = rect.top + rect.height / 2;
    if (el === comp) return { target: comp, position: 'inside' };
    // If the element has children and cursor is well inside it, go inside
    if (el.children.length > 0 && y > rect.top + 8 && y < rect.bottom - 8 && x > rect.left + 8 && x < rect.right - 8) {
      return { target: el, position: 'inside' };
    }
    return { target: el, position: y < mid ? 'before' : 'after' };
  }

  function showDropPoint(point){
    clearDropUI();
    if (!point) return;
    var ind = ensureIndicator();
    var rect = point.target.getBoundingClientRect();
    var sy = window.scrollY || document.documentElement.scrollTop;
    var sx = window.scrollX || document.documentElement.scrollLeft;
    if (point.position === 'before') {
      ind.style.top = (rect.top + sy - 2) + 'px';
      ind.style.left = (rect.left + sx) + 'px';
      ind.style.width = rect.width + 'px';
      ind.style.height = '3px';
    } else if (point.position === 'after') {
      ind.style.top = (rect.bottom + sy - 1) + 'px';
      ind.style.left = (rect.left + sx) + 'px';
      ind.style.width = rect.width + 'px';
      ind.style.height = '3px';
    } else {
      point.target.classList.add('ve-drop-target-hover');
      ind.style.display = 'none';
    }
  }

  function performDrop(point, html){
    if (!point || !html) return;
    var temp = document.createElement('div');
    temp.innerHTML = html;
    var nodes = Array.prototype.slice.call(temp.childNodes);
    var firstInserted = null;
    nodes.forEach(function(n){
      if (point.position === 'before') {
        point.target.parentNode.insertBefore(n, point.target);
      } else if (point.position === 'after') {
        if (point.target.nextSibling) point.target.parentNode.insertBefore(n, point.target.nextSibling);
        else point.target.parentNode.appendChild(n);
      } else {
        point.target.appendChild(n);
      }
      if (!firstInserted && n.nodeType === 1) firstInserted = n;
    });
    clearDropUI();
    wireElements();
    var comp = (firstInserted || point.target).closest('.ve-comp');
    if (comp) notifyCompChange(comp);
    if (firstInserted) {
      var kind = classifyElement(firstInserted);
      if (kind && kind !== 'container') {
        setTimeout(function(){ selectElement(firstInserted, kind); }, 50);
      }
    }
  }

  // Native drag listeners inside the iframe. These fire because the drag
  // started from the parent window actually enters the iframe's document.
  document.addEventListener('dragenter', function(e){
    if (!DRAG_PAYLOAD) return;
    e.preventDefault();
    e.dataTransfer.dropEffect = 'copy';
  });
  document.addEventListener('dragover', function(e){
    if (!DRAG_PAYLOAD) return;
    e.preventDefault();
    e.dataTransfer.dropEffect = 'copy';
    showDropPoint(findDropPoint(e.clientX, e.clientY));
  });
  document.addEventListener('dragleave', function(e){
    if (!DRAG_PAYLOAD) return;
    // Only clear if actually leaving the document (not just moving between children)
    if (e.clientX <= 0 || e.clientY <= 0 ||
        e.clientX >= document.documentElement.clientWidth ||
        e.clientY >= document.documentElement.clientHeight) {
      clearDropUI();
    }
  });
  document.addEventListener('drop', function(e){
    if (!DRAG_PAYLOAD) return;
    e.preventDefault();
    var point = findDropPoint(e.clientX, e.clientY);
    performDrop(point, DRAG_PAYLOAD.html);
    post({ type: 'VE_DROP_COMPLETE', name: DRAG_PAYLOAD.name });
    DRAG_PAYLOAD = null;
  });

  // Apply a property/style change from the parent
  function applyStyleUpdate(elemId, styleText, className){
    var el = document.querySelector('[data-ve-elem-id="' + elemId + '"]');
    if (!el) return;
    if (styleText !== undefined) {
      if (styleText) el.setAttribute('style', styleText);
      else el.removeAttribute('style');
    }
    if (className !== undefined) {
      if (className) el.className = className;
      else el.removeAttribute('class');
    }
    // Reposition toolbar since bounds may have changed
    if (el === SELECTED && TOOLBAR) positionToolbar(el);
    var comp = el.closest('.ve-comp');
    if (comp) notifyCompChange(comp);
  }

  // Apply an update to an element (from the text/image/link popup or code editor)
  function applyUpdateToElement(msg){
    var el = document.querySelector('[data-ve-elem-id="' + msg.elemId + '"]');
    if (!el) return;
    if (msg.kind === 'text') {
      el.textContent = msg.text != null ? msg.text : '';
    } else if (msg.kind === 'image') {
      // Capture the original src BEFORE mutating, so we can find sibling copies
      // that refer to the same image (e.g. carousel/track clones) and update them too.
      var oldSrc = el.getAttribute('src') || '';
      if (msg.src != null) el.setAttribute('src', msg.src);
      if (msg.alt != null) el.setAttribute('alt', msg.alt);
      if (msg.title != null) { if (msg.title) el.setAttribute('title', msg.title); else el.removeAttribute('title'); }
      // Carousels like cttTimeSlider keep a "source list" in a .track div and
      // a "currently displayed" copy in .display. When the displayed copy is
      // edited, the next tick of the carousel stamps the original from .track
      // back into .display, which looks like the edit reverted.
      // Fix: find ALL other <img> tags in the same owning component whose src
      // matches the old src, and update them too.
      if (oldSrc && msg.src && msg.src !== oldSrc) {
        var owner = el.closest('.ve-comp');
        if (owner) {
          var twins = owner.querySelectorAll('img[src="' + cssEscapeAttr(oldSrc) + '"]');
          twins.forEach(function(twin){
            if (twin !== el) {
              twin.setAttribute('src', msg.src);
              if (msg.alt != null) twin.setAttribute('alt', msg.alt);
            }
          });
        }
      }
    } else if (msg.kind === 'link') {
      if (msg.href != null) el.setAttribute('href', msg.href || '#');
      if (msg.target != null) { if (msg.target) el.setAttribute('target', msg.target); else el.removeAttribute('target'); }
      if (msg.title != null) { if (msg.title) el.setAttribute('title', msg.title); else el.removeAttribute('title'); }
      if (msg.text != null && el.childNodes.length === 1 && el.childNodes[0].nodeType === 3) {
        el.textContent = msg.text;
      }
    } else if (msg.kind === 'code') {
      // Replace the element with the new outerHTML
      var temp = document.createElement('div');
      temp.innerHTML = msg.outerHtml;
      var newEl = temp.firstElementChild;
      if (newEl && el.parentNode) {
        el.parentNode.replaceChild(newEl, el);
        el = newEl;
      }
    }
    var comp = el.closest('.ve-comp');
    if (comp) {
      wireElements();
      notifyCompChange(comp);
    }
  }

  // Escape a string for use as a CSS attribute-selector value.
  function cssEscapeAttr(v){ return (v || '').replace(/(["\\\\])/g, '\\\\$1'); }

  function deleteConfirmedElement(elemId){
    var el = document.querySelector('[data-ve-elem-id="' + elemId + '"]');
    if (!el) return;
    var comp = el.closest('.ve-comp');
    clearSelection();
    el.parentNode.removeChild(el);
    if (comp) notifyCompChange(comp);
  }

  // Parent → iframe message handler
  window.addEventListener('message', function(e){
    if (!e.data) return;
    var d = e.data;
    if (d.type === 'VE_APPLY_ELEMENT') { applyUpdateToElement(d); clearSelection(); return; }
    if (d.type === 'VE_APPLY_STYLE') { applyStyleUpdate(d.elemId, d.style, d.className); return; }
    if (d.type === 'VE_DELETE_ELEMENT') { deleteConfirmedElement(d.elemId); return; }
    if (d.type === 'VE_PARENT_UPDATE_COMP') {
      var comp = document.querySelector('.ve-comp[data-comp-idx="' + d.idx + '"]');
      if (comp) { clearSelection(); comp.innerHTML = d.innerHtml; wireComp(comp); wireElements(); }
      return;
    }
    if (d.type === 'VE_CLEAR_SELECTION') { clearSelection(); return; }
    if (d.type === 'VE_DRAG_START') {
      DRAG_PAYLOAD = { html: d.html, name: d.name };
      return;
    }
    if (d.type === 'VE_DRAG_END') {
      DRAG_PAYLOAD = null;
      clearDropUI();
      return;
    }
    if (d.type === 'VE_REQUEST_HIERARCHY') {
      post({ type: 'VE_HIERARCHY_SNAPSHOT', tree: buildHierarchy() });
      return;
    }
    if (d.type === 'VE_SELECT_ELEM_ID') {
      selectByElemId(d.elemId);
      return;
    }
  });

  function init(){
    Array.prototype.slice.call(document.querySelectorAll('.ve-comp')).forEach(wireComp);
    wireElements();
    post({ type: 'VE_READY' });
    post({ type: 'VE_HIERARCHY_SNAPSHOT', tree: buildHierarchy() });
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
  else init();
})();
<\/script>
  `.trim();

function renderIframe() {
  const frame = document.getElementById('viewport-frame');
  frame.srcdoc = buildFullHTML({ forEdit: true });
}

/* ═══════════════════════════════════════════
   IFRAME MESSAGE HANDLER
═══════════════════════════════════════════ */
window.addEventListener('message', (e) => {
  const d = e.data;
  if (!d || !d.type) return;
  if (d.type === 'VE_READY') { /* iframe is ready */ }
  if (d.type === 'VE_EDIT_COMP') { openSourceModal(d.idx); }
  if (d.type === 'VE_EDIT_ELEMENT') { openElemModal(d); }
  if (d.type === 'VE_EDIT_ELEMENT_CODE') { openElementCodeEditor(d); }
  if (d.type === 'VE_CONFIRM_DELETE') { handleConfirmDelete(d); }
  if (d.type === 'VE_SELECTION_CHANGED') {
    onSelectionChanged(d);
    HIERARCHY.selectedElemId = d.elemId || null;
    renderHierarchy();
    // If the hierarchy tab is visible, scroll the selected node into view
    if (d.elemId) {
      setTimeout(() => {
        const selectedNode = document.querySelector('.hier-node.is-selected');
        if (selectedNode && selectedNode.scrollIntoView) {
          selectedNode.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }
      }, 60);
    }
  }
  if (d.type === 'VE_HIERARCHY_SNAPSHOT') { onHierarchySnapshot(d.tree); }
  if (d.type === 'VE_REORDER_COMP') {
    // Move a top-level component up or down in the page order
    const from = d.fromIdx;
    const to = d.direction === 'up' ? from - 1 : from + 1;
    if (from < 0 || from >= STATE.components.length || to < 0 || to >= STATE.components.length) {
      toast('Component is already at the ' + (d.direction === 'up' ? 'top' : 'bottom'), 'info', 2000);
      return;
    }
    const [moved] = STATE.components.splice(from, 1);
    STATE.components.splice(to, 0, moved);
    STATE.components.forEach((c, i) => { c.content_order = i + 1; });
    STATE.components.forEach((_, i) => STATE.dirty.add(i));
    renderSidebar();
    renderIframe();
    updateStatus();
    toast('Component moved ' + d.direction, 'success', 2000);
  }
  if (d.type === 'VE_DROP_COMPLETE') { toast('Inserted: ' + d.name, 'success', 2500); }
  if (d.type === 'VE_DRAG_FEEDBACK') { /* optional visual feedback */ }
  if (d.type === 'VE_UPDATE_COMP') {
    const idx = d.idx;
    if (idx >= 0 && idx < STATE.components.length) {
      STATE.components[idx].content_details = d.innerHtml;
      STATE.dirty.add(idx);
      renderSidebar();
      updateStatus();
      flashSaveIndicator('Updated');
    }
  }
});

function flashSaveIndicator(msg = 'Applied') {
  const ind = document.getElementById('tbSaveInd');
  const txt = document.getElementById('tbSaveIndTxt');
  txt.textContent = msg;
  ind.classList.add('visible');
  clearTimeout(flashSaveIndicator._t);
  flashSaveIndicator._t = setTimeout(() => ind.classList.remove('visible'), 2000);
}

/* ═══════════════════════════════════════════
   SOURCE EDITOR MODAL
═══════════════════════════════════════════ */
function openSourceModal(idx) {
  if (idx < 0 || idx >= STATE.components.length) return;
  STATE.currentEditIdx = idx;
  const c = STATE.components[idx];
  const isPhp = !!c.content_is_php;
  document.getElementById('srcModalTitle').textContent =
    c.content_name + (isPhp ? '  —  PHP source (server-rendered)' : '');

  const backdrop = document.getElementById('srcModalBackdrop');
  backdrop.classList.add('visible');
  showSrcTab('editor');

  if (!STATE.aceEditor) {
    STATE.aceEditor = ace.edit('srcEditor', {
      mode: 'ace/mode/html',
      theme: 'ace/theme/tomorrow_night',
      fontSize: '12px',
      wrap: true,
      showPrintMargin: false,
      tabSize: 2,
      useSoftTabs: true,
      enableBasicAutocompletion: true,
      enableLiveAutocompletion: true,
      enableSnippets: true,
    });
    STATE.aceEditor.container.style.fontFamily = "'JetBrains Mono', ui-monospace, monospace";
  }
  // Switch mode based on component type
  STATE.aceEditor.session.setMode(isPhp ? 'ace/mode/php' : 'ace/mode/html');
  STATE.aceEditor.setValue(c.content_details, -1);
  STATE.aceEditor.clearSelection();
  STATE.aceEditor.focus();
  setTimeout(() => STATE.aceEditor.resize(), 100);
}

function closeSourceModal() {
  document.getElementById('srcModalBackdrop').classList.remove('visible');
  STATE.currentEditIdx = -1;
  STATE.currentElemCodeMode = false;
  CODE_EDIT.compIdx = -1; CODE_EDIT.elemId = null;
}

function showSrcTab(tab) {
  const tabs = document.querySelectorAll('.modal-tab');
  const panels = document.querySelectorAll('.modal-tab-panel');
  tabs.forEach(t => t.classList.remove('active'));
  panels.forEach(p => p.classList.remove('active'));
  if (tab === 'editor') {
    tabs[0].classList.add('active');
    document.getElementById('srcTabEditor').classList.add('active');
    setTimeout(() => STATE.aceEditor?.resize(), 50);
  } else {
    tabs[1].classList.add('active');
    document.getElementById('srcTabPreview').classList.add('active');
    renderSrcPreview();
  }
}

function renderSrcPreview() {
  if (STATE.currentEditIdx < 0) return;
  const html = STATE.aceEditor ? STATE.aceEditor.getValue() : STATE.components[STATE.currentEditIdx].content_details;
  const baseTag = getBaseTag();
  // Prefer the JSON's header/footer when available so the preview matches the real page
  let previewHTML;
  if (STATE.header && STATE.footer) {
    let headerHtml = STATE.header.header_content;
    if (baseTag && /<head[^>]*>/i.test(headerHtml)) {
      headerHtml = headerHtml.replace(/<head[^>]*>/i, (m) => m + baseTag);
    }
    previewHTML = headerHtml + html + STATE.footer.footer_content;
  } else {
    const head = STATE.headTemplate || '';
    previewHTML = `<!DOCTYPE html><html><head>${baseTag}${head}</head><body class="bkrm-body ms-backgroundImage">${html}</body></html>`;
  }
  document.getElementById('previewPanel').srcdoc = previewHTML;
}

function applySourceEdit() {
  if (!STATE.aceEditor) return;
  const newContent = STATE.aceEditor.getValue();

  // Per-element code edit mode
  if (STATE.currentElemCodeMode && CODE_EDIT.elemId) {
    sendToIframe({
      type: 'VE_APPLY_ELEMENT',
      kind: 'code',
      elemId: CODE_EDIT.elemId,
      outerHtml: newContent,
    });
    STATE.currentElemCodeMode = false;
    CODE_EDIT.compIdx = -1; CODE_EDIT.elemId = null;
    closeSourceModal();
    flashSaveIndicator('Element updated');
    toast('Element HTML updated', 'success');
    return;
  }

  // Whole-component mode
  if (STATE.currentEditIdx < 0) return;
  const idx = STATE.currentEditIdx;
  const orig = STATE.components[idx]._originalDetails;
  STATE.components[idx].content_details = newContent;
  if (newContent !== orig) STATE.dirty.add(idx);
  else STATE.dirty.delete(idx);
  renderSidebar();
  renderIframe();
  updateStatus();
  closeSourceModal();
  flashSaveIndicator('Applied');
  toast('Component updated: ' + STATE.components[idx].content_name, 'success');
}

function resetCurrentComponent() {
  if (STATE.currentEditIdx < 0) return;
  const c = STATE.components[STATE.currentEditIdx];
  if (STATE.aceEditor) {
    STATE.aceEditor.setValue(c._originalDetails, -1);
    STATE.aceEditor.clearSelection();
  }
  toast('Reverted to original', 'info');
}

/* ═══════════════════════════════════════════
   SAVE / EXPORT
═══════════════════════════════════════════ */
function buildPayload() {
  // Reassemble the JSON in the same shape the API sends it.
  // content_order is recomputed from the current array order (1..N) so drag-reorder
  // in the UI translates directly to the saved order.
  const data = STATE.components.map((c, i) => {
    const row = {
      content_id: c.content_id,
      content_name: c.content_name,
      content_details: c.content_details,
      content_is_php: c.content_is_php,
      content_status: c.content_status,
      content_order: i + 1,
    };
    if (c._isNew) row._isNew = true;
    return row;
  });

  const obj = { status: 'success', data };

  if (STATE.header) {
    obj.header = {
      header_id: STATE.header.header_id,
      header_content: STATE.header.header_content,
      header_is_php: STATE.header.header_is_php,
      header_description: STATE.header.header_description,
    };
    if (STATE.dirtyHeader) obj.header._isDirty = true;
  }
  if (STATE.footer) {
    obj.footer = {
      footer_id: STATE.footer.footer_id,
      footer_content: STATE.footer.footer_content,
      footer_is_php: STATE.footer.footer_is_php,
      footer_description: STATE.footer.footer_description,
    };
    if (STATE.dirtyFooter) obj.footer._isDirty = true;
  }

  const pid = document.getElementById('apiPageId').value.trim();
  if (pid) obj.page_id = pid;

  return obj;
}

function openSaveDialog() {
  if (!STATE.components.length) {
    toast('Load a components.json first', 'warning');
    return;
  }
  if (STATE.dirty.size === 0) {
    toast('No changes to save', 'info');
    return;
  }

  const payload = buildPayload();
  const payloadStr = JSON.stringify(payload, null, 2);

  document.getElementById('saveTotalComp').textContent = STATE.components.length;
  document.getElementById('saveDirtyComp').textContent = STATE.dirty.size;
  document.getElementById('savePayloadSize').textContent = formatBytes(new Blob([payloadStr]).size);

  // List
  const list = document.getElementById('saveList');
  list.innerHTML = '';
  STATE.components.forEach((c, i) => {
    const row = document.createElement('div');
    row.className = 'save-list-item';
    const dirty = STATE.dirty.has(i);
    row.innerHTML = `
      <div class="save-list-status ${dirty ? 'dirty' : ''}"></div>
      <div class="save-list-name">${escapeHtml(c.content_name)} ${dirty ? '<span style="color:var(--accent);font-size:10px;margin-left:6px;font-weight:700;">MODIFIED</span>' : ''}</div>
      <div class="save-list-size">${formatBytes(c.content_details.length)}</div>
    `;
    list.appendChild(row);
  });

  // Preview (first 4000 chars)
  let preview = payloadStr;
  if (preview.length > 4000) preview = preview.substring(0, 4000) + '\n… [truncated, ' + (payloadStr.length - 4000) + ' more chars]';
  document.getElementById('savePayloadPreview').textContent = preview;

  document.getElementById('saveModalBackdrop').classList.add('visible');
}

function closeSaveModal() {
  document.getElementById('saveModalBackdrop').classList.remove('visible');
}

function copyPayload() {
  const str = JSON.stringify(buildPayload(), null, 2);
  navigator.clipboard.writeText(str).then(
    () => toast('Payload copied to clipboard', 'success'),
    () => toast('Could not copy', 'error')
  );
}

function downloadPayload() {
  const str = JSON.stringify(buildPayload(), null, 2);
  const blob = new Blob([str], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  const pid = document.getElementById('apiPageId').value.trim() || 'page';
  a.download = `components_${pid}_${new Date().toISOString().slice(0,10)}.json`;
  a.click();
  URL.revokeObjectURL(url);
  toast('Downloaded', 'success');
}

async function sendToServer() {
  const tmpl = document.getElementById('apiSaveUrl').value.trim();
  const pid  = document.getElementById('apiPageId').value.trim();
  if (!tmpl) {
    toast('Please set the Save URL first', 'warning');
    return;
  }
  const url = resolveUrl(tmpl, pid);
  showLoader('Sending to server…');
  try {
    const payload = buildPayload();
    const res = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        ...parseCustomHeaders(),
      },
      body: JSON.stringify(payload),
      credentials: 'include',
    });
    hideLoader();
    let body;
    try { body = await res.json(); } catch(_) { body = await res.text(); }
    if (!res.ok) {
      toast(`Server error ${res.status}: ${typeof body === 'string' ? body.substring(0,120) : (body.message || 'Unknown')}`, 'error', 6000);
      console.error('Save failed:', body);
      return;
    }
    toast('Saved to server ✓', 'success', 4000);
    //console.log(JSON.stringify(payload));
    
    // Mark all as clean
    STATE.components.forEach(c => { c._originalDetails = c.content_details; });
    STATE.dirty.clear();
    renderSidebar();
    updateStatus();
    closeSaveModal();
    flashSaveIndicator('Saved');
  } catch (err) {
    hideLoader();
    toast('Network error: ' + (err.message || 'Could not reach server'), 'error', 6000);
    console.error(err);
  }
}

/* ═══════════════════════════════════════════
   ELEMENT EDITOR (text / image / link)
═══════════════════════════════════════════ */
// Tracks the element currently being edited (by component index + element id)
const ELEM_EDIT = { compIdx: -1, elemId: null, kind: null, tag: null };

function openElemModal(payload) {
  ELEM_EDIT.compIdx = payload.compIdx;
  ELEM_EDIT.elemId = payload.elemId;
  ELEM_EDIT.kind = payload.kind;
  ELEM_EDIT.tag = payload.tag || '';

  // Reset all variants
  document.querySelectorAll('.elem-variant').forEach(v => v.style.display = 'none');

  const iconEl = document.getElementById('elemModalIcon');
  const titleEl = document.getElementById('elemModalTitle');
  const eyebrowEl = document.getElementById('elemModalEyebrow');

  if (payload.kind === 'text') {
    eyebrowEl.textContent = 'Edit Text';
    titleEl.textContent = 'Change text inside <' + (payload.tag || 'element') + '>';
    iconEl.style.background = 'linear-gradient(135deg,#10b981,#059669)';
    iconEl.innerHTML = '<i class="bi bi-fonts"></i>';
    document.getElementById('elemVariantText').style.display = 'flex';
    document.getElementById('elemText').value = payload.text || '';
    document.getElementById('elemTextTag').textContent = '<' + (payload.tag || 'element') + '>';
    setTimeout(() => document.getElementById('elemText').focus(), 100);
  } else if (payload.kind === 'image') {
    eyebrowEl.textContent = 'Edit Image';
    titleEl.textContent = 'Replace or adjust image';
    iconEl.style.background = 'linear-gradient(135deg,#a78bfa,#7c3aed)';
    iconEl.innerHTML = '<i class="bi bi-image"></i>';
    document.getElementById('elemVariantImage').style.display = 'flex';
    const srcEl = document.getElementById('elemImgSrc');
    const previewEl = document.getElementById('elemImgPreview');
    srcEl.value = payload.src || '';
    document.getElementById('elemImgAlt').value = payload.alt || '';
    document.getElementById('elemImgTitle').value = payload.title || '';
    // Preview: if src is relative, resolve against asset base
    previewEl.src = resolveImgPreviewUrl(payload.src || '');
    previewEl.onload = () => updateElemImgSize();
    previewEl.onerror = () => {
      document.getElementById('elemImgSize').textContent = '(preview failed to load)';
    };
    updateElemImgSize();
    // Reset file input
    document.getElementById('elemImgFile').value = '';
  } else if (payload.kind === 'link') {
    eyebrowEl.textContent = 'Edit Link';
    titleEl.textContent = 'Change link target';
    iconEl.style.background = 'linear-gradient(135deg,#06b6d4,#0891b2)';
    iconEl.innerHTML = '<i class="bi bi-link-45deg"></i>';
    document.getElementById('elemVariantLink').style.display = 'flex';
    const isTextLink = payload.text != null;
    document.getElementById('elemLinkTextRow').style.display = isTextLink ? 'block' : 'none';
    document.getElementById('elemLinkNonTextHint').style.display = isTextLink ? 'none' : 'flex';
    document.getElementById('elemLinkText').value = isTextLink ? payload.text : '';
    document.getElementById('elemLinkHref').value = payload.href || '';
    document.getElementById('elemLinkTarget').value = payload.target || '';
    document.getElementById('elemLinkTitle').value = payload.title || '';
    setTimeout(() => document.getElementById(isTextLink ? 'elemLinkText' : 'elemLinkHref').focus(), 100);
  } else {
    toast('Unknown element type', 'error');
    return;
  }

  document.getElementById('elemModalBackdrop').classList.add('visible');
}

function closeElemModal() {
  document.getElementById('elemModalBackdrop').classList.remove('visible');
  // Tell iframe to clear its selection
  sendToIframe({ type: 'VE_CLEAR_SELECTION' });
  ELEM_EDIT.compIdx = -1; ELEM_EDIT.elemId = null; ELEM_EDIT.kind = null; ELEM_EDIT.tag = null;
}

function sendToIframe(msg) {
  const f = document.getElementById('viewport-frame');
  try { f.contentWindow.postMessage(msg, '*'); } catch(_) {}
}

function resolveImgPreviewUrl(src) {
  if (!src) return 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
  if (/^(https?:|data:|blob:)/i.test(src)) return src;
  // Relative path → resolve against asset base
  let base = document.getElementById('assetBase').value.trim();
  if (!base || base === '/') base = window.location.origin + '/';
  else if (!base.endsWith('/')) base += '/';
  return base.replace(/\/$/, '') + (src.startsWith('/') ? src : '/' + src);
}

function updateElemImgSize() {
  const img = document.getElementById('elemImgPreview');
  const sizeEl = document.getElementById('elemImgSize');
  if (img.naturalWidth) {
    sizeEl.textContent = img.naturalWidth + ' × ' + img.naturalHeight + ' px';
  } else {
    sizeEl.textContent = '';
  }
}

// File upload: read as base64 data URL
function elemImgOnFile(file) {
  if (!file) return;
  if (!file.type.startsWith('image/')) { toast('Not an image file', 'error'); return; }
  const MAX = 8 * 1024 * 1024; // 8MB
  if (file.size > MAX) {
    toast('Image is ' + (file.size / 1024 / 1024).toFixed(1) + ' MB — may bloat the payload', 'warning', 4500);
  }
  const reader = new FileReader();
  reader.onload = (e) => {
    const dataUrl = e.target.result;
    document.getElementById('elemImgSrc').value = dataUrl;
    const preview = document.getElementById('elemImgPreview');
    preview.src = dataUrl;
    preview.onload = updateElemImgSize;
    // If alt is empty, suggest filename
    const altEl = document.getElementById('elemImgAlt');
    if (!altEl.value) altEl.value = file.name.replace(/\.[^.]+$/, '').replace(/[-_]/g, ' ');
    toast('Image loaded as base64 (' + formatBytes(dataUrl.length) + ')', 'success', 3000);
  };
  reader.onerror = () => toast('Could not read file', 'error');
  reader.readAsDataURL(file);
}

function wireElemImgDrop() {
  const drop = document.getElementById('elemImgDrop');
  const input = document.getElementById('elemImgFile');
  if (!drop || !input || drop._wired) return;
  drop._wired = true;
  input.addEventListener('change', (e) => elemImgOnFile(e.target.files?.[0]));
  drop.addEventListener('dragover', (e) => { e.preventDefault(); drop.classList.add('drag-over'); });
  drop.addEventListener('dragleave', () => drop.classList.remove('drag-over'));
  drop.addEventListener('drop', (e) => {
    e.preventDefault();
    drop.classList.remove('drag-over');
    elemImgOnFile(e.dataTransfer.files?.[0]);
  });
  // Also listen to src input changes for preview refresh
  document.getElementById('elemImgSrc').addEventListener('change', (e) => {
    document.getElementById('elemImgPreview').src = resolveImgPreviewUrl(e.target.value);
  });
}

function applyElemEdit() {
  if (!ELEM_EDIT.elemId || ELEM_EDIT.compIdx < 0) return;
  const msg = {
    type: 'VE_APPLY_ELEMENT',
    kind: ELEM_EDIT.kind,
    elemId: ELEM_EDIT.elemId,
    compIdx: ELEM_EDIT.compIdx,
  };
  if (ELEM_EDIT.kind === 'text') {
    msg.text = document.getElementById('elemText').value;
  } else if (ELEM_EDIT.kind === 'image') {
    msg.src = document.getElementById('elemImgSrc').value.trim();
    msg.alt = document.getElementById('elemImgAlt').value;
    msg.title = document.getElementById('elemImgTitle').value;
  } else if (ELEM_EDIT.kind === 'link') {
    msg.href = document.getElementById('elemLinkHref').value.trim();
    msg.target = document.getElementById('elemLinkTarget').value;
    msg.title = document.getElementById('elemLinkTitle').value;
    const textRow = document.getElementById('elemLinkTextRow');
    if (textRow.style.display !== 'none') {
      msg.text = document.getElementById('elemLinkText').value;
    }
  }
  sendToIframe(msg);
  document.getElementById('elemModalBackdrop').classList.remove('visible');
  flashSaveIndicator('Applied');
  toast('Element updated', 'success', 2500);
  ELEM_EDIT.compIdx = -1; ELEM_EDIT.elemId = null; ELEM_EDIT.kind = null;
}


function openAuthHelp(evt) {
  if (evt) { evt.preventDefault(); evt.stopPropagation(); }
  document.getElementById('authHelpBackdrop').classList.add('visible');
}
function closeAuthHelp() {
  document.getElementById('authHelpBackdrop').classList.remove('visible');
}

/* ═══════════════════════════════════════════
   PREVIEW
═══════════════════════════════════════════ */
function openPreviewInNewTab() {
  if (!STATE.components.length) { toast('Load components first', 'warning'); return; }
  // Use buildFullHTML with forEdit:false (no editor UI) and absoluteBase:true
  // (blob URL needs an absolute base for relative paths to resolve).
  // This uses the SAME state as the editor iframe, so your edits are always current.
  const html = buildFullHTML({ forEdit: false, absoluteBase: true });
  const blob = new Blob([html], { type: 'text/html' });
  const url = URL.createObjectURL(blob);
  const win = window.open(url, '_blank');
  setTimeout(() => URL.revokeObjectURL(url), 5000);
  if (!win) toast('Pop-up blocked', 'warning');
}

// Explicit refresh — re-render the iframe from current state.
function refreshPreview() {
  if (!STATE.components.length) {
    toast('Nothing to refresh — load components first', 'info');
    return;
  }
  renderIframe();
  flashSaveIndicator('Refreshed');
}

/* ═══════════════════════════════════════════
   HIERARCHY TAB (right panel)
═══════════════════════════════════════════ */
const HIERARCHY = {
  tree: null,
  selectedElemId: null,
  collapsed: new Set(),     // component roots collapsed by the user
  filter: '',
};

function switchRightTab(tab) {
  document.querySelectorAll('.props-tab').forEach(t => t.classList.toggle('active', t.dataset.rtab === tab));
  document.querySelectorAll('.props-tab-panel').forEach(p => p.classList.toggle('active', p.dataset.rtabPanel === tab));
  if (tab === 'hierarchy') refreshHierarchy();
}

function refreshHierarchy() {
  // Ask the iframe for a fresh snapshot
  sendToIframe({ type: 'VE_REQUEST_HIERARCHY' });
}

function onHierarchySnapshot(tree) {
  HIERARCHY.tree = tree;
  renderHierarchy();
}

function renderHierarchy() {
  const emptyEl = document.getElementById('hierEmpty');
  const treeEl = document.getElementById('hierTree');
  const tree = HIERARCHY.tree;
  if (!tree || tree.length === 0) {
    emptyEl.style.display = 'block';
    treeEl.style.display = 'none';
    return;
  }
  emptyEl.style.display = 'none';
  treeEl.style.display = 'block';
  treeEl.innerHTML = '';
  tree.forEach(compRoot => {
    treeEl.appendChild(renderHierarchyNode(compRoot, 0));
  });
  if (HIERARCHY.filter) applyHierarchyFilter();
}

function renderHierarchyNode(node, depth) {
  const wrapper = document.createElement('div');
  wrapper.className = 'hier-node-wrap';

  const nodeEl = document.createElement('div');
  nodeEl.className = 'hier-node';
  if (node.isCompRoot) {
    nodeEl.classList.add('is-comp-root');
  }
  if (node.elemId && node.elemId === HIERARCHY.selectedElemId) {
    nodeEl.classList.add('is-selected');
  }
  // Indentation
  nodeEl.style.paddingLeft = (depth * 12 + 8) + 'px';

  const hasChildren = node.children && node.children.length > 0;
  // Expand/collapse toggle
  const toggle = document.createElement('span');
  toggle.className = 'hier-toggle' + (hasChildren ? '' : ' leaf');
  const collapsed = node.isCompRoot && HIERARCHY.collapsed.has(node.compIdx);
  toggle.classList.toggle('collapsed', collapsed);
  toggle.innerHTML = '▾';
  if (hasChildren) {
    toggle.onclick = (e) => {
      e.stopPropagation();
      if (node.isCompRoot) {
        if (HIERARCHY.collapsed.has(node.compIdx)) HIERARCHY.collapsed.delete(node.compIdx);
        else HIERARCHY.collapsed.add(node.compIdx);
      }
      // For non-root nodes we use the DOM toggle directly
      const container = wrapper.querySelector('.hier-children');
      if (container) container.classList.toggle('collapsed');
      toggle.classList.toggle('collapsed');
    };
  }
  nodeEl.appendChild(toggle);

  if (node.isCompRoot) {
    // Component root: show name + order (lookup from STATE)
    const comp = STATE.components.find((c, i) => i === node.compIdx);
    const icon = document.createElement('span');
    icon.className = 'hier-icon';
    icon.innerHTML = comp?.content_is_php
      ? '<i class="bi bi-filetype-php" style="color:#a78bfa;"></i>'
      : (isInfra(node.name) ? '<i class="bi bi-braces-asterisk" style="color:var(--accent);"></i>' : '<i class="bi bi-window-stack" style="color:var(--accent);"></i>');
    nodeEl.appendChild(icon);
    const nameSpan = document.createElement('span');
    nameSpan.className = 'hier-tag';
    nameSpan.textContent = prettyName(node.name);
    nodeEl.appendChild(nameSpan);
    nodeEl.onclick = () => {
      // Clicking component root opens the source modal (since the whole thing is the editable unit)
      openSourceModal(node.compIdx);
    };
  } else {
    // DOM node
    const icon = document.createElement('span');
    icon.className = 'hier-icon kind-' + (node.kind || 'container');
    const iconMap = {
      text: '<i class="bi bi-fonts"></i>',
      image: '<i class="bi bi-image"></i>',
      link: '<i class="bi bi-link-45deg"></i>',
      list: '<i class="bi bi-list-ul"></i>',
      container: '<i class="bi bi-square"></i>',
    };
    icon.innerHTML = iconMap[node.kind] || iconMap.container;
    nodeEl.appendChild(icon);

    const tag = document.createElement('span');
    tag.className = 'hier-tag';
    tag.textContent = node.tag;
    nodeEl.appendChild(tag);

    if (node.id) {
      const idSpan = document.createElement('span');
      idSpan.className = 'hier-id';
      idSpan.textContent = '#' + node.id.substring(0, 20);
      nodeEl.appendChild(idSpan);
    }
    if (node.classes && node.classes.length > 0) {
      const cls = document.createElement('span');
      cls.className = 'hier-cls';
      cls.textContent = '.' + node.classes.join('.');
      nodeEl.appendChild(cls);
    }
    if (node.preview) {
      const txt = document.createElement('span');
      txt.className = 'hier-txt';
      txt.textContent = '"' + node.preview + (node.preview.length >= 40 ? '…' : '') + '"';
      nodeEl.appendChild(txt);
    }
    nodeEl.onclick = () => {
      if (node.elemId) {
        sendToIframe({ type: 'VE_SELECT_ELEM_ID', elemId: node.elemId });
        // Also switch right panel to Properties so the user can start editing immediately
        switchRightTab('properties');
      }
    };
  }
  wrapper.appendChild(nodeEl);

  if (hasChildren) {
    const childrenDiv = document.createElement('div');
    childrenDiv.className = 'hier-children' + (collapsed ? ' collapsed' : '');
    node.children.forEach(child => {
      childrenDiv.appendChild(renderHierarchyNode(child, depth + 1));
    });
    wrapper.appendChild(childrenDiv);
  }
  return wrapper;
}

function filterHierarchy(query) {
  HIERARCHY.filter = (query || '').trim().toLowerCase();
  applyHierarchyFilter();
}

function applyHierarchyFilter() {
  const f = HIERARCHY.filter;
  const nodes = document.querySelectorAll('.hier-node');
  if (!f) {
    nodes.forEach(n => n.classList.remove('hier-hidden'));
    return;
  }
  nodes.forEach(n => {
    const txt = n.textContent.toLowerCase();
    n.classList.toggle('hier-hidden', !txt.includes(f));
  });
}


const NEW_COMP_TEMPLATES = {
  empty: '<div class="new-section" style="padding:20px;">\n  \n</div>',
  section: '<section style="padding:40px 20px;max-width:1200px;margin:0 auto;">\n  <h2 style="margin:0 0 12px;">Section title</h2>\n  <p style="line-height:1.6;color:#555;">Your section content goes here.</p>\n</section>',
  banner: '<div style="position:relative;padding:60px 40px;background:linear-gradient(135deg,#4f6ef7,#7c5ef5);color:#fff;text-align:center;border-radius:8px;margin:20px 0;">\n  <h2 style="margin:0 0 12px;font-size:28px;">Banner headline</h2>\n  <p style="margin:0 0 20px;opacity:0.9;">Compelling banner description.</p>\n  <a href="#" style="display:inline-block;padding:12px 28px;background:#fff;color:#4f6ef7;text-decoration:none;border-radius:6px;font-weight:700;">Call to action</a>\n</div>',
  grid2: '<div style="display:grid;grid-template-columns:1fr 1fr;gap:24px;padding:40px 20px;max-width:1200px;margin:0 auto;">\n  <div>\n    <h3>Left column</h3>\n    <p>First column content.</p>\n  </div>\n  <div>\n    <h3>Right column</h3>\n    <p>Second column content.</p>\n  </div>\n</div>',
  cards3: '<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:20px;padding:40px 20px;max-width:1200px;margin:0 auto;">\n  <div style="padding:24px;background:#fff;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,.1);">\n    <h3 style="margin:0 0 8px;">Feature one</h3>\n    <p style="margin:0;color:#666;">Describe your first feature.</p>\n  </div>\n  <div style="padding:24px;background:#fff;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,.1);">\n    <h3 style="margin:0 0 8px;">Feature two</h3>\n    <p style="margin:0;color:#666;">Describe your second feature.</p>\n  </div>\n  <div style="padding:24px;background:#fff;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,.1);">\n    <h3 style="margin:0 0 8px;">Feature three</h3>\n    <p style="margin:0;color:#666;">Describe your third feature.</p>\n  </div>\n</div>',
  custom: '',
};

function openNewCompModal() {
  // Suggest a name based on existing prefix pattern
  const existing = STATE.components[0]?.content_name || 'MARCOMM - COMPONENT';
  const prefix = existing.match(/^([A-Z]+\s*-\s*)/)?.[1] || 'MARCOMM - ';
  const n = STATE.components.filter(c => c._isNew).length + 1;
  document.getElementById('newCompName').value = prefix + 'CUSTOM ' + n;
  document.getElementById('newCompTemplate').value = 'section';
  onNewCompTemplateChange();
  document.getElementById('newCompInsertAt').value = 'before-footer';
  document.getElementById('newCompBackdrop').classList.add('visible');
  setTimeout(() => document.getElementById('newCompName').focus(), 100);
}

function closeNewCompModal() {
  document.getElementById('newCompBackdrop').classList.remove('visible');
}

function onNewCompTemplateChange() {
  const key = document.getElementById('newCompTemplate').value;
  const html = NEW_COMP_TEMPLATES[key];
  if (html !== undefined) {
    document.getElementById('newCompHtml').value = html;
    updateNewCompCharCount();
  }
}

function updateNewCompCharCount() {
  const n = document.getElementById('newCompHtml').value.length;
  document.getElementById('newCompCharCount').textContent = n + ' chars';
}

function createNewComponent() {
  const name = document.getElementById('newCompName').value.trim();
  const html = document.getElementById('newCompHtml').value;
  const insertAt = document.getElementById('newCompInsertAt').value;
  if (!name) { toast('Component name is required', 'warning'); return; }
  if (STATE.components.some(c => c.content_name === name)) {
    toast('A component with this name already exists', 'error');
    return;
  }

  // Build the new component — use a negative temporary content_id so the server
  // knows this is new (combined with the _isNew flag).
  const newComp = {
    content_id: STATE.nextNewCompId--,
    content_name: name,
    content_details: html || '<div></div>',
    content_is_php: 0,
    content_status: 1,
    content_order: 0, // will be reassigned below after insertion
    _originalDetails: '',   // empty so it's always considered dirty
    _isNew: true,
  };

  // Determine insertion index
  const find = (n) => STATE.components.findIndex(c => c.content_name === n);
  let idx;
  switch (insertAt) {
    case 'after-header': {
      const i = find('MARCOMM - HEADER');
      idx = i >= 0 ? i + 1 : STATE.components.length;
      break;
    }
    case 'before-home': {
      const i = find('MARCOMM - HOME');
      idx = i >= 0 ? i : STATE.components.length;
      break;
    }
    case 'after-home': {
      const i = find('MARCOMM - HOME');
      idx = i >= 0 ? i + 1 : STATE.components.length;
      break;
    }
    case 'before-footer': {
      const i = find('MARCOMM - FOOTER');
      idx = i >= 0 ? i : STATE.components.length;
      break;
    }
    default:
      idx = STATE.components.length;
  }

  STATE.components.splice(idx, 0, newComp);
  // Renumber content_order 1..N to reflect the new insertion
  STATE.components.forEach((c, i) => { c.content_order = i + 1; });
  // Shift dirty indices that were at-or-after the insertion point
  const newDirty = new Set();
  STATE.dirty.forEach(d => newDirty.add(d >= idx ? d + 1 : d));
  newDirty.add(idx); // mark the new component as dirty so it saves
  STATE.dirty = newDirty;

  closeNewCompModal();
  renderSidebar();
  renderIframe();
  updateStatus();
  flashSaveIndicator('Component added');
  toast('Added new component: ' + name, 'success', 3000);
}

// Remove a newly-added component (no-op if it was loaded from API)
function removeNewComponent(idx) {
  const c = STATE.components[idx];
  if (!c || !c._isNew) return;
  if (!confirm('Remove this new component? It hasn\'t been saved to the server yet.')) return;
  STATE.components.splice(idx, 1);
  // Rebuild dirty set
  const newDirty = new Set();
  STATE.dirty.forEach(d => {
    if (d < idx) newDirty.add(d);
    else if (d > idx) newDirty.add(d - 1);
  });
  STATE.dirty = newDirty;
  renderSidebar();
  renderIframe();
  updateStatus();
  toast('Removed new component', 'info', 2500);
}


function toggleLeftPanel() {
  const app = document.getElementById('app');
  app.classList.toggle('left-collapsed');
  document.getElementById('btnToggleLeft').classList.toggle('active', !app.classList.contains('left-collapsed'));
}
function toggleRightPanel() {
  const app = document.getElementById('app');
  app.classList.toggle('right-collapsed');
  document.getElementById('btnToggleRight').classList.toggle('active', !app.classList.contains('right-collapsed'));
}
function switchSidebarTab(tab) {
  document.querySelectorAll('.sb-tab').forEach(t => t.classList.toggle('active', t.dataset.tab === tab));
  document.querySelectorAll('.sb-tab-panel').forEach(p => p.classList.toggle('active', p.dataset.tabPanel === tab));
}

/* ═══════════════════════════════════════════
   LIBRARY (draggable HTML blocks)
═══════════════════════════════════════════ */
const LIBRARY = [
  { category: 'Layout', items: [
    { name: 'Section',   icon: 'bi-square',           html: '<section style="padding:40px 20px;"><h2>Section title</h2><p>Section content goes here.</p></section>', cat: 'layout' },
    { name: 'Container', icon: 'bi-bounding-box',     html: '<div class="container" style="max-width:1200px;margin:0 auto;padding:0 20px;"><!-- content --></div>', cat: 'layout' },
    { name: 'Row (flex)', icon: 'bi-distribute-horizontal', html: '<div style="display:flex;gap:16px;align-items:stretch;"><div style="flex:1;padding:16px;background:#f5f5f5;">Column 1</div><div style="flex:1;padding:16px;background:#eee;">Column 2</div></div>', cat: 'layout' },
    { name: '2 Columns', icon: 'bi-layout-split',     html: '<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px;"><div>Left column</div><div>Right column</div></div>', cat: 'layout' },
    { name: '3 Columns', icon: 'bi-layout-three-columns', html: '<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px;"><div>Column 1</div><div>Column 2</div><div>Column 3</div></div>', cat: 'layout' },
    { name: 'Divider',   icon: 'bi-dash-lg',          html: '<hr style="border:none;border-top:1px solid #ddd;margin:24px 0;">', cat: 'layout' },
    { name: 'Spacer',    icon: 'bi-arrows-expand',    html: '<div style="height:40px;"></div>', cat: 'layout' },
  ]},
  { category: 'Text', items: [
    { name: 'Heading 1', icon: 'bi-type-h1', html: '<h1 style="margin:0 0 12px;">Heading 1</h1>', cat: 'text' },
    { name: 'Heading 2', icon: 'bi-type-h2', html: '<h2 style="margin:0 0 10px;">Heading 2</h2>', cat: 'text' },
    { name: 'Heading 3', icon: 'bi-type-h3', html: '<h3 style="margin:0 0 8px;">Heading 3</h3>', cat: 'text' },
    { name: 'Paragraph', icon: 'bi-paragraph', html: '<p style="margin:0 0 12px;line-height:1.6;">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>', cat: 'text' },
    { name: 'Quote',     icon: 'bi-quote', html: '<blockquote style="border-left:3px solid #4f6ef7;padding:8px 16px;margin:16px 0;color:#555;font-style:italic;">A meaningful quote goes here.</blockquote>', cat: 'text' },
    { name: 'Ordered List', icon: 'bi-list-ol', html: '<ol><li>First item</li><li>Second item</li><li>Third item</li></ol>', cat: 'text' },
    { name: 'Bullet List',  icon: 'bi-list-ul', html: '<ul><li>First item</li><li>Second item</li><li>Third item</li></ul>', cat: 'text' },
  ]},
  { category: 'Media', items: [
    { name: 'Image',  icon: 'bi-image', html: '<img src="https://via.placeholder.com/600x300" alt="Placeholder" style="max-width:100%;display:block;">', cat: 'media' },
    { name: 'Video',  icon: 'bi-camera-video', html: '<video src="" controls style="max-width:100%;display:block;">Your browser does not support video.</video>', cat: 'media' },
    { name: 'Icon',   icon: 'bi-star-fill', html: '<i class="bi bi-star-fill" style="font-size:24px;color:#f59e0b;"></i>', cat: 'media' },
    { name: 'Figure', icon: 'bi-card-image', html: '<figure style="margin:0;"><img src="https://via.placeholder.com/600x300" alt="Placeholder" style="max-width:100%;display:block;"><figcaption style="padding:8px 0;color:#666;font-size:14px;">Figure caption</figcaption></figure>', cat: 'media' },
  ]},
  { category: 'Form', items: [
    { name: 'Button',    icon: 'bi-hand-index-thumb', html: '<button type="button" style="padding:10px 20px;background:#4f6ef7;color:#fff;border:none;border-radius:6px;font-weight:600;cursor:pointer;">Click me</button>', cat: 'form' },
    { name: 'Outline Btn', icon: 'bi-square', html: '<button type="button" style="padding:10px 20px;background:transparent;color:#4f6ef7;border:2px solid #4f6ef7;border-radius:6px;font-weight:600;cursor:pointer;">Outline button</button>', cat: 'form' },
    { name: 'Pill Btn',  icon: 'bi-capsule', html: '<button type="button" style="padding:10px 24px;background:#10b981;color:#fff;border:none;border-radius:999px;font-weight:700;cursor:pointer;">Rounded button</button>', cat: 'form' },
    { name: 'Link Btn',  icon: 'bi-link-45deg', html: '<a href="#" style="display:inline-block;padding:10px 20px;background:#4f6ef7;color:#fff;text-decoration:none;border-radius:6px;font-weight:600;">Learn more</a>', cat: 'form' },
    { name: 'Icon Btn',  icon: 'bi-star-fill', html: '<button type="button" style="width:40px;height:40px;background:#4f6ef7;color:#fff;border:none;border-radius:50%;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;"><i class="bi bi-star-fill"></i></button>', cat: 'form' },
    { name: 'Text Input', icon: 'bi-input-cursor-text', html: '<input type="text" placeholder="Enter text" style="padding:8px 12px;border:1px solid #ccc;border-radius:6px;width:100%;">', cat: 'form' },
    { name: 'Textarea',  icon: 'bi-textarea-t', html: '<textarea placeholder="Enter message" rows="4" style="padding:8px 12px;border:1px solid #ccc;border-radius:6px;width:100%;"></textarea>', cat: 'form' },
    { name: 'Checkbox',  icon: 'bi-check-square', html: '<label style="display:flex;align-items:center;gap:8px;"><input type="checkbox"> Check this</label>', cat: 'form' },
  ]},
  { category: 'UI', items: [
    { name: 'Card',     icon: 'bi-card-heading', html: '<div style="border:1px solid #e5e7eb;border-radius:8px;padding:20px;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.08);"><h3 style="margin:0 0 8px;">Card title</h3><p style="margin:0;color:#666;">Card description goes here.</p></div>', cat: 'ui' },
    { name: 'Alert',    icon: 'bi-exclamation-triangle', html: '<div style="padding:12px 16px;background:#fef3c7;border-left:3px solid #f59e0b;border-radius:6px;color:#92400e;"><strong>Note:</strong> An important message.</div>', cat: 'ui' },
    { name: 'Badge',    icon: 'bi-tag', html: '<span style="display:inline-block;padding:2px 10px;background:#e0e7ff;color:#3730a3;border-radius:10px;font-size:12px;font-weight:600;">NEW</span>', cat: 'ui' },
    { name: 'Progress', icon: 'bi-bar-chart-line', html: '<div style="background:#e5e7eb;border-radius:10px;height:8px;overflow:hidden;"><div style="width:60%;height:100%;background:#4f6ef7;"></div></div>', cat: 'ui' },
    { name: 'HTML',     icon: 'bi-code-slash', html: '<!-- Custom HTML block -->\n<div>Your content</div>', cat: 'ui' },
  ]},
];

function renderLibrary() {
  const list = document.getElementById('libList');
  list.innerHTML = '';
  LIBRARY.forEach(cat => {
    const title = document.createElement('div');
    title.className = 'lib-cat-title';
    title.textContent = cat.category;
    list.appendChild(title);
    cat.items.forEach(item => {
      const el = document.createElement('div');
      el.className = 'lib-item cat-' + item.cat;
      el.draggable = true;
      el.innerHTML = `
        <div class="lib-item-icon"><i class="bi ${item.icon}"></i></div>
        <div class="lib-item-name">${item.name}</div>
      `;
      el.addEventListener('dragstart', (e) => {
        e.dataTransfer.setData('text/html', item.html);
        e.dataTransfer.effectAllowed = 'copy';
        el.classList.add('dragging');
        document.body.classList.add('drag-active');
        DRAG_STATE.html = item.html;
        DRAG_STATE.name = item.name;
        // Announce to iframe so it knows a drag is in progress and what HTML to insert on drop
        sendToIframe({ type: 'VE_DRAG_START', html: item.html, name: item.name });
      });
      el.addEventListener('dragend', () => {
        el.classList.remove('dragging');
        document.body.classList.remove('drag-active');
        sendToIframe({ type: 'VE_DRAG_END' });
        DRAG_STATE.html = null; DRAG_STATE.name = null;
      });
      list.appendChild(el);
    });
  });
}

// Drag state (parent coordinates)
const DRAG_STATE = { html: null, name: null };

// The iframe now listens for its own dragenter/dragover/drop events.
// The parent just pre-announces the HTML payload via VE_DRAG_START
// so the iframe knows what to insert when the drop happens.
// No wiring needed on the parent side beyond the library items' dragstart/dragend.
function wireIframeDrag() {
  // kept for symmetry; nothing to do here anymore
}

/* ═══════════════════════════════════════════
   PROPERTIES PANEL
═══════════════════════════════════════════ */
const PROPS_STATE = { compIdx: -1, elemId: null, kind: null, tag: null, style: '', className: '' };

function onSelectionChanged(sel) {
  const emptyEl = document.getElementById('propsEmpty');
  const contentEl = document.getElementById('propsContent');
  const chipEl = document.getElementById('propsTagChip');
  if (!sel || !sel.elemId) {
    emptyEl.style.display = 'block';
    contentEl.style.display = 'none';
    chipEl.style.display = 'none';
    PROPS_STATE.compIdx = -1; PROPS_STATE.elemId = null; PROPS_STATE.kind = null;
    return;
  }
  PROPS_STATE.compIdx = sel.compIdx;
  PROPS_STATE.elemId = sel.elemId;
  PROPS_STATE.kind = sel.kind;
  PROPS_STATE.tag = sel.tag;
  PROPS_STATE.style = sel.style || '';
  PROPS_STATE.className = sel.className || '';

  emptyEl.style.display = 'none';
  contentEl.style.display = 'block';
  chipEl.style.display = 'inline-block';
  chipEl.textContent = '<' + sel.tag + '>';

  populatePropsFromStyle(sel.style || '', sel.className || '');
}

// Parse an inline `style="..."` string into a map of property → value
function parseInlineStyle(styleStr) {
  const out = {};
  (styleStr || '').split(';').forEach(part => {
    const idx = part.indexOf(':');
    if (idx < 1) return;
    const k = part.substring(0, idx).trim().toLowerCase();
    const v = part.substring(idx + 1).trim();
    if (k) out[k] = v;
  });
  return out;
}

// Serialize a property map back into a style string
function stringifyInlineStyle(map) {
  const parts = [];
  Object.keys(map).forEach(k => {
    const v = map[k];
    if (v !== '' && v != null) parts.push(k + ': ' + v);
  });
  return parts.join('; ') + (parts.length ? ';' : '');
}

function populatePropsFromStyle(styleStr, className) {
  const map = parseInlineStyle(styleStr);
  // Set each field's value by looking up its data-style mapping
  document.querySelectorAll('[data-style]').forEach(input => {
    const prop = input.dataset.style;
    input.value = map[prop] || '';
  });
  // Color inputs
  document.querySelectorAll('[data-style-color]').forEach(input => {
    const prop = input.dataset.styleColor;
    const v = map[prop] || '';
    input.value = cssColorToHex(v) || '#000000';
  });
  document.getElementById('pClassName').value = className || '';
  document.getElementById('pRawStyle').value = styleStr || '';
}

// Best-effort conversion of a CSS color value to #rrggbb for a <input type="color">
function cssColorToHex(v) {
  if (!v) return '';
  if (/^#[0-9a-f]{6}$/i.test(v)) return v.toLowerCase();
  if (/^#[0-9a-f]{3}$/i.test(v)) return '#' + v.substring(1).split('').map(c => c + c).join('').toLowerCase();
  const rgb = v.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i);
  if (rgb) {
    return '#' + [rgb[1], rgb[2], rgb[3]].map(n => parseInt(n, 10).toString(16).padStart(2, '0')).join('');
  }
  return '';
}

function commitPropsChange() {
  if (!PROPS_STATE.elemId) return;
  // Gather current field values into a style map
  const map = {};
  document.querySelectorAll('[data-style]').forEach(input => {
    const prop = input.dataset.style;
    const val = (input.value || '').trim();
    if (val) map[prop] = val;
  });
  const styleStr = stringifyInlineStyle(map);
  const className = document.getElementById('pClassName').value.trim();
  // Update the raw style mirror
  document.getElementById('pRawStyle').value = styleStr;
  PROPS_STATE.style = styleStr;
  PROPS_STATE.className = className;
  sendToIframe({
    type: 'VE_APPLY_STYLE',
    elemId: PROPS_STATE.elemId,
    style: styleStr,
    className: className,
  });
}

function commitRawStyleChange() {
  if (!PROPS_STATE.elemId) return;
  const raw = document.getElementById('pRawStyle').value;
  // Push raw directly
  PROPS_STATE.style = raw;
  // Re-populate individual fields
  populatePropsFromStyle(raw, document.getElementById('pClassName').value);
  sendToIframe({
    type: 'VE_APPLY_STYLE',
    elemId: PROPS_STATE.elemId,
    style: raw,
    className: document.getElementById('pClassName').value.trim(),
  });
}

function wirePropsPanel() {
  // All regular data-style inputs
  document.querySelectorAll('[data-style]').forEach(input => {
    const ev = (input.tagName === 'SELECT' ? 'change' : 'input');
    input.addEventListener(ev, commitPropsChange);
    if (ev === 'input') input.addEventListener('blur', commitPropsChange);
  });
  // Color pickers mirror into their sibling text input
  document.querySelectorAll('[data-style-color]').forEach(color => {
    color.addEventListener('input', (e) => {
      const prop = color.dataset.styleColor;
      const textInput = document.getElementById('pStyle_' + prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase()));
      if (textInput) { textInput.value = e.target.value; commitPropsChange(); }
    });
  });
  document.getElementById('pClassName').addEventListener('input', commitPropsChange);
  document.getElementById('pClassName').addEventListener('blur', commitPropsChange);
  document.getElementById('pRawStyle').addEventListener('blur', commitRawStyleChange);

  // Background image uploader → base64
  const bgFile = document.getElementById('pBgImageFile');
  if (bgFile) {
    bgFile.addEventListener('change', (e) => {
      const file = e.target.files?.[0];
      if (!file) return;
      if (!file.type.startsWith('image/')) { toast('Not an image file', 'error'); return; }
      const MAX = 8 * 1024 * 1024;
      if (file.size > MAX) {
        toast('Image is ' + (file.size / 1024 / 1024).toFixed(1) + ' MB — may bloat the payload', 'warning', 4500);
      }
      const reader = new FileReader();
      reader.onload = (ev) => {
        const dataUrl = ev.target.result;
        const bgInput = document.getElementById('pStyle_backgroundImage');
        bgInput.value = 'url("' + dataUrl + '")';
        commitPropsChange();
        toast('Background image set (' + formatBytes(dataUrl.length) + ')', 'success', 3000);
      };
      reader.onerror = () => toast('Could not read file', 'error');
      reader.readAsDataURL(file);
      e.target.value = '';
    });
  }
}

function clearBgImage() {
  const bgInput = document.getElementById('pStyle_backgroundImage');
  if (bgInput) {
    bgInput.value = '';
    commitPropsChange();
  }
}

/* ═══════════════════════════════════════════
   ELEMENT CODE EDITOR (per-element source)
═══════════════════════════════════════════ */
const CODE_EDIT = { compIdx: -1, elemId: null, aceInstance: null };

function openElementCodeEditor(payload) {
  CODE_EDIT.compIdx = payload.compIdx;
  CODE_EDIT.elemId = payload.elemId;

  const modalTitle = document.getElementById('srcModalTitle');
  modalTitle.textContent = 'Edit element HTML: <' + payload.tag + '>';
  document.getElementById('srcModalBackdrop').classList.add('visible');
  showSrcTab('editor');
  // Flag that we're in per-element code mode
  STATE.currentEditIdx = -1;   // not a component
  STATE.currentElemCodeMode = true;

  if (!STATE.aceEditor) {
    STATE.aceEditor = ace.edit('srcEditor', {
      mode: 'ace/mode/html', theme: 'ace/theme/tomorrow_night',
      fontSize: '12px', wrap: true, showPrintMargin: false,
      tabSize: 2, useSoftTabs: true,
      enableBasicAutocompletion: true, enableLiveAutocompletion: true,
    });
    STATE.aceEditor.container.style.fontFamily = "'JetBrains Mono', ui-monospace, monospace";
  }
  STATE.aceEditor.setValue(payload.outerHtml, -1);
  STATE.aceEditor.clearSelection();
  STATE.aceEditor.focus();
  setTimeout(() => STATE.aceEditor.resize(), 100);
}

/* ═══════════════════════════════════════════
   DELETE CONFIRM
═══════════════════════════════════════════ */
function handleConfirmDelete(payload) {
  if (confirm('Delete this <' + payload.tag + '> element? This cannot be undone unless you reload.')) {
    sendToIframe({ type: 'VE_DELETE_ELEMENT', elemId: payload.elemId });
    toast('Element deleted', 'success', 2500);
  }
}


// On load: populate head template only. Components load manually via
// "Load File" / "Load from API" / "Use demo data".
window.addEventListener('DOMContentLoaded', () => {
  // Head template: text/plain script tag contains raw HTML with closing-script tags escaped as <\/script
  const headTag = document.getElementById('__head_template_data__');
  if (headTag) {
    let raw = headTag.textContent;
    if (raw) raw = raw.replace(/<\\\/script/gi, '<\/script');
    raw = raw.trim();
    if (raw && !raw.startsWith('/*')) {
      STATE.headTemplate = raw;
    }
  }
  // Initialize the new panels
  renderLibrary();
  wireIframeDrag();
  wirePropsPanel();

  // Start with both panels HIDDEN so the workspace takes the full width
  const app = document.getElementById('app');
  app.classList.add('left-collapsed', 'right-collapsed');
  document.getElementById('btnToggleLeft').classList.remove('active');
  document.getElementById('btnToggleRight').classList.remove('active');

  // Empty breadcrumb at start — populated when a page loads
  updateBreadcrumb();

  // ── URL parameter auto-load ──
  // Supports ?page_id=N to auto-fetch a page from the API on startup.
  // Optional overrides:  ?load_url=...  ?save_url=...  ?asset_base=...
  // After a manual load, we also rewrite the URL via history.replaceState so
  // the current editor state is bookmarkable/shareable.
  applyUrlParams();
});

function applyUrlParams() {
  const params = new URLSearchParams(window.location.search);
  const pid = params.get('page_id') || params.get('pageId') || params.get('id');
  const loadUrl = params.get('load_url');
  const saveUrl = params.get('save_url');
  const assetBase = params.get('asset_base') || params.get('assetBase');

  if (loadUrl) document.getElementById('apiLoadUrl').value = loadUrl;
  if (saveUrl) document.getElementById('apiSaveUrl').value = saveUrl;
  if (assetBase) document.getElementById('assetBase').value = assetBase;

  if (pid) {
    document.getElementById('apiPageId').value = pid;
    // Show a brief loader on the empty state so the user knows we're auto-fetching
    toast('Auto-loading page ' + pid + '…', 'info', 2500);
    // Give the DOM a tick to settle before firing the API call
    setTimeout(() => loadFromAPI(), 60);
  }
}

// When a page successfully loads via the API, update the URL to reflect the
// current page_id so it's bookmarkable. Also handles browser back/forward if
// the user later navigates.
function syncUrlWithPageId(pid) {
  if (!pid) return;
  try {
    const url = new URL(window.location.href);
    url.searchParams.set('page_id', pid);
    history.replaceState(null, '', url.toString());
  } catch (e) { /* ignore — some embedded contexts disallow pushState */ }
}

// Keyboard: Esc to close modals, Ctrl/Cmd+S to open save dialog
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    if (document.getElementById('newCompBackdrop').classList.contains('visible')) {
      closeNewCompModal(); e.preventDefault();
    } else if (document.getElementById('elemModalBackdrop').classList.contains('visible')) {
      closeElemModal(); e.preventDefault();
    } else if (document.getElementById('srcModalBackdrop').classList.contains('visible')) {
      closeSourceModal(); e.preventDefault();
    } else if (document.getElementById('saveModalBackdrop').classList.contains('visible')) {
      closeSaveModal(); e.preventDefault();
    } else if (document.getElementById('authHelpBackdrop').classList.contains('visible')) {
      closeAuthHelp(); e.preventDefault();
    }
  }
  if ((e.ctrlKey || e.metaKey) && e.key === 's') {
    e.preventDefault();
    if (document.getElementById('newCompBackdrop').classList.contains('visible')) {
      createNewComponent();
    } else if (document.getElementById('elemModalBackdrop').classList.contains('visible')) {
      applyElemEdit();
    } else if (document.getElementById('srcModalBackdrop').classList.contains('visible')) {
      applySourceEdit();
    } else {
      openSaveDialog();
    }
  }
});

// Click outside modal to close (on backdrop itself, not the modal card)
document.getElementById('srcModalBackdrop').addEventListener('click', (e) => {
  if (e.target.id === 'srcModalBackdrop') closeSourceModal();
});
document.getElementById('saveModalBackdrop').addEventListener('click', (e) => {
  if (e.target.id === 'saveModalBackdrop') closeSaveModal();
});
document.getElementById('authHelpBackdrop').addEventListener('click', (e) => {
  if (e.target.id === 'authHelpBackdrop') closeAuthHelp();
});
document.getElementById('elemModalBackdrop').addEventListener('click', (e) => {
  if (e.target.id === 'elemModalBackdrop') closeElemModal();
});
document.getElementById('newCompBackdrop').addEventListener('click', (e) => {
  if (e.target.id === 'newCompBackdrop') closeNewCompModal();
});

// Enter in single-line element editor inputs → apply
['elemLinkText','elemLinkHref','elemLinkTitle','elemImgSrc','elemImgAlt','elemImgTitle'].forEach(id => {
  const el = document.getElementById(id);
  if (el) el.addEventListener('keydown', (e) => {
    if (e.key === 'Enter') { e.preventDefault(); applyElemEdit(); }
  });
});

// Wire image upload / drop on modal open (called once on DOMContentLoaded)
wireElemImgDrop();

// Auto-refresh the preview when Asset Base changes (on blur or Enter).
// Using 'change' not 'input' so we don't flicker on every keystroke.
document.getElementById('assetBase').addEventListener('change', () => {
  if (STATE.components.length) {
    renderIframe();
    flashSaveIndicator('Asset base updated');
  }
});
// Also refresh on Enter inside the Asset Base field
document.getElementById('assetBase').addEventListener('keydown', (e) => {
  if (e.key === 'Enter') { e.target.blur(); }
});
</script>

<!-- ═══════════════════════════════════════════
     EMBEDDED HEAD TEMPLATE (extracted from page-source.html)
     This is the <head> inner HTML used to render the iframe preview.
══════════════════════════════════════════════ -->
<script type="text/plain" id="__head_template_data__"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=10">
        <meta name="GENERATOR" content="Microsoft SharePoint">
        <meta http-equiv="Expires" content="0">
        <title>
            Marcomm
        </title>
        <link rel="stylesheet" type="text/css" href="/portalassets/Marcomm/corev15.css">
        <link rel="stylesheet" type="text/css" href="/portalassets/Marcomm/bkrmportalmaster.css">
        <link rel="stylesheet" type="text/css" href="/portalassets/Marcomm/bkrmportalwebpart.css">
        <link rel="stylesheet" type="text/css" href="/portalassets/Marcomm/carousel.css">
        <link rel="stylesheet" type="text/css" href="/portalassets/Marcomm/SuiteNav.css">

        <script type="text/javascript" src="/portalassets/Marcomm/initstrings.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/init.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/jquery1.12.4.min.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/jquery.ctt.timeslider.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/ScriptResource.axd"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/blank.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/ScriptResource(1).axd"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/suitenav.js.download"><\/script>
        <script type="text/javascript">RegisterSod("require.js", "\u002f_layouts\u002f15\u002frequire.js?rev=\u00252BRRfOnYW0VaAgSoCgcIN8Q\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("strings.js", "\u002f_layouts\u002f15\u002f1033\u002fstrings.js?rev=k\u00252FSaOdWtcHDDvsb\u00252FUFykOA\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("sp.res.resx", "\u002f_layouts\u002f15\u002f1033\u002fsp.res.js?rev=MbB92HT8biYuFa\u00252B1vTMilA\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("sp.runtime.js", "\u002f_layouts\u002f15\u002fsp.runtime.js?rev=LiLvWscZ25MQUF\u00252BucpVI\u00252FQ\u00253D\u00253DTAG0"); RegisterSodDep("sp.runtime.js", "sp.res.resx");<\/script>
        <script type="text/javascript">RegisterSod("sp.js", "\u002f_layouts\u002f15\u002fsp.js?rev=wodXBbvfSljkJvZKPlUJug\u00253D\u00253DTAG0"); RegisterSodDep("sp.js", "sp.runtime.js"); RegisterSodDep("sp.js", "sp.ui.dialog.js"); RegisterSodDep("sp.js", "sp.res.resx");<\/script>
        <script type="text/javascript">RegisterSod("sp.init.js", "\u002f_layouts\u002f15\u002fsp.init.js?rev=e\u00252BK\u00252BgPRahLRqldGOZRBeEA\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("sp.ui.dialog.js", "\u002f_layouts\u002f15\u002fsp.ui.dialog.js?rev=jGY\u00252BLOSvHa47C54DL7qxOA\u00253D\u00253DTAG0"); RegisterSodDep("sp.ui.dialog.js", "sp.init.js"); RegisterSodDep("sp.ui.dialog.js", "sp.res.resx");<\/script>
        <script type="text/javascript">RegisterSod("core.js", "\u002f_layouts\u002f15\u002fcore.js?rev=ooFtNhoOE2el6ilWzci55w\u00253D\u00253DTAG0"); RegisterSodDep("core.js", "strings.js");<\/script>
        <script type="text/javascript">RegisterSod("menu.js", "\u002f_layouts\u002f15\u002fmenu.js?rev=Py67mQ0RAr9mlkQz\u00252BmYM8w\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("mQuery.js", "\u002f_layouts\u002f15\u002fmquery.js?rev=1i9Wf5cruQ3eBhWimvF8LQ\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("callout.js", "\u002f_layouts\u002f15\u002fcallout.js?rev=7aZaGYa7iCsTKwQxNHL1uA\u00253D\u00253DTAG0"); RegisterSodDep("callout.js", "strings.js"); RegisterSodDep("callout.js", "mQuery.js"); RegisterSodDep("callout.js", "core.js");<\/script>
        <script type="text/javascript">RegisterSod("sp.core.js", "\u002f_layouts\u002f15\u002fsp.core.js?rev=HIq0NKatYLdTt5Qvq4rfgA\u00253D\u00253DTAG0"); RegisterSodDep("sp.core.js", "strings.js"); RegisterSodDep("sp.core.js", "sp.init.js"); RegisterSodDep("sp.core.js", "core.js");<\/script>
        <script type="text/javascript">RegisterSod("sharedhovercard.strings.js", "\u002f_layouts\u002f15\u002f1033\u002fsharedhovercard.strings.js?rev=sLsS\u00252FNPqFzOSO42e3s6lgw\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("sharedhovercard.js", "\u002f_layouts\u002f15\u002fsharedhovercard.js?rev=uB89up9szoXj8bAMKPkPSg\u00253D\u00253DTAG0"); RegisterSodDep("sharedhovercard.js", "sharedhovercard.strings.js");<\/script>
        <script type="text/javascript">RegisterSod("clienttemplates.js", "\u002f_layouts\u002f15\u002fclienttemplates.js?rev=j6\u00252Bz4BDO342fu4R4shpumw\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("sharing.js", "\u002f_layouts\u002f15\u002fsharing.js?rev=OM3H6lospXttTRqs0FqXSA\u00253D\u00253DTAG0"); RegisterSodDep("sharing.js", "strings.js"); RegisterSodDep("sharing.js", "mQuery.js"); RegisterSodDep("sharing.js", "clienttemplates.js"); RegisterSodDep("sharing.js", "core.js");<\/script>
        <script type="text/javascript">RegisterSod("suitelinks.js", "\u002f_layouts\u002f15\u002fsuitelinks.js?rev=iz6Biq\u00252FcdEEEbjmO8ge\u00252BxQ\u00253D\u00253DTAG0"); RegisterSodDep("suitelinks.js", "strings.js"); RegisterSodDep("suitelinks.js", "core.js");<\/script>
        <script type="text/javascript">RegisterSod("clientrenderer.js", "\u002f_layouts\u002f15\u002fclientrenderer.js?rev=icbWdD\u00252FlpVz8Naz\u00252FialdVQ\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("srch.resources.resx", "\u002f_layouts\u002f15\u002f1033\u002fsrch.resources.js?rev=YFZFsHKXct9hchZcv\u00252BUURA\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("search.clientcontrols.js", "\u002f_layouts\u002f15\u002fsearch.clientcontrols.js?rev=PlIH2VsdUhIBLzSKwU9PJQ\u00253D\u00253DTAG0"); RegisterSodDep("search.clientcontrols.js", "sp.init.js"); RegisterSodDep("search.clientcontrols.js", "clientrenderer.js"); RegisterSodDep("search.clientcontrols.js", "srch.resources.resx");<\/script>
        <script type="text/javascript">RegisterSod("cui.js", "\u002f_layouts\u002f15\u002fcui.js?rev=ss63uooxySpkPrQCHE\u00252Bu0Q\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("inplview", "\u002f_layouts\u002f15\u002finplview.js?rev=Qzgy7\u00252FqUZ9RKQe2Ivw9ZsQ\u00253D\u00253DTAG0"); RegisterSodDep("inplview", "strings.js"); RegisterSodDep("inplview", "core.js"); RegisterSodDep("inplview", "clienttemplates.js"); RegisterSodDep("inplview", "sp.js");<\/script>
        <script type="text/javascript">RegisterSod("ribbon", "\u002f_layouts\u002f15\u002fsp.ribbon.js?rev=XDUkPbH3Dw4Ozb7wYPpMpA\u00253D\u00253DTAG0"); RegisterSodDep("ribbon", "strings.js"); RegisterSodDep("ribbon", "core.js"); RegisterSodDep("ribbon", "sp.core.js"); RegisterSodDep("ribbon", "sp.js"); RegisterSodDep("ribbon", "cui.js"); RegisterSodDep("ribbon", "sp.res.resx"); RegisterSodDep("ribbon", "sp.runtime.js"); RegisterSodDep("ribbon", "inplview");<\/script>
        <script type="text/javascript">RegisterSod("sp.ui.policy.resources.resx", "\u002f_layouts\u002f15\u002fScriptResx.ashx?culture=en\u00252Dus\u0026name=SP\u00252EUI\u00252EPolicy\u00252EResources\u0026rev=m2Nvtm13DRgodCVi\u00252BsRukw\u00253D\u00253D");<\/script>
        <script type="text/javascript">RegisterSod("mdn.js", "\u002f_layouts\u002f15\u002fmdn.js?rev=8NNwivaC8jSLGWcNFulEiA\u00253D\u00253DTAG0"); RegisterSodDep("mdn.js", "sp.init.js"); RegisterSodDep("mdn.js", "core.js"); RegisterSodDep("mdn.js", "sp.runtime.js"); RegisterSodDep("mdn.js", "sp.js"); RegisterSodDep("mdn.js", "cui.js"); RegisterSodDep("mdn.js", "ribbon"); RegisterSodDep("mdn.js", "sp.ui.policy.resources.resx");<\/script>
        <script type="text/javascript">RegisterSod("socialdata.js", "\u002f_layouts\u002f15\u002fsocialdata.js?rev=bkq3o\u00252BkeqS8mhx5XUQWd\u00252BQ\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("sp.ui.socialribbon.js", "\u002f_layouts\u002f15\u002fsp.ui.socialribbon.js?rev=KiZAgV\u00252FKHVNmWf8h04Ua2Q\u00253D\u00253DTAG0"); RegisterSodDep("sp.ui.socialribbon.js", "ribbon"); RegisterSodDep("sp.ui.socialribbon.js", "socialdata.js");<\/script>
        <script type="text/javascript">RegisterSod("userprofile", "\u002f_layouts\u002f15\u002fsp.userprofiles.js?rev=cx6U8sP\u00252ByP0OFLjk6ekyIg\u00253D\u00253DTAG0"); RegisterSodDep("userprofile", "sp.runtime.js");<\/script>
        <script type="text/javascript">RegisterSod("followingcommon.js", "\u002f_layouts\u002f15\u002ffollowingcommon.js?rev=bJTBCEv1HgjaWwx\u00252BYKODBw\u00253D\u00253DTAG0"); RegisterSodDep("followingcommon.js", "strings.js"); RegisterSodDep("followingcommon.js", "sp.js"); RegisterSodDep("followingcommon.js", "userprofile"); RegisterSodDep("followingcommon.js", "core.js"); RegisterSodDep("followingcommon.js", "mQuery.js");<\/script>
        <script type="text/javascript">RegisterSod("profilebrowserscriptres.resx", "\u002f_layouts\u002f15\u002f1033\u002fprofilebrowserscriptres.js?rev=qwf69WaVc1mYlJLXqmZmVA\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("sp.ui.mysitecommon.js", "\u002f_layouts\u002f15\u002fsp.ui.mysitecommon.js?rev=RwXcuvJsiysDLpAqtmAQDQ\u00253D\u00253DTAG0"); RegisterSodDep("sp.ui.mysitecommon.js", "sp.init.js"); RegisterSodDep("sp.ui.mysitecommon.js", "sp.runtime.js"); RegisterSodDep("sp.ui.mysitecommon.js", "userprofile"); RegisterSodDep("sp.ui.mysitecommon.js", "profilebrowserscriptres.resx");<\/script>
        <script type="text/javascript">RegisterSod("browserScript", "\u002f_layouts\u002f15\u002fie55up.js?rev=sH5pKoCb6296RyPJOzqDLQ\u00253D\u00253DTAG0"); RegisterSodDep("browserScript", "strings.js");<\/script>
        <script type="text/javascript">RegisterSod("offline.js", "\u002f_layouts\u002f15\u002foffline.js?rev=TNvrnrBr6gGqmX6tutKqbQ\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("theming.js", "\u002f_layouts\u002f15\u002ftheming.js?rev=AQsQZgsKbypSwgIb\u00252BD\u00252FmYA\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("WPAdderClass", "\u002f_layouts\u002f15\u002fwpadder.js?rev=1Xu0VPodqII\u00252FBTg1dJEROA\u00253D\u00253DTAG0");<\/script>
        <script type="text/javascript">RegisterSod("dragdrop.js", "\u002f_layouts\u002f15\u002fdragdrop.js?rev=sS\u00252FVNxxoVRWr9Jx1O3\u00252BJLw\u00253D\u00253DTAG0"); RegisterSodDep("dragdrop.js", "strings.js");<\/script>
        <script type="text/javascript">RegisterSod("quicklaunch.js", "\u002f_layouts\u002f15\u002fquicklaunch.js?rev=vVofmuHQaUBrnociTb9cjQ\u00253D\u00253DTAG0"); RegisterSodDep("quicklaunch.js", "strings.js"); RegisterSodDep("quicklaunch.js", "dragdrop.js");<\/script>
        <link type="text/xml" rel="alternate" href="/marcomm/_vti_bin/spsdisco.aspx">

        <style type="text/css">
            .bkrm-pagetitle,
            .bkrm-sitetitle
            {
                display: none;
            }
            .bkrm-maincontent
            {
                background-color: transparent;
                overflow-x: hidden; /*custom page layout no scrolling*/
            }
            .bkrm-placeholdermain
            {
                width: 100%; /*show 100% coz no need show navigation or quick launch */
                overflow-x: hidden;
                padding-bottom: 0px; /*reduce from 100px in master page*/
            }
            #s4-ribbonrow
            {
                /*display: none;*/ /*to get extra height in display mode, appear back in edit mode*/
            }
            #s4-bodyContainer {
                min-height: 100vh;
            }
        </style>
        <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1">
        <link rel="canonical" href="http://brprodsp16web02:20000/marcomm">


        <script type="text/javascript" src="/portalassets/Marcomm/strings.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/sp.init.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/core.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/socialdata.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/mquery.js.download"><\/script>
        <script type="text/javascript" src="/portalassets/Marcomm/sp.core.js.download"><\/script></script>

<!-- ═══════════════════════════════════════════
     EMBEDDED DEMO DATA (the user's components.json)
══════════════════════════════════════════════ -->
<script type="application/json" id="__demo_data__">{"status":"success","data":[{"content_id":524,"content_name":"MARCOMM - WRAPPER START","content_details":"<style>\r\n    #s4-bodyContainer {\r\n    padding-bottom: 0px !important;\r\n    background: url(/assets/BRSPACE/images/bg-pattern.png) no-repeat;\r\n    background-size: cover;\r\n}\r\n</style>\r\n<span id=\"DeltaSPWebPartManager\">\r\n\r\n        </span>\r\n        <script type=\"text/javascript\">//<![CDATA[\r\n\r\n    $(document).ready(function () {\r\n\r\n    var a = window.location.href;\r\n    if (a.indexOf(\"osssearchresults\") != - 1) {\r\n\r\n    var divsToHide = document.getElementsByClassName(\"bkrm-search\");\r\n    for (var i = 0; i < divsToHide.length; i++) {\r\n    divsToHide[i].style.display = \"none\";\r\n    }\r\n    }\r\n    });\r\n    //]]><\/script>\r\n        <style type=\"text/css\">\r\n            .s4-skipribbonshortcut {\r\n                display:none;\r\n            }\r\n\r\n        </style>\r\n        <div id=\"imgPrefetch\" style=\"display:none\">\r\n            <img src=\"/portalassets/Marcomm/spcommon.png\">\r\n            <img src=\"/portalassets/Marcomm/logo-bkrm.png\">\r\n            <img src=\"/portalassets/Marcomm/spcommon.png\">\r\n        </div>\r\n        <form method=\"post\" action=\"/marcomm\" onsubmit=\"javascript:return WebForm_OnSubmit();\" id=\"aspnetForm\">\r\n            <div class=\"aspNetHidden\">\r\n                <input type=\"hidden\" name=\"_wpcmWpid\" id=\"_wpcmWpid\" value=\"\">\r\n                <input type=\"hidden\" name=\"wpcmVal\" id=\"wpcmVal\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOWebPartPage_PostbackSource\" id=\"MSOWebPartPage_PostbackSource\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOTlPn_SelectedWpId\" id=\"MSOTlPn_SelectedWpId\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOTlPn_View\" id=\"MSOTlPn_View\" value=\"0\">\r\n                <input type=\"hidden\" name=\"MSOTlPn_ShowSettings\" id=\"MSOTlPn_ShowSettings\" value=\"False\">\r\n                <input type=\"hidden\" name=\"MSOGallery_SelectedLibrary\" id=\"MSOGallery_SelectedLibrary\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOGallery_FilterString\" id=\"MSOGallery_FilterString\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOTlPn_Button\" id=\"MSOTlPn_Button\" value=\"none\">\r\n                <input type=\"hidden\" name=\"__EVENTTARGET\" id=\"__EVENTTARGET\" value=\"\">\r\n                <input type=\"hidden\" name=\"__EVENTARGUMENT\" id=\"__EVENTARGUMENT\" value=\"\">\r\n                <input type=\"hidden\" name=\"__REQUESTDIGEST\" id=\"__REQUESTDIGEST\" value=\"0x6FC9E39FAD18AB61B695E010CCD04DFCEAF10FBA581AEB94FEAAD42B9CE1FC40702E9F59B5D4B0943737444E08BB67BD0E9EB05E8250FD19D5533539062B9B9D,01 Oct 2024 03:48:15 -0000\">\r\n                <input type=\"hidden\" name=\"MSOAuthoringConsole_FormContext\" id=\"MSOAuthoringConsole_FormContext\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOAC_EditDuringWorkflow\" id=\"MSOAC_EditDuringWorkflow\" value=\"\">\r\n                <input type=\"hidden\" name=\"InputComments\" id=\"InputComments\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOSPWebPartManager_DisplayModeName\" id=\"MSOSPWebPartManager_DisplayModeName\" value=\"Browse\">\r\n                <input type=\"hidden\" name=\"MSOSPWebPartManager_ExitingDesignMode\" id=\"MSOSPWebPartManager_ExitingDesignMode\" value=\"false\">\r\n                <input type=\"hidden\" name=\"MSOWebPartPage_Shared\" id=\"MSOWebPartPage_Shared\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOLayout_LayoutChanges\" id=\"MSOLayout_LayoutChanges\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOLayout_InDesignMode\" id=\"MSOLayout_InDesignMode\" value=\"\">\r\n                <input type=\"hidden\" name=\"_wpSelected\" id=\"_wpSelected\" value=\"\">\r\n                <input type=\"hidden\" name=\"_wzSelected\" id=\"_wzSelected\" value=\"\">\r\n                <input type=\"hidden\" name=\"MSOSPWebPartManager_OldDisplayModeName\" id=\"MSOSPWebPartManager_OldDisplayModeName\" value=\"Browse\">\r\n                <input type=\"hidden\" name=\"MSOSPWebPartManager_StartWebPartEditingName\" id=\"MSOSPWebPartManager_StartWebPartEditingName\" value=\"false\">\r\n                <input type=\"hidden\" name=\"MSOSPWebPartManager_EndWebPartEditing\" id=\"MSOSPWebPartManager_EndWebPartEditing\" value=\"false\">\r\n                <input type=\"hidden\" name=\"_maintainWorkspaceScrollPosition\" id=\"_maintainWorkspaceScrollPosition\" value=\"0\">\r\n                <input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"/wEPDwUJNDQwMjg3NTk5D2QWAmYPZBYCAgEPZBYEAgEPZBYEAhEPZBYCAgMPZBYCZg9kFgJmDxQrAAZkBS5odHRwOi8vbXlzaXRlLmJhbmtyYWt5YXQuY29tLm15OjgwL1BlcnNvbi5hc3B4BSNodHRwOi8vbXlzaXRlLmJhbmtyYWt5YXQuY29tLm15OjgwLwUgL21hcmNvbW0vX2xheW91dHMvMTUvbXlzdWJzLmFzcHgFcC9tYXJjb21tL19sYXlvdXRzLzE1L3JlZ2lvbmFsc2V0bmcuYXNweD90eXBlPXVzZXImc291cmNlPWh0dHBzJTNBJTJGJTJGYnJzcGFjZSUyRWJhbmtyYWt5YXQlMkVjb20lMkVteSUyRm1hcmNvbW0FwwFodHRwOi8vbXlzaXRlLmJhbmtyYWt5YXQuY29tLm15OjgwL19sYXlvdXRzLzE1L0VkaXRQcm9maWxlLmFzcHg/VXNlclNldHRpbmdzUHJvdmlkZXI9MjM0YmYwZWQlMkQ3MGRiJTJENDE1OCUyRGEzMzIlMkQ0ZGZkNjgzYjQxNDgmUmV0dXJuVXJsPWh0dHBzJTNBJTJGJTJGYnJzcGFjZSUyRWJhbmtyYWt5YXQlMkVjb20lMkVteSUyRm1hcmNvbW1kAhMPZBYCAgEPZBYIBSZnXzY5OTAwMzY1X2Y5ZDdfNGNjNl85NjE0XzBmOTBiOTZlYWExZg9kFgJmD2QWBAIED2QWBAIBDxYCHgtfIUl0ZW1Db3VudAIBFgJmD2QWBmYPFQMVS2FkIEtyZWRpdC1pIE11c2xpbWFoYC9tYXJjb21tL1B1Ymxpc2hpbmdJbWFnZXMvTGlzdHMvQW5ub3VuY2VtZW50cy9BbGxJdGVtcy84NzN4MzgwLUludHJhbmV0LUJSU3BhY2UtQW5ub3VuY2VtZW50LmpwZ2RodHRwczovL2Jyc3BhY2UuYmFua3Jha3lhdC5jb20ubXkvbWFyY29tbS9wYWdlcy9Bbm5vdW5jZW1lbnREZXRhaWxzLmFzcHg/aXRlbUlEPTgmTGlzdD1Bbm5vdW5jZW1lbnRzZAIBDw8WAh4EVGV4dAUVS2FkIEtyZWRpdC1pIE11c2xpbWFoZGQCBQ8PFgIfAWVkZAIDDw8WAh4LTmF2aWdhdGVVcmwFWGh0dHBzOi8vYnJzcGFjZS5iYW5rcmFreWF0LmNvbS5teS9tYXJjb21tL3BhZ2VzL0FsbEFubm91bmNlbWVudHMuYXNweD9MaXN0PUFubm91bmNlbWVudHNkZAIGDxYCHwFlZAUmZ19hNjZmMmMyOV9hY2FiXzQzMmNfYjViM19mMjc0YmE1MTI3M2MPZBYCZg9kFgJmDxYCHgVzdHlsZQU7YmFja2dyb3VuZC1pbWFnZTp1cmwoL21hcmNvbW0vcGljdHVyZWxpYnJhcnkvb3JkZXJpbmcuanBnKTsWAgIBDxYCHgRocmVmBTBodHRwOi8vaW50cmFuZXQuYmFua3Jha3lhdC5jb20ubXkvbWtjbS9pbmRleC5waHAWBAIBDw8WAh8BBQhPcmRlcmluZ2RkAgMPDxYCHghJbWFnZVVybAUfL0JLUk1icmFuZGluZy9pY28vYXJyb3ctYnRuLnBuZ2RkBSZnXzkzMDUyODc5X2Y1OGFfNGIxYV84ZjhiXzhiMTVkZDIyYTk4ZA9kFgJmD2QWCgIBDw8WAh8BBQtMYXRlc3QgTmV3c2RkAgMPFgIfAGZkAgUPDxYCHgdWaXNpYmxlaGRkAgcPDxYCHwZoZGQCCQ8WAh8BBRxUaGVyZSBhcmUgY3VycmVudGx5IG5vIG5ld3MuZAUmZ181MDAwNTlhZF83ZTQyXzQzYWJfOGI4Y18xOWMxYmE1NzM5YzgPZBYCZg9kFgoCAQ8PFgIfAQUIQ2FtcGFpZ25kZAIDDxYCHwBmZAIFDw8WAh8GaGRkAgcPDxYCHwZoZGQCCQ8WAh8BBSBUaGVyZSBhcmUgY3VycmVudGx5IG5vIGNhbXBhaWduLmQCBQ9kFggCBA9kFgICAg9kFgQCAQ9kFgICAw9kFgJmD2QWBAIDD2QWDAIBDxYGHhNDbGllbnRPbkNsaWNrU2NyaXB0BY4BRW5zdXJlU2NyaXB0RnVuYygnc2hhcmluZy5qcycsICdEaXNwbGF5U2hhcmVkV2l0aERpYWxvZycsIGZ1bmN0aW9uICgpIHsgRGlzcGxheVNoYXJlZFdpdGhEaWFsb2coJ1x1MDAyZm1hcmNvbW1cdTAwMmYnLG51bGwsbnVsbCxudWxsLHRydWUpOyB9KR4oQ2xpZW50T25DbGlja1NjcmlwdENvbnRhaW5pbmdQcmVmaXhlZFVybAWOAUVuc3VyZVNjcmlwdEZ1bmMoJ3NoYXJpbmcuanMnLCAnRGlzcGxheVNoYXJlZFdpdGhEaWFsb2cnLCBmdW5jdGlvbiAoKSB7IERpc3BsYXlTaGFyZWRXaXRoRGlhbG9nKCdcdTAwMmZtYXJjb21tXHUwMDJmJyxudWxsLG51bGwsbnVsbCx0cnVlKTsgfSkeGENsaWVudE9uQ2xpY2tOYXZpZ2F0ZVVybGRkAgMPFgIfBmhkAgUPFgIfBmhkAgcPFgIfBmhkAgsPFgIfBmhkAg0PFgIfBmhkAgQPDxYCHglBY2Nlc3NLZXkFAS9kZAIDD2QWAgIBD2QWAgIBD2QWBgIBDw8WBB4EXyFTQgICHghDc3NDbGFzcwUXbXMtcHJvbW90ZWRBY3Rpb25CdXR0b25kZAIDD2QWAmYPDxYEHwsCAh8MBRdtcy1wcm9tb3RlZEFjdGlvbkJ1dHRvbmRkAgUPDxYGHwwFF21zLXByb21vdGVkQWN0aW9uQnV0dG9uHwsCAh8GaGRkAgoPZBYCAgMPZBYCAgEPPCsADQIADxYCHgtfIURhdGFCb3VuZGdkDBQrAAYFEzA6MCwwOjEsMDoyLDA6MywwOjQUKwACFhAfAQUESG9tZR4FVmFsdWUFBEhvbWUfAgUJL21hcmNvbW0vHgdFbmFibGVkZx4KU2VsZWN0YWJsZWceCERhdGFQYXRoBSQ2OTg3NDMyZC04NDA4LTRjMTctOTUxZC1lODliMDcxM2E3NzEeCURhdGFCb3VuZGceCFNlbGVjdGVkZ2QUKwACFg4fAQUIQWJvdXQgVXMfDgUIQWJvdXQgVXMfAgUbL21hcmNvbW0vUGFnZXMvQWJvdXRVcy5hc3B4Hw9nHxBnHxEFJDRiNzc3NTFjLTYzMTktNGY1MC1iMjkzLWM5NDg0ZTE3ZjYyZB8SZxQrAAQFCzA6MCwwOjEsMDoyFCsAAhYOHwEFEEV2ZW50IE1hbmFnZW1lbnQfDgUQRXZlbnQgTWFuYWdlbWVudB8CBS4vbWFyY29tbS9wYWdlcy9hYm91dHVzLmFzcHg/ZD1FdmVudCtNYW5hZ2VtZW50Hw9nHxBnHxEFJGUwZjljZWM0LTE3NGQtNGNkYi1hMDIzLTg3NDlkZjI0YzcyNB8SZ2QUKwACFg4fAQUJTWFya2V0aW5nHw4FCU1hcmtldGluZx8CBScvbWFyY29tbS9wYWdlcy9hYm91dHVzLmFzcHg/ZD1NYXJrZXRpbmcfD2cfEGcfEQUkYjg4MTQ0ODAtMWZjMC00MmEzLTgzMmUtNTBiMjI4OTgzNmUzHxJnZBQrAAIWDh8BBSVQdWJsaWMgUmVsYXRpb25zICYgQ29ycG9yYXRlIEJyYW5kaW5nHw4FJVB1YmxpYyBSZWxhdGlvbnMgJiBDb3Jwb3JhdGUgQnJhbmRpbmcfAgVFL21hcmNvbW0vcGFnZXMvYWJvdXR1cy5hc3B4P2Q9UHVibGljK1JlbGF0aW9ucyslMjYrQ29ycG9yYXRlK0JyYW5kaW5nHw9nHxBnHxEFJDU1ZWU4YjUxLTQ5MTgtNGNkZi1hMzRiLTIwOWJlOTM5MTYxMh8SZ2QUKwACFg4fAQUIQ2FtcGFpZ24fDgUIQ2FtcGFpZ24fAgUuL21hcmNvbW0vcGFnZXMvYWxsY2FtcGFpZ25zLmFzcHg/TGlzdD1DYW1wYWlnbh8PZx8QZx8RBSQyYmEzNzhjNy01MWUzLTQ3OWUtYWRjZC1iMWZlZjYzYTg1ZTMfEmdkFCsAAhYOHwEFCERvd25sb2FkHw4FCERvd25sb2FkHwIFEC9tYXJjb21tL2FyY2hpdmUfD2cfEGcfEQUkZjM4ZDI2ODktZGJkMy00YTlhLTg0ZDQtZDZjM2U5MmU4ZWIzHxJnZBQrAAIWDh8BBQROZXdzHw4FBE5ld3MfAgUsL21hcmNvbW0vcGFnZXMvYWxsbmV3cy5hc3B4P0xpc3Q9TGF0ZXN0K05ld3MfD2cfEGcfEQUkNzM3YjFhMzAtZDRiOS00MWY5LThlMmItY2M2YWEwNTU4MjllHxJnZGQCEA9kFgICAQ9kFgICAQ8WAh4TUHJldmlvdXNDb250cm9sTW9kZQspiAFNaWNyb3NvZnQuU2hhcmVQb2ludC5XZWJDb250cm9scy5TUENvbnRyb2xNb2RlLCBNaWNyb3NvZnQuU2hhcmVQb2ludCwgVmVyc2lvbj0xNi4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj03MWU5YmNlMTExZTk0MjljAWQCFA9kFgICAQ9kFgICAQ8PFgIfBmhkFgICAQ9kFgJmD2QWAgIDD2QWAgIFD2QWAgIBDzwrAAkBAA8WBB4NUGF0aFNlcGFyYXRvcgQIHg1OZXZlckV4cGFuZGVkZ2RkGAEFLGN0bDAwJFBsYWNlSG9sZGVyVG9wTmF2QmFyJFRvcE5hdmlnYXRpb25NZW51Dw9kBQRIb21lZKGE1lEVWskHJMGoHWLYbOUUc0ot9e1zdRvh3ii9/nAS\">\r\n            </div>\r\n\r\n            <script type=\"text/javascript\">\r\n            //<![CDATA[\r\n                var theForm = document.forms['aspnetForm'];\r\n                if (!theForm) {\r\n                theForm = document.aspnetForm;\r\n                }\r\n                function __doPostBack(eventTarget, eventArgument) {\r\n                if (!theForm.onsubmit || (theForm.onsubmit() != false)) {\r\n                theForm.__EVENTTARGET.value = eventTarget;\r\n                theForm.__EVENTARGUMENT.value = eventArgument;\r\n                theForm.submit();\r\n                }\r\n                }\r\n            //]]>\r\n            <\/script>\r\n\r\n\r\n            <script src=\"/portalassets/Marcomm/WebResource.axd\" type=\"text/javascript\"><\/script>\r\n\r\n\r\n            <script type=\"text/javascript\">\r\n            //<![CDATA[\r\n                var MSOWebPartPageFormName = 'aspnetForm';\r\n                var g_presenceEnabled = true;\r\n                var g_wsaEnabled = false;\r\n                var g_correlationId = 'e38555a1-82e0-205c-87fb-6ab78bb29ae0';\r\n                var g_wsaQoSEnabled = false;\r\n                var g_wsaQoSDataPoints = [];\r\n                var g_wsaRUMEnabled = false;\r\n                var g_wsaLCID = 1033;\r\n                var g_wsaListTemplateId = 850;\r\n                var g_wsaSiteTemplateId = 'STS#0';\r\n                var _fV4UI = true; var _spPageContextInfo = {webServerRelativeUrl: \"\\u002fmarcomm\", webAbsoluteUrl: \"https:\\u002f\\u002fbrspace.bankrakyat.com.my\\u002fmarcomm\", siteAbsoluteUrl: \"https:\\u002f\\u002fbrspace.bankrakyat.com.my\", serverRequestPath: \"\\u002fmarcomm\\u002fPages\\u002fHome.aspx\", layoutsUrl: \"_layouts\\u002f15\", webTitle: \"Marcomm\", webTemplate: \"1\", tenantAppVersion: \"0\", isAppWeb: false, webLogoUrl: \"\\u002fbkrmbranding\\u002flogo-bkrm.png\", webLanguage: 1033, currentLanguage: 1033, currentUICultureName: \"en-US\", currentCultureName: \"en-MY\", clientServerTimeDelta: new Date(\"2024-10-01T03:48:15.5277927Z\") - new Date(), updateFormDigestPageLoaded: new Date(\"2024-10-01T03:48:15.5277927Z\"), siteClientTag: \"86$16.0.4507.1000\", crossDomainPhotosEnabled:false, webUIVersion:15, webPermMasks:{High:176, Low:138612833}, pageListId:\"{91c71bb3-48b2-45ca-baf2-6adcd580162f}\", pageItemId:1, pagePersonalizationScope:1, userId:3399, userLoginName:\"bkrm\\\\2011014\", systemUserKey:\"i:0\\u0029.w|s-1-5-21-1343192282-1664774781-917132190-224503\", alertsEnabled:true, siteServerRelativeUrl: \"\\u002f\", allowSilverlightPrompt:'True', isSiteAdmin: false}; function CallServer_42262246(arg, context) {WebForm_DoCallback('ctl00$ctl20', arg, SP.UI.MyLinksRibbon.MyLinksRibbonPageComponent.ribbonActionCallback, context, null, false); }function _myLinksRibbonLoad2()\r\n                        {\r\n                        var fnd = function () {\r\n                        try {\r\n                        mylinks_init.MyLinksInit('CallServer_42262246');\r\n                        }\r\n                       catch (Ex)\r\n                        { }\r\n                        };\r\n                        RegisterSod('mylinks_init', '/_layouts/15/sp.ui.mylinksribbon.js?rev=0StMaEfxj2Emiye6tWPA%2BA%3D%3DTAG0');\r\n                        LoadSodByKey('mylinks_init', fnd);\r\n                        }\r\n\r\n                function _myLinksRibbonLoad1()\r\n                        {\r\n                        ExecuteOrDelayUntilScriptLoaded(_myLinksRibbonLoad2, 'SP.Ribbon.js');\r\n                        }\r\n\r\n                _spBodyOnLoadFunctionNames.push('_myLinksRibbonLoad1');\r\n                var L_Menu_BaseUrl = \"/marcomm\";\r\n                var L_Menu_LCID = \"1033\";\r\n                var L_Menu_SiteTheme = \"null\";\r\n                document.onreadystatechange = fnRemoveAllStatus; function fnRemoveAllStatus(){removeAllStatus(true)}; var dlc_fvsi = {\"DefaultViews\":[], \"ViewUrls\":[], \"WebUrl\":\"\\/marcomm\"};\r\n                function _spNavigateHierarchy(nodeDiv, dataSourceId, dataPath, url, listInContext, type) {\r\n\r\n                CoreInvoke('ProcessDefaultNavigateHierarchy', nodeDiv, dataSourceId, dataPath, url, listInContext, type, document.forms.aspnetForm, \"\", \"\\u002fmarcomm\");\r\n                }\r\n                Flighting.ExpFeatures = [480215056, 1880287568, 1561350208, 302071836, 3212816, 69473024, 4194310, - 2113396707, 268502022, - 872284160, 1049232, - 2147421952, 65536, 65536, 2097472, 917504, - 2147474174, 1372324107, 67108882, 0, 0, - 2147483648, 2097152, 0, 0, 32768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32768]; var __SafeRunFunctionLoadedScripts = new Array(); function SafeRunFunction(fnc, script, type){    if (!_spBodyOnLoadCalled)    {        __QueueFunctionForSafeRunFunction(fnc, script, type); return; }    var executed = ExecuteOrDelayUntilScriptLoaded(fnc, script); if (executed)    {        return; }    var loaded = false; for (var i = 0; i < __SafeRunFunctionLoadedScripts.length; i++)    {        if (__SafeRunFunctionLoadedScripts[i].toLowerCase() != script.toLowerCase())        {            continue; }        loaded = true; break; }    if (loaded)    {        return; }    __SafeRunFunctionLoadedScripts.push(script); SP.SOD.executeFunc(script, type, function(){}); }var __SafeRunFunctionQueue = null; function __QueueFunctionForSafeRunFunction(fnc, script, type){    if (!__SafeRunFunctionQueue)    {        __SafeRunFunctionQueue = new Array(); }    var container = new Object(); container['Function'] = fnc; container['Script'] = script; container['Type'] = type; __SafeRunFunctionQueue.push(container); }function __ProcessQueuedFunctions(){    if (!__SafeRunFunctionQueue || __SafeRunFunctionQueue.length <= 0)    {        return; }    for (var i = 0; i < __SafeRunFunctionQueue.length; i++)    {        var container = __SafeRunFunctionQueue[i]; var fnc = container['Function']; var script = container['Script']; var type = container['Type']; SafeRunFunction(fnc, script, type); }    __SafeRunFunctionQueue = null; }_spBodyOnLoadFunctionNames.push('__ProcessQueuedFunctions'); (function()\r\n                        {\r\n                        if (typeof (window.SP) == \"undefined\") window.SP = {};\r\n                        if (typeof (window.SP.YammerSwitch) == \"undefined\") window.SP.YammerSwitch = {};\r\n                        var ysObj = window.SP.YammerSwitch;\r\n                        ysObj.IsEnabled = false;\r\n                        ysObj.TargetYammerHostName = \"www.yammer.com\";\r\n                        })(); var _spWebPartComponents = new Object();\r\n                var g_syncButtonUsePopup = true;\r\n                //]]>\r\n            <\/script>\r\n\r\n            <script src=\"/portalassets/Marcomm/blank.js.download\" type=\"text/javascript\"><\/script>\r\n            <script type=\"text/javascript\">\r\n            //<![CDATA[\r\n                (function(){\r\n\r\n                if (typeof (_spBodyOnLoadFunctions) === 'undefined' || _spBodyOnLoadFunctions === null) {\r\n                return;\r\n                }\r\n                _spBodyOnLoadFunctions.push(function() {\r\n                SP.SOD.executeFunc('core.js', 'FollowingDocument', function() { FollowingDocument(); });\r\n                });\r\n                })(); (function(){\r\n\r\n                if (typeof (_spBodyOnLoadFunctions) === 'undefined' || _spBodyOnLoadFunctions === null) {\r\n                return;\r\n                }\r\n                _spBodyOnLoadFunctions.push(function() {\r\n                SP.SOD.executeFunc('core.js', 'FollowingCallout', function() { FollowingCallout(); });\r\n                });\r\n                })(); if (typeof (DeferWebFormInitCallback) == 'function') DeferWebFormInitCallback(); function WebForm_OnSubmit() {\r\n                UpdateFormDigest('\\u002fmarcomm', 1440000);\r\n                var workspaceElem = GetCachedElement(\"s4-workspace\");\r\n                if (workspaceElem != null)\r\n                {\r\n                var scrollElem = GetCachedElement(\"_maintainWorkspaceScrollPosition\");\r\n                if (scrollElem != null)\r\n                {\r\n                scrollElem.value = workspaceElem.scrollTop;\r\n                }\r\n                };\r\n                if (typeof (_spFormOnSubmitWrapper) != 'undefined') {return _spFormOnSubmitWrapper(); } else {return true; };\r\n                return true;\r\n                }\r\n            //]]>\r\n            <\/script>\r\n\r\n            <div class=\"aspNetHidden\">\r\n\r\n                <input type=\"hidden\" name=\"__VIEWSTATEGENERATOR\" id=\"__VIEWSTATEGENERATOR\" value=\"329ABBF6\">\r\n                <input type=\"hidden\" name=\"__SCROLLPOSITIONX\" id=\"__SCROLLPOSITIONX\" value=\"0\">\r\n                <input type=\"hidden\" name=\"__SCROLLPOSITIONY\" id=\"__SCROLLPOSITIONY\" value=\"0\">\r\n                <input type=\"hidden\" name=\"__EVENTVALIDATION\" id=\"__EVENTVALIDATION\" value=\"/wEdAAPB2HQatoJsqIC/VgQ90tF6u4eYfKkX6xhtnBGD4QYURDfOtfxWTc+UtmovlRpTzhZnMSx9MM1ys7naTj0qIssKn3bJKLBFZf83g86hn5MX8A==\">\r\n            </div><script type=\"text/javascript\">\r\n            //<![CDATA[\r\n                Sys.WebForms.PageRequestManager._initialize('ctl00$ScriptManager', 'aspnetForm', ['fctl00$ctl45$WebPartAdderUpdatePanel', ''], [], ['ctl00$ctl45$WebPartAdder', ''], 90, 'ctl00');\r\n            //]]>\r\n            <\/script>\r\n\r\n\r\n\r\n\r\n            <div>\r\n\r\n                <div id=\"TurnOnAccessibility\" style=\"\" class=\"s4-notdlg noindex\">\r\n                    <a id=\"linkTurnOnAcc\" href=\"/marcomm#\" class=\"ms-accessible ms-acc-button\" onclick=\"SetIsAccessibilityFeatureEnabled(true); UpdateAccessibilityUI(); document.getElementById( & #39; linkTurnOffAcc & #39; ).focus(); return false;\">\r\n                        Turn on more accessible mode\r\n                    </a>\r\n                </div>\r\n                <div id=\"TurnOffAccessibility\" style=\"display:none\" class=\"s4-notdlg noindex\">\r\n                    <a id=\"linkTurnOffAcc\" href=\"/marcomm#\" class=\"ms-accessible ms-acc-button\" onclick=\"SetIsAccessibilityFeatureEnabled(false); UpdateAccessibilityUI(); document.getElementById( & #39; linkTurnOnAcc & #39; ).focus(); return false;\">\r\n                        Turn off more accessible mode\r\n                    </a>\r\n                </div>\r\n\r\n            </div>\r\n            <div id=\"ms-designer-ribbon\" style=\"display:none;\">\r\n\r\n                <div>\r\n\r\n                    <div id=\"suiteBarDelta\" class=\"ms-dialogHidden ms-fullWidth noindex\">\r\n\r\n                        <div id=\"suiteMenuData\" class=\"ms-hide\">\r\n\r\n\r\n                            <span style=\"display:none\"><menu type=\"ServerMenu\" id=\"zz1_ID_PersonalActionMenu\" hideicons=\"true\"><ie:menuitem id=\"ID_AboutMe\" type=\"option\" onmenuclick=\"STSNavigate2(event,&quot;http://mysite.bankrakyat.com.my:80/Person.aspx&quot;)\" text=\"About Me\" description=\"View and manage your profile.\" menugroupid=\"100\"></ie:menuitem><ie:menuitem id=\"zz2_ID_PersonalInformation\" type=\"option\" iconsrc=\"/_layouts/15/images/menuprofile.gif?rev=40\" onmenuclick=\"STSNavigate2(event,&quot;http://mysite.bankrakyat.com.my:80/_layouts/15/EditProfile.aspx?UserSettingsProvider=234bf0ed%2D70db%2D4158%2Da332%2D4dfd683b4148&amp;ReturnUrl=https%3A%2F%2Fbrspace%2Ebankrakyat%2Ecom%2Emy%2Fmarcomm&quot;)\" text=\"My Settings\" description=\"Update your profile, as well as your language and regional settings.\" menugroupid=\"100\" hidden=\"true\"></ie:menuitem>\r\n                                    <ie:menuitem id=\"zz3_ID_Logout\" type=\"option\" onmenuclick=\"STSNavigate2(event,&#39;/marcomm/_layouts/15/SignOut.aspx&#39;);\" text=\"Sign Out\" description=\"Logout of this site.\" menugroupid=\"100\"></ie:menuitem>\r\n                                </menu></span>\r\n\r\n\r\n                            <span class=\"ms-siteactions-root\" id=\"siteactiontd\">\r\n\r\n\r\n\r\n                                <span style=\"display:none\"><menu type=\"ServerMenu\" id=\"zz4_SiteActionsMenuMainData\" hideicons=\"true\"><ie:menuitem id=\"zz5_MenuItem_ShareThisSite\" type=\"option\" onmenuclick=\"EnsureScriptFunc(&#39;sharing.js&#39;, &#39;DisplaySharedWithDialog&#39;, function () { DisplaySharedWithDialog(&#39;\\u002fmarcomm\\u002f&#39;,null,null,null,true); })\" text=\"Shared with...\" description=\"See who&#39;s here and invite new people.\" menugroupid=\"100\"></ie:menuitem>\r\n                                        <ie:menuitem id=\"zz6_MenuItem_ViewAllSiteContents\" type=\"option\" iconsrc=\"/_layouts/15/images/allcontent32.png?rev=40\" onmenuclick=\"STSNavigate2(event,&#39;/marcomm/_layouts/15/viewlsts.aspx&#39;);\" text=\"Site contents\" description=\"View all libraries and lists in this site.\" menugroupid=\"200\"></ie:menuitem>\r\n                                    </menu></span></span>\r\n                        </div>\r\n                        <script type=\"text/javascript\">// <![CDATA[ \r\n\r\n\r\n                            var g_navBarHelpDefaultKey = \"HelpHome\";\r\n                            // ]]>\r\n                        <\/script>\r\n                        <div id=\"suiteBarTop\" class=\"ms-fullWidth \" style=\"height:50px; position:relative;\"><div tabindex=\"0\" class=\"o365cs-base o365cst o365cs-nav-navMenu o365cs-newAL-off o365cs-rsp-off\" style=\"display: none; position: absolute; z-index: 2001;\"><div><div class=\"o365cs-nav-appItem\"><a class=\"o365button o365cs-nav-appTile o365cs-nav-appTileMedium\" role=\"link\" id=\"O365_AppTile_Newsfeed\" title=\"Newsfeed\" href=\"http://mysite.bankrakyat.com.my/default.aspx\" target=\"_top\" aria-label=\"Newsfeed\" style=\"background-color: rgb(0, 114, 198); outline-color: rgb(0, 114, 198);\"><span class=\"wf wf-size-x55 wf-family-o365 wf-o365-newsfeed o365cs-nav-appTileIcon ms-fcl-w\" role=\"presentation\" style=\"display: inline-block; font-size: 55px; vertical-align: middle;\"></span><span class=\"o365cs-nav-appTileTitle ms-fcl-w\"><span>Newsfeed</span></span></a></div><div class=\"o365cs-nav-appItem\"><a class=\"o365button o365cs-nav-appTile o365cs-nav-appTileMedium\" role=\"link\" id=\"O365_AppTile_Documents\" title=\"OneDrive\" href=\"http://mysite.bankrakyat.com.my/_layouts/15/MySite.aspx?MySiteRedirect=AllDocuments\" target=\"_top\" aria-label=\"OneDrive\" style=\"background-color: rgb(0, 114, 198); outline-color: rgb(0, 114, 198);\"><span class=\"wf wf-size-x55 wf-family-o365 wf-o365-cloud o365cs-nav-appTileIcon ms-fcl-w\" role=\"presentation\" style=\"display: inline-block; font-size: 55px; vertical-align: middle;\"></span><span class=\"o365cs-nav-appTileTitle ms-fcl-w\"><span>OneDrive</span></span></a></div><div class=\"o365cs-nav-appItem\"><a class=\"o365button o365cs-nav-appTile o365cs-nav-appTileMedium\" role=\"link\" id=\"O365_AppTile_Sites\" title=\"Sites\" href=\"http://mysite.bankrakyat.com.my/_layouts/15/MySite.aspx?MySiteRedirect=AllSites\" target=\"_top\" aria-label=\"Sites\" style=\"background-color: rgb(0, 114, 198); outline-color: rgb(0, 114, 198);\"><span class=\"wf wf-size-x55 wf-family-o365 wf-o365-sharepointlogo o365cs-nav-appTileIcon ms-fcl-w\" role=\"presentation\" style=\"display: inline-block; font-size: 55px; vertical-align: middle;\"></span><span class=\"o365cs-nav-appTileTitle ms-fcl-w\"><span>Sites</span></span></a></div></div></div><div id=\"O365_NavHeader\" class=\"o365cs-coremin o365cs-nav-header16 o365cs-base o365cst o365spo o365cs-nav-header o365cs-topnavBGColor-2 o365cs-topnavBGImage o365cs-rsp-off o365cs-rsp-affordance-off\"><div class=\"o365cs-nav-leftAlign\"><div class=\"o365cs-nav-topItem o365cs-rsp-tw-hide o365cs-rsp-tn-hide\"><button class=\"o365button o365cs-nav-item o365cs-nav-button o365cs-navMenuButton ms-bgc-tdr-h ms-bgc-tp  o365cs-newAL-off\" type=\"button\" id=\"O365_MainLink_NavMenu\" aria-haspopup=\"true\" aria-label=\"Open the app launcher to access your SharePoint apps\" role=\"menuitem\"><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-waffle\" role=\"presentation\" style=\"display: inline-block; font-size: 18px; vertical-align: middle;\"></span><div class=\"o365cs-nav-navMenuBeak\" style=\"display: none;\"></div></button></div><div class=\"o365cs-nav-topItem o365cs-rsp-off-hide o365cs-rsp-m-hide o365cs-rsp-tn-hideIfAffordanceOn\"><button class=\"o365button o365cs-nav-item o365cs-nav-button o365cs-navMenuButton ms-bgc-tdr-h ms-bgc-tp\" type=\"button\" id=\"O365_MainLink_HamburgerButton\" aria-haspopup=\"true\" aria-label=\"Open the menu to access additional app options\" role=\"menuitem\" style=\"display: none;\"><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-hamburger\" role=\"presentation\" style=\"display: inline-block; font-size: 18px; vertical-align: middle;\"></span></button></div><div class=\"o365cs-nav-topItem o365cs-rsp-off-hide o365cs-rsp-m-hide o365cs-rsp-tw-hide o365cs-rsp-tn-hideIfAffordanceOff\"><button class=\"o365button o365cs-nav-item o365cs-nav-button o365cs-navMenuButton ms-bgc-tdr-h ms-bgc-tp\" type=\"button\" id=\"O365_MainLink_AffordanceClose\" aria-label=\"Close menu\"><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-cross\" role=\"presentation\" style=\"display: inline-block; font-size: 18px; vertical-align: middle;\"></span></button></div><div class=\"o365cs-nav-topItem o365cs-nav-o365Branding o365cs-rsp-tn-hideIfAffordanceOn \"><span class=\"o365cs-nav-bposLogo o365cs-topnavText o365cs-o365logo o365cs-rsp-tw-hide o365cs-rsp-tn-hide\"><span class=\"o365cs-nav-brandingText\">BR Space</span></span><span class=\"o365cs-nav-appTitleLine o365cs-nav-brandingText o365cs-topnavText o365cs-rsp-tw-hide o365cs-rsp-tn-hide\"></span><a class=\"o365button o365cs-nav-appTitle o365cs-topnavText\" role=\"link\" href=\"http://mysite.bankrakyat.com.my/_layouts/15/MySite.aspx?MySiteRedirect=AllSites\" id=\"Sites_BrandBar\" aria-label=\"Sites\"><span class=\"o365cs-nav-brandingText\">Sites</span></a></div><div class=\"o365cs-nav-topItem o365cs-breadCrumbContainer o365cs-rsp-tw-hide o365cs-rsp-tn-hide\"><span class=\"o365cs-breadCrumbTemplate\"><span><a class=\"o365button o365cs-breadCrumb o365cs-semiLightFont ms-fcl-w\" role=\"link\"></a><span class=\"o365cs-folderSeparator ms-fcl-w\">▸</span></span></span></div></div><div class=\"o365cs-nav-centerAlign\"><div class=\"o365cs-rsp-tw-hide o365cs-rsp-tn-hide\"></div><div class=\"o365cs-rsp-tw-hide o365cs-rsp-tn-hide\"><div style=\"display: none;\"><a class=\"o365button o365cs-topnavText\" role=\"link\" id=\"O365_MainLink_Title\" href=\"/marcomm#\"><span class=\"o365cs-nav-docTitleText  o365cs-semiLightFont\"></span></a></div></div></div><div id=\"O365_TopMenu\" class=\"o365cs-nav-rightAlign o365cs-topnavLinkBackground-2\"><div><span class=\"o365cs-nav-rightMenus\"><div class=\"o365cs-nav-topItem\" style=\"display: none; position: relative;\"><div class=\"ms-bcl-w\"><button class=\"o365button ms-bgc-tdr-h ms-bgc-tp o365cs-topnavText o365cs-shareButton \" type=\"button\" id=\"O365_MainLink_ShareButton\" aria-haspopup=\"true\" aria-label=\"Share\"><span class=\"wf wf-size-x22 wf-family-o365 wf-o365-personAdd\" role=\"presentation\" style=\"display: inline-block; font-size: 22px; vertical-align: middle;\"></span><span class=\"ms-fcl-w o365cs-shareButton-Label\">Share</span></button></div></div><div class=\"o365cs-nav-topItem o365cs-rsp-off-hide o365cs-rsp-m-hide o365cs-rsp-tw-hide o365cs-rsp-tn-hideIfAffordanceOn\"><button class=\"o365button o365cs-nav-item o365cs-nav-button ms-bgc-tdr-h o365cs-topnavText\" type=\"button\" id=\"O365_MainLink_Affordance\" aria-haspopup=\"true\" aria-label=\"Open the menu to access notifications, settings, and help\" role=\"menuitem\"><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-ellipsis\" role=\"presentation\" style=\"display: inline-block; font-size: 18px; vertical-align: middle;\"></span></button></div><div class=\"o365cs-nav-topItem o365cs-rsp-off-hide o365cs-rsp-m-hide o365cs-rsp-tn-hideIfAffordanceOff\"><button class=\"o365button o365cs-nav-item o365cs-nav-button ms-bgc-tdr-h o365cs-topnavText\" type=\"button\" id=\"O365_MainLink_NavMenu_Responsive\" aria-haspopup=\"true\" aria-label=\"Open the app launcher to access your SharePoint apps\" role=\"menuitem\"><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-waffle\" role=\"presentation\" style=\"display: inline-block; font-size: 18px; vertical-align: middle;\"></span></button></div><div class=\"o365cs-nav-topItem o365cs-rsp-tn-hideIfAffordanceOff\" style=\"position: relative;\"><button class=\"o365button o365cs-nav-item o365cs-nav-button o365cs-topnavText ms-bgc-tdr-h\" type=\"button\" id=\"O365_MainLink_Settings\" aria-haspopup=\"true\" aria-label=\"Open the Settings menu\" role=\"menuitem\"><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-gear\" role=\"presentation\" style=\"display: inline-block; font-size: 18px; vertical-align: middle;\"></span></button><div tabindex=\"0\" class=\"o365cs-nav-contextMenu o365spo contextMenuPopup\" style=\"display: none; position: absolute; z-index: 2001; top: 50px; right: -1px;\"><span class=\"o365cs-contextMenuItem o365cs-labelledContextMenuSeparator ms-bcl-nl ms-fcl-tp\">Sites settings</span><a class=\"o365button o365cs-contextMenuItem ms-fcl-b\" role=\"link\" id=\"O365_SubLink_SuiteMenu_zz5_MenuItem_ShareThisSite\" aria-label=\"Shared with...\" href=\"javascript:SuiteOnClick(&quot;EnsureScriptFunc\\u0028\\u0027sharing.js\\u0027, \\u0027DisplaySharedWithDialog\\u0027, function \\u0028\\u0029 { DisplaySharedWithDialog\\u0028\\u0027\\\\u002fmarcomm\\\\u002f\\u0027,null,null,null,true\\u0029; }\\u0029&quot;)\" style=\"text-decoration: none;\">Shared with...</a><div class=\"o365cs-contextMenuSeparator ms-bcl-nl\"></div><a class=\"o365button o365cs-contextMenuItem ms-fcl-b\" role=\"link\" id=\"O365_SubLink_SuiteMenu_zz6_MenuItem_ViewAllSiteContents\" aria-label=\"Site contents\" href=\"javascript:SuiteOnClick(&quot;STSNavigate2\\u0028event,\\u0027\\u002fmarcomm\\u002f_layouts\\u002f15\\u002fviewlsts.aspx\\u0027\\u0029;&quot;)\" style=\"text-decoration: none;\">Site contents</a></div></div><div class=\"o365cs-nav-topItem o365cs-rsp-tn-hideIfAffordanceOff\" style=\"position: relative;\"><button class=\"o365button o365cs-nav-item o365cs-nav-button o365cs-topnavText ms-bgc-tdr-h\" type=\"button\" id=\"O365_MainLink_Help\" aria-haspopup=\"true\" aria-label=\"Open the Help menu to access help documentation, and legal and privacy information from Microsoft\" role=\"menuitem\"><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-question\" role=\"presentation\" style=\"display: inline-block; font-size: 18px; vertical-align: middle;\"></span></button><div tabindex=\"0\" class=\"o365cs-nav-contextMenu o365spo contextMenuPopup\" style=\"display: none; position: absolute; z-index: 2001; top: 50px; right: -1px;\"><a class=\"o365button o365cs-contextMenuItem ms-fcl-b\" role=\"link\" id=\"O365_SubLink_HelpLink\" aria-label=\"Help\" href=\"javascript:TopHelpButtonClick(&quot;HelpHome&quot;)\" style=\"text-decoration: none;\">Help</a></div></div><div class=\"o365cs-nav-topItem o365cs-rsp-tn-hideIfAffordanceOn\" style=\"position: relative;\"><button class=\"o365button o365cs-nav-item o365cs-nav-button ms-fcl-w o365cs-me-nav-item\" type=\"button\" id=\"O365_MainLink_Me\" aria-haspopup=\"true\" aria-label=\"Open Menu\" role=\"menuitem\"><div class=\"o365cs-me-tile-nophoto\"><div class=\"o365cs-me-tile-nophoto-username-container\"><span class=\"o365cs-me-tile-nophoto-username o365cs-me-bidi\">SITI AISHAH BINTI SURIF</span></div><span class=\"wf wf-size-x18 wf-family-o365 wf-o365-downcarat ms-fcl-nt o365cs-me-tile-nophoto-down\" role=\"presentation\" style=\"display: table-cell; font-size: 18px; vertical-align: middle;\"></span></div></button><div tabindex=\"0\" class=\"o365cs-nav-contextMenu o365spo contextMenuPopup\" style=\"display: none; position: absolute; z-index: 2001; top: 50px; right: 0px;\"><a class=\"o365button o365cs-contextMenuItem ms-fcl-b\" role=\"link\" id=\"O365_SubLink_ShellAboutMe\" aria-label=\"About Me\" href=\"http://mysite.bankrakyat.com.my/person.aspx\" style=\"text-decoration: none;\">About Me</a><a class=\"o365button o365cs-contextMenuItem ms-fcl-b\" role=\"link\" id=\"O365_SubLink_ShellSignout\" aria-label=\"Sign Out\" href=\"javascript:SuiteOnClick(&quot;STSNavigate2\\u0028event,\\u0027\\u002fmarcomm\\u002f_layouts\\u002f15\\u002fSignOut.aspx\\u0027\\u0029;&quot;)\" style=\"text-decoration: none;\">Sign Out</a></div></div></span></div></div></div></div><div id=\"SuiteNavUserName\" style=\"display:none\">SITI AISHAH BINTI SURIF</div><div class=\"wf-family-o365 o365wf\" style=\"display:none\">\r\n\r\n                        </div>\r\n\r\n                    </div>\r\n                    <div id=\"s4-ribbonrow\" style=\"height: 35px;\">\r\n                        <div id=\"globalNavBox\">\r\n                            <div id=\"ribbonBox\">\r\n                                <div id=\"s4-ribboncont\">\r\n                                    <div id=\"DeltaSPRibbon\">\r\n\r\n                                        <div class=\"ms-cui-ribbonTopBars\"><div class=\"ms-cui-topBar1\"></div><div class=\"ms-cui-topBar2\"><div id=\"RibbonContainer-TabRowLeft\" class=\"ms-cui-TabRowLeft ms-core-defaultFont ms-dialogHidden\">\r\n                                                </div><div id=\"RibbonContainer-TabRowRight\" class=\"ms-cui-TabRowRight s4-trc-container s4-notdlg ms-core-defaultFont\">\r\n                                                    <a onmouseover=\"this.firstChild.firstChild.style.left = & #39; - 91px & #39; ; this.firstChild.firstChild.style.top = & #39; - 232px & #39; ;\" onmouseout=\"this.firstChild.firstChild.style.left = & #39; - 200px & #39; ; this.firstChild.firstChild.style.top = & #39; - 48px & #39; ;\" onclick=\"EnsureScriptFunc( & #39; sharing.js & #39; , & #39; DisplaySharingDialog & #39; , function(){DisplaySharingDialog( & #39; \\u002fmarcomm & #39; )}); return false;\" id=\"ctl00_ctl45_site_share_button\" title=\"Give people access to this site.\" class=\"ms-promotedActionButton\" href=\"javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;ctl00$ctl45$site_share_button&quot;, &quot;&quot;, true, &quot;&quot;, &quot;&quot;, false, true))\" style=\"display:inline-block;\"><span style=\"height:16px;width:16px;position:relative;display:inline-block;overflow:hidden;\" class=\"s4-clust ms-promotedActionButton-icon\"><img src=\"/portalassets/Marcomm/spcommon.png\" alt=\"Share\" style=\"position:absolute;left:-200px;top:-48px;\"></span><span class=\"ms-promotedActionButton-text\">Share</span></a>\r\n                                                    <a onmouseover=\"this.firstChild.firstChild.style.left = & #39; - 217px & #39; ; this.firstChild.firstChild.style.top = & #39; - 192px & #39; ;\" onmouseout=\"this.firstChild.firstChild.style.left = & #39; - 218px & #39; ; this.firstChild.firstChild.style.top = & #39; - 48px & #39; ;\" onclick=\"SP.SOD.executeFunc( & #39; followingcommon.js & #39; , & #39; FollowSite & #39; , function() { FollowSite(); }); return false;\" id=\"site_follow_button\" title=\"Follow this site and get back to it easily from your sites page.\" class=\"ms-promotedActionButton\" href=\"javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;ctl00$ctl45$site_follow_button&quot;, &quot;&quot;, true, &quot;&quot;, &quot;&quot;, false, true))\" style=\"display:inline-block;\"><span style=\"height:16px;width:16px;position:relative;display:inline-block;overflow:hidden;\" class=\"s4-clust ms-promotedActionButton-icon\"><img src=\"/portalassets/Marcomm/spcommon.png\" alt=\"Follow\" style=\"position:absolute;left:-218px;top:-48px;\"></span><span class=\"ms-promotedActionButton-text\">Follow</span></a>\r\n\r\n\r\n                                                    <span id=\"fullscreenmodebox\" class=\"ms-qatbutton\">\r\n                                                        <span id=\"fullscreenmode\">\r\n                                                            <a onmouseover=\"this.firstChild.firstChild.firstChild.style.left = & #39; - 125px & #39; ; this.firstChild.firstChild.firstChild.style.top = & #39; - 178px & #39; ;\" onmouseout=\"this.firstChild.firstChild.firstChild.style.left = & #39; - 143px & #39; ; this.firstChild.firstChild.firstChild.style.top = & #39; - 178px & #39; ;\" id=\"ctl00_ctl45_fullscreenmodeBtn\" title=\"Focus on Content\" onclick=\"SetFullScreenMode(true); PreventDefaultNavigation(); return false;\" href=\"/_controltemplates/15/#\" style=\"display:inline-block;height:30px;width:30px;\"><span style=\"display:inline-block;overflow:hidden;height:16px;width:16px;padding-left:7px;padding-top:7px;padding-right:7px;padding-bottom:7px;\"><span style=\"height:16px;width:16px;position:relative;display:inline-block;overflow:hidden;\" class=\"s4-clust\"><img src=\"/portalassets/Marcomm/spcommon.png\" alt=\"Focus on Content\" style=\"border:0;position:absolute;left:-143px;top:-178px;\"></span></span></a>\r\n                                                        </span>\r\n                                                        <span id=\"exitfullscreenmode\" style=\"display: none;\">\r\n                                                            <a onmouseover=\"this.firstChild.firstChild.firstChild.style.left = & #39; - 179px & #39; ; this.firstChild.firstChild.firstChild.style.top = & #39; - 96px & #39; ;\" onmouseout=\"this.firstChild.firstChild.firstChild.style.left = & #39; - 107px & #39; ; this.firstChild.firstChild.firstChild.style.top = & #39; - 178px & #39; ;\" id=\"ctl00_ctl45_exitfullscreenmodeBtn\" title=\"Focus on Content\" onclick=\"SetFullScreenMode(false); PreventDefaultNavigation(); return false;\" href=\"/_controltemplates/15/#\" style=\"display:inline-block;height:30px;width:30px;\"><span style=\"display:inline-block;overflow:hidden;height:16px;width:16px;padding-left:7px;padding-top:7px;padding-right:7px;padding-bottom:7px;\"><span style=\"height:16px;width:16px;position:relative;display:inline-block;overflow:hidden;\" class=\"s4-clust\"><img src=\"/portalassets/Marcomm/spcommon.png\" alt=\"Focus on Content\" style=\"border:0;position:absolute;left:-107px;top:-178px;\"></span></span></a>\r\n                                                        </span>\r\n                                                    </span>\r\n\r\n\r\n                                                </div></div></div>\r\n\r\n                                    </div>\r\n                                </div>\r\n                                <span id=\"DeltaSPNavigation\">\r\n                                    <span id=\"ctl00_ctl45_ctl11_publishingRibbon\"></span>\r\n\r\n                                </span>\r\n                            </div>\r\n                            <div id=\"DeltaWebPartAdderUpdatePanelContainer\" class=\"ms-core-webpartadder\" style=\"top: 35px;\">\r\n\r\n                                <div id=\"WebPartAdderUpdatePanelContainer\">\r\n                                    <div id=\"ctl00_ctl45_WebPartAdderUpdatePanel\">\r\n\r\n                                        <span id=\"ctl00_ctl45_WebPartAdder\"></span>\r\n\r\n                                    </div>\r\n                                </div>\r\n\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n\r\n                </div>\r\n\r\n\r\n            </div>\r\n\r\n\r\n            <div id=\"s4-workspace\" style=\"height: 679px; width: 798px;\">\r\n                <div id=\"s4-bodyContainer\">","content_is_php":0,"content_status":1,"content_order":1},{"content_id":525,"content_name":"MARCOMM - HEADER","content_details":"<style>\r\n#ctl00_ctl49_csr{display:none;}\r\n    .dynamic-children {\r\n        position : relative;\r\n    }\r\n    .isVisible {\r\n        z-index: 1100 !important;\r\n        width: 250px !important; \r\n        left: 0px !important; \r\n        top: 34px !important;\r\n        position : relative;\r\n    }\r\n    .isVisible ul.isVisible{\r\n        z-index: 1100 !important;\r\n        width: 250px !important; \r\n        left: auto !important; \r\n        right : -100px !important;\r\n        top: 0px !important;\r\n    }\r\n</style>\r\n<script>\r\n    $(document).ready(function(){\r\n        $('.dynamic-children').hover(\r\n            function() {\r\n            // On hover, add a class to the nearest child ul\r\n            $(this).children('ul').addClass('isVisible');\r\n        }, function() {\r\n          // On hover out, remove the class from the child ul\r\n          $(this).children('ul').removeClass('isVisible');\r\n        }\r\n      );\r\n    });\r\n<\/script>\r\n<div class=\"bkrm-topcontent ms-dialogHidden\">\r\n                        <div class=\"bkrm-topcontent-mid\">\r\n                            <div data-name=\"SiteLogo\" class=\"bkrm-sitelogo\" id=\"bkrmlogo\">\r\n\r\n\r\n                                <div>\r\n\r\n\r\n                                    <a id=\"ctl00_onetidProjectPropertyTitleGraphic\" href=\"/web/home\">\r\n                                        <img id=\"ctl00_onetidHeadbnnr2\" name=\"onetidHeadbnnr0\" src=\"/portalassets/Marcomm/logo-bkrm(1).png\" alt=\"Marcomm\">\r\n                                    </a>\r\n\r\n\r\n                                </div>\r\n\r\n                            </div>\r\n                            <div data-name=\"TopNavigationNoFlyoutWithStartNode\" class=\"bkrm-topnavigation\" id=\"BKRMPortalTopNav\">\r\n\r\n\r\n                                <div id=\"DeltaTopNavigation\" class=\"ms-displayInline ms-core-navigation ms-dialogHidden\">\r\n\r\n\r\n\r\n                                    <a name=\"startNavigation\">\r\n                                    </a>\r\n\r\n                                    <div id=\"zz7_TopNavigationMenu\" class=\" noindex ms-core-listMenu-horizontalBox\">\r\n                                        <ul id=\"zz8_RootAspMenu\" class=\"root ms-core-listMenu-root static\">\r\n                                            <li class=\"static selected\">\r\n                                                <a class=\"static selected menu-item ms-core-listMenu-item ms-displayInline ms-core-listMenu-selected ms-navedit-linkNode\" href=\"/marcomm/home\" accesskey=\"1\">\r\n                                                    <span class=\"additional-background ms-navedit-flyoutArrow\"><span class=\"menu-item-text\">Home</span>\r\n                                                    <span class=\"ms-hidden\">Currently selected</span></span>\r\n                                                </a>\r\n                                            </li>\r\n                                            <li class=\"static dynamic-children\">\r\n                                                <a class=\"static dynamic-children menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode\" href=\"#\">\r\n                                                    <span aria-haspopup=\"true\" class=\"additional-background ms-navedit-flyoutArrow dynamic-children\"><span class=\"menu-item-text\">About Us</span></span>\r\n                                                </a>\r\n                                                <ul class=\"dynamic\" style=\"z-index: 1100;\">\r\n                                                    <li class=\"dynamic\">\r\n                                                        <a class=\"dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode\" \r\n                                                        href=\"/marcomm/about-us?d=Event+Management\">\r\n                                                            <span class=\"additional-background ms-navedit-flyoutArrow\"><span class=\"menu-item-text\">Event Management</span></span>\r\n                                                        </a>\r\n                                                    </li>\r\n                                                    <li class=\"dynamic\">\r\n                                                        <a class=\"dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode\" \r\n                                                         href=\"/marcomm/about-us?d=Marketing\"><span class=\"additional-background ms-navedit-flyoutArrow\">\r\n                                                            <span class=\"menu-item-text\">Marketing</span></span>\r\n                                                        </a>\r\n                                                    </li>\r\n                                                    <li class=\"dynamic\">\r\n                                                        <a class=\"dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode\" \r\n                                                        href=\"/marcomm/about-us?d=Public+Relations\">\r\n                                                            <span class=\"additional-background ms-navedit-flyoutArrow\"><span class=\"menu-item-text\">Public Relations &amp; Corporate Branding</span></span>\r\n                                                        </a>\r\n                                                    </li>\r\n                                                </ul>\r\n                                            </li>\r\n                                            <li class=\"static\">\r\n                                                <a class=\"static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode\" href=\"/marcomm/campaign\">\r\n                                                    <span class=\"additional-background ms-navedit-flyoutArrow\"><span class=\"menu-item-text\">Campaign</span></span>\r\n                                                </a>\r\n                                            </li>\r\n                                            <li class=\"static\">\r\n                                                <a class=\"static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode\" href=\"/marcomm/download\">\r\n                                                    <span class=\"additional-background ms-navedit-flyoutArrow\"><span class=\"menu-item-text\">Download</span></span>\r\n                                                </a>\r\n                                            </li>\r\n                                            <li class=\"static\">\r\n                                                <a class=\"static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode\" href=\"/marcomm/news\">\r\n                                                    <span class=\"additional-background ms-navedit-flyoutArrow\"><span class=\"menu-item-text\">News</span></span>\r\n                                                </a>\r\n                                            </li>\r\n                                        </ul>\r\n                                    </div>\r\n\r\n\r\n\r\n                                </div>\r\n\r\n                            </div>\r\n                            <div data-name=\"SearchBox\" class=\"bkrm-search\">\r\n\r\n\r\n                                <div class=\"ms-webpart-chrome ms-webpart-chrome-fullWidth \">\r\n                                    <div webpartid=\"00000000-0000-0000-0000-000000000000\" haspers=\"true\" id=\"WebPartWPQ1\" width=\"100%\" class=\"ms-WPBody noindex \" onlyformepart=\"true\" allowdelete=\"false\" style=\"\"><div componentid=\"ctl00_ctl49_csr\" id=\"ctl00_ctl49_csr\"><div id=\"SearchBox\" name=\"Control\"><div class=\"ms-srch-sb ms-srch-sb-border\" id=\"ctl00_ctl49_csr_sboxdiv\"><input type=\"text\" value=\"Search this site\" maxlength=\"2048\" accesskey=\"S\" title=\"Search this site\" id=\"ctl00_ctl49_csr_sbox\" autocomplete=\"off\" autocorrect=\"off\" onkeypress=\"EnsureScriptFunc( & #39; Search.ClientControls.js & #39; , & #39; Srch.U & #39; , function() {if (Srch.U.isEnterKey(String.fromCharCode(event.keyCode))) {$find( & #39; ctl00_ctl49_csr & #39; ).search($get( & #39; ctl00_ctl49_csr_sbox & #39; ).value); return Srch.U.cancelEvent(event); }})\" onkeydown=\"EnsureScriptFunc( & #39; Search.ClientControls.js & #39; , & #39; Srch.U & #39; , function() {var ctl = $find( & #39; ctl00_ctl49_csr & #39; ); ctl.activateDefaultQuerySuggestionBehavior(); })\" onfocus=\"EnsureScriptFunc( & #39; Search.ClientControls.js & #39; , & #39; Srch.U & #39; , function() {var ctl = $find( & #39; ctl00_ctl49_csr & #39; ); ctl.hidePrompt(); ctl.setBorder(true); })\" onblur=\"EnsureScriptFunc( & #39; Search.ClientControls.js & #39; , & #39; Srch.U & #39; , function() {var ctl = $find( & #39; ctl00_ctl49_csr & #39; ); if (ctl){ ctl.showPrompt(); ctl.setBorder(false); }})\" class=\"ms-textSmall ms-srch-sb-prompt ms-helperText\"><a title=\"Search\" role=\"button\" class=\"ms-srch-sb-searchLink\" id=\"ctl00_ctl49_csr_SearchLink\" onclick=\"EnsureScriptFunc( & #39; Search.ClientControls.js & #39; , & #39; Srch.U & #39; , function() {$find( & #39; ctl00_ctl49_csr & #39; ).search($get( & #39; ctl00_ctl49_csr_sbox & #39; ).value); })\" href=\"javascript: {}\"><img src=\"/portalassets/Marcomm/searchresultui.png\" class=\"ms-srch-sb-searchImg\" id=\"searchImg\" alt=\"Search\"></a></div></div></div><noscript><div id=\"ctl00_ctl49_noscript\">It looks like your browser does not have JavaScript enabled. Please turn on JavaScript and try again.</div></noscript><div id=\"ctl00_ctl49\">\r\n\r\n\r\n\r\n                                        </div><div class=\"ms-clear\"></div></div>\r\n                                </div>\r\n\r\n                            </div>\r\n                        </div>\r\n                    </div>","content_is_php":0,"content_status":1,"content_order":2},{"content_id":526,"content_name":"MARCOMM - HOME","content_details":"<div class=\"bkrm-midbody\">\r\n                        <div class=\"bkrm-sitetitle ms-dialogHidden\">\r\n                            <div data-name=\"SiteTitle\">\r\n\r\n\r\n                                <span>\r\n\r\n                                    <a href=\"/marcomm/\">\r\n\r\n                                        Marcomm\r\n\r\n                                    </a>\r\n\r\n                                </span>\r\n\r\n                            </div>\r\n                        </div>\r\n                        <div class=\"bkrm-break ms-dialogHidden\">\r\n                        </div>\r\n                        <div class=\"bkrm-pagetitle ms-dialogHidden\">\r\n                            <h1 id=\"pageTitle\" class=\"ms-core-pageTitle\">\r\n                                <span id=\"DeltaPlaceHolderPageTitleInTitleArea\">\r\n\r\n                                    MARCOMM Home\r\n\r\n                                </span>\r\n                                <div id=\"DeltaPlaceHolderPageDescription\" class=\"ms-displayInlineBlock ms-normalWrap\">\r\n\r\n                                    <a href=\"javascript:;\" id=\"ms-pageDescriptionDiv\" style=\"display:none\" data-accessibility-nocheck=\"true\" title=\"\r\n\r\n                                       \">\r\n                                        <span id=\"ms-pageDescriptionImage\">\r\n                                        </span>\r\n                                    </a>\r\n                                    <span class=\"ms-accessible\" id=\"ms-pageDescription\">\r\n\r\n                                    </span>\r\n                                    <script type=\"text/javascript\">// <![CDATA[ \r\n\r\n\r\n                                        _spBodyOnLoadFunctionNames.push(\"setupPageDescriptionCallout\");\r\n                                        // ]]>\r\n                                    <\/script>\r\n\r\n                                </div>\r\n                            </h1>\r\n                        </div>\r\n                        <div class=\"bkrm-break ms-dialogHidden\">\r\n                        </div>\r\n                        <div class=\"bkrm-maincontent\" id=\"BKRMPortalMainContent\">\r\n                            <div class=\"bkrm-quicklaunch\">\r\n                                <div data-name=\"QuickLaunch\" id=\"BKRMPortalQuickLaunch\">\r\n\r\n\r\n\r\n                                    <div id=\"sideNavBox\" class=\"ms-dialogHidden ms-forceWrap ms-noList\">\r\n                                        <div id=\"DeltaPlaceHolderLeftNavBar\" class=\"ms-core-navigation\">\r\n\r\n\r\n\r\n\r\n\r\n                                        </div>\r\n                                    </div>\r\n\r\n                                </div>\r\n                            </div>\r\n                            <div class=\"bkrm-placeholdermain\">\r\n                                <div id=\"contentBox\" aria-live=\"polite\" aria-relevant=\"all\">\r\n                                    <div id=\"notificationArea\" class=\"ms-notif-box\">\r\n                                    </div>\r\n                                    <div id=\"DeltaPageStatusBar\">\r\n\r\n                                        <div id=\"pageStatusBar\" class=\"ms-status-blue\" style=\"display: none;\"></div>\r\n\r\n                                    </div>\r\n                                </div>\r\n\r\n\r\n                                <span id=\"DeltaPlaceHolderMain\">\r\n\r\n                                    <div style=\"padding: 0px 5px 0px 0px;\" class=\"bkrm-webpartzone75\">\r\n\r\n\r\n                                        <div style=\"clear: both\">\r\n                                            <div class=\"bkrm-webpartzone100\" style=\"padding: 0px 0px 0px 0px\">\r\n                                                <div class=\"ms-webpart-zone ms-fullWidth\">\r\n                                                    <div id=\"MSOZoneCell_WebPartctl00_ctl36_g_69900365_f9d7_4cc6_9614_0f90b96eaa1f\" class=\"s4-wpcell-plain ms-webpartzone-cell ms-webpart-cell-vertical ms-fullWidth \">\r\n                                                        <div class=\"ms-webpart-chrome ms-webpart-chrome-vertical ms-webpart-chrome-fullWidth \">\r\n                                                            <div webpartid=\"69900365-f9d7-4cc6-9614-0f90b96eaa1f\" haspers=\"false\" id=\"WebPartctl00_ctl36_g_69900365_f9d7_4cc6_9614_0f90b96eaa1f\" width=\"100%\" class=\"ms-WPBody noindex \" allowdelete=\"false\" allowexport=\"false\" style=\"\"><div id=\"ctl00_ctl36_g_69900365_f9d7_4cc6_9614_0f90b96eaa1f\">\r\n\r\n                                                                    <script type=\"text/javascript\">\r\n                                                                        $(document).ready(function () {\r\n                                                                        $('.time-slider').cttTimeSlider();\r\n                                                                        });<\/script>\r\n\r\n                                                                    <div id=\"ctl00_ctl36_g_69900365_f9d7_4cc6_9614_0f90b96eaa1f_ctl00_pnlBanners\" class=\"AnnouncementPanel\">\r\n\r\n                                                                        <div class=\"time-slider\">\r\n                                                                            <div class=\"display\"><a href=\"#\" target=\"_blank\"><img alt=\"Kad Kredit-i Muslimah\" src=\"/portalassets/Marcomm/873x380-Intranet-BRSpace-Announcement.jpg\" class=\"bkrm-announcement-image\"></a></div>\r\n                                                                            <div class=\"active\">\r\n                                                                                <div class=\"pagination\">1 of 1</div>\r\n                                                                                <a class=\"next\" href=\"#\"></a>\r\n                                                                                <a class=\"controls\" href=\"#\"></a>\r\n                                                                                <a class=\"previous\" href=\"#\"></a>\r\n                                                                            </div>\r\n                                                                            <div class=\"carousel\">\r\n                                                                                <div class=\"track\" style=\"width: 31px;\">\r\n                                                                                    <div class=\"bar\" style=\"width: 5.58px;\"></div>\r\n\r\n                                                                                    <div class=\"item current\" rel=\"0\">\r\n                                                                                        <img alt=\"Kad Kredit-i Muslimah\" src=\"/portalassets/Marcomm/873x380-Intranet-BRSpace-Announcement.jpg\" class=\"bkrm-announcement-image\">\r\n\r\n                                                                                        <a href=\"#\" style=\"cursor:default;\">\r\n                                                                                            <span class=\"title\">\r\n                                                                                                <span id=\"ctl00_ctl36_g_69900365_f9d7_4cc6_9614_0f90b96eaa1f_ctl00_rptBanners_ctl00_lblTitle\">Kad Kredit-i Muslimah</span>\r\n                                                                                                <br>\r\n                                                                                                <div class=\"readmore\">Read More <img id=\"ctl00_ctl36_g_69900365_f9d7_4cc6_9614_0f90b96eaa1f_ctl00_rptBanners_ctl00_imgArrow\" src=\"/portalassets/Marcomm/arrow-btn.png\"></div>\r\n                                                                                            </span>\r\n                                                                                            <span class=\"description\" style=\"display: none\">\r\n                                                                                                <span id=\"ctl00_ctl36_g_69900365_f9d7_4cc6_9614_0f90b96eaa1f_ctl00_rptBanners_ctl00_lblDesc\"></span>\r\n                                                                                            </span>\r\n                                                                                            <span class=\"itempointer\">\r\n                                                                                                o\r\n                                                                                            </span>\r\n                                                                                        </a>\r\n                                                                                    </div>\r\n\r\n                                                                                </div> <!-- div.track -->\r\n                                                                            </div> <!-- div.carousel -->\r\n                                                                        </div> <!-- div.time-slider -->\r\n\r\n\r\n                                                                    </div>\r\n                                                                    <span style=\"color:red\"></span>\r\n\r\n                                                                </div><div class=\"ms-clear\"></div></div>\r\n                                                        </div><div class=\"ms-PartSpacingVertical\"></div>\r\n                                                    </div><div id=\"MSOZoneCell_WebPartctl00_ctl36_g_a66f2c29_acab_432c_b5b3_f274ba51273c\" class=\"s4-wpcell-plain ms-webpartzone-cell ms-webpart-cell-vertical ms-fullWidth \">\r\n                                                        <div class=\"ms-webpart-chrome ms-webpart-chrome-vertical ms-webpart-chrome-fullWidth \">\r\n                                                            <div webpartid=\"a66f2c29-acab-432c-b5b3-f274ba51273c\" haspers=\"false\" id=\"WebPartctl00_ctl36_g_a66f2c29_acab_432c_b5b3_f274ba51273c\" width=\"100%\" class=\"ms-WPBody noindex \" allowdelete=\"false\" allowexport=\"false\" style=\"\"><div id=\"ctl00_ctl36_g_a66f2c29_acab_432c_b5b3_f274ba51273c\">\r\n                                                                    <div id=\"ctl00_ctl36_g_a66f2c29_acab_432c_b5b3_f274ba51273c_ctl00_bkrmorderingdiv\" class=\"bkrm-ordering\" style=\"background-image:url(/marcomm/picturelibrary/ordering.jpg);\">\r\n                                                                        <a href=\"http://intranet.bankrakyat.com.my/mkcm/index.php\" id=\"ctl00_ctl36_g_a66f2c29_acab_432c_b5b3_f274ba51273c_ctl00_linkOrdering\" target=\"_blank\">\r\n                                                                            <div class=\"bkrm-ordering-button\">\r\n                                                                                <span id=\"ctl00_ctl36_g_a66f2c29_acab_432c_b5b3_f274ba51273c_ctl00_lblOrder\">Ordering</span>\r\n                                                                                <img id=\"ctl00_ctl36_g_a66f2c29_acab_432c_b5b3_f274ba51273c_ctl00_imgArrow\" src=\"/portalassets/Marcomm/arrow-btn.png\">\r\n                                                                            </div>\r\n                                                                        </a>\r\n                                                                    </div>\r\n\r\n                                                                </div><div class=\"ms-clear\"></div></div>\r\n                                                        </div>\r\n                                                    </div>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div>\r\n                                        <div style=\"clear: both\">\r\n                                            <div class=\"bkrm-webpartzone60\" style=\"padding: 2px 5px 2px 0px\">\r\n                                                <div class=\"ms-webpart-zone ms-fullWidth\">\r\n                                                    <div id=\"MSOZoneCell_WebPartctl00_ctl36_g_500059ad_7e42_43ab_8b8c_19c1ba5739c8\" class=\"s4-wpcell-plain ms-webpartzone-cell ms-webpart-cell-vertical ms-fullWidth \">\r\n                                                        <div class=\"ms-webpart-chrome ms-webpart-chrome-vertical ms-webpart-chrome-fullWidth \">\r\n                                                            <div webpartid=\"500059ad-7e42-43ab-8b8c-19c1ba5739c8\" haspers=\"false\" id=\"WebPartctl00_ctl36_g_500059ad_7e42_43ab_8b8c_19c1ba5739c8\" width=\"100%\" class=\"ms-WPBody noindex \" allowdelete=\"false\" allowexport=\"false\" style=\"\"><div id=\"ctl00_ctl36_g_500059ad_7e42_43ab_8b8c_19c1ba5739c8\">\r\n\r\n\r\n                                                                    <div class=\"bkrm-webpart bkrm-campaign\">\r\n\r\n                                                                        <div style=\"float: left\"><img src=\"/portalassets/Marcomm/ico-campaign.png\" alt=\"\" id=\"img\"></div>\r\n                                                                        <div class=\"bkrm-campaign-header\">&nbsp; <span id=\"ctl00_ctl36_g_500059ad_7e42_43ab_8b8c_19c1ba5739c8_ctl00_lblHeader\">Campaign</span></div>\r\n\r\n\r\n                                                                        <br style=\"clear:left;\">\r\n                                                                        <div style=\"width: 100%; height: 10px;\"></div>\r\n                                                                        <div style=\"float:right\">\r\n\r\n                                                                        </div>\r\n                                                                        <span style=\"color:red\">There are currently no campaign.</span>\r\n                                                                    </div>\r\n\r\n                                                                </div><div class=\"ms-clear\"></div></div>\r\n                                                        </div>\r\n                                                    </div>\r\n                                                </div>\r\n                                            </div>\r\n                                            <div class=\"bkrm-webpartzone40\" style=\"padding: 2px 0px 2px 0%\">\r\n                                                <div class=\"ms-webpart-zone ms-fullWidth\">\r\n                                                    <div id=\"MSOZoneCell_WebPartctl00_ctl36_g_93052879_f58a_4b1a_8f8b_8b15dd22a98d\" class=\"s4-wpcell-plain ms-webpartzone-cell ms-webpart-cell-vertical ms-fullWidth \">\r\n                                                        <div class=\"ms-webpart-chrome ms-webpart-chrome-vertical ms-webpart-chrome-fullWidth \">\r\n                                                            <div webpartid=\"93052879-f58a-4b1a-8f8b-8b15dd22a98d\" haspers=\"false\" id=\"WebPartctl00_ctl36_g_93052879_f58a_4b1a_8f8b_8b15dd22a98d\" width=\"100%\" class=\"ms-WPBody noindex \" allowdelete=\"false\" allowexport=\"false\" style=\"\"><div id=\"ctl00_ctl36_g_93052879_f58a_4b1a_8f8b_8b15dd22a98d\">\r\n\r\n\r\n                                                                    <div class=\"bkrm-webpart bkrm-latestnews\">\r\n\r\n                                                                        <div style=\"float: left\"><img src=\"/portalassets/Marcomm/ico-news.png\" alt=\"\" id=\"img\"></div>\r\n                                                                        <div class=\"bkrm-latestnews-header\">&nbsp; <span id=\"ctl00_ctl36_g_93052879_f58a_4b1a_8f8b_8b15dd22a98d_ctl00_lblHeader\">Latest News</span></div>\r\n\r\n\r\n                                                                        <br style=\"clear:left;\">\r\n                                                                        <div style=\"width: 100%; height: 10px;\"></div>\r\n                                                                        <div style=\"float:right\">\r\n\r\n                                                                        </div>\r\n                                                                        <span style=\"color:red\">There are currently no news.</span>\r\n                                                                    </div>\r\n\r\n                                                                </div><div class=\"ms-clear\"></div></div>\r\n                                                        </div>\r\n                                                    </div>\r\n                                                </div>\r\n                                            </div>\r\n                                        </div>\r\n                                    </div>\r\n\r\n                                    <div class=\"bkrm-webpartzone25\">\r\n                                        <div style=\"width: 100%\">\r\n                                            <menu class=\"ms-hide\">\r\n                                                <ie:menuitem id=\"MSOMenu_Help\" iconsrc=\"/_layouts/15/images/HelpIcon.gif\" onmenuclick=\"MSOWebPartPage_SetNewWindowLocation(MenuWebPart.getAttribute(&#39;helpLink&#39;), MenuWebPart.getAttribute(&#39;helpMode&#39;))\" text=\"Help\" type=\"option\" style=\"display:none\">\r\n\r\n                                                </ie:menuitem>\r\n                                            </menu>\r\n                                        </div>\r\n                                    </div>\r\n\r\n                                    <div>\r\n                                        <script type=\"text/javascript\">// <![CDATA[ \r\n\r\n                                            if (typeof (MSOLayout_MakeInvisibleIfEmpty) == \"function\") {MSOLayout_MakeInvisibleIfEmpty(); }// ]]>\r\n                                        <\/script>\r\n                                    </div>\r\n\r\n                                    <div style=\"display:none\" id=\"hidZone\"></div>\r\n                                </span>\r\n\r\n                            </div>\r\n                        </div>\r\n\r\n                    </div>","content_is_php":0,"content_status":1,"content_order":3},{"content_id":527,"content_name":"MARCOMM - FOOTER","content_details":"<footer class=\"bkrm-footer ms-dialogHidden\">\r\n                        <div class=\"bkrm-footer-div\">\r\n                            <a href=\"/marcomm#bkrmlogo\" style=\"text-decoration: none; color: inherit\">\r\n                                Copyright © 2022 Bank Kerjasama Rakyat Malaysia. Hak Cipta Terpelihara.\r\n\r\n                            </a>\r\n                        </div>\r\n                    </footer>","content_is_php":0,"content_status":1,"content_order":4},{"content_id":528,"content_name":"MARCOMM - WRAPPER END","content_details":"</div>\r\n            </div>\r\n            <div id=\"DeltaFormDigest\">\r\n                <script type=\"text/javascript\">//<![CDATA[\r\n                    var formDigestElement = document.getElementsByName('__REQUESTDIGEST')[0];\r\n                    if (!((formDigestElement == null) || (formDigestElement.tagName.toLowerCase() != 'input') || (formDigestElement.type.toLowerCase() != 'hidden') ||\r\n                            (formDigestElement.value == null) || (formDigestElement.value.length <= 0)))\r\n                    {\r\n                    formDigestElement.value = '0x6FC9E39FAD18AB61B695E010CCD04DFCEAF10FBA581AEB94FEAAD42B9CE1FC40702E9F59B5D4B0943737444E08BB67BD0E9EB05E8250FD19D5533539062B9B9D,01 Oct 2024 03:48:15 -0000'; _spPageContextInfo.updateFormDigestPageLoaded = new Date();\r\n                    }\r\n                    //]]>\r\n                <\/script>\r\n            </div>\r\n\r\n            <script type=\"text/javascript\">\r\n            //<![CDATA[\r\n\r\n                var callBackFrameUrl = '/WebResource.axd?d=vO6itXRryPBErQ3r760z2d7Wol3h3QkOpmhXf6zgbxlEAqOQ28DMahyyBSj0D1FLQFnaNvlVltoTzA6_4XR7OzdEB1bWBaGaWFsJ9xsCP-o1&t=638164444906150010';\r\n                WebForm_InitCallback(); var _spFormDigestRefreshInterval = 1440000; function loadMDN2() { EnsureScript('MDN.js', typeof (loadFilterFn), null); }\r\n                function loadMDN1() { ExecuteOrDelayUntilScriptLoaded(loadMDN2, 'sp.ribbon.js'); }\r\n                _spBodyOnLoadFunctionNames.push('loadMDN1');\r\n                function _spNavigateHierarchyEx(nodeDiv, dataSourceId, dataPath, url, listInContext, type, additionalQString) {\r\n                CoreInvoke('SetAdditionalNavigateHierarchyQString', additionalQString);\r\n                g_originalSPNavigateFunc(nodeDiv, dataSourceId, dataPath, url, listInContext, type);\r\n                }\r\n\r\n                g_originalSPNavigateFunc = _spNavigateHierarchy;\r\n                _spNavigateHierarchy = _spNavigateHierarchyEx;\r\n                function GetPageNormalizedUrl(){    alert('This SharePoint Tags And Notes Tool link is out of date. To get the latest Tags And Notes Tool, click OK. In the Tags and Note Board dialog, click the My Tags link. From here you can access the new SharePoint Tags And Notes tool.'); return document.location.href; }var _openTagDialog_DialogUrl = ''; var _openTagDialog_PageUrl = ''; function OpenTagDialog(dialogUrl){    _openTagDialog_DialogUrl = dialogUrl; _openTagDialog_PageUrl = 'https:\\u002f\\u002fbrspace.bankrakyat.com.my\\u002fmarcomm'; SafeRunFunction(_OpenTagDialogInternal, 'SocialData.js', 'TagDialogOpener'); }ExecuteOrDelayUntilScriptLoaded(function() {    InitializeSocialRibbonComponentWrapper('ctl00_ctl19', true, true, '{91c71bb3-48b2-45ca-baf2-6adcd580162f}', 'Add Tag...', 'Verifying ...', 'https:\\u002f\\u002fbrspace.bankrakyat.com.my\\u002fmarcomm\\u002fPages\\u002fHome.aspx', 'Tagged this page with \\u0027I Like It.\\u0027', 'Failed tagging this page.', 'Add Tag...', function() { WebForm_DoCallback('ctl00$ctl19', Sys.Serialization.JavaScriptSerializer.serialize(request), Function.createDelegate(ribbonComponent, ribbonComponent._OnSucceededCallback), notificationId, Function.createDelegate(ribbonComponent, ribbonComponent._OnFailedCallback), true) }); }, 'socialdata.js'); function ctl00_ctl19_SocialNavControl_insertMyProfileMenu() {    SP.SOD.executeFunc('socialdata.js', 'InsertMyProfileMenu', function() {        InsertMyProfileMenu('http:\\u002f\\u002fmysite.bankrakyat.com.my:80\\u002fPerson.aspx', 'View and manage your profile.', 'About Me', 'http:\\u002f\\u002fmysite.bankrakyat.com.my:80\\u002f_layouts\\u002f15\\u002fEditProfile.aspx?UserSettingsProvider=234bf0ed\\u00252D70db\\u00252D4158\\u00252Da332\\u00252D4dfd683b4148\\u0026ReturnUrl=https\\u00253A\\u00252F\\u00252Fbrspace\\u00252Ebankrakyat\\u00252Ecom\\u00252Emy\\u00252Fmarcomm', 'Update your profile, as well as your language and regional settings.', '', '', '', true, false); }); }if (typeof (_spBodyOnLoadFunctionNames) != 'undefined' && _spBodyOnLoadFunctionNames != null) { _spBodyOnLoadFunctionNames.push('ctl00_ctl19_SocialNavControl_insertMyProfileMenu'); } IsSPSocialSwitchEnabled = function() { return true; }; var _fV4UI = true;\r\n                function _RegisterWebPartPageCUI()\r\n                        {\r\n                        var initInfo = {editable: false, isEditMode: false, allowWebPartAdder: false, listId: \"{91c71bb3-48b2-45ca-baf2-6adcd580162f}\", itemId: 1, recycleBinEnabled: true, enableMinorVersioning: true, enableModeration: false, forceCheckout: true, rootFolderUrl: \"\\u002fmarcomm\\u002fPages\", itemPermissions:{High:176, Low:138612833}};\r\n                        SP.Ribbon.WebPartComponent.registerWithPageManager(initInfo);\r\n                        var wpcomp = SP.Ribbon.WebPartComponent.get_instance();\r\n                        var hid;\r\n                        hid = document.getElementById(\"_wpSelected\");\r\n                        if (hid != null)\r\n                        {\r\n                        var wpid = hid.value;\r\n                        if (wpid.length > 0)\r\n                        {\r\n                        var zc = document.getElementById(wpid);\r\n                        if (zc != null)\r\n                                wpcomp.selectWebPart(zc, false);\r\n                        }\r\n                        }\r\n                        hid = document.getElementById(\"_wzSelected\");\r\n                        if (hid != null)\r\n                        {\r\n                        var wzid = hid.value;\r\n                        if (wzid.length > 0)\r\n                        {\r\n                        wpcomp.selectWebPartZone(null, wzid);\r\n                        }\r\n                        }\r\n                        };\r\n                function __RegisterWebPartPageCUI() {\r\n                ExecuteOrDelayUntilScriptLoaded(_RegisterWebPartPageCUI, \"sp.ribbon.js\"); }\r\n                _spBodyOnLoadFunctionNames.push(\"__RegisterWebPartPageCUI\"); var __wpmExportWarning = 'This Web Part Page has been personalized. As a result, one or more Web Part properties may contain confidential information. Make sure the properties contain information that is safe for others to read. After exporting this Web Part, view properties in the Web Part description file (.WebPart) by using a text editor such as Microsoft Notepad.'; var __wpmCloseProviderWarning = 'You are about to close this Web Part.  It is currently providing data to other Web Parts, and these connections will be deleted if this Web Part is closed.  To close this Web Part, click OK.  To keep this Web Part, click Cancel.'; var __wpmDeleteWarning = 'You are about to permanently delete this Web Part.  Are you sure you want to do this?  To delete this Web Part, click OK.  To keep this Web Part, click Cancel.'; SuiteNavRendering.RenderSuiteNav({top:'suiteBarTop', version:2, dataEndpoint:'Microsoft.SharePoint.Portal.SuiteNavData.GetSuiteNavData', culture:'en-US', signInLink:'\\u002fmarcomm\\u002f_layouts\\u002f15\\u002fAuthenticate.aspx?Source=\\u00252Fmarcomm', brandingText:'BR Space', brandingLogo:'', brandingLogoLink:'', brandingLogoTitle:''});\r\n                ExecuteOrDelayUntilScriptLoaded(\r\n                        function()\r\n                                {\r\n                                var initInfo =\r\n                                        {\r\n                                        itemPermMasks: {High:176, Low:138612833},\r\n                                                listPermMasks: {High:176, Low:138612833},\r\n                                                listId: \"91c71bb3-48b2-45ca-baf2-6adcd580162f\",\r\n                                                itemId: 1,\r\n                                                workflowsAssociated: false,\r\n                                                editable: false,\r\n                                                doNotShowProperties: false,\r\n                                                enableVersioning: true\r\n                                                };\r\n                                SP.Ribbon.DocLibAspxPageComponent.registerWithPageManager(initInfo);\r\n                                },\r\n                                \"sp.ribbon.js\");\r\n                        var g_disableCheckoutInEditMode = false;\r\n                        var _spWebPermMasks = {High:176, Low:138612833}; function _cUpdonetidHeadbnnr2(){var myd = null; if (typeof (dataonetidHeadbnnr2) != 'undefined') {myd = dataonetidHeadbnnr2; } var myc = document.getElementById('ctl00_onetidHeadbnnr2'); _cUpdconetidHeadbnnr2(myd, myc); }function _cUpdconetidHeadbnnr2(data, ctrl){SiteLogoImagePageUpdate(ctrl, data); }g_spPreFetchKeys.push('sp.core.js');\r\n                        ExecuteOrDelayUntilScriptLoaded(\r\n                                function()\r\n                                {\r\n                                Srch.ScriptApplicationManager.get_current().states = {\"browserLanguage\":1033, \"webUILanguageName\":\"en-US\", \"webDefaultLanguageName\":\"en-US\", \"contextUrl\":\"/marcomm\", \"contextTitle\":\"Marcomm\", \"supportedLanguages\":[{\"id\":1025, \"label\":\"Arabic\"}, {\"id\":1093, \"label\":\"Bangla\"}, {\"id\":1026, \"label\":\"Bulgarian\"}, {\"id\":1027, \"label\":\"Catalan\"}, {\"id\":2052, \"label\":\"Chinese (Simplified)\"}, {\"id\":1028, \"label\":\"Chinese (Traditional)\"}, {\"id\":1050, \"label\":\"Croatian\"}, {\"id\":1029, \"label\":\"Czech\"}, {\"id\":1030, \"label\":\"Danish\"}, {\"id\":1043, \"label\":\"Dutch\"}, {\"id\":1033, \"label\":\"English\"}, {\"id\":1035, \"label\":\"Finnish\"}, {\"id\":1036, \"label\":\"French\"}, {\"id\":1031, \"label\":\"German\"}, {\"id\":1032, \"label\":\"Greek\"}, {\"id\":1095, \"label\":\"Gujarati\"}, {\"id\":1037, \"label\":\"Hebrew\"}, {\"id\":1081, \"label\":\"Hindi\"}, {\"id\":1038, \"label\":\"Hungarian\"}, {\"id\":1039, \"label\":\"Icelandic\"}, {\"id\":1057, \"label\":\"Indonesian\"}, {\"id\":1040, \"label\":\"Italian\"}, {\"id\":1041, \"label\":\"Japanese\"}, {\"id\":1099, \"label\":\"Kannada\"}, {\"id\":1042, \"label\":\"Korean\"}, {\"id\":1062, \"label\":\"Latvian\"}, {\"id\":1063, \"label\":\"Lithuanian\"}, {\"id\":1086, \"label\":\"Malay\"}, {\"id\":1100, \"label\":\"Malayalam\"}, {\"id\":1102, \"label\":\"Marathi\"}, {\"id\":1044, \"label\":\"Norwegian\"}, {\"id\":1045, \"label\":\"Polish\"}, {\"id\":1046, \"label\":\"Portuguese (Brazil)\"}, {\"id\":2070, \"label\":\"Portuguese (Portugal)\"}, {\"id\":1094, \"label\":\"Punjabi\"}, {\"id\":1048, \"label\":\"Romanian\"}, {\"id\":1049, \"label\":\"Russian\"}, {\"id\":3098, \"label\":\"Serbian (Cyrillic)\"}, {\"id\":2074, \"label\":\"Serbian (Latin)\"}, {\"id\":1051, \"label\":\"Slovak\"}, {\"id\":1060, \"label\":\"Slovenian\"}, {\"id\":3082, \"label\":\"Spanish (Spain)\"}, {\"id\":2058, \"label\":\"Spanish (Mexico)\"}, {\"id\":1053, \"label\":\"Swedish\"}, {\"id\":1097, \"label\":\"Tamil\"}, {\"id\":1098, \"label\":\"Telugu\"}, {\"id\":1054, \"label\":\"Thai\"}, {\"id\":1055, \"label\":\"Turkish\"}, {\"id\":1058, \"label\":\"Ukrainian\"}, {\"id\":1056, \"label\":\"Urdu\"}, {\"id\":1066, \"label\":\"Vietnamese\"}], \"navigationNodes\":[{\"id\":0, \"name\":\"This Site\", \"url\":\"~site/_layouts/15/osssearchresults.aspx?u={contexturl}\", \"promptString\":\"Search this site\"}], \"webUILanguageDirectory\":\"en-US\", \"showAdminDetails\":false, \"defaultPagesListName\":\"Pages\", \"isSPFSKU\":false, \"defaultQueryProperties\":{\"culture\":17417, \"uiLanguage\":17417, \"summaryLength\":180, \"desiredSnippetLength\":90, \"enableStemming\":true, \"enablePhonetic\":false, \"enableNicknames\":false, \"trimDuplicates\":true, \"bypassResultTypes\":false, \"enableInterleaving\":true, \"enableQueryRules\":true, \"processBestBets\":true, \"enableOrderingHitHighlightedProperty\":false, \"hitHighlightedMultivaluePropertyLimit\": - 1, \"processPersonalFavorites\":true}};\r\n                                Srch.U.trace(null, 'SerializeToClient', 'ScriptApplicationManager state initialized.');\r\n                                }, 'Search.ClientControls.js'); var g_clientIdDeltaPlaceHolderMain = \"DeltaPlaceHolderMain\";\r\n                        var g_clientIdDeltaPlaceHolderPageTitleInTitleArea = \"DeltaPlaceHolderPageTitleInTitleArea\";\r\n                        var g_clientIdDeltaPlaceHolderUtilityContent = \"DeltaPlaceHolderUtilityContent\";\r\n                        theForm.oldSubmit = theForm.submit;\r\n                        theForm.submit = WebForm_SaveScrollPositionSubmit;\r\n                        theForm.oldOnSubmit = theForm.onsubmit;\r\n                        theForm.onsubmit = WebForm_SaveScrollPositionOnSubmit;\r\n                        var g_commandUIHandlers = {\"name\":\"CommandHandlers\", \"attrs\":{}, \"children\":[]};\r\n                        g_QuickLaunchControlIds.push(\"zz7_TopNavigationMenu\"); \r\n                        _spBodyOnLoadFunctionNames.push('QuickLaunchInitDroppable'); \r\n                        var g_zz7_TopNavigationMenu = null; function init_zz7_TopNavigationMenu() { \r\n                            if (g_zz7_TopNavigationMenu == null) g_zz7_TopNavigationMenu = $create(SP.UI.AspMenu, null, null, null, $get('zz7_TopNavigationMenu')); \r\n                            \r\n                        } \r\n                        if (g_spPreFetchKeys) {\r\n                            { \r\n                                g_spPreFetchKeys.push('SP.Core.js'); \r\n                                \r\n                            }\r\n                            \r\n                        }\r\n                        EnsureScriptFunc('SP.Core.js', 'SP.UI.AspMenu', init_zz7_TopNavigationMenu);\r\n                        ExecuteOrDelayUntilScriptLoaded(\r\n                                function()\r\n                                {\r\n                                if ($isNull($find('ctl00_ctl49_csr')))\r\n                                {\r\n                                var sb = $create(Srch.SearchBox, {\"delayLoadTemplateScripts\":true, \"initialPrompt\":\"Search this site\", \"messages\":[], \"navigationNodes\":[{\"id\":0, \"name\":\"This Site\", \"url\":\"~site/_layouts/15/osssearchresults.aspx?u={contexturl}\", \"promptString\":\"Search this site\"}], \"queryGroupNames\":[\"Default\"], \"renderTemplateId\":\"~sitecollection/_catalogs/masterpage/Display Templates/Search/Control_SearchBox.js\", \"resultsPageAddress\":\"~site/_layouts/15/osssearchresults.aspx?u={contexturl}\", \"serverInitialRender\":true, \"showDataErrors\":true, \"showNavigation\":true, \"showQuerySuggestions\":false, \"states\":{}, \"tryInplaceQuery\":false}, null, null, $get(\"ctl00_ctl49_csr\"));\r\n                                sb.activate('Search this site', 'ctl00_ctl49_csr_sbox', 'ctl00_ctl49_csr_sboxdiv', 'ctl00_ctl49_csr_NavButton', 'ctl00_ctl49_csr_AutoCompList', 'ctl00_ctl49_csr_NavDropdownList', 'ctl00_ctl49_csr_SearchLink', 'ms-srch-sbprogress', 'ms-srch-sb-prompt ms-helperText');\r\n                                }\r\n                                }, 'Search.ClientControls.js'); //]]>\r\n            <\/script>\r\n        </form><span id=\"DeltaPlaceHolderUtilityContent\"></span>","content_is_php":0,"content_status":1,"content_order":5}],"header":{"header_id":7,"header_content":"<!DOCTYPE html>\r\n<!-- saved from url=(0041)/marcomm -->\r\n<html dir=\"ltr\" lang=\"en-MY\">\r\n    <head>\r\n        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=10\">\r\n        <meta name=\"GENERATOR\" content=\"Microsoft SharePoint\">\r\n        <meta http-equiv=\"Expires\" content=\"0\">\r\n        <title>\r\n            Marcomm\r\n        </title>\r\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/portalassets/Marcomm/corev15.css\">\r\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/portalassets/Marcomm/bkrmportalmaster.css\">\r\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/portalassets/Marcomm/bkrmportalwebpart.css\">\r\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/portalassets/Marcomm/carousel.css\">\r\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/portalassets/Marcomm/SuiteNav.css\">\r\n\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/initstrings.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/init.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/jquery1.12.4.min.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/jquery.ctt.timeslider.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/ScriptResource.axd\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/blank.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/ScriptResource(1).axd\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/suitenav.js.download\"><\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"require.js\", \"\\u002f_layouts\\u002f15\\u002frequire.js?rev=\\u00252BRRfOnYW0VaAgSoCgcIN8Q\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"strings.js\", \"\\u002f_layouts\\u002f15\\u002f1033\\u002fstrings.js?rev=k\\u00252FSaOdWtcHDDvsb\\u00252FUFykOA\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.res.resx\", \"\\u002f_layouts\\u002f15\\u002f1033\\u002fsp.res.js?rev=MbB92HT8biYuFa\\u00252B1vTMilA\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.runtime.js\", \"\\u002f_layouts\\u002f15\\u002fsp.runtime.js?rev=LiLvWscZ25MQUF\\u00252BucpVI\\u00252FQ\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sp.runtime.js\", \"sp.res.resx\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.js\", \"\\u002f_layouts\\u002f15\\u002fsp.js?rev=wodXBbvfSljkJvZKPlUJug\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sp.js\", \"sp.runtime.js\"); RegisterSodDep(\"sp.js\", \"sp.ui.dialog.js\"); RegisterSodDep(\"sp.js\", \"sp.res.resx\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.init.js\", \"\\u002f_layouts\\u002f15\\u002fsp.init.js?rev=e\\u00252BK\\u00252BgPRahLRqldGOZRBeEA\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.ui.dialog.js\", \"\\u002f_layouts\\u002f15\\u002fsp.ui.dialog.js?rev=jGY\\u00252BLOSvHa47C54DL7qxOA\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sp.ui.dialog.js\", \"sp.init.js\"); RegisterSodDep(\"sp.ui.dialog.js\", \"sp.res.resx\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"core.js\", \"\\u002f_layouts\\u002f15\\u002fcore.js?rev=ooFtNhoOE2el6ilWzci55w\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"core.js\", \"strings.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"menu.js\", \"\\u002f_layouts\\u002f15\\u002fmenu.js?rev=Py67mQ0RAr9mlkQz\\u00252BmYM8w\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"mQuery.js\", \"\\u002f_layouts\\u002f15\\u002fmquery.js?rev=1i9Wf5cruQ3eBhWimvF8LQ\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"callout.js\", \"\\u002f_layouts\\u002f15\\u002fcallout.js?rev=7aZaGYa7iCsTKwQxNHL1uA\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"callout.js\", \"strings.js\"); RegisterSodDep(\"callout.js\", \"mQuery.js\"); RegisterSodDep(\"callout.js\", \"core.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.core.js\", \"\\u002f_layouts\\u002f15\\u002fsp.core.js?rev=HIq0NKatYLdTt5Qvq4rfgA\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sp.core.js\", \"strings.js\"); RegisterSodDep(\"sp.core.js\", \"sp.init.js\"); RegisterSodDep(\"sp.core.js\", \"core.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sharedhovercard.strings.js\", \"\\u002f_layouts\\u002f15\\u002f1033\\u002fsharedhovercard.strings.js?rev=sLsS\\u00252FNPqFzOSO42e3s6lgw\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sharedhovercard.js\", \"\\u002f_layouts\\u002f15\\u002fsharedhovercard.js?rev=uB89up9szoXj8bAMKPkPSg\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sharedhovercard.js\", \"sharedhovercard.strings.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"clienttemplates.js\", \"\\u002f_layouts\\u002f15\\u002fclienttemplates.js?rev=j6\\u00252Bz4BDO342fu4R4shpumw\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sharing.js\", \"\\u002f_layouts\\u002f15\\u002fsharing.js?rev=OM3H6lospXttTRqs0FqXSA\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sharing.js\", \"strings.js\"); RegisterSodDep(\"sharing.js\", \"mQuery.js\"); RegisterSodDep(\"sharing.js\", \"clienttemplates.js\"); RegisterSodDep(\"sharing.js\", \"core.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"suitelinks.js\", \"\\u002f_layouts\\u002f15\\u002fsuitelinks.js?rev=iz6Biq\\u00252FcdEEEbjmO8ge\\u00252BxQ\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"suitelinks.js\", \"strings.js\"); RegisterSodDep(\"suitelinks.js\", \"core.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"clientrenderer.js\", \"\\u002f_layouts\\u002f15\\u002fclientrenderer.js?rev=icbWdD\\u00252FlpVz8Naz\\u00252FialdVQ\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"srch.resources.resx\", \"\\u002f_layouts\\u002f15\\u002f1033\\u002fsrch.resources.js?rev=YFZFsHKXct9hchZcv\\u00252BUURA\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"search.clientcontrols.js\", \"\\u002f_layouts\\u002f15\\u002fsearch.clientcontrols.js?rev=PlIH2VsdUhIBLzSKwU9PJQ\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"search.clientcontrols.js\", \"sp.init.js\"); RegisterSodDep(\"search.clientcontrols.js\", \"clientrenderer.js\"); RegisterSodDep(\"search.clientcontrols.js\", \"srch.resources.resx\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"cui.js\", \"\\u002f_layouts\\u002f15\\u002fcui.js?rev=ss63uooxySpkPrQCHE\\u00252Bu0Q\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"inplview\", \"\\u002f_layouts\\u002f15\\u002finplview.js?rev=Qzgy7\\u00252FqUZ9RKQe2Ivw9ZsQ\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"inplview\", \"strings.js\"); RegisterSodDep(\"inplview\", \"core.js\"); RegisterSodDep(\"inplview\", \"clienttemplates.js\"); RegisterSodDep(\"inplview\", \"sp.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"ribbon\", \"\\u002f_layouts\\u002f15\\u002fsp.ribbon.js?rev=XDUkPbH3Dw4Ozb7wYPpMpA\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"ribbon\", \"strings.js\"); RegisterSodDep(\"ribbon\", \"core.js\"); RegisterSodDep(\"ribbon\", \"sp.core.js\"); RegisterSodDep(\"ribbon\", \"sp.js\"); RegisterSodDep(\"ribbon\", \"cui.js\"); RegisterSodDep(\"ribbon\", \"sp.res.resx\"); RegisterSodDep(\"ribbon\", \"sp.runtime.js\"); RegisterSodDep(\"ribbon\", \"inplview\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.ui.policy.resources.resx\", \"\\u002f_layouts\\u002f15\\u002fScriptResx.ashx?culture=en\\u00252Dus\\u0026name=SP\\u00252EUI\\u00252EPolicy\\u00252EResources\\u0026rev=m2Nvtm13DRgodCVi\\u00252BsRukw\\u00253D\\u00253D\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"mdn.js\", \"\\u002f_layouts\\u002f15\\u002fmdn.js?rev=8NNwivaC8jSLGWcNFulEiA\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"mdn.js\", \"sp.init.js\"); RegisterSodDep(\"mdn.js\", \"core.js\"); RegisterSodDep(\"mdn.js\", \"sp.runtime.js\"); RegisterSodDep(\"mdn.js\", \"sp.js\"); RegisterSodDep(\"mdn.js\", \"cui.js\"); RegisterSodDep(\"mdn.js\", \"ribbon\"); RegisterSodDep(\"mdn.js\", \"sp.ui.policy.resources.resx\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"socialdata.js\", \"\\u002f_layouts\\u002f15\\u002fsocialdata.js?rev=bkq3o\\u00252BkeqS8mhx5XUQWd\\u00252BQ\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.ui.socialribbon.js\", \"\\u002f_layouts\\u002f15\\u002fsp.ui.socialribbon.js?rev=KiZAgV\\u00252FKHVNmWf8h04Ua2Q\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sp.ui.socialribbon.js\", \"ribbon\"); RegisterSodDep(\"sp.ui.socialribbon.js\", \"socialdata.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"userprofile\", \"\\u002f_layouts\\u002f15\\u002fsp.userprofiles.js?rev=cx6U8sP\\u00252ByP0OFLjk6ekyIg\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"userprofile\", \"sp.runtime.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"followingcommon.js\", \"\\u002f_layouts\\u002f15\\u002ffollowingcommon.js?rev=bJTBCEv1HgjaWwx\\u00252BYKODBw\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"followingcommon.js\", \"strings.js\"); RegisterSodDep(\"followingcommon.js\", \"sp.js\"); RegisterSodDep(\"followingcommon.js\", \"userprofile\"); RegisterSodDep(\"followingcommon.js\", \"core.js\"); RegisterSodDep(\"followingcommon.js\", \"mQuery.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"profilebrowserscriptres.resx\", \"\\u002f_layouts\\u002f15\\u002f1033\\u002fprofilebrowserscriptres.js?rev=qwf69WaVc1mYlJLXqmZmVA\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"sp.ui.mysitecommon.js\", \"\\u002f_layouts\\u002f15\\u002fsp.ui.mysitecommon.js?rev=RwXcuvJsiysDLpAqtmAQDQ\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"sp.ui.mysitecommon.js\", \"sp.init.js\"); RegisterSodDep(\"sp.ui.mysitecommon.js\", \"sp.runtime.js\"); RegisterSodDep(\"sp.ui.mysitecommon.js\", \"userprofile\"); RegisterSodDep(\"sp.ui.mysitecommon.js\", \"profilebrowserscriptres.resx\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"browserScript\", \"\\u002f_layouts\\u002f15\\u002fie55up.js?rev=sH5pKoCb6296RyPJOzqDLQ\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"browserScript\", \"strings.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"offline.js\", \"\\u002f_layouts\\u002f15\\u002foffline.js?rev=TNvrnrBr6gGqmX6tutKqbQ\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"theming.js\", \"\\u002f_layouts\\u002f15\\u002ftheming.js?rev=AQsQZgsKbypSwgIb\\u00252BD\\u00252FmYA\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"WPAdderClass\", \"\\u002f_layouts\\u002f15\\u002fwpadder.js?rev=1Xu0VPodqII\\u00252FBTg1dJEROA\\u00253D\\u00253DTAG0\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"dragdrop.js\", \"\\u002f_layouts\\u002f15\\u002fdragdrop.js?rev=sS\\u00252FVNxxoVRWr9Jx1O3\\u00252BJLw\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"dragdrop.js\", \"strings.js\");<\/script>\r\n        <script type=\"text/javascript\">RegisterSod(\"quicklaunch.js\", \"\\u002f_layouts\\u002f15\\u002fquicklaunch.js?rev=vVofmuHQaUBrnociTb9cjQ\\u00253D\\u00253DTAG0\"); RegisterSodDep(\"quicklaunch.js\", \"strings.js\"); RegisterSodDep(\"quicklaunch.js\", \"dragdrop.js\");<\/script>\r\n        <link type=\"text/xml\" rel=\"alternate\" href=\"/marcomm/_vti_bin/spsdisco.aspx\">\r\n\r\n        <style type=\"text/css\">\r\n            .bkrm-pagetitle,\r\n            .bkrm-sitetitle\r\n            {\r\n                display: none;\r\n            }\r\n            .bkrm-maincontent\r\n            {\r\n                background-color: transparent;\r\n                overflow-x: hidden; /*custom page layout no scrolling*/\r\n            }\r\n            .bkrm-placeholdermain\r\n            {\r\n                width: 100%; /*show 100% coz no need show navigation or quick launch */\r\n                overflow-x: hidden;\r\n                padding-bottom: 0px; /*reduce from 100px in master page*/\r\n            }\r\n            #s4-ribbonrow\r\n            {\r\n                /*display: none;*/ /*to get extra height in display mode, appear back in edit mode*/\r\n            }\r\n            #s4-bodyContainer {\r\n                min-height: 100vh;\r\n            }\r\n        </style>\r\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1,maximum-scale=1\">\r\n        <link rel=\"canonical\" href=\"http://brprodsp16web02:20000/marcomm\">\r\n\r\n\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/strings.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/sp.init.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/core.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/socialdata.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/mquery.js.download\"><\/script>\r\n        <script type=\"text/javascript\" src=\"/portalassets/Marcomm/sp.core.js.download\"><\/script>\r\n    </head>\r\n    <body class=\"bkrm-body ms-backgroundImage\" onhashchange=\"if (typeof(_spBodyOnHashChange) != &#39;undefined&#39;) _spBodyOnHashChange();\">\r\n        ","header_is_php":0,"header_description":"Header - MarComm"},"footer":{"footer_id":7,"footer_content":"</body></html>","footer_is_php":0,"footer_description":"Footer - MarComm"}}</script>

</body>
</html>