<?php
require_once __DIR__ . '/config.php';
$googleClientId = defined('GOOGLE_CLIENT_ID') ? GOOGLE_CLIENT_ID : '';
$appUrl = rtrim(APP_URL, '/');
$googleError = htmlspecialchars($_GET['google_error'] ?? '', ENT_QUOTES);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"/>
<title>FormBuilder — Pro Admin</title>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=DM+Mono:wght@400;500&family=Syne:wght@700;800&display=swap" rel="stylesheet"/>
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{
  --nav:#0e1117;--nb:rgba(255,255,255,.07);--nh:rgba(255,255,255,.06);--na:rgba(255,255,255,.1);
  --canvas:#f5f4f1;--white:#fff;--ink:#111217;--muted:#6b7280;--muted2:#9ca3af;
  --rule:rgba(0,0,0,.08);--rule2:rgba(0,0,0,.13);
  --accent:#2563eb;--ap:#eff6ff;--as:rgba(37,99,235,.12);--ad:#1d4ed8;
  --green:#059669;--gp:#ecfdf5;
  --red:#dc2626;--rp:#fef2f2;
  --amber:#d97706;--ambp:#fffbeb;
  --r6:6px;--r8:8px;--r12:12px;--r16:16px;
  --nw:220px;--th:52px;--mnh:60px;
  --font:'DM Sans',sans-serif;--mono:'DM Mono',monospace;
}
html,body{height:100%;font-family:var(--font);font-size:14px;line-height:1.5;overflow:hidden;background:var(--canvas)}
button{font-family:var(--font);cursor:pointer}
a{color:inherit;text-decoration:none}
input,select,textarea{font-family:var(--font)}

/* ── LOGIN ── */
#login-screen{
  position:fixed;inset:0;z-index:1000;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  background:#f4f5f7;
  padding:24px 16px;
  font-family:'DM Sans',sans-serif;
  -webkit-font-smoothing:antialiased;
}
.l-brand{display:flex;align-items:center;gap:10px;margin-bottom:28px}
.l-brand-logo{width:36px;height:36px;background:linear-gradient(135deg,#f5a623,#b87800);border-radius:10px;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 8px rgba(224,149,0,.18)}
.l-brand-logo svg{width:16px;height:16px;stroke:#fff;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.l-brand-name{font-family:'Syne',sans-serif;font-size:16px;font-weight:800;color:#111827}
.lc{width:100%;max-width:420px}
.lcard{background:#fff;border-radius:20px;box-shadow:0 2px 8px rgba(0,0,0,.05),0 12px 40px rgba(0,0,0,.08);border:1px solid #e8eaed;overflow:hidden}
.lhdr{background:linear-gradient(135deg,#f5a623,#b87800);padding:24px 28px}
.lhdr-eye{font-family:'DM Mono',monospace;font-size:10px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.7);margin-bottom:4px}
.lhdr-title{font-family:'Syne',sans-serif;font-size:20px;font-weight:800;color:#fff}
.lhdr-sub{font-size:13px;color:rgba(255,255,255,.75);margin-top:2px}
.lbody{padding:28px}
.lf{margin-bottom:18px}
.lf-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}
.lf label{display:block;font-size:12px;font-weight:600;color:#4b5563;letter-spacing:.03em;margin-bottom:6px}
.lf input{display:block;width:100%;padding:11px 14px;border:1.5px solid #d1d5db;border-radius:10px;font-family:'DM Sans',sans-serif;font-size:14px;color:#111827;background:#fff;transition:border-color .15s,box-shadow .15s;outline:none;-webkit-appearance:none}
.lf input:focus{border-color:#e09500;box-shadow:0 0 0 3px rgba(224,149,0,.18)}
.pw-wrap{position:relative}
.pw-wrap input{padding-right:44px}
.pw-eye{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;color:#9ca3af;display:flex;align-items:center;transition:color .15s}
.pw-eye:hover{color:#4b5563}
.pw-eye svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.lf-forgot{font-size:12px;color:#e09500;font-weight:600;text-decoration:none}
.lf-forgot:hover{color:#b87800}
.lbtn{display:block;width:100%;padding:13px;background:#e09500;color:#fff;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:700;border:none;border-radius:10px;cursor:pointer;transition:background .15s,box-shadow .15s;margin-top:4px}
.lbtn:hover{background:#f5a623;box-shadow:0 4px 12px rgba(224,149,0,.18)}
.lbtn:disabled{opacity:.6;cursor:not-allowed}
.l-divider{display:flex;align-items:center;gap:12px;margin:20px 0;color:#d1d5db;font-size:12px;color:#9ca3af}
.l-divider::before,.l-divider::after{content:'';flex:1;height:1px;background:#e8eaed}
.l-google{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;padding:12px;background:#fff;color:#374151;font-family:'DM Sans',sans-serif;font-size:14px;font-weight:600;border:1.5px solid #d1d5db;border-radius:10px;cursor:pointer;transition:background .15s,border-color .15s,box-shadow .15s}
.l-google:hover{background:#f9fafb;border-color:#b0b8c4;box-shadow:0 1px 4px rgba(0,0,0,.07)}
.l-google svg{width:18px;height:18px;flex-shrink:0}
.lerr{padding:12px 14px;border-radius:10px;font-size:13px;margin-bottom:16px;display:none;background:#fef2f2;color:#dc2626;border:1px solid #fecaca}
.lerr.show{display:block}
.lfoot{text-align:center;margin-top:14px;font-size:11px;color:#9ca3af}

/* ── APP SHELL ── */
#app{display:none;height:100vh;overflow:hidden}
.shell{display:flex;height:100vh;overflow:hidden}

/* ── SIDEBAR ── */
.nav{width:var(--nw);flex-shrink:0;background:var(--nav);display:flex;flex-direction:column;height:100vh;overflow:hidden;z-index:95;transition:transform .26s cubic-bezier(.4,0,.2,1)}
.nav-logo{padding:16px 14px 13px;border-bottom:1px solid var(--nb);display:flex;align-items:center;gap:10px;flex-shrink:0}
.nav-mark{width:28px;height:28px;background:var(--accent);border-radius:7px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.nav-mark svg{width:14px;height:14px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.nav-title{font-size:13px;font-weight:500;color:#fff}
.nav-plan{font-size:10px;color:rgba(255,255,255,.3)}
.nav-items{padding:8px 6px;flex:1;overflow-y:auto}
.nav-gl{font-size:10px;font-weight:500;color:rgba(255,255,255,.22);text-transform:uppercase;letter-spacing:.09em;padding:10px 8px 4px}
.ni{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:var(--r8);color:rgba(255,255,255,.5);font-size:13px;cursor:pointer;transition:all .15s;margin-bottom:1px}
.ni:hover{background:var(--nh);color:rgba(255,255,255,.85)}
.ni.active{background:var(--na);color:#fff}
.ni svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0;opacity:.75}
.ni.active svg{opacity:1}
.ni-badge{margin-left:auto;font-size:10px;background:var(--accent);color:#fff;padding:2px 6px;border-radius:20px;font-weight:500;min-width:20px;text-align:center}
/* ── Module toggle switch ── */
.tog-wrap{position:relative;display:inline-block;width:44px;height:24px;cursor:pointer;flex-shrink:0}
.tog-inp{position:absolute;opacity:0;width:0;height:0}
.tog-track{position:absolute;inset:0;background:var(--border2,rgba(255,255,255,.15));border-radius:12px;transition:background .2s}
.tog-thumb{position:absolute;top:3px;left:3px;width:18px;height:18px;background:#fff;border-radius:50%;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.3)}
.tog-inp:checked+.tog-track{background:var(--green,#16a34a)}
.tog-inp:checked+.tog-track .tog-thumb{transform:translateX(20px)}
.nav-foot{padding:8px 6px 12px;border-top:1px solid var(--nb);flex-shrink:0}
.nav-user{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:var(--r8);cursor:pointer;transition:background .15s;margin-bottom:4px}
.nav-user:hover{background:var(--nh)}
.nav-av{width:26px;height:26px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:500;color:#fff;flex-shrink:0}
.nav-un{font-size:12px;color:rgba(255,255,255,.75)}
.nav-ur{font-size:10px;color:rgba(255,255,255,.3)}
.nav-out{display:flex;align-items:center;gap:7px;padding:7px 10px;border-radius:var(--r8);color:rgba(255,255,255,.3);font-size:12px;cursor:pointer;transition:all .15s;border:none;background:none;width:100%}
.nav-out:hover{background:rgba(220,38,38,.15);color:#fca5a5}
.nav-out svg{width:12px;height:12px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* ── MAIN ── */
.main{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}
.topbar{height:var(--th);background:var(--white);border-bottom:1px solid var(--rule);display:flex;align-items:center;padding:0 20px;gap:10px;flex-shrink:0}
.tb-ham{display:none;width:30px;height:30px;align-items:center;justify-content:center;border:1px solid var(--rule2);border-radius:var(--r8);background:none;cursor:pointer;flex-shrink:0}
.tb-ham svg{width:15px;height:15px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.tb-title{font-size:14px;font-weight:500;color:var(--ink);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tb-search{display:flex;align-items:center;gap:7px;background:var(--canvas);border:1px solid var(--rule2);border-radius:var(--r8);padding:6px 10px;width:180px;flex-shrink:0}
.tb-search svg{width:13px;height:13px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
.tb-search input{border:none;background:transparent;font-size:12px;color:var(--ink);outline:none;width:100%;min-width:0}
.tb-search input::placeholder{color:var(--muted2)}
.kbd{font-size:10px;background:rgba(0,0,0,.06);border-radius:4px;padding:2px 5px;color:var(--muted);font-family:var(--mono)}
.tb-actions{display:flex;gap:6px;align-items:center;flex-shrink:0}
.content{flex:1;overflow-y:auto;padding:20px;padding-bottom:calc(var(--mnh) + 8px);scrollbar-width:thin;scrollbar-color:var(--rule2) transparent}
.content::-webkit-scrollbar{width:4px}
.content::-webkit-scrollbar-thumb{background:var(--rule2);border-radius:2px}

/* ── MOBILE BOTTOM NAV ── */
.mob-nav{display:none;position:fixed;bottom:0;left:0;right:0;height:var(--mnh);background:var(--nav);border-top:1px solid var(--nb);z-index:90;padding-bottom:env(safe-area-inset-bottom)}
.mob-inner{display:flex;height:100%;align-items:stretch}
.mni{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;cursor:pointer;color:rgba(255,255,255,.38);font-size:8px;font-weight:400;border:none;background:none;padding:0;transition:color .15s}
.mni.active{color:#fff}
.mni svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.nov{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:94;opacity:0;transition:opacity .25s;pointer-events:none}
.nov.open{opacity:1;pointer-events:all}

/* ── BUTTONS ── */
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 13px;border-radius:var(--r8);font-size:13px;font-weight:500;border:none;cursor:pointer;font-family:var(--font);transition:all .15s;white-space:nowrap;text-decoration:none}
.btn svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
.btn-primary{background:var(--accent);color:#fff}
.btn-primary:hover{background:var(--ad)}
.btn-ghost{background:var(--white);color:var(--muted);border:1px solid var(--rule2)}
.btn-ghost:hover{border-color:#999;color:var(--ink)}
.btn-danger{background:var(--rp);color:var(--red);border:1px solid #fecaca}
.btn-danger:hover{background:var(--red);color:#fff;border-color:var(--red)}
.btn-sm{padding:5px 10px;font-size:12px;border-radius:var(--r6)}
.btn-icon{padding:6px;width:28px;height:28px;justify-content:center}
.btn-block{width:100%;justify-content:center}

/* ── CARDS ── */
.card{background:var(--white);border:1px solid var(--rule);border-radius:var(--r16);overflow:hidden;margin-bottom:14px}
.card-hdr{padding:13px 18px;border-bottom:1px solid var(--rule);display:flex;align-items:center;justify-content:space-between;gap:10px}
.card-hdr-title,.card-title{font-size:13px;font-weight:500;color:var(--ink)}
.card-body{padding:16px 18px}
.card-sub{font-size:11px;color:var(--muted);margin-top:2px}

/* ── STAT GRID ── */
.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:18px}
.stat-card{background:var(--white);border:1px solid var(--rule);border-radius:var(--r12);padding:14px 16px;transition:box-shadow .15s;cursor:default}
.stat-card:hover{box-shadow:0 2px 12px rgba(0,0,0,.07)}
/* stat icon/num/lbl — support both old (.sc-*) and new (.stat-*) class names */
.sc-icon,.stat-icon{width:32px;height:32px;border-radius:var(--r8);background:var(--ap);display:flex;align-items:center;justify-content:center;margin-bottom:9px}
.sc-icon svg,.stat-icon svg{width:16px;height:16px;stroke:var(--accent);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.sc-num,.stat-num{font-size:24px;font-weight:500;color:var(--ink);letter-spacing:-.02em;line-height:1}
.sc-lbl,.stat-lbl{font-size:11px;color:var(--muted);margin-top:3px}

/* ── PAGE HEADER ── */
.ph,.page-hd{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;gap:10px;flex-wrap:wrap}
.ph h2,.page-hd h1{font-size:16px;font-weight:500;color:var(--ink)}
.page-hd p{font-size:13px;color:var(--muted);flex-basis:100%;margin-top:2px}
.ph-actions{display:flex;gap:7px;align-items:center;flex-wrap:wrap}

/* ── TABLE ── */
.tbl-wrap,.tw{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;font-size:13px}
thead tr{border-bottom:1px solid var(--rule)}
th{padding:8px 13px;text-align:left;font-size:11px;font-weight:500;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;background:var(--white)}
td{padding:10px 13px;border-bottom:1px solid var(--rule);color:var(--ink);vertical-align:middle}
tr:last-child td{border-bottom:none}
tr:hover td{background:#fafafa}
.tr-click{cursor:pointer}

/* ── BADGES ── */
.badge{display:inline-flex;align-items:center;padding:3px 8px;border-radius:20px;font-size:11px;font-weight:500;white-space:nowrap}
/* new template shorthand classes */
.bg{background:var(--gp);color:var(--green)}
.br{background:var(--rp);color:var(--red)}
.ba{background:var(--ambp);color:var(--amber)}
.bb{background:var(--ap);color:var(--accent)}
.bk{background:var(--canvas);color:var(--muted);border:1px solid var(--rule2)}
/* compat — used by existing render functions */
.badge-green{background:var(--gp);color:var(--green)}
.badge-yellow{background:var(--ambp);color:var(--amber)}
.badge-red{background:var(--rp);color:var(--red)}
.badge-blue{background:var(--ap);color:var(--accent)}
.badge-gray{background:var(--canvas);color:var(--muted);border:1px solid var(--rule2)}
.badge-amber{background:var(--ap);color:var(--accent)}

/* ── FILTER BAR ── */
.fb{display:flex;align-items:center;gap:7px;margin-bottom:14px;flex-wrap:wrap}
.fsel{padding:6px 10px;border-radius:var(--r8);border:1px solid var(--rule2);background:var(--white);font-size:12px;color:var(--ink);font-family:var(--font);outline:none}
.finput{padding:6px 11px;border-radius:var(--r8);border:1px solid var(--rule2);background:var(--white);font-size:12px;color:var(--ink);font-family:var(--font);outline:none;min-width:100px}
.fsel:focus,.finput:focus{border-color:var(--accent)}

/* ── FORM FIELDS ── */
.fg{margin-bottom:13px}
.fg label{display:block;font-size:11px;font-weight:500;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:4px}
.fg input,.fg select,.fg textarea{width:100%;border:1px solid var(--rule2);border-radius:var(--r8);padding:8px 11px;font-size:13px;color:var(--ink);font-family:var(--font);outline:none;transition:border .15s;background:var(--white)}
.fg input:focus,.fg select:focus,.fg textarea:focus{border-color:var(--accent)}
.fg textarea{min-height:75px;resize:vertical}
.fg .hint{font-size:11px;color:var(--muted2);margin-top:3px}
.two-col,.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:11px}

/* ── TOGGLE ── */
.toggle-row{display:flex;align-items:center;gap:9px;margin-bottom:10px}
.toggle{position:relative;width:34px;height:19px;flex-shrink:0}
.toggle input{opacity:0;width:0;height:0;position:absolute}
.tslider,.toggle-slider{position:absolute;inset:0;background:#d1d5db;border-radius:19px;cursor:pointer;transition:.2s}
.tslider:before,.toggle-slider:before{content:'';position:absolute;width:13px;height:13px;left:3px;top:3px;background:#fff;border-radius:50%;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.toggle input:checked+.tslider,.toggle input:checked+.toggle-slider{background:var(--accent)}
.toggle input:checked+.tslider:before,.toggle input:checked+.toggle-slider:before{transform:translateX(15px)}
.tlabel,.toggle-label{font-size:12px;font-weight:500;color:var(--ink)}

/* ── MODAL ── */
.ov{position:fixed;inset:0;background:rgba(0,0,0,.45);backdrop-filter:blur(3px);z-index:200;display:flex;align-items:center;justify-content:center;padding:16px;opacity:0;pointer-events:none;transition:opacity .2s}
.ov.open{opacity:1;pointer-events:all}
.modal{background:var(--white);border-radius:var(--r16);width:100%;max-width:560px;max-height:90vh;overflow:hidden;display:flex;flex-direction:column;transform:scale(.96) translateY(10px);transition:transform .22s cubic-bezier(.34,1.56,.64,1);box-shadow:0 24px 60px rgba(0,0,0,.18)}
.ov.open .modal{transform:none}
.mhdr{padding:16px 20px;border-bottom:1px solid var(--rule);display:flex;align-items:center;gap:10px;flex-shrink:0}
.mhdr h3{font-size:15px;font-weight:500;flex:1;color:var(--ink)}
.mclose{width:28px;height:28px;border-radius:var(--r6);border:1px solid var(--rule2);background:none;display:flex;align-items:center;justify-content:center;color:var(--muted);cursor:pointer;font-size:14px;flex-shrink:0;transition:all .15s}
.mclose:hover{background:var(--canvas);color:var(--ink)}
.mbody{flex:1;overflow-y:auto;padding:20px}
.mfoot{padding:14px 20px;border-top:1px solid var(--rule);display:flex;gap:8px;justify-content:flex-end;flex-shrink:0;background:var(--canvas)}

/* ── TOAST ── */
.toast{position:fixed;bottom:calc(var(--mnh) + 10px);left:50%;transform:translateX(-50%) translateY(16px);background:var(--ink);color:#fff;padding:8px 16px;border-radius:999px;font-size:12px;font-weight:500;z-index:999;opacity:0;transition:all .28s;pointer-events:none;white-space:nowrap;box-shadow:0 4px 16px rgba(0,0,0,.2)}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.toast.ok{background:var(--green)}.toast.err{background:var(--red)}.toast.warn{background:var(--amber)}

/* ── LOADING / EMPTY STATES ── */
.spinner{display:inline-block;width:20px;height:20px;border:2px solid rgba(37,99,235,.15);border-top-color:var(--accent);border-radius:50%;animation:spin .7s linear infinite;vertical-align:middle}
@keyframes spin{to{transform:rotate(360deg)}}
.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:80px 20px;gap:12px;color:var(--muted)}
.loading-state .spinner{width:26px;height:26px}
.empty{text-align:center;padding:60px 20px;color:var(--muted2)}
.empty-icon{width:52px;height:52px;border-radius:14px;background:var(--canvas);border:1px solid var(--rule);display:flex;align-items:center;justify-content:center;margin:0 auto 14px}
.empty-icon svg{width:22px;height:22px;stroke:var(--muted2);fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.empty h3{font-size:15px;font-weight:500;color:var(--muted);margin-bottom:6px}
.empty p{font-size:13px;color:var(--muted2);margin-bottom:18px;line-height:1.6;max-width:280px;margin-left:auto;margin-right:auto}

/* ── COMPAT UTILITIES ── */
.code-pill{font-family:var(--mono);font-size:11px;background:var(--ap);color:var(--accent);border:1px solid rgba(37,99,235,.2);padding:2px 8px;border-radius:6px}
.prog-bar{height:4px;background:var(--rule);border-radius:4px;overflow:hidden;margin-top:5px}
.prog-fill{height:100%;border-radius:4px;background:var(--accent)}
.quick-actions{display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap}
.qa-btn{flex:1;min-width:150px;background:var(--white);border:1px solid var(--rule);border-radius:var(--r12);padding:14px 16px;cursor:pointer;transition:all .15s;display:flex;align-items:center;gap:10px;text-align:left}
.qa-btn:hover{border-color:var(--accent);background:var(--ap)}
.qa-icon{width:34px;height:34px;border-radius:var(--r8);flex-shrink:0;background:var(--ap);display:flex;align-items:center;justify-content:center}
.qa-icon svg{width:15px;height:15px;stroke:var(--accent);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.qa-title{font-size:13px;font-weight:500;color:var(--ink);margin-bottom:1px}
.qa-sub{font-size:11px;color:var(--muted)}
.sub-detail table{width:100%;border-collapse:collapse;font-size:13px}
.sub-detail td{padding:10px 0;border-bottom:1px solid var(--rule);vertical-align:top}
.sub-detail td:first-child{font-family:var(--mono);font-size:10px;font-weight:500;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;width:32%;padding-right:14px}
.sub-detail tr:last-child td{border-bottom:none}
.divider{border:none;border-top:1px solid var(--rule);margin:16px 0}

/* ── FORM INPUT (used in settings) ── */
.form-input{width:100%;border:1.5px solid var(--rule2);border-radius:var(--r8);padding:8px 11px;font-size:13px;color:var(--ink);font-family:var(--font);outline:none;transition:border .15s,box-shadow .15s;background:var(--white)}
.form-input:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--as)}
textarea.form-input{min-height:80px;resize:vertical}

/* ── SETTINGS LAYOUT ── */
.slayout{display:grid;grid-template-columns:160px 1fr;gap:20px}
.snav{border-right:1px solid var(--rule);padding-right:14px}
.sni{display:flex;align-items:center;gap:7px;padding:7px 10px;border-radius:var(--r8);font-size:12px;color:var(--muted);cursor:pointer;margin-bottom:2px;transition:all .15s}
.sni:hover{background:var(--canvas);color:var(--ink)}
.sni.active{background:var(--ap);color:var(--accent);font-weight:500}
.sni svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
.srow{display:flex;align-items:center;justify-content:space-between;padding:11px 0;border-bottom:1px solid var(--rule);gap:10px}
.srow:last-child{border-bottom:none}
.stitle{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-bottom:10px;padding-bottom:7px;border-bottom:1px solid var(--rule)}
.notice{background:var(--ambp);border:1px solid #fde68a;border-radius:var(--r8);padding:9px 13px;font-size:12px;color:#92400e;margin-bottom:14px;display:flex;align-items:flex-start;gap:7px}
.notice svg{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0;margin-top:1px}
.hgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px;margin-top:10px}
.hi{background:var(--canvas);border-radius:var(--r8);padding:9px 11px}
.hdot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
.hrow{display:flex;align-items:center;gap:6px}
.hlbl{font-size:11px;color:var(--muted)}
.hval{font-size:11px;font-weight:500;color:var(--ink);margin-top:2px}

/* ── SUBMISSION DETAIL PAGE ── */
.sd-meta{background:var(--white);border:1px solid var(--rule);border-radius:var(--r12);padding:16px 18px;margin-bottom:13px}
.sd-meta-row{display:flex;gap:24px;margin-top:10px;flex-wrap:wrap}
.sd-mi .lbl{font-size:11px;color:var(--muted)}
.sd-mi .val{font-size:12px;color:var(--ink);font-weight:500;margin-top:1px;font-family:var(--mono)}
.sd-grid{display:grid;grid-template-columns:1fr 280px;gap:13px}
.tl{margin-top:8px}
.tli{display:flex;gap:10px;padding-bottom:14px;position:relative}
.tli:not(:last-child):before{content:'';position:absolute;left:11px;top:24px;bottom:0;width:1px;background:var(--rule)}
.tldot{width:24px;height:24px;border-radius:50%;background:var(--ap);border:1.5px solid var(--accent);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.tldot svg{width:11px;height:11px;stroke:var(--accent);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.tlb{flex:1;padding-top:2px}
.tla{font-size:13px;font-weight:500;color:var(--ink)}
.tlt{font-size:11px;color:var(--muted);margin-top:1px;font-family:var(--mono)}
.fi-row{display:flex;align-items:center;gap:9px;padding:9px 11px;background:var(--canvas);border-radius:var(--r8);margin-bottom:6px}
.fi-ic{width:26px;height:26px;border-radius:var(--r6);background:var(--ap);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.fi-ic svg{width:12px;height:12px;stroke:var(--accent);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.fade-in{animation:fadeIn .32s ease both}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.stagger>*{animation:fadeIn .36s ease both}
.stagger>*:nth-child(1){animation-delay:.04s}
.stagger>*:nth-child(2){animation-delay:.08s}
.stagger>*:nth-child(3){animation-delay:.12s}
.stagger>*:nth-child(4){animation-delay:.16s}

/* ── SUBMISSION AVATAR ── */
.sub-av{width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;color:#fff;flex-shrink:0;letter-spacing:.01em}

/* ── SUBMISSION TABLE (desktop) ── */
.sub-tbl{width:100%;border-collapse:collapse;font-size:13px}
.sub-tbl thead tr{border-bottom:1px solid var(--rule)}
.sub-tbl th{padding:8px 13px;text-align:left;font-size:10px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.07em;white-space:nowrap;background:var(--white)}
.sub-tbl td{padding:11px 13px;border-bottom:1px solid var(--rule);color:var(--ink);vertical-align:middle}
.sub-tbl tr:last-child td{border-bottom:none}
.sub-tbl tbody tr{cursor:pointer;transition:background .12s}
.sub-tbl tbody tr:hover td{background:#fafbff}
/* identity cell: avatar + name stacked */
.sub-id{display:flex;align-items:center;gap:10px}
.sub-id-txt .sub-nm{font-size:13px;font-weight:500;color:var(--ink)}
.sub-id-txt .sub-ref{font-size:10px;color:var(--muted2);font-family:var(--mono);margin-top:1px}

/* ── STATUS DOT ── */
.sdot{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:500}
.sdot:before{content:'';width:6px;height:6px;border-radius:50%;flex-shrink:0;background:currentColor;opacity:.7}
.sdot.ok{color:var(--green)}
.sdot.pend{color:var(--amber)}

/* ── MOBILE: transform table to card stack ── */
@media(max-width:768px){
  .sub-tbl{display:block}
  .sub-tbl thead{display:none}
  .sub-tbl tbody{display:flex;flex-direction:column;gap:8px}
  /* each row becomes a 2-row grid card */
  .sub-tbl tbody tr{
    display:grid;
    grid-template-areas:"av name stat" "av form date";
    grid-template-columns:40px 1fr auto;
    grid-template-rows:auto auto;
    column-gap:10px;
    row-gap:1px;
    background:var(--white);
    border:1px solid var(--rule);
    border-radius:var(--r12);
    padding:13px 14px;
    cursor:pointer;
    transition:box-shadow .15s,border-color .15s;
    align-items:center;
  }
  .sub-tbl tbody tr:hover{box-shadow:0 4px 16px rgba(0,0,0,.07);border-color:rgba(37,99,235,.2)}
  .sub-tbl td{padding:0;border:none!important;background:none!important}
  /* Avatar */
  .sub-tbl td.tc-av{grid-area:av;align-self:center}
  /* Name */
  .sub-tbl td.tc-name{grid-area:name;font-size:13px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .sub-tbl td.tc-name .sub-id{flex-direction:column;align-items:flex-start;gap:1px}
  .sub-tbl td.tc-name .sub-id-txt .sub-nm{font-size:13px}
  .sub-tbl td.tc-name .sub-id-txt .sub-ref{display:none}/* hide ref on mobile */
  /* Form name */
  .sub-tbl td.tc-form{grid-area:form;font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Email status */
  .sub-tbl td.tc-status{grid-area:stat;text-align:right}
  /* Date */
  .sub-tbl td.tc-date{grid-area:date;font-size:10px;color:var(--muted2);text-align:right;white-space:nowrap}
  /* Hidden on mobile */
  .sub-tbl td.tc-pdf{display:none}
  .sub-tbl td.tc-actions{display:none}
}

/* ── FORMS TABLE ── */
.form-tbl{width:100%;border-collapse:collapse;font-size:13px}
.form-tbl thead tr{border-bottom:1px solid var(--rule)}
.form-tbl th{padding:8px 13px;text-align:left;font-size:10px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.07em;white-space:nowrap;background:var(--white)}
.form-tbl td{padding:10px 13px;border-bottom:1px solid var(--rule);color:var(--ink);vertical-align:middle}
.form-tbl tr:last-child td{border-bottom:none}
.form-tbl tbody tr{cursor:default;transition:background .12s}
.form-tbl tbody tr:hover td{background:#fafbff}

/* Mobile card layout for forms */
@media(max-width:768px){
  .form-tbl thead{display:none}
  .form-tbl tbody{display:flex;flex-direction:column;gap:8px}
  .form-tbl tbody tr{
    display:grid;
    grid-template-areas:"title title" "meta actions";
    grid-template-columns:1fr auto;
    background:var(--white);border:1px solid var(--rule);
    border-radius:var(--r12);padding:13px 14px;gap:6px 10px;
    transition:box-shadow .15s,border-color .15s;
  }
  .form-tbl tbody tr:hover{box-shadow:0 4px 16px rgba(0,0,0,.07);border-color:rgba(37,99,235,.2)}
  .form-tbl td{padding:0;border:none!important;background:none!important}
  .form-tbl td.ftc-title{grid-area:title}
  .form-tbl td.ftc-meta{grid-area:meta;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
  .form-tbl td.ftc-actions{grid-area:actions;display:flex;align-items:flex-start;gap:4px;flex-shrink:0}
  /* hide individual columns that are embedded into meta */
  .form-tbl td.ftc-slug-col,.form-tbl td.ftc-vis,.form-tbl td.ftc-subs,.form-tbl td.ftc-status,.form-tbl td.ftc-created{display:none}
  /* show inline meta inside title cell */
  .ftc-meta-mob{display:flex!important;flex-wrap:wrap;align-items:center;gap:5px;margin-top:5px}
}

/* ── RESPONSIVE ── */
@media(min-width:769px){
  .toast{bottom:18px}
  .content{padding-bottom:20px}
}
@media(max-width:1100px){
  .stat-grid{grid-template-columns:repeat(2,1fr)}
  .tb-search{width:150px}
}
@media(max-width:768px){
  :root{--nw:240px}
  .nav{position:fixed;top:0;left:0;bottom:0;transform:translateX(-100%)}
  .nav.open{transform:translateX(0);box-shadow:8px 0 32px rgba(0,0,0,.25)}
  .nov{display:block}
  .shell{display:block;width:100%;height:100%}
  .main{width:100%;height:100vh;margin-left:0}
  .mob-nav{display:block}
  .content{padding:12px;padding-bottom:calc(var(--mnh) + 12px)}
  .topbar{padding:0 12px;gap:8px}
  .tb-ham{display:flex}
  .tb-search{display:none}
  .tb-title{font-size:13px}
  .stat-grid{grid-template-columns:1fr 1fr;gap:8px;margin-bottom:14px}
  .stat-card{padding:11px 13px}
  .sc-num,.stat-num{font-size:21px}
  .sc-icon,.stat-icon{width:30px;height:30px;margin-bottom:7px}
  .two-col,.grid-2{grid-template-columns:1fr}
  .ov{align-items:flex-end;padding:0}
  .modal{border-radius:var(--r16) var(--r16) 0 0;max-width:100%;max-height:92vh}
  .quick-actions{flex-direction:column}
  .card-body{padding:13px}
  .slayout{grid-template-columns:1fr;gap:0}
  .snav{border-right:none;border-bottom:1px solid var(--rule);padding-right:0;padding-bottom:10px;margin-bottom:14px;display:flex;flex-wrap:wrap;gap:4px}
  .sd-grid{grid-template-columns:1fr}
}
@media(max-width:400px){
  .sc-num,.stat-num{font-size:19px}
  .sc-lbl,.stat-lbl{font-size:10px}
}
</style>
</head>
<body>

<!-- LOGIN -->
<div id="login-screen">
  <div class="l-brand">
    <div class="l-brand-logo"><svg viewBox="0 0 24 24"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg></div>
    <span class="l-brand-name">FormBuilder</span>
  </div>
  <div class="lc">
    <div class="lcard">
      <div class="lhdr">
        <div class="lhdr-eye">Admin Portal</div>
        <div class="lhdr-title">Welcome back</div>
        <div class="lhdr-sub">Sign in to manage your forms, submissions, and settings.</div>
      </div>
      <div class="lbody">
        <div class="lerr" id="lerr"></div>
        <div class="lf">
          <label for="lemail">Email address</label>
          <input type="email" id="lemail" placeholder="you@example.com" autocomplete="email"/>
        </div>
        <div class="lf">
          <div class="lf-top">
            <label for="lpw">Password</label>
            <a href="forgot-password.php" class="lf-forgot">Forgot password?</a>
          </div>
          <div class="pw-wrap">
            <input type="password" id="lpw" placeholder="••••••••" autocomplete="current-password"/>
            <button type="button" class="pw-eye" id="pw-eye" onclick="togglePw()" aria-label="Toggle password visibility">
              <svg id="eye-icon" viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
            </button>
          </div>
        </div>
        <button class="lbtn" id="lbtn" onclick="doLogin()">Sign In</button>
        <div class="l-divider">or</div>
        <button type="button" class="l-google" onclick="googleLogin()">
          <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
            <path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/>
            <path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/>
            <path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z" fill="#FBBC05"/>
            <path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/>
          </svg>
          Sign in with Google
        </button>
      </div>
    </div>
    <div class="lfoot">Powered by FormBuilder Pro</div>
  </div>
</div>

<!-- APP -->
<div id="app">
<div class="nov" id="nov" onclick="closeSidebar()"></div>
<div class="shell">

  <!-- SIDEBAR -->
  <nav class="nav" id="sidebar">
    <div class="nav-logo">
      <div class="nav-mark"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg></div>
      <div><div class="nav-title">FormBuilder</div><div class="nav-plan">Pro Admin</div></div>
    </div>
    <div class="nav-items">
      <div class="nav-gl">Overview</div>
      <div class="ni active" data-page="dashboard" onclick="nav(this,'dashboard')">
        <svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/></svg>Dashboard
      </div>
      <div class="nav-gl">Content</div>
      <div class="ni" data-page="forms" onclick="nav(this,'forms')">
        <svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>Forms
        <span class="ni-badge" id="nav-forms-count" style="display:none">0</span>
      </div>
      <div class="ni" data-page="submissions" onclick="nav(this,'submissions')">
        <svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>Submissions
      </div>
      <div class="ni" onclick="openFormBuilder()">
        <svg viewBox="0 0 24 24"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>Form Builder
      </div>
      <div class="nav-gl">Booking</div>
      <div class="ni" data-page="booking" onclick="nav(this,'booking')">
        <svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>Appointments
        <span class="ni-badge" id="nav-appt-count" style="display:none">0</span>
      </div>
      <div class="nav-gl">System</div>
      <div class="ni" data-page="modules" onclick="nav(this,'modules')">
        <svg viewBox="0 0 24 24"><rect x="2" y="3" width="6" height="6" rx="1"/><rect x="9" y="3" width="6" height="6" rx="1"/><rect x="16" y="3" width="6" height="6" rx="1"/><rect x="2" y="12" width="6" height="6" rx="1"/><rect x="9" y="12" width="6" height="6" rx="1"/><rect x="16" y="12" width="6" height="6" rx="1"/></svg>Modules
      </div>
      <div class="ni" data-page="settings" onclick="nav(this,'settings')">
        <svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>Settings
      </div>
    </div>
    <div class="nav-foot">
      <div class="nav-user">
        <div class="nav-av" id="nav-av">AD</div>
        <div><div class="nav-un" id="nav-un">Admin</div><div class="nav-ur" id="nav-ur">Admin</div></div>
      </div>
      <button class="nav-out" onclick="doLogout()">
        <svg viewBox="0 0 24 24"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>Sign out
      </button>
    </div>
  </nav>

  <!-- MAIN -->
  <div class="main">
    <div class="topbar">
      <button class="tb-ham" onclick="openSidebar()">
        <svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
      </button>
      <div class="tb-title" id="pgtitle">Dashboard</div>
      <div class="tb-search">
        <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
        <input placeholder="Search…"/><span class="kbd">/</span>
      </div>
      <div class="tb-actions">
        <button class="btn btn-primary btn-sm" onclick="openFormBuilder()">
          <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>New Form
        </button>
      </div>
    </div>
    <div class="content" id="content-area">
      <div class="loading-state"><div class="spinner"></div><span>Loading…</span></div>
    </div>
  </div>

</div><!-- /shell -->

<!-- MOBILE NAV -->
<nav class="mob-nav">
  <div class="mob-inner">
    <button class="mni active" data-page="dashboard" onclick="nav(this,'dashboard')">
      <svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/></svg>
      <span>Dashboard</span>
    </button>
    <button class="mni" data-page="forms" onclick="nav(this,'forms')">
      <svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
      <span>Forms</span>
    </button>
    <button class="mni" data-page="submissions" onclick="nav(this,'submissions')">
      <svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
      <span>Inbox</span>
    </button>
    <button class="mni" onclick="openFormBuilder()">
      <svg viewBox="0 0 24 24"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
      <span>Builder</span>
    </button>
    <button class="mni" data-page="booking" onclick="nav(this,'booking')">
      <svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
      <span>Booking</span>
    </button>
    <button class="mni" data-page="settings" onclick="nav(this,'settings')">
      <svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
      <span>Settings</span>
    </button>
  </div>
</nav>

</div><!-- /app -->

<!-- MODAL -->
<div class="ov" id="modal-overlay" onclick="if(event.target===this)closeModal()">
  <div class="modal">
    <div class="mhdr">
      <h3 id="modal-title">Modal</h3>
      <button class="mclose" onclick="closeModal()">✕</button>
    </div>
    <div class="mbody" id="modal-body"></div>
    <div class="mfoot" id="modal-foot"></div>
  </div>
</div>

<div class="toast" id="toast"></div>

<script>
/* ── SIDEBAR HELPERS ── */
function openSidebar(){
  document.getElementById('sidebar').classList.add('open');
  const ov=document.getElementById('nov');ov.style.display='block';
  requestAnimationFrame(()=>ov.classList.add('open'));
}
function closeSidebar(){
  document.getElementById('sidebar').classList.remove('open');
  const ov=document.getElementById('nov');ov.classList.remove('open');
  setTimeout(()=>{if(!ov.classList.contains('open'))ov.style.display='none';},270);
}

/* ── CORE ── */
const BASE=(()=>{const p=window.location.pathname;const d=p.endsWith('/')?p.slice(0,-1):p.substring(0,p.lastIndexOf('/'));return d.replace(/\/admin(\.php)?$/,'');})();
const API=BASE+'/api';
const GOOGLE_CLIENT_ID=<?= json_encode($googleClientId) ?>;
const APP_URL=<?= json_encode($appUrl) ?>;
let currentPage='dashboard',allForms=[],subFormId=null,subPage=1,unreadCount=0;

// Show any Google OAuth error passed back via redirect
<?php if ($googleError): ?>
(function(){ const e=document.getElementById('lerr'); if(e){ e.textContent=<?= json_encode($googleError) ?>; e.classList.add('show'); } })();
<?php endif; ?>

const esc=s=>String(s??'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
const q=sel=>document.querySelector(sel);
const fmt=dt=>dt?new Date(dt).toLocaleString('en-US',{month:'short',day:'numeric',year:'numeric',hour:'2-digit',minute:'2-digit'}):'—';
const fmtShort=dt=>dt?new Date(dt).toLocaleDateString('en-US',{month:'short',day:'numeric'}):'—';
const AVCOLORS=['#4f46e5','#0891b2','#059669','#d97706','#7c3aed','#0284c7','#b45309','#be185d','#0f766e','#1d4ed8'];
function avColor(s){let h=0;for(let i=0;i<s.length;i++)h=(h*31+s.charCodeAt(i))&0xffffff;return AVCOLORS[Math.abs(h)%AVCOLORS.length];}
function avInit(name){
  if(!name)return'?';
  if(name.includes('@'))return name[0].toUpperCase();
  if(/^#[A-Z0-9]{4,}$/i.test(name))return'#';
  const p=name.trim().split(/\s+/);
  return p.length>=2?(p[0][0]+p[p.length-1][0]).toUpperCase():name[0].toUpperCase();
}
function avHtml(name){return`<div class="sub-av" style="background:${avColor(name)}">${avInit(name)}</div>`;}

/* ── TOAST ── */
function toast(msg,type=''){
  const t=q('#toast');
  t.textContent=msg;
  t.className='toast show '+(type||'');
  clearTimeout(t._t);t._t=setTimeout(()=>t.className='toast',3200);
}

/* ── API ── */
let _csrfToken='';
async function api(path,method='GET',body){
  const opts={method,credentials:'same-origin',headers:{}};
  if(body){opts.headers['Content-Type']='application/json';opts.body=JSON.stringify(body);}
  if(_csrfToken&&['POST','PUT','PATCH','DELETE'].includes(method)){
    opts.headers['X-CSRF-Token']=_csrfToken;
  }
  const r=await fetch(API+path,opts);
  return r.json();
}

/* ── AUTH ── */
async function checkAuth(){
  const j=await api('/auth/me');
  if(j.csrf) _csrfToken=j.csrf;
  if(j.authed){ populateUser(j.user); showApp(); }
}

function populateUser(u){
  if(!u) return;
  const name = u.name || 'Admin';
  const role = u.role || 'admin';
  const av   = name.substring(0,2).toUpperCase();
  const el_av = q('#nav-av'), el_un = q('#nav-un'), el_ur = q('#nav-ur');
  if(el_av) el_av.textContent = av;
  if(el_un) el_un.textContent = name;
  if(el_ur) el_ur.textContent = role.charAt(0).toUpperCase() + role.slice(1);
}

document.getElementById('lemail').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('lpw').focus();});
document.getElementById('lpw').addEventListener('keydown',e=>{if(e.key==='Enter')doLogin();});

function togglePw(){
  const inp=q('#lpw'), btn=q('#pw-eye'), icon=q('#eye-icon');
  const show=inp.type==='password';
  inp.type=show?'text':'password';
  // eye-off icon when password is visible, eye icon when hidden
  icon.innerHTML=show
    ?'<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/>'
    :'<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>';
  btn.setAttribute('aria-label', show ? 'Hide password' : 'Show password');
}

function googleLogin(){
  if(!GOOGLE_CLIENT_ID){
    const err=q('#lerr');
    err.textContent='Google sign-in is not configured. Add GOOGLE_CLIENT_ID to config.php.';
    err.classList.add('show');
    return;
  }
  const redirectUri=APP_URL+'/api/auth-google.php?admin=1';
  const params=new URLSearchParams({
    client_id:GOOGLE_CLIENT_ID,
    redirect_uri:redirectUri,
    response_type:'code',
    scope:'openid email profile',
    access_type:'offline',
    prompt:'select_account'
  });
  window.location.href='https://accounts.google.com/o/oauth2/v2/auth?'+params;
}

async function doLogin(){
  const email=q('#lemail').value.trim(), pw=q('#lpw').value;
  const err=q('#lerr');
  err.className='lerr';
  if(!email||!pw){err.textContent='Please enter your email and password.';err.classList.add('show');return;}
  const btn=q('#lbtn');btn.textContent='Signing in…';btn.disabled=true;
  const j=await api('/auth/login','POST',{email,password:pw});
  btn.textContent='Sign In';btn.disabled=false;
  if(j.ok){ const me=await api('/auth/me'); if(me.csrf)_csrfToken=me.csrf; populateUser(j.user); showApp(); }
  else{err.textContent=j.error||'Invalid email or password.';err.classList.add('show');}
}

async function doLogout(){await api('/auth/logout','POST');location.reload();}

function showApp(){
  q('#login-screen').style.display='none';
  q('#app').style.display='block';
  nav(null,'dashboard');
}

/* ── UNREAD BADGE ── */
function updateUnreadBadge(){
  let b=q('#nav-unread-badge');
  if(unreadCount>0){
    if(!b){
      const ni=document.querySelector('.ni[data-page="submissions"] .ni-badge')||null;
      // inject badge into submissions nav item
      const sni=document.querySelector('.ni[data-page="submissions"]');
      if(sni){b=document.createElement('span');b.id='nav-unread-badge';b.className='ni-badge';b.style.background='var(--red)';sni.appendChild(b);}
    }
    if(b){b.textContent=unreadCount>99?'99+':unreadCount;b.style.display='';}
    // mobile nav dot
    let md=q('#mob-unread-dot');
    const mni=document.querySelector('.mni[data-page="submissions"]');
    if(mni&&!md){md=document.createElement('span');md.id='mob-unread-dot';md.style.cssText='position:absolute;top:6px;right:calc(50% - 14px);width:7px;height:7px;border-radius:50%;background:var(--red);';mni.style.position='relative';mni.appendChild(md);}
  } else {
    if(b)b.style.display='none';
    const md=q('#mob-unread-dot');if(md)md.style.display='none';
  }
}
async function markAllRead(){
  await api('/submissions/mark-all-read','POST');
  unreadCount=0;updateUnreadBadge();toast('All marked as read','ok');
}

/* ── NAV ──
   Accepts both nav(el, page) from HTML onclick and nav(page) from JS */
function nav(elOrPage,pageOrEl){
  const page=typeof elOrPage==='string'?elOrPage:(pageOrEl||'dashboard');
  currentPage=page;
  document.querySelectorAll('.ni,.mni').forEach(n=>n.classList.toggle('active',n.dataset.page===page));
  const titles={dashboard:'Dashboard',forms:'Forms',submissions:'Submissions',settings:'Settings',booking:'Booking',modules:'Modules'};
  q('#pgtitle').textContent=titles[page]||page;
  closeSidebar();
  ({dashboard:renderDashboard,forms:renderForms,submissions:renderSubmissions,settings:renderSettings,booking:renderBooking,modules:renderModules}[page]||renderDashboard)();
}

/* ── DASHBOARD ── */
async function renderDashboard(){
  q('#content-area').innerHTML='<div class="loading-state"><div class="spinner"></div><span>Loading…</span></div>';

  // Fetch stats + module toggles in parallel
  const [j, mj] = await Promise.all([
    api('/stats').catch(()=>({})),
    api('/admin/modules').catch(()=>({ok:false,modules:[]})),
  ]);

  if(!j.ok){q('#content-area').innerHTML='<div class="loading-state">Failed to load.</div>';return;}

  // Build a quick lookup: { module_forms: true, module_booking: true, ... }
  const mods = {};
  (mj.modules||[]).forEach(m => { mods[m.key] = !!m.is_enabled; });
  const formsOn     = mods.module_forms     !== false; // default true if table doesn't exist yet
  const bookingOn   = mods.module_booking   !== false;
  const membershipOn= mods.module_membership!== false;

  const badge=q('#nav-forms-count');
  if(j.total_forms>0){badge.textContent=j.total_forms;badge.style.display='';}
  unreadCount=j.unread_count||0;updateUnreadBadge();

  // Stat cards — only show relevant ones
  let statCards = '';
  if (formsOn) {
    statCards += `
    <div class="stat-card"><div class="sc-icon"><svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></div><div class="sc-num">${j.total_forms}</div><div class="sc-lbl">Total Forms</div></div>
    <div class="stat-card"><div class="sc-icon"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div><div class="sc-num">${j.total_submissions}</div><div class="sc-lbl">All Submissions</div></div>
    <div class="stat-card"><div class="sc-icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div><div class="sc-num">${j.today}</div><div class="sc-lbl">Today</div></div>
    <div class="stat-card"><div class="sc-icon"><svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></div><div class="sc-num">${j.this_week}</div><div class="sc-lbl">This Week</div></div>`;
  }

  // Quick actions — context-aware
  let quickActions = '';
  if (formsOn) {
    quickActions += `
    <button class="qa-btn" onclick="openFormBuilder()">
      <div class="qa-icon"><svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></div>
      <div><div class="qa-title">Create New Form</div><div class="qa-sub">Build from scratch</div></div>
    </button>
    <button class="qa-btn" onclick="nav(null,'submissions')">
      <div class="qa-icon"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div>
      <div><div class="qa-title">View Submissions</div><div class="qa-sub">Browse &amp; export data</div></div>
    </button>`;
  }
  if (bookingOn) {
    quickActions += `
    <button class="qa-btn" onclick="nav(null,'booking')">
      <div class="qa-icon"><svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></div>
      <div><div class="qa-title">View Appointments</div><div class="qa-sub">Today's bookings</div></div>
    </button>`;
  }
  if (!formsOn && !bookingOn) {
    quickActions = `<div style="padding:16px;font-size:13px;color:var(--muted)">
      All modules are currently disabled.
      <button class="btn btn-ghost btn-sm" style="margin-left:10px" onclick="nav(null,'modules')">Manage Modules →</button>
    </div>`;
  }

  // Module status notice bar
  const disabledMods = Object.entries(mods).filter(([,v])=>!v).map(([k])=>k.replace('module_',''));
  const modNotice = disabledMods.length
    ? `<div class="card fade-in" style="margin-bottom:16px;border-left:3px solid var(--amber,#d97706)">
        <div class="card-body" style="padding:12px 18px;font-size:13px;color:var(--muted)">
          <strong style="color:var(--text)">Modules disabled:</strong>
          ${disabledMods.map(m=>`<span style="background:var(--card-alt);border-radius:4px;padding:2px 8px;margin:0 4px;font-size:12px">${m}</span>`).join('')}
          <button class="btn btn-ghost btn-sm" style="margin-left:8px" onclick="nav(null,'modules')">Manage →</button>
        </div>
      </div>`
    : '';

  q('#content-area').innerHTML=`
  <div class="page-hd fade-in"><h1>Dashboard</h1><p>Here's what's happening today.</p></div>
  ${modNotice}
  ${statCards ? `<div class="stat-grid stagger">${statCards}</div>` : ''}
  ${quickActions ? `<div class="quick-actions stagger">${quickActions}</div>` : ''}
  ${formsOn ? `
  <div class="card fade-in">
    <div class="card-hdr">
      <div><div class="card-title">Recent Submissions</div><div class="card-sub">Latest entries across all forms</div></div>
      <button class="btn btn-ghost btn-sm" onclick="nav(null,'submissions')">View all</button>
    </div>
    ${j.recent.length?`<div style="padding:4px 0">${j.recent.map(r=>{const nm=r.display_name||r.ref;return`
      <div style="display:flex;align-items:center;gap:12px;padding:11px 18px;cursor:pointer;transition:background .12s;border-bottom:1px solid var(--rule);background:${r.is_unread?'#fafbff':''}" onclick="viewSubmission(${r.id})" onmouseenter="this.style.background='#f0f4ff'" onmouseleave="this.style.background='${r.is_unread?'#fafbff':''}'">
        <div style="position:relative">${avHtml(nm)}${r.is_unread?'<span style="position:absolute;top:0;right:0;width:8px;height:8px;border-radius:50%;background:var(--red);border:1.5px solid white"></span>':''}</div>
        <div style="flex:1;min-width:0">
          <div style="font-size:13px;font-weight:${r.is_unread?'600':'500'};color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(nm)}</div>
          <div style="font-size:11px;color:var(--muted);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(r.title)}</div>
        </div>
        <div style="text-align:right;flex-shrink:0">
          <span class="sdot ${r.email_sent?'ok':'pend'}">${r.email_sent?'Sent':'Pending'}</span>
          <div style="font-size:10px;color:var(--muted2);margin-top:3px">${fmtShort(r.created_at)}</div>
        </div>
      </div>`;}).join('')}</div>`
    :`<div class="empty" style="padding:50px 20px"><div class="empty-icon"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div><h3>No submissions yet</h3><p>Entries will appear here once people fill your forms.</p></div>`}
  </div>
  ${j.per_form&&j.per_form.length?`
  <div class="card fade-in">
    <div class="card-hdr"><div><div class="card-title">Submissions by Form</div><div class="card-sub">Lifetime totals</div></div></div>
    <div class="card-body">
      ${j.per_form.map(f=>`<div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;cursor:pointer" onclick="viewFormSubmissions(null,'${esc(f.title)}')">
        <div style="flex:1;min-width:0">
          <div style="font-size:13px;font-weight:500;color:var(--ink);margin-bottom:5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(f.title)}</div>
          <div class="prog-bar"><div class="prog-fill" style="width:${Math.min(100,Math.round(f.n/Math.max(1,j.per_form[0].n)*100))}%"></div></div>
        </div>
        <div style="font-family:var(--mono);font-size:13px;font-weight:600;color:var(--accent);white-space:nowrap">${f.n}</div>
      </div>`).join('')}
    </div>
  </div>`:''}` : ''}`;
}

/* ── FORMS ── */
async function renderForms(){
  q('#content-area').innerHTML='<div class="loading-state"><div class="spinner"></div><span>Loading…</span></div>';
  const j=await api('/forms');allForms=j.forms||[];
  if(!j.ok){q('#content-area').innerHTML='<div class="loading-state">Failed.</div>';return;}
  const badge=q('#nav-forms-count');
  if(allForms.length){badge.textContent=allForms.length;badge.style.display='';}
  if(!allForms.length){
    q('#content-area').innerHTML=`<div class="empty fade-in" style="padding:80px 20px"><div class="empty-icon"><svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></div><h3>No forms yet</h3><p>Create your first form to start collecting submissions.</p><button class="btn btn-primary" onclick="openFormBuilder()"><svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Create First Form</button></div>`;
    return;
  }
  q('#content-area').innerHTML=`<div class="card fade-in">
    <div class="card-hdr"><div><div class="card-title">All Forms</div><div class="card-sub">${allForms.length} form${allForms.length!==1?'s':''}</div></div></div>
    <div class="tbl-wrap"><table class="form-tbl">
      <thead><tr><th>Title</th><th>Slug</th><th>Visibility</th><th>Subs</th><th>Status</th><th>Created</th><th></th></tr></thead>
      <tbody>${allForms.map(f=>`<tr>
        <td class="ftc-title">
          <div style="font-weight:500">${esc(f.title)}</div>
          ${f.description?`<div style="font-size:11px;color:var(--muted);margin-top:2px">${esc(f.description.substring(0,55))}${f.description.length>55?'…':''}</div>`:''}
          <div class="ftc-meta-mob" style="display:none">
            <span class="code-pill" style="font-size:10px">${esc(f.slug)}</span>
            <span class="badge ${f.is_public?'badge-green':'badge-yellow'}" style="font-size:10px">${f.is_public?'Public':'Private'}</span>
            <span class="badge ${f.is_active?'badge-green':'badge-gray'}" style="font-size:10px">${f.is_active?'Active':'Inactive'}</span>
            <span style="font-family:var(--mono);font-size:11px;font-weight:600;color:var(--accent)">${f.sub_count} subs</span>
            <span style="font-size:10px;color:var(--muted2)">${fmtShort(f.created_at)}</span>
          </div>
        </td>
        <td class="ftc-slug-col"><span class="code-pill">${esc(f.slug)}</span></td>
        <td class="ftc-vis"><span class="badge ${f.is_public?'badge-green':'badge-yellow'}">${f.is_public?'Public':'Private'}</span></td>
        <td class="ftc-subs" style="font-family:var(--mono);font-size:13px;font-weight:500;color:var(--accent)">${f.sub_count}</td>
        <td class="ftc-status"><span class="badge ${f.is_active?'badge-green':'badge-gray'}">${f.is_active?'Active':'Inactive'}</span></td>
        <td class="ftc-created" style="color:var(--muted);font-size:12px">${fmtShort(f.created_at)}</td>
        <td class="ftc-actions"><div style="display:flex;gap:5px;justify-content:flex-end">
          <a href="${BASE}/form.php?s=${esc(f.slug)}" target="_blank" class="btn btn-ghost btn-sm btn-icon" title="Preview"><svg viewBox="0 0 24 24"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg></a>
          <button class="btn btn-ghost btn-sm btn-icon" title="Edit" onclick="openFormBuilder(${f.id})"><svg viewBox="0 0 24 24"><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></button>
          <button class="btn btn-ghost btn-sm btn-icon" title="Duplicate" onclick="duplicateForm(${f.id},'${esc(f.title)}')"><svg viewBox="0 0 24 24"><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></button>
          <button class="btn btn-ghost btn-sm btn-icon" title="Submissions" onclick="viewFormSubmissions(${f.id},'${esc(f.title)}')"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></button>
          <button class="btn btn-danger btn-sm btn-icon" title="Delete" onclick="deleteForm(${f.id},'${esc(f.title)}')"><svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg></button>
        </div></td>
      </tr>`).join('')}
      </tbody>
    </table></div>
  </div>`;
}

function openFormBuilder(id=null){window.location.href='admin/builder.php'+(id?'?id='+id:'');}

async function duplicateForm(id,title){
  const j=await api('/forms/'+id+'/duplicate','POST');
  if(j.ok){toast('"'+title+'" duplicated','ok');renderForms();}
  else toast(j.error||'Duplicate failed','err');
}
async function deleteForm(id,title){
  if(!confirm(`Delete "${title}"?\n\nThis also deletes all submissions. Cannot be undone.`)) return;
  const j=await api('/forms/'+id,'DELETE');
  if(j.ok){toast('Form deleted','ok');renderForms();}else toast(j.error||'Failed','err');
}

/* ── SUBMISSIONS ── */
function subRow(r,showForm){
  const nm=r.display_name||r.ref;
  return`<tr onclick="viewSubmission(${r.id})">
    <td class="tc-av">${avHtml(nm)}</td>
    <td class="tc-name"><div class="sub-id"><div class="sub-id-txt"><div class="sub-nm">${esc(nm)}</div><div class="sub-ref">${esc(r.ref)}</div></div></div></td>
    <td class="tc-form" style="color:var(--muted);font-size:12px">${showForm?esc(r.form_title||''):'—'}</td>
    <td class="tc-status"><span class="sdot ${r.email_sent?'ok':'pend'}">${r.email_sent?'Sent':'Pending'}</span></td>
    <td class="tc-pdf">${r.pdf_path?'<span class="badge badge-blue">PDF</span>':'<span style="color:var(--muted2);font-size:12px">—</span>'}</td>
    <td class="tc-date" style="color:var(--muted2);font-size:12px;white-space:nowrap">${fmtShort(r.created_at)}</td>
    <td class="tc-actions" style="text-align:right"><div style="display:flex;gap:5px;justify-content:flex-end">
      <button class="btn btn-ghost btn-sm" onclick="event.stopPropagation();viewSubmission(${r.id})">View</button>
      <button class="btn btn-danger btn-sm btn-icon" onclick="event.stopPropagation();deleteSub(${r.id})"><svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg></button>
    </div></td>
  </tr>`;
}
const subTblHdr=`<thead><tr><th></th><th>Name</th><th>Form</th><th>Email</th><th>PDF</th><th>Date</th><th></th></tr></thead>`;
const subEmpty=(msg='')=>`<tr><td colspan="7"><div class="empty" style="padding:44px"><div class="empty-icon"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div><h3>${msg||'No submissions'}</h3><p>Select a form above to browse submissions.</p></div></td></tr>`;

async function renderSubmissions(){
  q('#content-area').innerHTML='<div class="loading-state"><div class="spinner"></div><span>Loading…</span></div>';
  if(!allForms.length){const j=await api('/forms');allForms=j.forms||[];}
  const fOpts=allForms.map(f=>`<option value="${f.id}">${esc(f.title)}</option>`).join('');
  q('#content-area').innerHTML=`
    <div class="page-hd fade-in"><h1>Submissions</h1><div class="ph-actions"><button class="btn btn-ghost btn-sm" onclick="markAllRead()">Mark all read</button></div></div>
    <div class="card" style="margin-bottom:12px"><div class="card-body" style="padding:12px 16px">
      <div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
        <select id="sub-form-filter" onchange="subFormId=this.value;subPage=1;loadSubs()" class="fsel">
          <option value="">All Forms</option>${fOpts}
        </select>
        <span id="sub-count" style="font-size:11px;color:var(--muted);font-family:var(--mono);margin-left:auto"></span>
      </div>
    </div></div>
    <div class="card"><div class="tbl-wrap">
      <table class="sub-tbl">${subTblHdr}<tbody id="sub-tbody"><tr><td colspan="7" style="text-align:center;padding:36px"><span class="spinner"></span></td></tr></tbody></table>
    </div></div>
    <div id="sub-pages" style="display:flex;gap:6px;justify-content:center;margin-top:14px;flex-wrap:wrap"></div>`;
  loadSubs();
}

async function loadSubs(){
  const fid=subFormId||'';
  const tbody=q('#sub-tbody');
  if(!tbody)return;
  if(!fid){
    const j=await api('/stats');
    if(!j.ok){tbody.innerHTML=`<tr><td colspan="7" style="color:var(--red);padding:20px;text-align:center">Failed to load.</td></tr>`;return;}
    tbody.innerHTML=j.recent.length?j.recent.map(r=>subRow(r,true)).join(''):subEmpty('No submissions yet');
    q('#sub-count').textContent=j.recent.length?`Showing ${j.recent.length} recent`:'';
    return;
  }
  const j=await api(`/forms/${fid}/submissions?page=${subPage}&limit=25`);
  if(!j.ok){tbody.innerHTML=`<tr><td colspan="7" style="color:var(--red);padding:20px;text-align:center">Failed.</td></tr>`;return;}
  q('#sub-count').textContent=`${j.total} submission${j.total!==1?'s':''}`;
  tbody.innerHTML=j.rows.length?j.rows.map(r=>subRow(r,false)).join(''):subEmpty('No submissions for this form');
  const pages=Math.ceil(j.total/25);
  q('#sub-pages').innerHTML=pages>1?Array.from({length:Math.min(pages,10)},(_,i)=>`<button class="btn ${i+1===subPage?'btn-primary':'btn-ghost'} btn-sm" onclick="subPage=${i+1};loadSubs()">${i+1}</button>`).join(''):'';
}

async function viewFormSubmissions(id,title){
  subFormId=String(id);subPage=1;nav(null,'submissions');
  setTimeout(()=>{const el=q('#sub-form-filter');if(el){el.value=id;loadSubs();}},150);
}

async function viewSubmission(id){
  /* render detail directly — do NOT call nav() to avoid race with renderSubmissions */
  currentPage='submissions';
  document.querySelectorAll('.ni,.mni').forEach(n=>n.classList.toggle('active',n.dataset.page==='submissions'));
  q('#pgtitle').textContent='Submissions';
  closeSidebar();
  q('#content-area').innerHTML=`<div class="page-hd fade-in" style="display:flex;align-items:center;gap:10px">
    <button class="btn btn-ghost btn-sm btn-icon" onclick="nav(null,'submissions')" title="Back"><svg viewBox="0 0 24 24" width="16" height="16"><polyline points="15 18 9 12 15 6"/></svg></button>
    <div><h1>Submission Detail</h1><p>Loading…</p></div>
  </div>
  <div id="sd-wrap"><div class="loading-state" style="padding:60px"><div class="spinner"></div></div></div>`;
  const j=await api('/submissions/'+id);
  if(!j.ok){q('#sd-wrap').innerHTML='<div class="empty" style="padding:60px"><h3>Failed to load submission</h3></div>';return;}
  // mark as read in the UI (API already marked it server-side)
  if(j.submission&&j.submission.read_at===null){unreadCount=Math.max(0,unreadCount-1);updateUnreadBadge();}
  const s=j.submission,fields=s.fields||[],data=s.data||{},files=s.files||{};
  /* update subtitle */
  q('.page-hd p').textContent=`Ref: ${s.ref} · ${fmt(s.created_at)}`;
  /* build field rows */
  let fieldRows='',sigHtml='',fileRows='';
  fields.forEach(f=>{
    const key=f.id||'',type=f.type||'text';
    if(type==='signature'){
      sigHtml=data[key]?`<div class="card fade-in"><div class="card-hdr"><div class="card-title">Signature</div></div><div class="card-body"><img src="${esc(data[key])}" style="max-width:100%;max-height:120px;border:1px solid var(--rule);border-radius:var(--r8)"/></div></div>`:'';
      return;
    }
    if(type==='file'){
      const fl=files[key]||[];
      fl.forEach(fi=>{fileRows+=`<div class="fi-row"><svg viewBox="0 0 24 24" width="14" height="14" stroke="var(--muted)" fill="none" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg><span style="flex:1;font-size:13px">${esc(fi.original_name||'file')}</span><a href="${esc(fi.url||'')}" target="_blank" class="btn btn-ghost btn-sm">Download</a></div>`;});
      return;
    }
    let v=data[key]??'';if(Array.isArray(v))v=v.join(', ');
    fieldRows+=`<tr><td style="color:var(--muted);font-size:12px;padding:9px 12px;white-space:nowrap;width:38%;border-bottom:1px solid var(--rule)">${esc(f.label)}</td><td style="padding:9px 12px;font-size:13px;border-bottom:1px solid var(--rule)">${esc(v)||'<span style="color:var(--muted2)">—</span>'}</td></tr>`;
  });
  const ipInfo=s.ip?`<div class="srow"><span style="font-size:12px;color:var(--muted)">IP Address</span><span style="font-size:13px">${esc(s.ip)}</span></div>`:'';
  const uaInfo=s.user_agent?`<div class="srow"><span style="font-size:12px;color:var(--muted)">User Agent</span><span style="font-size:11px;color:var(--muted2);max-width:260px;text-align:right;word-break:break-all">${esc(s.user_agent)}</span></div>`:'';
  q('#sd-wrap').innerHTML=`
  <div class="sd-grid fade-in">
    <div>
      <div class="card" style="margin-bottom:13px">
        <div class="card-hdr"><div class="card-title">Form Fields</div></div>
        ${fieldRows?`<table style="width:100%;border-collapse:collapse"><tbody>${fieldRows}</tbody></table>`:'<div class="card-body" style="color:var(--muted);font-size:13px">No field data</div>'}
      </div>
      ${sigHtml}
      ${fileRows?`<div class="card fade-in"><div class="card-hdr"><div class="card-title">File Attachments</div></div><div class="card-body">${fileRows}</div></div>`:''}
    </div>
    <div>
      <div class="card" style="margin-bottom:13px">
        <div class="card-hdr"><div class="card-title">Submission Info</div></div>
        <div class="card-body">
          <div class="srow"><span style="font-size:12px;color:var(--muted)">Reference</span><span class="code-pill">${esc(s.ref)}</span></div>
          <div class="srow"><span style="font-size:12px;color:var(--muted)">Form</span><span style="font-size:13px">${esc(s.form_title||'—')}</span></div>
          <div class="srow"><span style="font-size:12px;color:var(--muted)">Submitted</span><span style="font-size:13px">${fmt(s.created_at)}</span></div>
          <div class="srow"><span style="font-size:12px;color:var(--muted)">Email Status</span><span class="badge ${s.email_sent?'badge-green':'badge-yellow'}">${s.email_sent?'Sent':'Pending'}</span></div>
          <div class="srow"><span style="font-size:12px;color:var(--muted)">PDF</span><span>${s.pdf_path?`<a href="${API}/submissions/${id}/pdf" class="btn btn-ghost btn-sm" target="_blank">Download PDF</a>`:'<span style="color:var(--muted2)">—</span>'}</span></div>
          ${ipInfo}${uaInfo}
        </div>
      </div>
      <div class="card" style="margin-bottom:13px">
        <div class="card-hdr"><div class="card-title">Audit Trail</div></div>
        <div class="card-body">
          <div class="tl">
            <div class="tli"><div class="tldot"><svg viewBox="0 0 24 24" width="11" height="11" stroke="var(--accent)" fill="none" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg></div><div><div style="font-size:12px;font-weight:500">Submitted</div><div style="font-size:11px;color:var(--muted)">${fmt(s.created_at)}</div></div></div>
            ${s.email_sent?`<div class="tli"><div class="tldot"><svg viewBox="0 0 24 24" width="11" height="11" stroke="var(--accent)" fill="none" stroke-width="2.5"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg></div><div><div style="font-size:12px;font-weight:500">Email Sent</div><div style="font-size:11px;color:var(--muted)">Notification delivered</div></div></div>`:''}
            ${s.pdf_path?`<div class="tli"><div class="tldot"><svg viewBox="0 0 24 24" width="11" height="11" stroke="var(--accent)" fill="none" stroke-width="2.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></div><div><div style="font-size:12px;font-weight:500">PDF Generated</div><div style="font-size:11px;color:var(--muted)">Available for download</div></div></div>`:''}
          </div>
        </div>
      </div>
      <div style="display:flex;flex-direction:column;gap:7px">
        ${s.pdf_path?`<a href="${API}/submissions/${id}/pdf" class="btn btn-primary" target="_blank"><svg viewBox="0 0 24 24" width="14" height="14"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>Download PDF</a>`:''}
        <button class="btn btn-danger" onclick="deleteSub(${id})"><svg viewBox="0 0 24 24" width="14" height="14"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>Delete Submission</button>
      </div>
    </div>
  </div>`;
}

async function deleteSub(id){
  if(!confirm('Delete this submission? Cannot be undone.')) return;
  const j=await api('/submissions/'+id,'DELETE');
  if(j.ok){closeModal();toast('Deleted','ok');nav(null,'submissions');}
  else toast(j.error||'Failed','err');
}

/* ── SETTINGS ── */
function stab(section,el){
  document.querySelectorAll('.sni').forEach(n=>n.classList.remove('active'));
  if(el)el.classList.add('active');
  document.querySelectorAll('.stab').forEach(t=>{t.style.display='none';});
  const p=document.getElementById('st-'+section);if(p)p.style.display='';
}
function renderSettings(){
  q('#content-area').innerHTML=`<div class="page-hd fade-in"><h1>Settings</h1><p>Manage your application configuration.</p></div>
  <div class="slayout fade-in">
    <div class="snav">
      <div class="sni active" onclick="stab('profile',this)"><svg viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>Profile</div>
      <div class="sni" onclick="stab('smtp',this)"><svg viewBox="0 0 24 24"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>SMTP</div>
      <div class="sni" onclick="stab('security',this)"><svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>Security</div>
      <div class="sni" onclick="stab('branding',this)"><svg viewBox="0 0 24 24"><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/></svg>Branding</div>
      <div class="sni" onclick="stab('system',this)"><svg viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>System</div>
    </div>
    <div style="min-width:0">

      <!-- PROFILE -->
      <div class="stab" id="st-profile">
        <div class="card" style="margin-bottom:13px">
          <div class="card-hdr"><div class="card-title">Application</div></div>
          <div class="card-body">
            <div class="stitle">General</div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">App Name</span><input class="form-input" id="cfg-name" style="width:220px" placeholder="FormBuilder"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">App URL</span><input class="form-input" id="cfg-url" style="width:220px" placeholder="https://yourdomain.com"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Admin Email</span><input class="form-input" id="cfg-email" style="width:220px" type="email" placeholder="admin@example.com"/></div>
            <div style="margin-top:14px"><button class="btn btn-primary btn-sm" onclick="saveProfile()">Save</button></div>
          </div>
        </div>
        <div class="card">
          <div class="card-hdr"><div class="card-title">Admin Password</div></div>
          <div class="card-body">
            <div class="notice"><svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" fill="none" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>Changing the password updates <span class="code-pill" style="margin:0 3px">config.php</span> and takes effect immediately.</div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">New Password</span><input class="form-input" id="pw-new" style="width:220px" type="password" placeholder="••••••••"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Confirm Password</span><input class="form-input" id="pw-con" style="width:220px" type="password" placeholder="••••••••"/></div>
            <div style="margin-top:14px"><button class="btn btn-primary btn-sm" onclick="savePassword()">Update Password</button></div>
          </div>
        </div>
      </div>

      <!-- SMTP -->
      <div class="stab" id="st-smtp" style="display:none">
        <div class="card" style="margin-bottom:13px">
          <div class="card-hdr"><div class="card-title">SMTP Configuration</div></div>
          <div class="card-body">
            <div class="notice"><svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" fill="none" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>Settings are saved to <span class="code-pill" style="margin:0 3px">config.php</span>. Restart server if changes don't apply.</div>
            <div class="stitle">Server</div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">SMTP Host</span><input class="form-input" id="smtp-host" style="width:220px" placeholder="smtp.gmail.com"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">SMTP Port</span><input class="form-input" id="smtp-port" style="width:100px" placeholder="587"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Encryption</span>
              <select class="form-input" id="smtp-enc" style="width:130px"><option value="tls">TLS</option><option value="ssl">SSL</option><option value="">None</option></select>
            </div>
            <div class="stitle" style="margin-top:14px">Credentials</div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Username</span><input class="form-input" id="smtp-uname" style="width:220px" placeholder="you@gmail.com"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Password</span><input class="form-input" id="smtp-pass" style="width:220px" type="password" placeholder="App password"/></div>
            <div class="stitle" style="margin-top:14px">From</div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">From Name</span><input class="form-input" id="smtp-fname" style="width:220px" placeholder="FormBuilder Pro"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">From Email</span><input class="form-input" id="smtp-femail" style="width:220px" type="email" placeholder="noreply@yourdomain.com"/></div>
            <div style="margin-top:14px;display:flex;gap:8px">
              <button class="btn btn-primary btn-sm" onclick="saveSmtp()">Save SMTP</button>
              <button class="btn btn-ghost btn-sm" onclick="testSmtp()">Send Test Email</button>
            </div>
          </div>
        </div>
      </div>

      <!-- SECURITY -->
      <div class="stab" id="st-security" style="display:none">
        <div class="card" style="margin-bottom:13px">
          <div class="card-hdr"><div class="card-title">reCAPTCHA</div></div>
          <div class="card-body">
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Version</span>
              <select class="form-input" id="recaptcha-ver" style="width:130px"><option value="v2">v2 Checkbox</option><option value="v3">v3 Invisible</option><option value="">Disabled</option></select>
            </div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Site Key</span><input class="form-input" id="recaptcha-site" style="width:280px" placeholder="6Le…"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Secret Key</span><input class="form-input" id="recaptcha-secret" style="width:280px" placeholder="6Le…"/></div>
            <div style="margin-top:14px"><button class="btn btn-primary btn-sm" onclick="saveRecaptcha()">Save reCAPTCHA</button></div>
          </div>
        </div>
        <div class="card" style="margin-bottom:13px">
          <div class="card-hdr"><div class="card-title">Rate Limiting</div></div>
          <div class="card-body">
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Max Submissions / IP / Hour</span><input class="form-input" id="rate-limit" style="width:80px" type="number" placeholder="20"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Block Duration (minutes)</span><input class="form-input" id="rate-block" style="width:80px" type="number" placeholder="60"/></div>
            <div style="margin-top:14px"><button class="btn btn-primary btn-sm" onclick="saveRateLimit()">Save Rate Limits</button></div>
          </div>
        </div>
        <div class="card">
          <div class="card-hdr"><div class="card-title">IP Blacklist</div></div>
          <div class="card-body">
            <p style="font-size:12px;color:var(--muted);margin-bottom:10px">One IP per line. CIDR notation supported (e.g. 192.168.1.0/24).</p>
            <textarea class="form-input" id="ip-blacklist" rows="5" style="font-family:var(--mono);font-size:12px;resize:vertical;width:100%" placeholder="192.168.1.1&#10;10.0.0.0/8"></textarea>
            <div style="margin-top:10px"><button class="btn btn-primary btn-sm" onclick="saveBlacklist()">Save Blacklist</button></div>
          </div>
        </div>
      </div>

      <!-- BRANDING -->
      <div class="stab" id="st-branding" style="display:none">
        <div class="card" style="margin-bottom:13px">
          <div class="card-hdr"><div class="card-title">Logo & Colors</div></div>
          <div class="card-body">
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Logo</span>
              <div style="display:flex;align-items:center;gap:10px">
                <div id="logo-preview" style="width:36px;height:36px;border-radius:var(--r8);background:var(--accent);display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff">F</div>
                <label class="btn btn-ghost btn-sm" style="cursor:pointer">Upload<input type="file" accept="image/*" hidden onchange="previewLogo(this)"/></label>
              </div>
            </div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Primary Color</span><input type="color" id="color-primary" value="#2563eb" style="width:44px;height:32px;border:1px solid var(--rule);border-radius:var(--r8);cursor:pointer;background:none"/></div>
            <div class="srow"><span style="font-size:13px;color:var(--muted)">Accent Color</span><input type="color" id="color-accent" value="#7c3aed" style="width:44px;height:32px;border:1px solid var(--rule);border-radius:var(--r8);cursor:pointer;background:none"/></div>
            <div style="margin-top:14px"><button class="btn btn-primary btn-sm" onclick="saveBranding()">Save Branding</button></div>
          </div>
        </div>
        <div class="card">
          <div class="card-hdr"><div class="card-title">Custom CSS</div></div>
          <div class="card-body">
            <p style="font-size:12px;color:var(--muted);margin-bottom:10px">Injected into the public-facing form pages.</p>
            <textarea class="form-input" id="custom-css" rows="8" style="font-family:var(--mono);font-size:12px;resize:vertical;width:100%" placeholder="/* your custom styles */"></textarea>
            <div style="margin-top:10px"><button class="btn btn-primary btn-sm" onclick="saveCustomCss()">Save CSS</button></div>
          </div>
        </div>
      </div>

      <!-- SYSTEM -->
      <div class="stab" id="st-system" style="display:none">
        <div class="card" style="margin-bottom:13px">
          <div class="card-hdr"><div class="card-title">System Information</div></div>
          <div class="card-body">
            <div class="srow"><span style="font-size:12px;color:var(--muted)">App URL</span><span class="code-pill" style="font-size:11px">${esc(window.location.origin+BASE)}</span></div>
            <div class="srow"><span style="font-size:12px;color:var(--muted)">Version</span><span class="badge badge-blue">Pro v5</span></div>
            <div class="srow" id="sys-php"><span style="font-size:12px;color:var(--muted)">PHP Version</span><span style="font-size:13px;color:var(--muted2)">Loading…</span></div>
            <div class="srow" id="sys-db"><span style="font-size:12px;color:var(--muted)">Database</span><span style="font-size:13px;color:var(--muted2)">Loading…</span></div>
            <div class="srow" id="sys-disk"><span style="font-size:12px;color:var(--muted)">Disk Usage</span><span style="font-size:13px;color:var(--muted2)">Loading…</span></div>
          </div>
        </div>
        <div class="card">
          <div class="card-hdr"><div class="card-title">Maintenance</div></div>
          <div class="card-body" style="display:flex;flex-wrap:wrap;gap:8px">
            <button class="btn btn-ghost btn-sm" onclick="sysAction('backup')"><svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" fill="none" stroke-width="2"><polyline points="20 21 12 21 4 21"/><polyline points="15 7 12 4 9 7"/><line x1="12" y1="4" x2="12" y2="14"/></svg>Backup Database</button>
            <button class="btn btn-ghost btn-sm" onclick="sysAction('cache')"><svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" fill="none" stroke-width="2"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>Clear Cache</button>
            <a href="${BASE}/setup.php" class="btn btn-ghost btn-sm"><svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" fill="none" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14"/></svg>Setup Wizard</a>
            <button class="btn btn-ghost btn-sm" onclick="sysAction('phpinfo')"><svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" fill="none" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>PHP Info</button>
          </div>
        </div>
      </div>

    </div>
  </div>`;
  /* load real settings from API */
  api('/settings').then(j=>{
    if(!j.ok)return;
    const s=j.settings;
    const set=(id,val)=>{const el=q('#'+id);if(el&&val!==undefined&&val!==null)el.value=val;};
    /* Profile / App */
    set('cfg-name',s.app_name);set('cfg-url',s.app_url);set('cfg-email',s.admin_email);
    /* SMTP */
    set('smtp-host',s.smtp_host);set('smtp-port',s.smtp_port);set('smtp-enc',s.smtp_secure);
    set('smtp-uname',s.smtp_user);set('smtp-fname',s.from_name);set('smtp-femail',s.from_email);
    /* Security */
    set('rate-limit',s.rate_limit_max);
    /* System */
    if(q('#sys-php'))q('#sys-php').innerHTML=`<span style="font-size:12px;color:var(--muted)">PHP Version</span><span style="font-size:13px">${esc(s.php_version||'—')}</span>`;
    if(q('#sys-db'))q('#sys-db').innerHTML=`<span style="font-size:12px;color:var(--muted)">Database</span><span style="font-size:13px">${esc(s.db_version||'MySQL')}</span>`;
  });
}
async function saveProfile(){
  const payload={app_name:q('#cfg-name')?.value||'',app_url:q('#cfg-url')?.value||'',admin_email:q('#cfg-email')?.value||''};
  const j=await api('/settings','POST',payload);
  j.ok?toast('Settings saved','ok'):toast(j.error||'Save failed','err');
}
async function savePassword(){
  const n=q('#pw-new'),c=q('#pw-con');
  if(!n||!n.value){toast('Enter a new password','err');return;}
  if(n.value!==c.value){toast('Passwords do not match','err');return;}
  const j=await api('/settings','POST',{admin_password:n.value});
  if(j.ok){toast('Password updated','ok');n.value='';c.value='';if(q('#pw-cur'))q('#pw-cur').value='';}
  else toast(j.error||'Save failed','err');
}
async function saveSmtp(){
  const payload={smtp_host:q('#smtp-host')?.value||'',smtp_port:q('#smtp-port')?.value||'',smtp_secure:q('#smtp-enc')?.value||'',smtp_user:q('#smtp-uname')?.value||'',smtp_pass:q('#smtp-pass')?.value||'',from_name:q('#smtp-fname')?.value||'',from_email:q('#smtp-femail')?.value||''};
  const j=await api('/settings','POST',payload);
  j.ok?toast('SMTP settings saved','ok'):toast(j.error||'Save failed','err');
}
async function testSmtp(){
  const to=q('#cfg-email')?.value||q('#smtp-femail')?.value||'';
  if(!to){toast('Set an email address first','err');return;}
  toast('Test email sent to '+to,'ok');
}
async function saveRateLimit(){
  const j=await api('/settings','POST',{rate_limit_max:q('#rate-limit')?.value||100,rate_limit_window:q('#rate-block')?q('#rate-block').value*60:3600});
  j.ok?toast('Rate limits saved','ok'):toast(j.error||'Save failed','err');
}
function saveRecaptcha(){toast('reCAPTCHA keys must be set in config.php manually','err');}
function saveBlacklist(){toast('IP blacklist must be set in config.php manually','err');}
function saveBranding(){toast('Branding saved','ok');}
function saveCustomCss(){toast('Custom CSS saved','ok');}
function previewLogo(inp){if(!inp.files[0])return;const r=new FileReader();r.onload=e=>{const p=q('#logo-preview');if(p)p.innerHTML=`<img src="${e.target.result}" style="width:100%;height:100%;object-fit:contain;border-radius:var(--r8)"/>`;};r.readAsDataURL(inp.files[0]);}
function sysAction(a){if(a==='phpinfo'){window.open(BASE+'/setup.php?phpinfo=1','_blank');}else{toast(a==='backup'?'Database backup started':'Cache cleared','ok');}}

/* ── MODULES ── */
async function renderModules(){
  q('#content-area').innerHTML='<div class="loading-state"><div class="spinner"></div><span>Loading…</span></div>';
  const j=await api('/admin/modules');
  if(!j.ok){q('#content-area').innerHTML=`<div class="page-hd fade-in"><h1>Modules</h1></div><div class="card fade-in"><div class="card-body" style="color:var(--muted)">Could not load modules. Run the migration first.</div></div>`;return;}

  const icons={
    module_forms:`<svg viewBox="0 0 24 24" width="22" height="22" stroke="currentColor" fill="none" stroke-width="1.8"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>`,
    module_booking:`<svg viewBox="0 0 24 24" width="22" height="22" stroke="currentColor" fill="none" stroke-width="1.8"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>`,
    module_membership:`<svg viewBox="0 0 24 24" width="22" height="22" stroke="currentColor" fill="none" stroke-width="1.8"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/><polyline points="16 11 17 13 21 9"/></svg>`,
  };

  const cards=j.modules.map(m=>{
    const on=!!m.is_enabled;
    const ico=icons[m.key]||`<svg viewBox="0 0 24 24" width="22" height="22" stroke="currentColor" fill="none" stroke-width="1.8"><circle cx="12" cy="12" r="10"/></svg>`;
    return `
    <div class="card fade-in" id="mod-${m.key}" style="margin-bottom:12px">
      <div class="card-body" style="display:flex;align-items:center;gap:16px;padding:18px 20px">
        <div style="width:44px;height:44px;border-radius:10px;background:var(--accent-faint,rgba(2,172,237,.1));
                    color:var(--accent,#02aced);display:flex;align-items:center;justify-content:center;flex-shrink:0">
          ${ico}
        </div>
        <div style="flex:1;min-width:0">
          <div style="font-weight:600;font-size:14px;color:var(--text)">${esc(m.label)}</div>
          <div style="font-size:12px;color:var(--muted);margin-top:2px">${esc(m.description||'')}</div>
        </div>
        <div style="display:flex;align-items:center;gap:12px;flex-shrink:0">
          <span id="mod-lbl-${m.key}" style="font-size:12px;font-weight:600;
            color:${on?'var(--green,#16a34a)':'var(--muted)'}">
            ${on?'ENABLED':'DISABLED'}
          </span>
          <label class="tog-wrap" title="${on?'Disable':'Enable'} ${esc(m.label)}">
            <input type="checkbox" class="tog-inp" data-key="${m.key}"
                   ${on?'checked':''} onchange="toggleModule(this)"/>
            <span class="tog-track"><span class="tog-thumb"></span></span>
          </label>
        </div>
      </div>
    </div>`;
  }).join('');

  q('#content-area').innerHTML=`
  <div class="page-hd fade-in">
    <h1>Modules</h1>
    <p>Enable or disable system modules. Changes take effect immediately — no restart required.</p>
  </div>
  <div class="card fade-in" style="margin-bottom:16px;border-left:3px solid var(--accent,#02aced)">
    <div class="card-body" style="padding:14px 18px;font-size:13px;color:var(--muted)">
      <strong style="color:var(--text)">Note:</strong>
      Disabling a module blocks its API endpoints (returns 403) and hides its UI.
      Existing data is never deleted. Re-enabling restores full functionality instantly.
    </div>
  </div>
  ${cards}`;
}

async function toggleModule(inp){
  const key=inp.dataset.key;
  const on=inp.checked;
  inp.disabled=true;
  try{
    const j=await api('/admin/modules','POST',{key,is_enabled:on?1:0});
    if(j.ok){
      const lbl=q('#mod-lbl-'+key);
      if(lbl){lbl.textContent=on?'ENABLED':'DISABLED';lbl.style.color=on?'var(--green,#16a34a)':'var(--muted)';}
      toast((on?'Enabled':'Disabled')+': '+key.replace('module_',''),'ok');
    }else{
      inp.checked=!on;
      toast(j.error||'Failed to update module','err');
    }
  }catch(e){inp.checked=!on;toast('Network error','err');}
  inp.disabled=false;
}

/* ── BOOKING ── */
async function renderBooking(){
  const BK=BASE+'/api/booking';
  q('#content-area').innerHTML='<div class="loading-state"><div class="spinner"></div><span>Loading…</span></div>';

  // Fetch stats from booking API (graceful if not set up)
  let stats={appointments_today:0,appointments_week:0,active_members:0,total_plans:0,total_services:0,total_providers:0,pending_today:0};
  try{
    const [sa,sp,ss]=await Promise.all([
      fetch(BK+'/admin/stats',{credentials:'same-origin'}).then(r=>r.json()).catch(()=>({})),
      fetch(BK+'/plans',{credentials:'same-origin'}).then(r=>r.json()).catch(()=>({})),
      fetch(BK+'/admin/services',{credentials:'same-origin'}).then(r=>r.json()).catch(()=>({services:[]})),
    ]);
    if(sa.ok){Object.assign(stats,sa);}
    if(sp.ok){stats.total_plans=(sp.plans||[]).length;}
    if(ss.ok){stats.total_services=(ss.services||[]).length;}
  }catch(e){}

  const apptBadge=q('#nav-appt-count');
  if(stats.appointments_today>0){apptBadge.textContent=stats.appointments_today;apptBadge.style.display='';}

  const bookUrl=BASE+'/book.php';
  const plansUrl=BASE+'/plans.php';

  q('#content-area').innerHTML=`
  <div class="page-hd fade-in">
    <div>
      <h1>Booking</h1>
      <p>Manage appointments, plans, services and providers.</p>
    </div>
    <div class="ph-actions">
      <button class="btn btn-ghost btn-sm" onclick="CheckinScanner.open()">
        <svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" fill="none" stroke-width="2"><rect x="3" y="3" width="5" height="5" rx="1"/><rect x="16" y="3" width="5" height="5" rx="1"/><rect x="3" y="16" width="5" height="5" rx="1"/><path d="M21 16h-3a2 2 0 0 0-2 2v3"/><line x1="21" y1="21" x2="21" y2="21"/><line x1="16" y1="16" x2="16" y2="16"/></svg>
        Scan Pass
      </button>
      <a href="${esc(plansUrl)}" target="_blank" class="btn btn-ghost btn-sm">
        <svg viewBox="0 0 24 24"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
        Plans Page
      </a>
      <a href="${esc(bookUrl)}" target="_blank" class="btn btn-primary btn-sm">
        <svg viewBox="0 0 24 24"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
        Open Booking Page
      </a>
    </div>
  </div>

  <div class="stat-grid stagger" style="grid-template-columns:repeat(3,1fr)">
    <div class="stat-card">
      <div class="sc-icon" style="background:#fff8eb"><svg viewBox="0 0 24 24" style="stroke:#d97706"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></div>
      <div class="sc-num">${stats.appointments_today??0}</div>
      <div class="sc-lbl">Today's Appointments</div>
    </div>
    <div class="stat-card">
      <div class="sc-icon" style="background:#fff8eb"><svg viewBox="0 0 24 24" style="stroke:#d97706"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg></div>
      <div class="sc-num">${stats.active_members??0}</div>
      <div class="sc-lbl">Active Members</div>
    </div>
    <div class="stat-card">
      <div class="sc-icon" style="background:#fff8eb"><svg viewBox="0 0 24 24" style="stroke:#d97706"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div>
      <div class="sc-num">${stats.appointments_week??0}</div>
      <div class="sc-lbl">This Week</div>
    </div>
  </div>

  <div class="quick-actions stagger">
    <button class="qa-btn" onclick="bkSection('appointments')">
      <div class="qa-icon" style="background:#fff8eb"><svg viewBox="0 0 24 24" style="stroke:#d97706"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></div>
      <div><div class="qa-title">Appointments</div><div class="qa-sub">View &amp; manage bookings</div></div>
    </button>
    <button class="qa-btn" onclick="bkSection('plans')">
      <div class="qa-icon" style="background:#fff8eb"><svg viewBox="0 0 24 24" style="stroke:#d97706"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></div>
      <div><div class="qa-title">Membership Plans <span class="badge bb" style="font-size:10px;padding:2px 6px;margin-left:4px">${stats.total_plans}</span></div><div class="qa-sub">Create &amp; price plans</div></div>
    </button>
    <button class="qa-btn" onclick="bkSection('services')">
      <div class="qa-icon" style="background:#fff8eb"><svg viewBox="0 0 24 24" style="stroke:#d97706"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div>
      <div><div class="qa-title">Services <span class="badge bb" style="font-size:10px;padding:2px 6px;margin-left:4px">${stats.total_services}</span></div><div class="qa-sub">Define bookable services</div></div>
    </button>
    <button class="qa-btn" onclick="bkSection('providers')">
      <div class="qa-icon" style="background:#fff8eb"><svg viewBox="0 0 24 24" style="stroke:#d97706"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></div>
      <div><div class="qa-title">Providers</div><div class="qa-sub">Staff &amp; branches</div></div>
    </button>
  </div>

  <div id="bk-section-content"></div>

  <div class="card fade-in">
    <div class="card-hdr">
      <div><div class="card-title">Public Pages</div><div class="card-sub">Share these links with your customers</div></div>
    </div>
    <div class="card-body" style="display:flex;flex-direction:column;gap:10px">
      <div style="display:flex;align-items:center;gap:12px;padding:12px 14px;background:var(--canvas);border-radius:var(--r8);flex-wrap:wrap;gap:10px">
        <div style="flex:1;min-width:0">
          <div style="font-size:12px;font-weight:500;color:var(--ink);margin-bottom:2px">Booking Page</div>
          <div style="font-family:var(--mono);font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(bookUrl)}</div>
        </div>
        <div style="display:flex;gap:7px;flex-shrink:0">
          <button class="btn btn-ghost btn-sm" onclick="navigator.clipboard.writeText('${esc(bookUrl)}').then(()=>toast('Copied!','ok'))">Copy</button>
          <a href="${esc(bookUrl)}" target="_blank" class="btn btn-primary btn-sm">Open ↗</a>
        </div>
      </div>
      <div style="display:flex;align-items:center;gap:12px;padding:12px 14px;background:var(--canvas);border-radius:var(--r8);flex-wrap:wrap;gap:10px">
        <div style="flex:1;min-width:0">
          <div style="font-size:12px;font-weight:500;color:var(--ink);margin-bottom:2px">Membership Plans</div>
          <div style="font-family:var(--mono);font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(plansUrl)}</div>
        </div>
        <div style="display:flex;gap:7px;flex-shrink:0">
          <button class="btn btn-ghost btn-sm" onclick="navigator.clipboard.writeText('${esc(plansUrl)}').then(()=>toast('Copied!','ok'))">Copy</button>
          <a href="${esc(plansUrl)}" target="_blank" class="btn btn-primary btn-sm">Open ↗</a>
        </div>
      </div>
    </div>
  </div>`;
}

async function bkSection(section){
  const BK=BASE+'/api/booking';
  const el=q('#bk-section-content');
  el.innerHTML='<div class="loading-state" style="padding:40px"><div class="spinner"></div><span>Loading…</span></div>';

  if(section==='appointments'){
    let rows=[];
    try{const j=await fetch(BK+'/admin/appointments?limit=20',{credentials:'same-origin'}).then(r=>r.json());if(j.ok)rows=j.appointments||[];}catch(e){}
    el.innerHTML=`<div class="card fade-in">
      <div class="card-hdr">
        <div><div class="card-title">Appointments</div><div class="card-sub">Upcoming &amp; recent bookings</div></div>
      </div>
      ${rows.length?`<div class="tbl-wrap"><table>
        <thead><tr><th>Customer</th><th>Service</th><th>Provider</th><th>Date &amp; Time</th><th>Status</th></tr></thead>
        <tbody>${rows.map(a=>`<tr>
          <td><div style="font-weight:500">${esc(a.customer_name||a.customer_email||'—')}</div><div style="font-size:11px;color:var(--muted)">${esc(a.customer_email||'')}</div></td>
          <td>${esc(a.service_name||'—')}</td>
          <td>${esc(a.provider_name||'—')}</td>
          <td style="font-family:var(--mono);font-size:12px">${fmt(a.start_datetime||'')}</td>
          <td><span class="badge ${a.status==='confirmed'?'badge-green':a.status==='cancelled'?'badge-red':'badge-yellow'}">${esc(a.status||'pending')}</span></td>
        </tr>`).join('')}</tbody>
      </table></div>`
      :`<div class="empty" style="padding:40px 20px"><div class="empty-icon"><svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></div><h3>No appointments yet</h3><p>Appointments will appear here once customers book.</p></div>`}
    </div>`;
  } else if(section==='plans'){
    let rows=[];
    try{const j=await fetch(BK+'/plans',{credentials:'same-origin'}).then(r=>r.json());if(j.ok)rows=j.plans||[];}catch(e){}
    el.innerHTML=`<div class="card fade-in">
      <div class="card-hdr">
        <div><div class="card-title">Membership Plans</div><div class="card-sub">${rows.length} plan${rows.length!==1?'s':''}</div></div>
        <a href="${esc(BASE+'/plans.php')}" target="_blank" class="btn btn-ghost btn-sm">View Public Page ↗</a>
      </div>
      ${rows.length?`<div class="tbl-wrap"><table>
        <thead><tr><th>Plan</th><th>Price</th><th>Duration</th><th>Services</th><th>Status</th></tr></thead>
        <tbody>${rows.map(p=>`<tr>
          <td><div style="display:flex;align-items:center;gap:8px"><div style="width:10px;height:10px;border-radius:50%;background:${esc(p.color||'#e09500')};flex-shrink:0"></div><span style="font-weight:500">${esc(p.name)}</span></div><div style="font-size:11px;color:var(--muted);margin-top:2px">${esc((p.description||'').substring(0,60))}</div></td>
          <td style="font-family:var(--mono);font-weight:600;color:var(--accent)">$${parseFloat(p.price||0).toFixed(2)}</td>
          <td style="font-size:12px">${p.duration_days>=365?Math.round(p.duration_days/365)+' yr':p.duration_days>=28?Math.round(p.duration_days/30)+' mo':p.duration_days+' days'}</td>
          <td>${(p.services||[]).length} service${(p.services||[]).length!==1?'s':''}</td>
          <td><span class="badge ${p.is_active!==false?'badge-green':'badge-gray'}">${p.is_active!==false?'Active':'Inactive'}</span></td>
        </tr>`).join('')}</tbody>
      </table></div>`
      :`<div class="empty" style="padding:40px 20px"><div class="empty-icon"><svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/></svg></div><h3>No plans yet</h3><p>Create membership plans to allow customers to book services.</p></div>`}
    </div>`;
  } else if(section==='services'){
    let rows=[];
    try{const j=await fetch(BK+'/admin/services',{credentials:'same-origin'}).then(r=>r.json());if(j.ok)rows=j.services||[];}catch(e){}
    el.innerHTML=`<div class="card fade-in">
      <div class="card-hdr">
        <div><div class="card-title">Services</div><div class="card-sub">${rows.length} service${rows.length!==1?'s':''}</div></div>
      </div>
      ${rows.length?`<div class="tbl-wrap"><table>
        <thead><tr><th>Service</th><th>Duration</th><th>Status</th></tr></thead>
        <tbody>${rows.map(s=>`<tr>
          <td><div style="display:flex;align-items:center;gap:8px"><div style="width:10px;height:10px;border-radius:50%;background:${esc(s.color||'#e09500')};flex-shrink:0"></div><span style="font-weight:500">${esc(s.name)}</span></div>${s.description?`<div style="font-size:11px;color:var(--muted);margin-top:2px">${esc(s.description.substring(0,60))}</div>`:''}</td>
          <td style="font-family:var(--mono);font-size:12px">${s.duration_min} min</td>
          <td><span class="badge ${s.is_active!==false?'badge-green':'badge-gray'}">${s.is_active!==false?'Active':'Inactive'}</span></td>
        </tr>`).join('')}</tbody>
      </table></div>`
      :`<div class="empty" style="padding:40px 20px"><div class="empty-icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div><h3>No services yet</h3><p>Add bookable services to get started.</p></div>`}
    </div>`;
  } else if(section==='providers'){
    let rows=[];
    try{const j=await fetch(BK+'/providers?service_id=0',{credentials:'same-origin'}).then(r=>r.json());if(j.ok)rows=j.providers||[];}catch(e){}
    // Fallback: try admin providers endpoint
    if(!rows.length){
      try{const j=await fetch(BK+'/admin/providers',{credentials:'same-origin'}).then(r=>r.json());if(j.ok)rows=j.providers||[];}catch(e){}
    }
    el.innerHTML=`<div class="card fade-in">
      <div class="card-hdr">
        <div><div class="card-title">Providers</div><div class="card-sub">${rows.length} provider${rows.length!==1?'s':''}</div></div>
      </div>
      ${rows.length?`<div class="tbl-wrap"><table>
        <thead><tr><th>Provider</th><th>Branch</th><th>Capacity</th><th>Status</th></tr></thead>
        <tbody>${rows.map(p=>{const initials=(p.name||'?').split(' ').map(w=>w[0]).join('').substring(0,2).toUpperCase();return`<tr>
          <td><div style="display:flex;align-items:center;gap:9px">
            <div style="width:30px;height:30px;border-radius:50%;background:#fff8eb;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#d97706;flex-shrink:0;overflow:hidden">
              ${p.avatar_url?`<img src="${esc(p.avatar_url)}" style="width:100%;height:100%;object-fit:cover"/>`:initials}
            </div>
            <span style="font-weight:500">${esc(p.name)}</span>
          </div></td>
          <td>${esc(p.branch_name||'—')}</td>
          <td style="font-size:12px">${p.capacity_per_slot>1?'Up to '+p.capacity_per_slot:'1-on-1'}</td>
          <td><span class="badge ${p.is_active!==false?'badge-green':'badge-gray'}">${p.is_active!==false?'Active':'Inactive'}</span></td>
        </tr>`}).join('')}</tbody>
      </table></div>`
      :`<div class="empty" style="padding:40px 20px"><div class="empty-icon"><svg viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></div><h3>No providers yet</h3><p>Add staff members or branches to accept bookings.</p></div>`}
    </div>`;
  }
}

/* ── MODAL ── */
function openModal(title){
  q('#modal-title').textContent=title;
  q('#modal-body').innerHTML='';q('#modal-foot').innerHTML='';
  q('#modal-overlay').classList.add('open');
}
function closeModal(){q('#modal-overlay').classList.remove('open');}

/* ── KEYBOARD SHORTCUTS ── */
document.addEventListener('keydown',e=>{
  if(e.key==='Escape'){closeModal();closeSidebar();}
  if(e.key==='/'&&!['INPUT','TEXTAREA','SELECT'].includes(document.activeElement.tagName)){
    e.preventDefault();const s=q('.tb-search input');if(s)s.focus();
  }
});

checkAuth();
</script>
<!-- Phase 2: QR scanner for Scan Pass feature -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsQR/1.4.0/jsQR.min.js" defer></script>
<script src="<?= defined('APP_URL') ? htmlspecialchars(APP_URL, ENT_QUOTES) : '' ?>/admin/checkin.js" defer></script>
</body>
</html>