<?php
require_once __DIR__ . '/auth.php';
require_login();
if (isset($_GET['logout'])) logout();
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Grove Admin</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{--nav:#1a1a1a;--accent:#4ade80;--bg:#f5f4f0;--white:#fff;--border:#e5e3de;--muted:#888;--danger:#e74c3c;--radius:10px}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Noto Sans Arabic',Tahoma,sans-serif;background:var(--bg);color:#1a1a1a;min-height:100vh;display:flex;flex-direction:column}
/* NAV */
nav{background:var(--nav);color:#fff;display:flex;align-items:center;padding:0 1.5rem;height:56px;gap:0;flex-shrink:0}
.nav-logo{font-size:17px;font-weight:600;letter-spacing:-0.3px;margin-right:2rem}
.nav-tabs{display:flex;height:100%}
.nav-tab{padding:0 18px;height:100%;display:flex;align-items:center;font-size:13px;color:rgba(255,255,255,0.6);cursor:pointer;border-bottom:2px solid transparent;transition:all 0.15s;white-space:nowrap}
.nav-tab:hover{color:#fff}
.nav-tab.active{color:#fff;border-bottom-color:var(--accent)}
.nav-right{margin-left:auto;display:flex;align-items:center;gap:12px}
.nav-user{font-size:12px;color:rgba(255,255,255,0.5)}
.nav-logout{font-size:12px;color:rgba(255,255,255,0.5);text-decoration:none;padding:5px 10px;border:1px solid rgba(255,255,255,0.2);border-radius:6px}
.nav-logout:hover{color:#fff;border-color:rgba(255,255,255,0.5)}
/* LAYOUT */
.main{flex:1;padding:1.5rem;max-width:1100px;width:100%;margin:0 auto}
.page{display:none}.page.active{display:block}
/* CARDS */
.card{background:var(--white);border:1px solid var(--border);border-radius:14px;padding:1.25rem 1.5rem;margin-bottom:1rem}
.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem}
.card-title{font-size:15px;font-weight:500}
/* BUTTONS */
.btn{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:500;cursor:pointer;border:1px solid var(--border);background:var(--white);color:#1a1a1a;transition:all 0.15s}
.btn:hover{background:var(--bg)}
.btn-primary{background:var(--nav);color:#fff;border-color:var(--nav)}
.btn-primary:hover{background:#333}
.btn-danger{background:var(--danger);color:#fff;border-color:var(--danger)}
.btn-danger:hover{background:#c0392b}
.btn-sm{padding:5px 10px;font-size:12px}
.btn-icon{padding:5px 8px;font-size:14px}
/* TABLES */
table{width:100%;border-collapse:collapse;font-size:13px}
th{text-align:left;font-weight:500;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;padding:0 12px 10px;border-bottom:1px solid var(--border)}
td{padding:12px;border-bottom:1px solid var(--border);vertical-align:middle}
tr:last-child td{border-bottom:none}
tr:hover td{background:#faf9f7}
.pill{display:inline-block;padding:2px 8px;border-radius:20px;font-size:11px;font-weight:500}
.pill-green{background:#dcfce7;color:#166534}
.pill-gray{background:#f1f0ea;color:#555}
.pill-popular{background:#dcfce7;color:#166534}
.pill-spicy{background:#fee2e2;color:#991b1b}

/* Inline visibility pills in the items list. Click to toggle.
   "On" state = item appears in that mode; "off" = hidden there. */
.vis-pill { display:inline-block; padding:3px 8px; margin-right:4px;
            border-radius:14px; font-size:14px; cursor:pointer;
            user-select:none; transition:transform 0.1s, opacity 0.15s; }
.vis-pill:hover { transform: scale(1.1); }
.vis-pill.on  { background:#dcfce7; opacity:1; }
.vis-pill.off { background:#f1f0ea; opacity:0.4; filter:grayscale(1); }
.pill-veg{background:#d1fae5;color:#065f46}
/* FORMS */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.form-group{display:flex;flex-direction:column;gap:5px}
.form-group.full{grid-column:1/-1}
label{font-size:12px;font-weight:500;color:#555}
input[type=text],input[type=number],input[type=password],input[type=url],select,textarea{width:100%;padding:8px 10px;border:1px solid var(--border);border-radius:8px;font-size:13px;font-family:inherit;outline:none;transition:border-color 0.15s;background:#fff}
input:focus,select:focus,textarea:focus{border-color:#1a1a1a}
textarea{resize:vertical;min-height:70px}
.form-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:1rem;padding-top:1rem;border-top:1px solid var(--border)}
/* BILINGUAL PAIRS — shows an English field and an Arabic field side by side.
   The Arabic input gets dir="rtl" so text aligns/types naturally.
   The small "EN" and "عربي" tag in the corner hints which language is which. */
.bi-pair{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.bi-field{position:relative}
.bi-field input,.bi-field textarea{padding-right:38px}
.bi-field input[dir=rtl],.bi-field textarea[dir=rtl]{padding-right:10px;padding-left:38px;text-align:right}
.bi-tag{position:absolute;top:8px;right:10px;font-size:10px;font-weight:600;color:var(--muted);background:#f5f4f0;border-radius:4px;padding:1px 5px;pointer-events:none;letter-spacing:0.5px}
.bi-field[data-lang=ar] .bi-tag{right:auto;left:10px}
/* MODAL */
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:100;align-items:center;justify-content:center;padding:1rem}
.modal-overlay.open{display:flex}
.modal-box{background:#fff;border-radius:14px;width:100%;max-width:640px;max-height:90vh;overflow-y:auto;padding:1.5rem}
.modal-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.25rem}
.modal-title{font-size:16px;font-weight:500}
.modal-close{background:none;border:none;font-size:20px;cursor:pointer;color:var(--muted);line-height:1}
/* MODIFIERS (sizes/extras rows, now bilingual) */
.mod-list{display:flex;flex-direction:column;gap:6px;margin-top:6px}
.mod-row{display:grid;grid-template-columns:1fr 1fr 90px 32px;gap:6px;align-items:center}
.mod-row input[type=text]{min-width:0}
.mod-row input.ar{text-align:right}
.mod-row input.price{width:100%}
.add-mod-btn{font-size:12px;color:var(--muted);cursor:pointer;margin-top:6px;display:inline-flex;align-items:center;gap:4px;border:none;background:none;padding:0}
.add-mod-btn:hover{color:#1a1a1a}
.mod-head{display:grid;grid-template-columns:1fr 1fr 90px 32px;gap:6px;font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:4px}
/* PHOTO */
.photo-preview{width:80px;height:60px;border-radius:8px;object-fit:cover;border:1px solid var(--border)}
.photo-placeholder-box{width:80px;height:60px;border-radius:8px;border:1px dashed var(--border);display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:11px}
/* PHOTO GALLERY ROWS — each gallery photo is a URL input + thumbnail + upload + remove */
.photo-row{display:grid;grid-template-columns:48px 1fr auto auto;gap:8px;align-items:center;padding:6px;border:1px solid var(--border-soft,#f0e8db);border-radius:8px;background:#fafaf7}
.photo-row .thumb{width:48px;height:48px;border-radius:6px;object-fit:cover;background:var(--bg);border:1px solid var(--border)}
.photo-row .thumb-ph{width:48px;height:48px;border-radius:6px;background:var(--bg);border:1px dashed var(--border);display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:10px}
.photo-row input[type=url]{width:100%;min-width:0}
/* TOAST */
.toast{position:fixed;bottom:24px;right:24px;background:#1a1a1a;color:#fff;padding:12px 18px;border-radius:10px;font-size:13px;z-index:999;opacity:0;transform:translateY(8px);transition:all 0.25s;pointer-events:none}
.toast.show{opacity:1;transform:translateY(0)}
/* SETTINGS */
.settings-section{margin-bottom:1.5rem}
.settings-section-title{font-size:12px;font-weight:500;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid var(--border)}
/* LAYOUT PICKER — radio cards with visual thumbnail previews */
.layout-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.layout-card{position:relative;display:block;border:2px solid var(--border);border-radius:10px;padding:10px;cursor:pointer;transition:all 0.15s;background:#fff}
.layout-card:hover{border-color:var(--muted)}
.layout-card input[type=radio]{position:absolute;opacity:0;pointer-events:none}
.layout-card:has(input:checked){border-color:var(--nav);box-shadow:0 0 0 2px rgba(26,26,26,0.08)}
.layout-thumb{width:100%;height:90px;border-radius:6px;overflow:hidden;margin-bottom:10px}
.layout-meta{padding:0 2px}
.layout-name{font-size:13px;font-weight:600;color:var(--nav);margin-bottom:3px}
.layout-desc{font-size:11px;color:var(--muted);line-height:1.4}
.color-row{display:flex;align-items:center;gap:10px}
.color-row input[type=color]{width:36px;height:36px;padding:2px;border-radius:6px;cursor:pointer}
/* STAT CARDS */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-bottom:1.5rem}
.stat{background:var(--white);border:1px solid var(--border);border-radius:12px;padding:1rem 1.25rem}
.stat-label{font-size:11px;color:var(--muted);margin-bottom:4px}
.stat-val{font-size:24px;font-weight:500}
</style>
</head>
<body>

<nav>
  <div class="nav-logo">Grove Admin</div>
  <div class="nav-tabs">
    <div class="nav-tab active" onclick="showPage('dashboard')">Dashboard</div>
<?php $perms = current_permissions(); ?>
<?php if ($perms['menu']): ?>
    <div class="nav-tab" onclick="showPage('categories')">Categories</div>
    <div class="nav-tab" onclick="showPage('items')">Menu Items</div>
    <div class="nav-tab" onclick="showPage('origins')">Origins</div>
<?php endif; ?>
<?php if ($perms['orders']): ?>
    <a class="nav-tab" href="orders.php" style="text-decoration:none;color:inherit">Orders</a>
<?php endif; ?>
<?php if ($perms['settings']): ?>
    <div class="nav-tab" onclick="showPage('settings')">Settings</div>
<?php endif; ?>
<?php if ($perms['users']): ?>
    <div class="nav-tab" onclick="showPage('branches')">Branches</div>
    <div class="nav-tab" onclick="showPage('users')">Users</div>
<?php endif; ?>
  </div>
  <div class="nav-right">
    <span class="nav-user">Hi, <?= htmlspecialchars($_SESSION['admin_user']) ?></span>
    <a class="nav-logout" href="?logout=1">Sign out</a>
  </div>
</nav>
<script>
  // Expose the current user's permissions to client-side JS so
  // showPage() and other logic can guard sections. This mirrors
  // the server-side gate — the server is the real enforcement,
  // this is just for UX (don't show what you can't use).
  window.ADMIN_PERMS = <?= json_encode(current_permissions()) ?>;
  // site_mode: 'multi_branch' (Brand B) or 'single_location'
  // (La Tarte). Branch / delivery UI only shows in multi_branch.
  window.SITE_MODE = <?= json_encode(setting('site_mode', 'single_location')) ?>;
  // The logged-in user's branch scope — null = all branches.
  window.ADMIN_BRANCH_ID = <?= json_encode(current_branch_id()) ?>;
</script>

<div class="main">

  <!-- DASHBOARD -->
  <div class="page active" id="page-dashboard">
    <div class="stats" id="statsRow"></div>
<?php if ($perms['menu']): ?>
    <div class="card">
      <div class="card-header"><div class="card-title">Quick actions</div></div>
      <div style="display:flex;gap:10px;flex-wrap:wrap">
        <button class="btn btn-primary" onclick="showPage('items');openItemModal()">+ Add menu item</button>
        <button class="btn" onclick="showPage('categories');openCatModal()">+ Add category</button>
        <a class="btn" href="../menu/index.html" target="_blank">View live menu ↗</a>
      </div>
    </div>
<?php else: ?>
    <div class="card">
      <div class="card-header"><div class="card-title">Quick actions</div></div>
      <div style="display:flex;gap:10px;flex-wrap:wrap">
        <a class="btn" href="../menu/index.html" target="_blank">View live menu ↗</a>
      </div>
    </div>
<?php endif; ?>
  </div>

  <!-- CATEGORIES -->
  <div class="page" id="page-categories">
    <div class="card">
      <div class="card-header">
        <div class="card-title">Categories</div>
        <button class="btn btn-primary" onclick="openCatModal()">+ Add category</button>
      </div>
      <table id="categoriesTable">
        <thead><tr><th style="width:24px"></th><th>Name (EN)</th><th>Name (عربي)</th><th>Slug</th><th>Order</th><th>Status</th><th></th></tr></thead>
        <tbody id="catTableBody"></tbody>
      </table>
    </div>
  </div>

  <!-- ITEMS -->
  <div class="page" id="page-items">
    <div class="card">
      <div class="card-header">
        <div style="display:flex;align-items:center;gap:12px">
          <div class="card-title">Menu items</div>
          <select id="catFilter" style="width:160px" onchange="loadItems()">
            <option value="">All categories</option>
          </select>
        </div>
        <button class="btn btn-primary" onclick="openItemModal()">+ Add item</button>
      </div>

      <!-- Bulk visibility toggle bar — applies to the items currently
           shown (filtered category, or "all" if no filter selected).
           Useful for power tasks like "hide all desserts from showcase
           during a tasting menu" or "make every item orderable again
           after a holiday closure." -->
      <div style="padding:12px 16px;background:#fafafa;border-top:1px solid var(--border);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:13px">
        <span style="color:#888;font-weight:500">Bulk:</span>
        <span id="bulkScope" style="color:#444"></span>
        <button class="btn btn-sm" onclick="bulkVisibility('show_in_ordering', 1)">🛒 Show all on /order</button>
        <button class="btn btn-sm" onclick="bulkVisibility('show_in_ordering', 0)" style="background:#fef2f2;color:#991b1b">🛒 Hide all from /order</button>
        <span style="color:#ddd">|</span>
        <button class="btn btn-sm" onclick="bulkVisibility('show_in_showcase', 1)">📋 Show all on /menu</button>
        <button class="btn btn-sm" onclick="bulkVisibility('show_in_showcase', 0)" style="background:#fef2f2;color:#991b1b">📋 Hide all from /menu</button>
      </div>

      <table id="itemsTable">
        <thead><tr><th style="width:24px"></th><th>Photo</th><th>Name</th><th>Category</th><th>Price</th><th>Visibility</th><th>Status</th><th></th></tr></thead>
        <tbody id="itemTableBody"></tbody>
      </table>
    </div>
  </div>

  <!-- ORIGINS — small master-data table shown on web + printable menu -->
  <div class="page" id="page-origins">
    <div class="card">
      <div class="card-header">
        <div class="card-title">
          Country of Origin
          <span style="font-size:12px;color:var(--muted);font-weight:normal;margin-left:8px">
            Shown on the web menu header (ℹ️ link) and the printable menu's last page.
          </span>
        </div>
        <button class="btn btn-primary" onclick="openOriginModal()">+ Add row</button>
      </div>
      <table>
        <thead><tr>
          <th>Item (EN)</th>
          <th>Item (عربي)</th>
          <th>Country (EN)</th>
          <th>Country (عربي)</th>
          <th>Order</th>
          <th></th>
        </tr></thead>
        <tbody id="originsTableBody"></tbody>
      </table>
    </div>
  </div>
  <!-- Modal: edit/add a single origin row. Four required fields. -->
  <div class="modal-overlay" id="originModal">
    <div class="modal-box">
      <div class="modal-head">
        <div class="modal-title" id="originModalTitle">Add origin</div>
        <button class="modal-close" onclick="closeOriginModal()">&#x2715;</button>
      </div>
      <input type="hidden" id="origin_id">
      <div class="form-grid">
        <div class="form-group">
          <label>Item (English)</label>
          <input type="text" id="origin_item_en" placeholder="e.g. Chicken">
        </div>
        <div class="form-group">
          <label>Item (عربي)</label>
          <input type="text" id="origin_item_ar" placeholder="مثال: دجاج" style="direction:rtl;text-align:right">
        </div>
        <div class="form-group">
          <label>Country (English)</label>
          <input type="text" id="origin_country_en" placeholder="e.g. Brazil">
        </div>
        <div class="form-group">
          <label>Country (عربي)</label>
          <input type="text" id="origin_country_ar" placeholder="مثال: برازيلي" style="direction:rtl;text-align:right">
        </div>
        <div class="form-group">
          <label>Sort order</label>
          <input type="number" id="origin_sort_order" value="0" style="max-width:120px">
          <small style="color:#888;font-size:11px">Lower numbers appear first.</small>
        </div>
      </div>
      <div class="form-actions">
        <button class="btn btn-danger" id="deleteOriginBtn" onclick="deleteOrigin()" style="display:none">Delete</button>
        <button class="btn" onclick="closeOriginModal()">Cancel</button>
        <button class="btn btn-primary" onclick="saveOrigin()">Save</button>
      </div>
    </div>
  </div>

  <!-- BRANCHES — branch management (super admin only) -->
  <div class="page" id="page-branches">
    <div class="card">
      <div class="card-header">
        <div class="card-title">
          Branches
          <span style="font-size:12px;color:var(--muted);font-weight:normal;margin-left:8px">
            Add and manage branch locations. Hide a branch to take it offline.
          </span>
        </div>
        <button class="btn btn-primary" onclick="openBranchModal()">+ Add branch</button>
      </div>
      <table>
        <thead><tr>
          <th>Name</th>
          <th>Arabic name</th>
          <th>Slug</th>
          <th>Phone</th>
          <th>Order</th>
          <th>Status</th>
          <th></th>
        </tr></thead>
        <tbody id="branchesTableBody"></tbody>
      </table>
    </div>
  </div>
  <!-- Modal: add / edit a branch -->
  <div class="modal-overlay" id="branchModal">
    <div class="modal-box">
      <div class="modal-head">
        <div class="modal-title" id="branchModalTitle">Add branch</div>
        <button class="modal-close" onclick="closeBranchModal()">&#x2715;</button>
      </div>
      <input type="hidden" id="branch_id">
      <div class="form-grid">
        <div class="form-group">
          <label>Branch name (English) <span style="color:#c4362c">*</span></label>
          <input type="text" id="branch_name" placeholder="e.g. Jabriya">
        </div>
        <div class="form-group">
          <label>Branch name (عربي)</label>
          <input type="text" id="branch_name_ar" placeholder="مثال: الجابرية" style="direction:rtl;text-align:right">
        </div>
        <div class="form-group">
          <label>Slug
            <span style="color:#888;font-weight:normal;font-size:11px">— for QR links; auto-generated if blank</span>
          </label>
          <input type="text" id="branch_slug" placeholder="e.g. jabriya" autocomplete="off">
        </div>
        <div class="form-group">
          <label>Phone</label>
          <input type="text" id="branch_phone" placeholder="e.g. +965 2200 0000">
        </div>
        <div class="form-group full">
          <label>Address (English)</label>
          <input type="text" id="branch_address" placeholder="Branch address">
        </div>
        <div class="form-group full">
          <label>Address (عربي)</label>
          <input type="text" id="branch_address_ar" placeholder="العنوان" style="direction:rtl;text-align:right">
        </div>
        <div class="form-group">
          <label>Sort order</label>
          <input type="number" id="branch_sort_order" value="0" style="max-width:120px">
        </div>
      </div>
      <div class="form-group full" style="margin-top:4px">
        <label style="display:flex;align-items:center;gap:8px;font-weight:normal;cursor:pointer">
          <input type="checkbox" id="branch_is_active" checked> Branch active (uncheck to hide it)
        </label>
      </div>
      <div class="form-actions">
        <button class="btn btn-danger" id="deleteBranchBtn" onclick="deleteBranch()" style="display:none">Delete</button>
        <button class="btn" onclick="closeBranchModal()">Cancel</button>
        <button class="btn btn-primary" onclick="saveBranch()">Save</button>
      </div>
    </div>
  </div>

  <!-- USERS — admin user management (super admin only) -->
  <div class="page" id="page-users">
    <div class="card">
      <div class="card-header">
        <div class="card-title">
          Admin Users
          <span style="font-size:12px;color:var(--muted);font-weight:normal;margin-left:8px">
            Create staff logins and control which sections each can access.
          </span>
        </div>
        <button class="btn btn-primary" onclick="openUserModal()">+ Add user</button>
      </div>
      <table>
        <thead><tr>
          <th>Username</th>
          <th>Display name</th>
          <th>Branch</th>
          <th>Access</th>
          <th>Status</th>
          <th></th>
        </tr></thead>
        <tbody id="usersTableBody"></tbody>
      </table>
    </div>
  </div>
  <!-- Modal: add / edit an admin user -->
  <div class="modal-overlay" id="userModal">
    <div class="modal-box">
      <div class="modal-head">
        <div class="modal-title" id="userModalTitle">Add user</div>
        <button class="modal-close" onclick="closeUserModal()">&#x2715;</button>
      </div>
      <input type="hidden" id="user_id">
      <div class="form-grid">
        <div class="form-group">
          <label>Username <span style="color:#c4362c">*</span></label>
          <input type="text" id="user_username" placeholder="e.g. ahmad" autocomplete="off">
        </div>
        <div class="form-group">
          <label>Display name</label>
          <input type="text" id="user_display_name" placeholder="e.g. Ahmad (Avenues)">
        </div>
        <div class="form-group full">
          <label>Password <span id="userPwHint" style="color:#888;font-weight:normal;font-size:11px"></span></label>
          <input type="password" id="user_password" placeholder="Set a password" autocomplete="new-password">
        </div>
        <div class="form-group full">
          <label>Branch
            <span style="color:#888;font-weight:normal;font-size:11px">— which branch this user manages</span>
          </label>
          <select id="user_branch_id">
            <option value="">All branches</option>
          </select>
        </div>
      </div>

      <!-- Section access — per-section checkboxes (Q2 choice b).
           Super admin is a separate master toggle; when checked,
           the section checkboxes are implied and disabled. -->
      <div class="form-group full" style="margin-top:8px">
        <label style="margin-bottom:8px;display:block">Section access</label>
        <label style="display:flex;align-items:center;gap:8px;margin-bottom:6px;font-weight:normal;cursor:pointer">
          <input type="checkbox" id="user_perm_menu"> Menu management (categories, items, origins)
        </label>
        <label style="display:flex;align-items:center;gap:8px;margin-bottom:6px;font-weight:normal;cursor:pointer">
          <input type="checkbox" id="user_perm_orders"> Order management
        </label>
        <label style="display:flex;align-items:center;gap:8px;margin-bottom:6px;font-weight:normal;cursor:pointer">
          <input type="checkbox" id="user_perm_settings"> Settings
        </label>
        <hr style="border:none;border-top:1px solid var(--border-soft);margin:10px 0">
        <label style="display:flex;align-items:center;gap:8px;margin-bottom:6px;font-weight:500;cursor:pointer">
          <input type="checkbox" id="user_is_super" onchange="onSuperToggle()"> Super Admin — full access + user management
        </label>
        <label style="display:flex;align-items:center;gap:8px;font-weight:normal;cursor:pointer">
          <input type="checkbox" id="user_is_active" checked> Account active (uncheck to disable login)
        </label>
      </div>

      <div class="form-actions">
        <button class="btn btn-danger" id="deleteUserBtn" onclick="deleteUser()" style="display:none">Delete</button>
        <button class="btn" onclick="closeUserModal()">Cancel</button>
        <button class="btn btn-primary" onclick="saveUser()">Save</button>
      </div>
    </div>
  </div>

  <!-- SETTINGS -->
  <div class="page" id="page-settings">
    <div class="card">
      <div class="card-header"><div class="card-title">Restaurant settings</div></div>

      <div class="settings-section">
        <div class="settings-section-title">General</div>
        <!-- Name: bilingual pair -->
        <div class="form-group" style="margin-bottom:12px">
          <label>Restaurant name</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_restaurant_name"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_restaurant_name_ar" dir="rtl"><span class="bi-tag">عربي</span></div>
          </div>
        </div>
        <!-- Tagline: bilingual pair -->
        <div class="form-group" style="margin-bottom:12px">
          <label>Tagline</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_restaurant_tagline"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_restaurant_tagline_ar" dir="rtl"><span class="bi-tag">عربي</span></div>
          </div>
        </div>
        <div class="form-grid">
          <div class="form-group full"><label>Logo URL</label><input type="url" id="s_logo_url" placeholder="https://..."></div>
          <div class="form-group full"><label>Meta description</label><input type="text" id="s_meta_description"></div>
          <div class="form-group">
            <label>Default language <span style="color:var(--muted);font-weight:normal">(shown first to new visitors)</span></label>
            <select id="s_default_language">
              <option value="en">English</option>
              <option value="ar">العربية</option>
            </select>
          </div>
        </div>
      </div>

      <div class="settings-section">
        <div class="settings-section-title">Currency</div>
        <div class="form-grid">
          <div class="form-group"><label>Currency code</label><input type="text" id="s_currency_code" maxlength="10"></div>
          <div class="form-group"><label>Decimal places</label><input type="number" id="s_currency_decimals" min="0" max="4"></div>
        </div>
      </div>

      <!-- ================================================================
           LAYOUT PICKER
           ================================================================
           Three visual layouts with different fonts, colors, and hero
           styling. Each radio card includes a tiny SVG preview so the
           admin can see at a glance what they're choosing without
           having to switch and reload the menu to compare. -->
      <div class="settings-section">
        <div class="settings-section-title">Layout</div>
        <div class="layout-grid">
          <label class="layout-card">
            <input type="radio" name="s_layout" value="editorial">
            <div class="layout-thumb" style="background:#faf7f2">
              <div style="font-family:Georgia,serif;font-style:italic;font-size:18px;color:#2a2420;text-align:center;margin-top:18px">Brand</div>
              <div style="width:30px;height:1.5px;background:#c9a961;margin:5px auto"></div>
              <div style="font-size:7px;color:#888;text-align:center;letter-spacing:1px">TAGLINE</div>
              <div style="display:flex;gap:3px;margin-top:10px;padding:0 8px">
                <div style="flex:1;height:28px;background:#e8dfd0;border-radius:3px"></div>
                <div style="flex:1;height:28px;background:#e8dfd0;border-radius:3px"></div>
              </div>
              <div style="display:flex;gap:3px;margin-top:3px;padding:0 8px">
                <div style="flex:1;height:4px;background:#c87856;border-radius:2px"></div>
              </div>
            </div>
            <div class="layout-meta">
              <div class="layout-name">Editorial</div>
              <div class="layout-desc">Modern magazine-style with italic serif headlines and warm cream background.</div>
            </div>
          </label>

          <label class="layout-card">
            <input type="radio" name="s_layout" value="patisserie">
            <div class="layout-thumb" style="background:#fdf9f0">
              <div style="width:70%;height:22px;margin:10px auto 4px;background:#2a2420;border-radius:2px;display:flex;align-items:center;justify-content:center;color:#fdf9f0;font-family:Georgia,serif;font-size:8px;letter-spacing:1px">LOGO</div>
              <div style="font-size:7px;color:#888;text-align:center;letter-spacing:1px;margin-top:3px">SINCE 1955</div>
              <div style="display:flex;gap:3px;margin-top:8px;padding:0 8px">
                <div style="flex:1;height:28px;background:#f0e5d1;border-radius:3px;border:1px solid #e8dfd0"></div>
                <div style="flex:1;height:28px;background:#f0e5d1;border-radius:3px;border:1px solid #e8dfd0"></div>
              </div>
              <div style="display:flex;gap:3px;margin-top:3px;padding:0 8px">
                <div style="flex:1;height:4px;background:#c4362c;border-radius:2px"></div>
              </div>
            </div>
            <div class="layout-meta">
              <div class="layout-name">Patisserie</div>
              <div class="layout-desc">Classic French bakery style with logo-forward header, red accent, gold details.</div>
            </div>
          </label>

          <label class="layout-card">
            <input type="radio" name="s_layout" value="modern">
            <div class="layout-thumb" style="background:#ffffff;border:1px solid #eee">
              <div style="display:flex;align-items:center;gap:6px;padding:12px 10px 6px">
                <div style="width:20px;height:20px;background:#111;border-radius:50%"></div>
                <div style="font-family:-apple-system,sans-serif;font-weight:700;font-size:12px">Brand</div>
              </div>
              <div style="display:flex;gap:3px;margin-top:6px;padding:0 8px">
                <div style="flex:1;height:28px;background:#f5f5f5;border-radius:3px"></div>
                <div style="flex:1;height:28px;background:#f5f5f5;border-radius:3px"></div>
                <div style="flex:1;height:28px;background:#f5f5f5;border-radius:3px"></div>
              </div>
              <div style="display:flex;gap:3px;margin-top:3px;padding:0 8px">
                <div style="flex:1;height:4px;background:#111;border-radius:2px"></div>
              </div>
            </div>
            <div class="layout-meta">
              <div class="layout-name">Modern</div>
              <div class="layout-desc">Minimalist with system fonts, compact spacing, and clean white background.</div>
            </div>
          </label>

          <label class="layout-card">
            <input type="radio" name="s_layout" value="tropezienne">
            <div class="layout-thumb" style="background:#c4362c">
              <div style="padding:10px 6px 4px;text-align:center">
                <div style="font-family:'Impact','Arial Black',sans-serif;font-weight:900;font-size:11px;color:#fff;letter-spacing:0.5px;text-transform:uppercase;line-height:1">BRAND</div>
                <div style="font-size:6px;color:rgba(255,255,255,0.8);text-align:center;letter-spacing:1.5px;margin-top:4px;display:flex;align-items:center;justify-content:center;gap:3px">
                  <span style="flex:1;height:1px;background:rgba(255,255,255,0.6);max-width:10px"></span>
                  <span>1955</span>
                  <span style="flex:1;height:1px;background:rgba(255,255,255,0.6);max-width:10px"></span>
                </div>
              </div>
              <div style="background:#fdf9f0;margin-top:4px;padding:4px 8px;height:42px">
                <div style="display:flex;gap:3px">
                  <div style="flex:1;height:28px;background:#f0e5d1;border-radius:2px;border:1px solid #e8dfd0"></div>
                  <div style="flex:1;height:28px;background:#f0e5d1;border-radius:2px;border:1px solid #e8dfd0"></div>
                </div>
                <div style="display:flex;gap:3px;margin-top:3px">
                  <div style="flex:1;height:3px;background:#c4362c;border-radius:2px"></div>
                </div>
              </div>
            </div>
            <div class="layout-meta">
              <div class="layout-name">Tropézienne</div>
              <div class="layout-desc">Bold red hero banner with condensed uppercase wordmark. Matches the official LTT brand aesthetic.</div>
            </div>
          </label>
        </div>
      </div>

      <div class="settings-section">
        <div class="settings-section-title">Branding colors</div>
        <div class="form-grid">
          <div class="form-group">
            <label>Primary color</label>
            <div class="color-row"><input type="color" id="s_primary_color"><input type="text" id="s_primary_color_hex" maxlength="7" style="width:90px"></div>
          </div>
          <div class="form-group">
            <label>Accent color</label>
            <div class="color-row"><input type="color" id="s_accent_color"><input type="text" id="s_accent_color_hex" maxlength="7" style="width:90px"></div>
          </div>
        </div>
      </div>

      <!-- ================================================================
           WELCOME POPUP SETTINGS
           ================================================================
           A bilingual popup that appears when the customer menu loads.
           The admin can:
             - enable/disable the popup
             - upload OR paste a URL for an image or video
             - write EN + AR title, body, and button label
           A live preview mirrors what the customer will see. -->
      <div class="settings-section">
        <div class="settings-section-title">Welcome popup</div>

        <div class="form-group" style="margin-bottom:12px">
          <label style="display:flex;align-items:center;gap:10px;cursor:pointer">
            <input type="checkbox" id="s_popup_enabled" style="width:auto;margin:0">
            <span>Show popup when menu opens</span>
          </label>
        </div>

        <!-- Media: kind selector (image / video / none) + URL + upload -->
        <div class="form-group" style="margin-bottom:12px">
          <label>Media type</label>
          <select id="s_popup_media_type">
            <option value="none">No media (text only)</option>
            <option value="image">Image (portrait recommended)</option>
            <option value="video">Video (portrait, muted, auto-plays)</option>
          </select>
        </div>

        <div class="form-group" id="popupMediaUrlWrap" style="margin-bottom:12px">
          <label>Media URL</label>
          <div style="display:flex;gap:10px;align-items:flex-start;flex-wrap:wrap">
            <input type="url" id="s_popup_media_url" placeholder="https://... (paste URL or upload below)" style="flex:1;min-width:200px">
            <label class="btn btn-sm" style="cursor:pointer" id="popupUploadLabel">
              Upload
              <input type="file" id="popup_media_file" accept="image/*,video/*" style="display:none" onchange="uploadPopupMedia()">
            </label>
          </div>
          <div id="popupPreviewWrap" style="margin-top:10px;display:none"></div>
        </div>

        <!-- Title: bilingual -->
        <div class="form-group" style="margin-bottom:12px">
          <label>Title</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_popup_title_en" placeholder="Welcome"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_popup_title_ar" dir="rtl" placeholder="أهلاً وسهلاً"><span class="bi-tag">عربي</span></div>
          </div>
        </div>

        <!-- Body: bilingual, multiline -->
        <div class="form-group" style="margin-bottom:12px">
          <label>Body text</label>
          <div class="bi-pair">
            <div class="bi-field"><textarea id="s_popup_body_en" placeholder="A short welcome message…"></textarea><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><textarea id="s_popup_body_ar" dir="rtl" placeholder="رسالة ترحيب قصيرة…"></textarea><span class="bi-tag">عربي</span></div>
          </div>
        </div>

        <!-- Button label: bilingual -->
        <div class="form-group" style="margin-bottom:12px">
          <label>Button label</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_popup_button_en" placeholder="View menu"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_popup_button_ar" dir="rtl" placeholder="عرض القائمة"><span class="bi-tag">عربي</span></div>
          </div>
        </div>
      </div>

      <!-- ==========================================================
           SHOWCASE POPUP — appears only on the showcase site
           (menu.latartekw.com). Use this to highlight new items,
           seasonal specials, or anything you want featured at the
           reception kiosk. Configured separately from the welcome
           popup so the QR ordering site and reception kiosk can
           show different things. -->
      <div class="settings-section">
        <div class="settings-section-title">Showcase popup (menu.latartekw.com)</div>

        <div class="form-group" style="margin-bottom:12px">
          <label style="display:flex;align-items:center;gap:10px;cursor:pointer">
            <input type="checkbox" id="s_popup_showcase_enabled" style="width:auto;margin:0">
            Show this popup on the showcase site
          </label>
        </div>

        <div class="form-grid" style="margin-bottom:12px">
          <div class="form-group">
            <label>Media type</label>
            <select id="s_popup_showcase_media_type">
              <option value="none">No media</option>
              <option value="image">Image</option>
              <option value="video">Video</option>
            </select>
          </div>
          <div class="form-group">
            <label>Media URL (image or video)</label>
            <input type="text" id="s_popup_showcase_media_url" placeholder="/uploads/new-item.jpg">
            <small style="color:#888;font-size:11px">Use the menu items page to upload, then copy the URL here</small>
          </div>
        </div>

        <div class="form-group" style="margin-bottom:12px">
          <label>Title</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_popup_showcase_title_en" placeholder="New on the menu"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_popup_showcase_title_ar" dir="rtl" placeholder="جديد في القائمة"><span class="bi-tag">عربي</span></div>
          </div>
        </div>

        <div class="form-group" style="margin-bottom:12px">
          <label>Body text</label>
          <div class="bi-pair">
            <div class="bi-field"><textarea id="s_popup_showcase_body_en" rows="2" placeholder="Try our new pistachio tarte"></textarea><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><textarea id="s_popup_showcase_body_ar" rows="2" dir="rtl" placeholder="جرب تارت الفستق الجديد"></textarea><span class="bi-tag">عربي</span></div>
          </div>
        </div>

        <div class="form-group" style="margin-bottom:12px">
          <label>Button label</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_popup_showcase_button_en" placeholder="View menu"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_popup_showcase_button_ar" dir="rtl" placeholder="عرض القائمة"><span class="bi-tag">عربي</span></div>
          </div>
        </div>
      </div>

      <!-- ==========================================================
           ORDERING & RECEIPT
           Where customer orders go (WhatsApp number), who gets
           notified (email), and what the printed receipt shows. -->
      <!-- ==========================================================
           PAYMENT METHODS & PLACEMENT MODE
           Controls which payment options the customer sees at
           checkout, and the master switch for whether WhatsApp
           ordering is allowed at all. -->
      <div class="settings-section">
        <div class="settings-section-title">Order placement mode</div>
        <div class="form-group" style="margin-bottom:12px">
          <label>How do customers place orders?</label>
          <select id="s_order_placement_mode" style="max-width:340px">
            <option value="both">Both — WhatsApp and online payment</option>
            <option value="payment_only">Online payment only (no WhatsApp)</option>
            <option value="whatsapp_only">WhatsApp only (legacy)</option>
          </select>
          <small style="color:#888;font-size:11px;display:block;margin-top:6px">
            Default during transition is "Both". Switch to "Online payment only" to eliminate ghost orders entirely.
          </small>
        </div>
      </div>

      <div class="settings-section">
        <div class="settings-section-title">Payment methods</div>
        <div class="form-group" style="margin-bottom:8px">
          <label style="display:flex;align-items:center;gap:10px;cursor:pointer">
            <input type="checkbox" id="s_payment_cash_enabled" style="width:auto;margin:0">
            💵 Cash on delivery
          </label>
          <small style="color:#888;font-size:11px;margin-left:24px">Customer chooses cash; staff sees the order immediately. Risk of fake orders — disable to avoid.</small>
        </div>
        <div class="form-group" style="margin-bottom:8px">
          <label style="display:flex;align-items:center;gap:10px;cursor:pointer">
            <input type="checkbox" id="s_payment_card_enabled" style="width:auto;margin:0">
            💳 KNET / Credit Card (MyFatoorah)
          </label>
          <small style="color:#888;font-size:11px;margin-left:24px">Routes through MyFatoorah hosted payment page. Configure credentials below.</small>
        </div>
        <div class="form-group" style="margin-bottom:8px">
          <label style="display:flex;align-items:center;gap:10px;cursor:pointer">
            <input type="checkbox" id="s_payment_counter_enabled" style="width:auto;margin:0">
            🏪 Pay at counter
          </label>
          <small style="color:#888;font-size:11px;margin-left:24px">Customer reserves the order; pays in person when collecting. Treated as confirmed for staff.</small>
        </div>
      </div>

      <div class="settings-section">
        <div class="settings-section-title">MyFatoorah credentials</div>
        <div class="form-grid">
          <div class="form-group">
            <label>Environment</label>
            <select id="s_myfatoorah_environment" style="max-width:200px">
              <option value="test">Test (sandbox)</option>
              <option value="live">Live (production)</option>
            </select>
          </div>
          <div class="form-group">
            <label>Country code</label>
            <input type="text" id="s_myfatoorah_country" placeholder="KWT" maxlength="3" style="max-width:120px">
            <small style="color:#888;font-size:11px">Use KWT for Kuwait. Test environment ignores this.</small>
          </div>
        </div>
        <div class="form-group" style="margin-bottom:12px">
          <label>API token</label>
          <input type="text" id="s_myfatoorah_token" placeholder="SK_KWT_…" style="font-family:monospace;font-size:12px">
          <small style="color:#888;font-size:11px">Get from MyFatoorah portal → Integration Settings → API Key. Defaults to the public test token.</small>
        </div>
        <div style="margin-top:8px">
          <button type="button" class="btn" onclick="testMyFatoorah()" style="font-size:12px;padding:6px 14px">
            🔌 Test connection
          </button>
          <span id="mfTestStatus" style="margin-left:10px;font-size:12px"></span>
        </div>
      </div>

      <!-- ==========================================================
           ORDERING & RECEIPT
           Where customer orders go (WhatsApp number), who gets
           notified (email), and what the printed receipt shows. -->
      <div class="settings-section">
        <div class="settings-section-title">Ordering &amp; WhatsApp</div>

        <div class="form-grid">
          <div class="form-group">
            <label>Branch WhatsApp number</label>
            <input type="text" id="s_whatsapp_number" placeholder="+96512345678">
            <small style="color:#888;font-size:11px">Include country code (e.g. +965…). Orders open in WhatsApp to this number.</small>
          </div>
          <div class="form-group">
            <label>Order number prefix</label>
            <input type="text" id="s_order_prefix" placeholder="LTK-" maxlength="10">
            <small style="color:#888;font-size:11px">Shown on receipts, e.g. LTK-1001</small>
          </div>
        </div>
      </div>

      <div class="settings-section">
        <div class="settings-section-title">Email notifications</div>
        <div class="form-group" style="margin-bottom:12px">
          <label style="display:flex;align-items:center;gap:10px;cursor:pointer">
            <input type="checkbox" id="s_order_email_enabled" style="width:auto;margin:0">
            Send an email copy of every order
          </label>
        </div>
        <div class="form-grid">
          <div class="form-group">
            <label>Recipient email address(es)</label>
            <input type="text" id="s_order_email_to" placeholder="orders@latartekw.com">
            <small style="color:#888;font-size:11px">Comma-separate for multiple, e.g. owner + kitchen</small>
            <div style="margin-top:8px">
              <button type="button" class="btn" onclick="sendTestEmail()" style="font-size:12px;padding:6px 14px">
                ✉ Send test email
              </button>
              <span id="testEmailStatus" style="margin-left:10px;font-size:12px"></span>
            </div>
          </div>
          <div class="form-group">
            <label>From address (optional)</label>
            <input type="text" id="s_order_email_from" placeholder="noreply@latartekw.com">
            <small style="color:#888;font-size:11px">Must be a verified sender on this server</small>
          </div>
        </div>
        <div class="form-group" style="margin-bottom:12px">
          <label>Abandonment report email (optional)</label>
          <input type="text" id="s_abandonment_report_to" placeholder="owner@latartekw.com">
          <small style="color:#888;font-size:11px">Separate address for a weekly digest of customers who placed orders but never sent WhatsApp. Leave blank to disable.</small>
        </div>
      </div>

      <div class="settings-section">
        <div class="settings-section-title">Printed receipt header</div>

        <div class="form-group" style="margin-bottom:12px">
          <label>Restaurant name on receipt</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_receipt_header_en" placeholder="LA TARTE TROPÉZIENNE"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_receipt_header_ar" dir="rtl" placeholder="لا تارت تروبيزيان"><span class="bi-tag">عربي</span></div>
          </div>
        </div>

        <div class="form-group" style="margin-bottom:12px">
          <label>Address line</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_receipt_address_en" placeholder="Kuwait City, Kuwait"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_receipt_address_ar" dir="rtl" placeholder="مدينة الكويت"><span class="bi-tag">عربي</span></div>
          </div>
        </div>

        <div class="form-grid">
          <div class="form-group">
            <label>Phone on receipt</label>
            <input type="text" id="s_receipt_phone" placeholder="+965 0000 0000">
          </div>
        </div>

        <div class="form-group" style="margin-bottom:12px">
          <label>Footer message</label>
          <div class="bi-pair">
            <div class="bi-field"><input type="text" id="s_receipt_footer_en" placeholder="Thank you for your order!"><span class="bi-tag">EN</span></div>
            <div class="bi-field" data-lang="ar"><input type="text" id="s_receipt_footer_ar" dir="rtl" placeholder="شكرًا لطلبكم!"><span class="bi-tag">عربي</span></div>
          </div>
        </div>
      </div>

      <div class="form-actions"><button class="btn btn-primary" onclick="saveSettings()">Save settings</button></div>
    </div>

    <div class="card">
      <div class="card-header"><div class="card-title">Change password</div></div>
      <div class="form-grid">
        <div class="form-group"><label>Current password</label><input type="password" id="pw_current"></div>
        <div class="form-group" style="grid-column:1/-1"></div>
        <div class="form-group"><label>New password</label><input type="password" id="pw_new"></div>
        <div class="form-group"><label>Confirm new</label><input type="password" id="pw_confirm"></div>
      </div>
      <div class="form-actions"><button class="btn btn-primary" onclick="changePassword()">Update password</button></div>
    </div>
  </div>

</div><!-- /main -->

<!-- CATEGORY MODAL — now bilingual -->
<div class="modal-overlay" id="catModal">
  <div class="modal-box">
    <div class="modal-head">
      <div class="modal-title" id="catModalTitle">Add category</div>
      <button class="modal-close" onclick="closeCatModal()">&#x2715;</button>
    </div>
    <input type="hidden" id="cat_id">
    <div class="form-group" style="margin-bottom:12px">
      <label>Category name</label>
      <div class="bi-pair">
        <div class="bi-field"><input type="text" id="cat_name" placeholder="e.g. Starters"><span class="bi-tag">EN</span></div>
        <div class="bi-field" data-lang="ar"><input type="text" id="cat_name_ar" dir="rtl" placeholder="مثال: المقبلات"><span class="bi-tag">عربي</span></div>
      </div>
    </div>
    <div class="form-grid">
      <div class="form-group"><label>Sort order</label><input type="number" id="cat_order" value="0" min="0"></div>
      <div class="form-group"><label>Status</label>
        <select id="cat_active"><option value="1">Active</option><option value="0">Hidden</option></select>
      </div>
    </div>

    <!-- Optional category header image — shows as a banner above
         the category items on the customer menu. If omitted, the
         menu falls back to a bold typography header (cleaner default). -->
    <div class="form-group" style="margin-bottom:12px">
      <label>Header image (optional)</label>
      <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
        <input type="url" id="cat_header_image" placeholder="https://... (paste URL or upload below)" style="flex:1;min-width:200px">
        <label class="btn btn-sm" style="cursor:pointer">Upload <input type="file" id="cat_header_file" accept="image/*" style="display:none" onchange="uploadCatHeader()"></label>
        <button type="button" class="btn btn-sm" onclick="openBrowseModal('image', 'cat_header_image')">Browse</button>
      </div>
      <small style="color:#888;font-size:11px">Leave blank to use a bold text header instead. Banner displays full-width on mobile, recommended size 1600×500px.</small>
      <div id="cat_header_preview" style="margin-top:8px"></div>
    </div>

    <!-- Optional video header. Plays muted on loop when the
         section enters the customer's viewport. If both image and
         video are set, the image acts as the video's poster (shown
         while video loads + fallback if autoplay blocked). Keep
         videos under 5 MB and 6 seconds for fast load. -->
    <div class="form-group" style="margin-bottom:12px">
      <label>Header video (optional)</label>
      <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
        <input type="url" id="cat_header_video" placeholder="https://... (.mp4 file)" style="flex:1;min-width:200px">
        <label class="btn btn-sm" style="cursor:pointer">Upload <input type="file" id="cat_header_video_file" accept="video/mp4,video/webm" style="display:none" onchange="uploadCatVideo()"></label>
        <button type="button" class="btn btn-sm" onclick="openBrowseModal('video', 'cat_header_video')">Browse</button>
      </div>
      <small style="color:#888;font-size:11px">MP4 only, muted &amp; auto-loop. Compress with HandBrake to under 5 MB before uploading. The image above acts as the video's poster image.</small>
      <div id="cat_video_preview" style="margin-top:8px"></div>
    </div>

    <div class="form-actions">
      <!-- Delete button (new — wires up the existing delete_category endpoint) -->
      <button class="btn btn-danger btn-sm" id="deleteCatBtn" onclick="deleteCategory()" style="margin-right:auto;display:none">Delete category</button>
      <button class="btn" onclick="closeCatModal()">Cancel</button>
      <button class="btn btn-primary" onclick="saveCategory()">Save category</button>
    </div>
  </div>
</div>

<!-- ITEM MODAL — now bilingual -->
<div class="modal-overlay" id="itemModal">
  <div class="modal-box">
    <div class="modal-head">
      <div class="modal-title" id="itemModalTitle">Add menu item</div>
      <button class="modal-close" onclick="closeItemModal()">&#x2715;</button>
    </div>
    <input type="hidden" id="item_id">
    <div class="form-grid">
      <div class="form-group"><label>Primary category</label>
        <select id="item_cat" onchange="onPrimaryCatChange()"></select>
      </div>
      <div class="form-group"><label>Badge</label>
        <select id="item_badge"><option value="">None</option><option value="popular">Popular</option><option value="spicy">Spicy</option><option value="veg">Veg</option></select>
      </div>

      <!-- Multi-category: pick additional categories this item
           should ALSO appear in on the customer menu. The primary
           category above is always included; these are extras.
           The list is built by JS from the categories list, with
           the primary category itself excluded/disabled. -->
      <div class="form-group full">
        <label>Also appears in
          <span style="color:var(--muted);font-weight:normal;font-size:11px">— optional extra categories</span>
        </label>
        <div id="item_extra_cats" style="display:flex;flex-wrap:wrap;gap:8px 16px;padding:8px 0"></div>
      </div>

      <!-- Branch availability (Brand B / multi_branch mode only).
           Which branches carry this item. "All branches" master
           toggle + per-branch checkboxes. Hidden entirely when
           site_mode is single_location. -->
      <div class="form-group full" id="item_branches_group" style="display:none">
        <label>Available at branches
          <span style="color:var(--muted);font-weight:normal;font-size:11px">— untick branches that don't carry this item</span>
        </label>
        <label style="display:flex;align-items:center;gap:8px;font-weight:500;cursor:pointer;margin:6px 0">
          <input type="checkbox" id="item_all_branches" onchange="onAllBranchesToggle()"> All branches
        </label>
        <div id="item_branches" style="display:flex;flex-wrap:wrap;gap:8px 16px;padding:4px 0 8px 22px"></div>
      </div>

      <!-- Per-mode availability (Brand B). Whether the item can be
           ordered for delivery / pickup / dine-in. Hidden in
           single_location mode. -->
      <div class="form-group full" id="item_modes_group" style="display:none">
        <label>Available for
          <span style="color:var(--muted);font-weight:normal;font-size:11px">— fulfilment modes this item can be ordered for</span>
        </label>
        <div style="display:flex;flex-wrap:wrap;gap:8px 20px;padding:8px 0">
          <label style="display:flex;align-items:center;gap:6px;font-weight:normal;cursor:pointer">
            <input type="checkbox" id="item_mode_delivery" checked> Delivery
          </label>
          <label style="display:flex;align-items:center;gap:6px;font-weight:normal;cursor:pointer">
            <input type="checkbox" id="item_mode_pickup" checked> Pickup
          </label>
          <label style="display:flex;align-items:center;gap:6px;font-weight:normal;cursor:pointer">
            <input type="checkbox" id="item_mode_dinein" checked> Dine-in
          </label>
        </div>
      </div>

      <!-- Item name: bilingual pair -->
      <div class="form-group full">
        <label>Item name</label>
        <div class="bi-pair">
          <div class="bi-field"><input type="text" id="item_name" placeholder="e.g. Garden grain bowl"><span class="bi-tag">EN</span></div>
          <div class="bi-field" data-lang="ar"><input type="text" id="item_name_ar" dir="rtl" placeholder="مثال: طبق الحبوب"><span class="bi-tag">عربي</span></div>
        </div>
      </div>

      <!-- Description: bilingual pair -->
      <div class="form-group full">
        <label>Description</label>
        <div class="bi-pair">
          <div class="bi-field"><textarea id="item_desc" placeholder="Ingredients, preparation style…"></textarea><span class="bi-tag">EN</span></div>
          <div class="bi-field" data-lang="ar"><textarea id="item_desc_ar" dir="rtl" placeholder="المكونات، طريقة التحضير…"></textarea><span class="bi-tag">عربي</span></div>
        </div>
      </div>

      <div class="form-group"><label>Base price</label><input type="number" id="item_price" step="0.001" min="0" placeholder="0.000"></div>
      <div class="form-group"><label>Status</label>
        <select id="item_active"><option value="1">Active</option><option value="0">Hidden</option></select>
      </div>
      <div class="form-group full" style="background:#fafafa;border-radius:6px;padding:10px 12px">
        <label style="margin-bottom:6px">Show this item on:</label>
        <div style="display:flex;gap:18px;flex-wrap:wrap">
          <label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:500">
            <input type="checkbox" id="item_show_in_ordering" style="width:auto;margin:0">
            <span>🛒 Ordering site <small style="color:#888;font-weight:normal">(/order)</small></span>
          </label>
          <label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:500">
            <input type="checkbox" id="item_show_in_showcase" style="width:auto;margin:0">
            <span>📋 Display menu <small style="color:#888;font-weight:normal">(/menu)</small></span>
          </label>
        </div>
        <small style="color:#888;display:block;margin-top:6px">Both default to ON for new items. Untick to hide from one side without removing the item entirely. The "Status" dropdown above hides from both at once.</small>
      </div>
      <div class="form-group full">
        <label>Main photo <span style="color:var(--muted);font-weight:normal">(shown in grid)</span></label>
        <div style="display:flex;gap:10px;align-items:flex-start;flex-wrap:wrap">
          <input type="url" id="item_photo" placeholder="https://... (paste URL or upload below)" style="flex:1;min-width:200px">
          <label class="btn btn-sm" style="cursor:pointer">Upload <input type="file" id="item_photo_file" accept="image/*" style="display:none" onchange="uploadPhoto()"></label>
          <button type="button" class="btn btn-sm" onclick="openBrowseModal('image', 'item_photo')">Browse</button>
        </div>
        <!-- Crop position controls how `object-fit: cover` anchors
             the photo when it's cropped to fit the frame. Default
             "bottom" works for most phone-shot food photos
             (food in lower portion of the frame). The preview
             below mirrors the customer-side rendering so the admin
             can verify before saving. -->
        <div style="display:flex;gap:10px;align-items:center;margin-top:8px;font-size:13px">
          <label for="item_photo_position" style="color:#555">Crop:</label>
          <select id="item_photo_position" onchange="refreshPhotoPreview()" style="padding:4px 8px">
            <option value="top">Top</option>
            <option value="center">Center</option>
            <option value="bottom" selected>Bottom (default)</option>
          </select>
          <span style="color:#888;font-size:11px">
            Preview below shows how customers see the photo cropped to a 4:3 frame.
          </span>
        </div>
        <div id="photoPreviewWrap" style="margin-top:8px;display:none">
          <!-- This frame matches the customer modal's 4:3 aspect ratio
               so the admin sees exactly what the customer will see. -->
          <div id="photoPreviewFrame" style="width:240px;aspect-ratio:4/3;background:#1a1410;border-radius:6px;overflow:hidden;border:1px solid #e5e5e5">
            <img id="photoPreview" src="" style="width:100%;height:100%;object-fit:cover;display:block;object-position:center bottom">
          </div>
        </div>
      </div>
    </div>

    <!-- Additional gallery photos: shown in a swipeable gallery
         in the customer-facing detail modal when the item has
         more than just its main photo. Each row is a single URL
         with upload-and-remove controls. -->
    <div style="margin-top:1rem">
      <div style="font-size:12px;font-weight:500;color:#555;margin-bottom:4px">Additional photos <span style="color:var(--muted);font-weight:normal">(for packaging, alternate angles, etc.)</span></div>
      <div style="font-size:11px;color:var(--muted);margin-bottom:8px">Customers swipe through these in the item detail view. The main photo above is always shown first.</div>
      <div class="mod-list" id="photosList"></div>
      <button class="add-mod-btn" onclick="addPhotoRow()">+ Add photo</button>
    </div>

    <!-- Sizes: each row now has an English label, an Arabic label, a price, and a remove button -->
    <div style="margin-top:1rem">
      <div style="font-size:12px;font-weight:500;color:#555;margin-bottom:8px">Sizes</div>
      <div class="mod-head">
        <div>Label (EN)</div><div>Label (عربي)</div><div>+ Price</div><div></div>
      </div>
      <div class="mod-list" id="sizesList"></div>
      <button class="add-mod-btn" onclick="addSizeRow()">+ Add size</button>
    </div>

    <!-- Extras: same bilingual layout as sizes -->
    <div style="margin-top:1rem">
      <div style="font-size:12px;font-weight:500;color:#555;margin-bottom:8px">Extras / add-ons</div>
      <div class="mod-head">
        <div>Name (EN)</div><div>Name (عربي)</div><div>+ Price</div><div></div>
      </div>
      <div class="mod-list" id="extrasList"></div>
      <button class="add-mod-btn" onclick="addExtraRow()">+ Add extra</button>
    </div>

    <div class="form-actions">
      <button class="btn" onclick="closeItemModal()">Cancel</button>
      <button class="btn btn-danger btn-sm" id="deleteItemBtn" onclick="deleteItem()" style="margin-right:auto;display:none">Delete item</button>
      <button class="btn btn-primary" onclick="saveItem()">Save item</button>
    </div>
  </div>
</div>

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

<!-- ============================================================
     BROWSE EXISTING UPLOADS MODAL
     ============================================================
     Opened by "Browse" buttons next to each upload control. Lists
     files already in /uploads/ and lets the admin pick one to fill
     the URL field, instead of re-uploading the same file.
     Renders ABOVE other modals (z-index higher than catModal/itemModal).
============================================================ -->
<div class="modal-overlay" id="browseModal" style="z-index: 200">
  <div class="modal-box" style="max-width: 900px">
    <div class="modal-head">
      <div class="modal-title">Browse uploads</div>
      <button class="modal-close" onclick="closeBrowseModal()">&#x2715;</button>
    </div>
    <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:12px;font-size:13px">
      <span style="color:#666">Filter:</span>
      <button class="browse-chip active" data-filter="type" data-value="all"     onclick="setBrowseFilter('type','all',this)">All</button>
      <button class="browse-chip"        data-filter="type" data-value="image"   onclick="setBrowseFilter('type','image',this)">Images</button>
      <button class="browse-chip"        data-filter="type" data-value="video"   onclick="setBrowseFilter('type','video',this)">Videos</button>
      <span style="margin-left:12px;color:#666">Show:</span>
      <button class="browse-chip active" data-filter="usage" data-value="all"    onclick="setBrowseFilter('usage','all',this)">All files</button>
      <button class="browse-chip"        data-filter="usage" data-value="unused" onclick="setBrowseFilter('usage','unused',this)">Unused only</button>
      <span style="flex:1"></span>
      <span id="browseStats" style="color:#666;font-size:12px"></span>
    </div>
    <div id="browseGrid" class="browse-grid">
      <div style="grid-column:1/-1;text-align:center;color:#888;padding:40px">Loading...</div>
    </div>
  </div>
</div>

<style>
/* Drag handle on sortable rows. Subtle but obvious — uses a
   dotted-grip glyph that's universally recognized. Cursor change
   on hover. */
.drag-handle {
  cursor: grab;
  user-select: none;
  color: #999;
  padding: 0 4px;
  font-size: 14px;
  letter-spacing: -3px;  /* tighten the two ⋮ glyphs into a 2x3 grip */
  flex-shrink: 0;
}
.drag-handle:hover { color: #555; }
.drag-handle:active { cursor: grabbing; }
/* Highlight while dragging — SortableJS adds .sortable-ghost to
   the placeholder slot. We want it visible but not too loud. */
.sortable-ghost {
  opacity: 0.4;
  background: #fff8e1;
}
.sortable-chosen { background: #fffaf0; }

/* Browse modal grid of file thumbnails */
.browse-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 4px;
}
.browse-tile {
  border: 2px solid var(--border-soft, #ddd);
  border-radius: 6px;
  cursor: pointer;
  overflow: hidden;
  background: #fafafa;
  transition: border-color 0.15s, transform 0.15s;
  position: relative;
}
.browse-tile:hover {
  border-color: var(--accent, #c4362c);
  transform: translateY(-1px);
}
.browse-tile img,
.browse-tile video {
  width: 100%;
  height: 100px;
  object-fit: cover;
  display: block;
  background: #1a1410;
}
.browse-tile .tile-meta {
  padding: 6px 8px;
  font-size: 11px;
  line-height: 1.3;
}
.browse-tile .tile-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #333;
}
.browse-tile .tile-size {
  color: #888;
  font-size: 10px;
  margin-top: 2px;
}
.browse-tile.unused .tile-name::before {
  content: "● ";
  color: #d97706;
}
.browse-chip {
  background: #f3f4f6;
  border: 1px solid #e5e7eb;
  padding: 4px 12px;
  border-radius: 16px;
  font-size: 12px;
  cursor: pointer;
  color: #555;
}
.browse-chip:hover { background: #e9ebef; }
.browse-chip.active {
  background: var(--ink, #2a2420);
  border-color: var(--ink, #2a2420);
  color: #fff;
}
</style>

<!-- SortableJS — handles drag-and-drop reordering with proper
     touch support. ~10KB, no dependencies. Used to reorder
     categories, items within a category, and gallery photos. -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>

<script>
/* ============================================================
   Admin panel JavaScript — bilingual edition
   ============================================================
   The admin never switches languages; both English and Arabic
   fields are always visible. We just make sure every save/load
   carries the _ar fields through to the API. Arabic fields are
   optional — the customer menu will fall back to English when
   a translation is missing.
   ============================================================ */

let categories = [], allItems = [];

// ── Helpers ───────────────────────────────────────────────────
function toast(msg, ok = true) {
  const t = document.getElementById('toast');
  t.textContent = msg;
  t.style.background = ok ? '#1a1a1a' : '#e74c3c';
  t.classList.add('show');
  setTimeout(() => t.classList.remove('show'), 2800);
}

async function api(action, body = null, method = 'POST') {
  const opts = { method, headers: { 'Content-Type': 'application/json' } };
  if (body) opts.body = JSON.stringify(body);
  const r = await fetch('api.php?action=' + action, opts);
  return r.json();
}

async function apiGet(action, params = '') {
  const r = await fetch('api.php?action=' + action + '&' + params);
  return r.json();
}

// Small helper so the item table preview can show Arabic if present,
// falling back to English — same logic the customer menu uses.
function pickLabel(en, ar) {
  return (ar && ar.trim()) ? ar : (en || '');
}

// HTML-escape arbitrary text for safe insertion into element
// content. Prevents user-entered characters like < > & " from
// breaking the page or being interpreted as markup.
function escHtml(s) {
  return (s == null ? '' : String(s))
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');
}
// Escape for values that sit inside HTML attributes (src, class,
// data-*). Same replacements but kept as a separate function
// for clarity at call sites.
function escAttr(s) { return escHtml(s); }

function showPage(name) {
  document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
  document.querySelectorAll('.nav-tab').forEach(t => t.classList.remove('active'));
  document.getElementById('page-' + name).classList.add('active');
  document.querySelectorAll('.nav-tab').forEach(t => {
    if (t.textContent.toLowerCase().includes(name.toLowerCase().slice(0, 4))) t.classList.add('active');
  });
  if (name === 'categories') loadCategories();
  if (name === 'items')      loadItems();
  if (name === 'origins')    loadOrigins();
  if (name === 'settings')   loadSettings();
  if (name === 'users')      loadUsers();
  if (name === 'branches')   loadBranches();
  if (name === 'dashboard')  loadDashboard();
}

// ── Dashboard ─────────────────────────────────────────────────
async function loadDashboard() {
  // The dashboard's stat cards rely on menu data (categories +
  // items). A user without the 'menu' permission can't call those
  // endpoints (they'd 403), so we only build the menu stats when
  // the user actually has menu access. Order-only users get a
  // simple welcome instead.
  const perms = window.ADMIN_PERMS || {};
  const statsRow = document.getElementById('statsRow');

  if (perms.menu) {
    await loadCategories(false);
    await loadAllItems();
    const active    = allItems.filter(i => i.is_active == 1).length;
    const catActive = categories.filter(c => c.is_active == 1).length;
    statsRow.innerHTML = `
      <div class="stat"><div class="stat-label">Total items</div><div class="stat-val">${allItems.length}</div></div>
      <div class="stat"><div class="stat-label">Active items</div><div class="stat-val">${active}</div></div>
      <div class="stat"><div class="stat-label">Categories</div><div class="stat-val">${catActive}</div></div>`;
  } else {
    // No menu access — show a plain welcome card. Order-focused
    // users typically jump straight to the Orders page anyway.
    statsRow.innerHTML = `
      <div class="stat" style="grid-column:1/-1">
        <div class="stat-label">Welcome</div>
        <div class="stat-val" style="font-size:18px">Use the tabs above to get started</div>
      </div>`;
  }
}

// ── Categories ────────────────────────────────────────────────
async function loadCategories(render = true) {
  categories = await apiGet('list_categories');

  // Populate the category dropdowns (items filter + item modal).
  // This MUST happen regardless of `render` — loadItems() calls
  // loadCategories(false) to load the data without rebuilding the
  // categories table, and the dropdowns still need filling. If
  // this were below the `if (!render) return` line, opening Menu
  // Items first (right after login) would leave the filter
  // dropdown empty until the Categories tab was visited.
  const sel = document.getElementById('catFilter');
  if (sel) {
    sel.innerHTML = '<option value="">All categories</option>' +
      categories.map(c => `<option value="${c.id}">${escHtml(c.name)}</option>`).join('');
  }
  const sel2 = document.getElementById('item_cat');
  if (sel2) {
    sel2.innerHTML = categories.map(c => `<option value="${c.id}">${escHtml(c.name)}</option>`).join('');
  }

  if (!render) return;

  const tb = document.getElementById('catTableBody');
  // Same pattern as loadItems: data-id + event listener instead
  // of inlining JSON into onclick, which breaks on apostrophes
  // and other special characters.
  tb.innerHTML = categories.map(c => `
    <tr data-id="${c.id}">
      <td style="text-align:center"><span class="drag-handle" title="Drag to reorder">⋮⋮</span></td>
      <td style="font-weight:500">${escHtml(c.name)}</td>
      <td style="font-weight:500;direction:rtl;text-align:right">${c.name_ar ? escHtml(c.name_ar) : '<span style="color:var(--muted);font-weight:normal">—</span>'}</td>
      <td style="color:var(--muted)">${escHtml(c.slug)}</td>
      <td>${c.sort_order}</td>
      <td><span class="pill ${c.is_active == 1 ? 'pill-green' : 'pill-gray'}">${c.is_active == 1 ? 'Active' : 'Hidden'}</span></td>
      <td><button class="btn btn-sm edit-cat-btn" data-id="${c.id}">Edit</button></td>
    </tr>`).join('');

  tb.querySelectorAll('.edit-cat-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      const id = parseInt(btn.dataset.id, 10);
      const cat = categories.find(x => x.id == id);
      if (cat) openCatModal(cat);
    });
  });

  // Wire up drag-and-drop reordering on the categories table.
  // Re-initialized after every render so it picks up the new rows.
  initCategoriesSortable();
}

function openCatModal(c = null) {
  document.getElementById('catModal').classList.add('open');
  document.getElementById('catModalTitle').textContent = c ? 'Edit category' : 'Add category';
  document.getElementById('cat_id').value     = c ? c.id            : '';
  document.getElementById('cat_name').value   = c ? c.name          : '';
  document.getElementById('cat_name_ar').value = c ? (c.name_ar || '') : '';
  document.getElementById('cat_header_image').value = c ? (c.header_image_url || '') : '';
  document.getElementById('cat_header_video').value = c ? (c.header_video_url || '') : '';
  refreshCatHeaderPreview();
  refreshCatVideoPreview();
  document.getElementById('cat_order').value  = c ? c.sort_order    : 0;
  document.getElementById('cat_active').value = c ? c.is_active     : 1;
  // Show the delete button only when editing an existing category.
  document.getElementById('deleteCatBtn').style.display = c ? 'inline-flex' : 'none';
}
function closeCatModal() { document.getElementById('catModal').classList.remove('open'); }

async function saveCategory() {
  const id = document.getElementById('cat_id').value;
  const res = await api('save_category', {
    id: id || 0,
    name:       document.getElementById('cat_name').value,
    name_ar:    document.getElementById('cat_name_ar').value,
    header_image_url: document.getElementById('cat_header_image').value,
    header_video_url: document.getElementById('cat_header_video').value,
    sort_order: document.getElementById('cat_order').value,
    is_active:  document.getElementById('cat_active').value
  });
  if (res.error) { toast(res.error, false); return; }
  toast('Category saved');
  closeCatModal();
  loadCategories();
}

// Delete category (wires up the previously-orphaned delete_category endpoint).
// A category delete cascades to all its items via the foreign key — we warn
// the user clearly so they understand the consequence.
async function deleteCategory() {
  const id = document.getElementById('cat_id').value;
  if (!id) return;
  if (!confirm('Delete this category AND all its menu items? This cannot be undone.')) return;
  const res = await api('delete_category', { id });
  if (res.error) { toast(res.error, false); return; }
  toast('Category deleted');
  closeCatModal();
  loadCategories();
}

// ── Items ─────────────────────────────────────────────────────
async function loadAllItems() {
  allItems = await apiGet('list_items');
}

// Bulk visibility toggle. Applies to:
//   - All items in the currently selected category, OR
//   - All items everywhere (if no category filter selected)
//
// Confirmation dialog before doing anything destructive (set to 0)
// because flipping a flag for hundreds of items isn't easily undone.
async function bulkVisibility(field, value) {
  const filterCat = document.getElementById('catFilter').value;
  const scope = filterCat
    ? `the "${categories.find(c => c.id == filterCat)?.name || ''}" category`
    : 'EVERY item across all categories';
  const fieldLabel = (field === 'show_in_ordering') ? '🛒 Ordering site (/order)' : '📋 Display menu (/menu)';
  const action     = value ? 'show' : 'hide';
  if (!confirm(`This will ${action} ALL items in ${scope} on the ${fieldLabel}.\n\nContinue?`)) return;

  const res = await api('bulk_set_visibility', {
    category_id: filterCat || 0,
    field, value
  });
  if (res.error) { toast(res.error, false); return; }
  toast(`Updated ${res.updated} item${res.updated === 1 ? '' : 's'}`);
  loadItems();
}

async function loadItems() {
  await loadCategories(false);
  // In multi_branch mode the item editor needs the branch list to
  // build its "available at branches" checkboxes. Load it once.
  if (window.SITE_MODE === 'multi_branch' && !_branches.length) {
    _branches = await apiGet('list_branches');
  }
  const catId = document.getElementById('catFilter').value;
  const items = await apiGet('list_items', 'cat=' + catId);
  allItems = items;

  const tb = document.getElementById('itemTableBody');
  // IMPORTANT: we pass the item ID via a data-id attribute and
  // look the item up from allItems on click, rather than trying
  // to inline a JSON-serialized item object into the onclick
  // attribute. That old approach broke whenever item names or
  // descriptions contained apostrophes (e.g. "Baby Trop'") —
  // the apostrophe terminated the attribute delimiter and the
  // button silently failed to register its handler.
  tb.innerHTML = items.map(i => `
    <tr data-id="${i.id}" data-cat-id="${i.category_id}">
      <td style="text-align:center"><span class="drag-handle" title="Drag to reorder within category">⋮⋮</span></td>
      <td>${i.photo_url ? `<img class="photo-preview" src="${escAttr(i.photo_url)}" onerror="this.style.display='none'">` : '<div class="photo-placeholder-box">No photo</div>'}</td>
      <td style="font-weight:500">
        ${escHtml(i.name)}
        ${i.name_ar ? `<div style="font-size:11px;color:var(--muted);direction:rtl;text-align:left">${escHtml(i.name_ar)}</div>` : ''}
      </td>
      <td style="color:var(--muted)">${escHtml(i.category_name)}</td>
      <td>${parseFloat(i.base_price).toFixed(3)}</td>
      <td>
        <span class="vis-pill ${i.show_in_ordering == 1 ? 'on' : 'off'}"
              data-id="${i.id}" data-field="show_in_ordering"
              title="Click to toggle ordering visibility">🛒</span>
        <span class="vis-pill ${i.show_in_showcase == 1 ? 'on' : 'off'}"
              data-id="${i.id}" data-field="show_in_showcase"
              title="Click to toggle display menu visibility">📋</span>
      </td>
      <td><span class="pill ${i.is_active == 1 ? 'pill-green' : 'pill-gray'}">${i.is_active == 1 ? 'Active' : 'Hidden'}</span></td>
      <td><button class="btn btn-sm edit-item-btn" data-id="${i.id}">Edit</button></td>
    </tr>`).join('');

  // Wire up the visibility toggle pills.
  tb.querySelectorAll('.vis-pill').forEach(p => {
    p.addEventListener('click', async () => {
      const id    = parseInt(p.dataset.id, 10);
      const field = p.dataset.field;
      const newValue = p.classList.contains('on') ? 0 : 1;
      const res = await api('set_item_visibility', { id, field, value: newValue });
      if (res.error) { toast(res.error, false); return; }
      // Optimistic UI update — no need to refetch the whole table
      p.classList.toggle('on');
      p.classList.toggle('off');
      const item = allItems.find(x => x.id == id);
      if (item) item[field] = newValue;
    });
  });

  // Update the "Bulk applies to..." label so the user knows what
  // scope the bulk buttons will affect.
  const filterCat = document.getElementById('catFilter').value;
  const scopeLabel = filterCat
    ? `applies to "${categories.find(c => c.id == filterCat)?.name || ''}" (${allItems.length} items)`
    : `applies to ALL ${allItems.length} items across every category`;
  document.getElementById('bulkScope').textContent = scopeLabel;

  // Wire up all the edit buttons. querySelectorAll + forEach is
  // the robust alternative to inline onclick attributes.
  tb.querySelectorAll('.edit-item-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      const id = parseInt(btn.dataset.id, 10);
      const item = allItems.find(x => x.id == id);
      if (item) openItemModal(item);
    });
  });

  // Wire up drag-and-drop reordering. Re-initialized after every
  // render so it picks up the new rows. Cross-category drags are
  // vetoed inside initItemsSortable.
  initItemsSortable();
}

function openItemModal(item = null) {
  loadCategories(false).then(() => {
    document.getElementById('itemModal').classList.add('open');
    document.getElementById('itemModalTitle').textContent = item ? 'Edit item' : 'Add item';

    // Fill all scalar fields (English + Arabic).
    document.getElementById('item_id').value       = item ? item.id                         : '';
    document.getElementById('item_cat').value      = item ? item.category_id                : (categories[0]?.id || '');
    document.getElementById('item_name').value     = item ? item.name                       : '';
    document.getElementById('item_name_ar').value  = item ? (item.name_ar || '')            : '';
    document.getElementById('item_desc').value     = item ? (item.description || '')        : '';
    document.getElementById('item_desc_ar').value  = item ? (item.description_ar || '')     : '';
    document.getElementById('item_price').value    = item ? parseFloat(item.base_price).toFixed(3) : '';
    document.getElementById('item_badge').value    = item ? (item.badge || '')              : '';
    document.getElementById('item_active').value   = item ? item.is_active                  : 1;
    // Visibility flags. Default to checked for new items (since 99%
    // of items will be visible everywhere). For existing items, fall
    // back to checked if the field is missing — handles the case
    // where the migration ran but old admin code still served stale
    // item objects.
    document.getElementById('item_show_in_ordering').checked =
      !item || (item.show_in_ordering ?? 1) == 1;
    document.getElementById('item_show_in_showcase').checked =
      !item || (item.show_in_showcase ?? 1) == 1;
    document.getElementById('item_photo').value    = item ? (item.photo_url || '')          : '';
    // Photo crop position. Defaults to 'bottom' for new items.
    document.getElementById('item_photo_position').value =
      (item && item.photo_position) ? item.photo_position : 'bottom';

    // Photo preview — frame uses the same 4:3 crop as customer
    // modal, so what admin sees is what customer sees.
    refreshPhotoPreview();

    // Delete button only visible when editing
    document.getElementById('deleteItemBtn').style.display = item ? 'inline-flex' : 'none';

    // Reset then populate size rows (default: one empty "Regular" row for new items).
    const sl = document.getElementById('sizesList');
    sl.innerHTML = '';
    (item?.sizes || [{ label: 'Regular', label_ar: '', price_add: 0 }])
      .forEach(s => addSizeRow(s.label, s.label_ar, s.price_add));

    // Reset then populate extras rows.
    const el = document.getElementById('extrasList');
    el.innerHTML = '';
    (item?.extras || []).forEach(e => addExtraRow(e.name, e.name_ar, e.price));

    // Reset then populate the additional-photos gallery list.
    // Each saved photo is identified by its URL; the admin can
    // add new ones or remove existing ones before saving.
    const pl = document.getElementById('photosList');
    pl.innerHTML = '';
    (item?.photos || []).forEach(p => addPhotoRow(p.url || '', p.is_video || 0));

    // Enable drag-to-reorder on the gallery list. Order is read
    // from the DOM at save time, so we don't post anything here —
    // SortableJS just rearranges the rows visually.
    initGallerySortable();

    // Build the "also appears in" checkboxes. extra_category_ids
    // comes from the API for existing items; empty for new ones.
    renderExtraCats(item ? (item.extra_category_ids || []) : []);

    // Branch + mode controls — only meaningful in multi_branch mode.
    // For a new item, default to ALL branches (Q12) and all modes.
    if (window.SITE_MODE === 'multi_branch') {
      document.getElementById('item_branches_group').style.display = '';
      document.getElementById('item_modes_group').style.display = '';
      const branchIds = item
        ? (item.branch_ids || [])
        : _branches.map(b => b.id);   // new item → all branches
      renderItemBranches(branchIds);
      // Mode flags — default all-on for new items.
      document.getElementById('item_mode_delivery').checked =
        item ? item.mode_delivery == 1 : true;
      document.getElementById('item_mode_pickup').checked =
        item ? item.mode_pickup == 1 : true;
      document.getElementById('item_mode_dinein').checked =
        item ? item.mode_dinein == 1 : true;
    } else {
      document.getElementById('item_branches_group').style.display = 'none';
      document.getElementById('item_modes_group').style.display = 'none';
    }
  });
}

// Render the per-branch checkboxes in the item editor. `checkedIds`
// is the array of branch IDs this item is currently assigned to.
function renderItemBranches(checkedIds) {
  const wrap = document.getElementById('item_branches');
  const checked = (checkedIds || []).map(Number);
  if (!_branches.length) {
    wrap.innerHTML = '<span style="color:var(--muted);font-size:12px">No branches defined.</span>';
    return;
  }
  wrap.innerHTML = _branches.map(b => `
    <label style="display:flex;align-items:center;gap:6px;font-weight:normal;cursor:pointer;font-size:13px">
      <input type="checkbox" class="item-branch-cb" value="${b.id}"
        ${checked.includes(b.id) ? 'checked' : ''} onchange="syncAllBranchesToggle()">
      ${escHtml(b.name)}
    </label>`).join('');
  syncAllBranchesToggle();
}

// "All branches" master toggle → ticks/unticks every branch box.
function onAllBranchesToggle() {
  const on = document.getElementById('item_all_branches').checked;
  document.querySelectorAll('.item-branch-cb').forEach(cb => { cb.checked = on; });
}

// Keep the "All branches" master in sync: checked only when every
// individual branch box is checked.
function syncAllBranchesToggle() {
  const boxes = Array.from(document.querySelectorAll('.item-branch-cb'));
  const all = boxes.length > 0 && boxes.every(cb => cb.checked);
  document.getElementById('item_all_branches').checked = all;
}

// Render the "also appears in" category checkboxes. The currently
// selected primary category is skipped (an item is always in its
// primary, so offering it as an "extra" would be confusing).
// `checkedIds` is the array of category IDs already linked.
function renderExtraCats(checkedIds) {
  const wrap = document.getElementById('item_extra_cats');
  const primaryId = parseInt(document.getElementById('item_cat').value, 10);
  const checked = (checkedIds || []).map(Number);
  const others = categories.filter(c => c.id !== primaryId);
  if (!others.length) {
    wrap.innerHTML = '<span style="color:var(--muted);font-size:12px">No other categories available.</span>';
    return;
  }
  wrap.innerHTML = others.map(c => `
    <label style="display:flex;align-items:center;gap:6px;font-weight:normal;cursor:pointer;font-size:13px">
      <input type="checkbox" class="extra-cat-cb" value="${c.id}"
        ${checked.includes(c.id) ? 'checked' : ''}>
      ${escHtml(c.name || ('Category ' + c.id))}
    </label>`).join('');
}

// When the primary category changes, re-render the extra-category
// list so the new primary is excluded. We preserve any already-
// ticked boxes that are still valid.
function onPrimaryCatChange() {
  const stillChecked = Array.from(document.querySelectorAll('.extra-cat-cb'))
    .filter(cb => cb.checked).map(cb => parseInt(cb.value, 10));
  renderExtraCats(stillChecked);
}

function closeItemModal() { document.getElementById('itemModal').classList.remove('open'); }

// Each size row has four inputs now: English label, Arabic label, price, remove.
function addSizeRow(label = '', labelAr = '', priceAdd = 0) {
  const row = document.createElement('div');
  row.className = 'mod-row';
  row.innerHTML = `
    <input type="text" placeholder="Large"               value="${(label || '').replace(/"/g,'&quot;')}">
    <input type="text" dir="rtl" class="ar" placeholder="كبير" value="${(labelAr || '').replace(/"/g,'&quot;')}">
    <input type="number" class="price" placeholder="0.000" step="0.001" min="0" value="${parseFloat(priceAdd || 0).toFixed(3)}">
    <button class="btn btn-icon" onclick="this.parentNode.remove()">&#x2715;</button>`;
  document.getElementById('sizesList').appendChild(row);
}

function addExtraRow(name = '', nameAr = '', price = 0) {
  const row = document.createElement('div');
  row.className = 'mod-row';
  row.innerHTML = `
    <input type="text" placeholder="Add avocado"            value="${(name || '').replace(/"/g,'&quot;')}">
    <input type="text" dir="rtl" class="ar" placeholder="إضافة أفوكادو" value="${(nameAr || '').replace(/"/g,'&quot;')}">
    <input type="number" class="price" placeholder="0.000" step="0.001" min="0" value="${parseFloat(price || 0).toFixed(3)}">
    <button class="btn btn-icon" onclick="this.parentNode.remove()">&#x2715;</button>`;
  document.getElementById('extrasList').appendChild(row);
}

// Add a row to the gallery-photos list. Each row: thumbnail,
// URL input, upload button, remove button. Typing into the URL
// input live-updates the thumbnail. The upload button uses a
// hidden file input — clicking it forwards to the browser's
// native file picker, and the uploaded URL is written back
// into the row's URL input.
function addPhotoRow(url = '', isVideo = 0) {
  const row = document.createElement('div');
  row.className = 'photo-row';
  // Each row gets a unique id so its child inputs can find one
  // another via querySelector; avoids brittle sibling-traversal.
  // We also stash is_video on the row's dataset so the saver can
  // round-trip it without inferring from URL extension.
  const rid = 'phr_' + Math.random().toString(36).slice(2, 8);
  row.id = rid;
  row.dataset.isVideo = isVideo ? '1' : '0';
  // Auto-detect is_video from URL extension when admin pastes
  // a URL directly. Server enforces actual file type at upload.
  const detectVideo = (u) => /\.(mp4|webm|mov)(\?|#|$)/i.test(u || '');
  if (!isVideo && detectVideo(url)) row.dataset.isVideo = '1';

  const thumb = url
    ? (row.dataset.isVideo === '1'
        ? `<video class="thumb" src="${url.replace(/"/g,'&quot;')}" muted></video>`
        : `<img class="thumb" src="${url.replace(/"/g,'&quot;')}" onerror="this.outerHTML='<div class=thumb-ph>?</div>'">`)
    : `<div class="thumb-ph">+</div>`;

  row.innerHTML = `
    <span class="drag-handle" title="Drag to reorder">⋮⋮</span>
    ${thumb}
    <input type="url" placeholder="https://..." value="${url.replace(/"/g,'&quot;')}">
    <label class="btn btn-sm" style="cursor:pointer">Upload
      <input type="file" accept="image/*,video/mp4,video/webm" style="display:none"
             onchange="uploadGalleryPhoto(this, '${rid}')">
    </label>
    <button type="button" class="btn btn-sm" onclick="openBrowseModal('all', '${rid}', 'galleryRow')">Browse</button>
    <button class="btn btn-icon" onclick="this.closest('.photo-row').remove()">&#x2715;</button>`;

  // When the URL input changes, refresh the thumbnail so the
  // admin can sanity-check that the URL resolves correctly.
  const urlInput = row.querySelector('input[type=url]');
  urlInput.addEventListener('input', () => {
    // Re-detect from extension on every edit so pasting an MP4
    // URL flips the row to video mode automatically.
    row.dataset.isVideo = detectVideo(urlInput.value) ? '1' : '0';
    refreshPhotoThumb(row);
  });

  document.getElementById('photosList').appendChild(row);
}

// Re-render the thumbnail portion of a gallery row based on the
// current URL input value. If the URL is empty we show a dashed
// placeholder; if it's set we show the image (which falls back
// to a placeholder if the image fails to load).
function refreshPhotoThumb(row) {
  const url = row.querySelector('input[type=url]').value.trim();
  const thumb = row.firstElementChild;
  if (!url) {
    thumb.outerHTML = '<div class="thumb-ph">+</div>';
  } else {
    const esc = url.replace(/"/g, '&quot;');
    // Video rows show a muted <video> as the thumbnail; image rows
    // show <img>. Either way, errors fall back to a "?" placeholder.
    if (row.dataset.isVideo === '1') {
      thumb.outerHTML = `<video class="thumb" src="${esc}" muted></video>`;
    } else {
      thumb.outerHTML = `<img class="thumb" src="${esc}" onerror="this.outerHTML='<div class=thumb-ph>?</div>'">`;
    }
  }
}

// Upload handler for a single gallery row. Now accepts both images
// and short videos. The server endpoint (api.php?action=upload_photo)
// supports kind=video which permits MP4/WebM. We sniff the file's
// MIME type to decide which kind to send and to flip the row's
// is_video flag for the on-save serialization.
async function uploadGalleryPhoto(fileInput, rowId) {
  const file = fileInput.files[0];
  if (!file) return;
  const isVideo = (file.type || '').startsWith('video/');
  const fd = new FormData();
  fd.append('photo', file);
  fd.append('kind', isVideo ? 'video' : 'photo');
  const r = await fetch('api.php?action=upload_photo', { method: 'POST', body: fd });
  const res = await r.json();
  if (res.url) {
    const row = document.getElementById(rowId);
    row.dataset.isVideo = isVideo ? '1' : '0';
    row.querySelector('input[type=url]').value = res.url;
    refreshPhotoThumb(row);
    toast(isVideo ? 'Video uploaded' : 'Photo uploaded');
  } else {
    toast(res.error || 'Upload failed', false);
  }
}

async function uploadPhoto() {
  const file = document.getElementById('item_photo_file').files[0];
  if (!file) return;
  const fd = new FormData(); fd.append('photo', file);
  const r = await fetch('api.php?action=upload_photo', { method: 'POST', body: fd });
  const res = await r.json();
  if (res.url) {
    document.getElementById('item_photo').value = res.url;
    refreshPhotoPreview();
    toast('Photo uploaded');
  } else toast(res.error || 'Upload failed', false);
}

document.getElementById('item_photo').addEventListener('input', refreshPhotoPreview);

// Refresh the item-photo preview thumb. Honors the chosen crop
// position so admin sees exactly what customers will see when
// the photo is cropped to 4:3 with `object-fit: cover`. Hides
// the preview frame when the URL field is empty.
function refreshPhotoPreview() {
  const url      = document.getElementById('item_photo').value;
  const position = document.getElementById('item_photo_position').value || 'bottom';
  const prev     = document.getElementById('photoPreview');
  const prevWrap = document.getElementById('photoPreviewWrap');
  if (url) {
    prev.src = url;
    prev.style.objectPosition = 'center ' + position;
    prevWrap.style.display = 'block';
  } else {
    prevWrap.style.display = 'none';
  }
}

// Upload + preview for the category banner image. Mirrors the
// item-photo flow but writes to a different field. Banner displays
// behind the category title on the customer menu when set.
async function uploadCatHeader() {
  const file = document.getElementById('cat_header_file').files[0];
  if (!file) return;
  const fd = new FormData(); fd.append('photo', file);
  const r = await fetch('api.php?action=upload_photo', { method: 'POST', body: fd });
  const res = await r.json();
  if (res.url) {
    document.getElementById('cat_header_image').value = res.url;
    refreshCatHeaderPreview();
    toast('Banner uploaded');
  } else toast(res.error || 'Upload failed', false);
}

function refreshCatHeaderPreview() {
  const url = document.getElementById('cat_header_image').value;
  const wrap = document.getElementById('cat_header_preview');
  if (!url) { wrap.innerHTML = ''; return; }
  wrap.innerHTML = '<img src="' + url + '" alt="" style="width:100%;max-width:400px;height:120px;object-fit:cover;border-radius:6px;border:1px solid #e5e5e5">';
}

document.getElementById('cat_header_image').addEventListener('input', refreshCatHeaderPreview);

// Upload + preview for the category header video. Mirrors the
// image flow but writes to header_video_url and also passes a
// video=1 hint to the upload endpoint so it allows MP4 mime types
// (the image-only endpoint rejects video uploads by default).
async function uploadCatVideo() {
  const file = document.getElementById('cat_header_video_file').files[0];
  if (!file) return;
  // Soft client-side check to catch obvious mistakes early. The
  // server enforces the real limit; this is just a courtesy.
  if (file.size > 8 * 1024 * 1024) {
    if (!confirm('This video is ' + Math.round(file.size / 1024 / 1024) + ' MB. Recommended max is 5 MB for fast load. Upload anyway?')) return;
  }
  const fd = new FormData();
  fd.append('photo', file);   // endpoint param is named 'photo' for both
  fd.append('kind', 'video'); // hint so endpoint allows mp4/webm mime
  const r = await fetch('api.php?action=upload_photo', { method: 'POST', body: fd });
  const res = await r.json();
  if (res.url) {
    document.getElementById('cat_header_video').value = res.url;
    refreshCatVideoPreview();
    toast('Video uploaded');
  } else toast(res.error || 'Upload failed', false);
}

function refreshCatVideoPreview() {
  const url = document.getElementById('cat_header_video').value;
  const wrap = document.getElementById('cat_video_preview');
  if (!url) { wrap.innerHTML = ''; return; }
  // Inline preview — use the actual <video> element so admin can
  // confirm playback before saving. Muted + autoplay so it loops
  // silently in admin too.
  wrap.innerHTML = '<video src="' + url + '" muted autoplay loop playsinline ' +
                   'style="width:100%;max-width:400px;height:120px;object-fit:cover;border-radius:6px;border:1px solid #e5e5e5;background:#000"></video>';
}

document.getElementById('cat_header_video').addEventListener('input', refreshCatVideoPreview);

// Save item: collects both English and Arabic values for each size/extra row.
async function saveItem() {
  // Each .mod-row has inputs in order: [EN label, AR label, price, (button)].
  // We read them by index to keep the collection logic simple.
  const sizes = [...document.querySelectorAll('#sizesList .mod-row')].map(r => {
    const ins = r.querySelectorAll('input');
    return {
      label:     ins[0].value,
      label_ar:  ins[1].value,
      price_add: parseFloat(ins[2].value) || 0
    };
  }).filter(s => s.label); // drop blank rows

  const extras = [...document.querySelectorAll('#extrasList .mod-row')].map(r => {
    const ins = r.querySelectorAll('input');
    return {
      name:    ins[0].value,
      name_ar: ins[1].value,
      price:   parseFloat(ins[2].value) || 0
    };
  }).filter(e => e.name);

  // Gallery photos: collect every non-empty URL with its is_video
  // flag, in row order. Rows with blank URLs are dropped so the
  // admin doesn't have to manually remove empty rows before saving.
  const photos = [...document.querySelectorAll('#photosList .photo-row')]
    .map(r => ({
      url: r.querySelector('input[type=url]').value.trim(),
      is_video: r.dataset.isVideo === '1' ? 1 : 0,
    }))
    .filter(p => p.url);

  // Collect the ticked "also appears in" category IDs.
  const extraCategoryIds = Array.from(document.querySelectorAll('.extra-cat-cb'))
    .filter(cb => cb.checked)
    .map(cb => parseInt(cb.value, 10));

  // Base payload — fields common to both site modes.
  const payload = {
    id:             document.getElementById('item_id').value || 0,
    category_id:    document.getElementById('item_cat').value,
    name:           document.getElementById('item_name').value,
    name_ar:        document.getElementById('item_name_ar').value,
    description:    document.getElementById('item_desc').value,
    description_ar: document.getElementById('item_desc_ar').value,
    base_price:     parseFloat(document.getElementById('item_price').value) || 0,
    photo_url:      document.getElementById('item_photo').value,
    photo_position: document.getElementById('item_photo_position').value,
    badge:          document.getElementById('item_badge').value,
    is_active:      document.getElementById('item_active').value,
    show_in_ordering: document.getElementById('item_show_in_ordering').checked ? 1 : 0,
    show_in_showcase: document.getElementById('item_show_in_showcase').checked ? 1 : 0,
    sort_order:     0,
    extra_category_ids: extraCategoryIds,
    sizes, extras, photos
  };

  // Multi-branch only: branch assignment + per-mode flags.
  // We send branch_ids ONLY in multi_branch mode — its presence
  // tells the API to rewrite item_branches. In single_location
  // mode we omit it entirely so the API leaves links untouched.
  if (window.SITE_MODE === 'multi_branch') {
    payload.branch_ids = Array.from(document.querySelectorAll('.item-branch-cb'))
      .filter(cb => cb.checked)
      .map(cb => parseInt(cb.value, 10));
    payload.mode_delivery = document.getElementById('item_mode_delivery').checked ? 1 : 0;
    payload.mode_pickup   = document.getElementById('item_mode_pickup').checked ? 1 : 0;
    payload.mode_dinein   = document.getElementById('item_mode_dinein').checked ? 1 : 0;
  }

  const res = await api('save_item', payload);
  if (res.error) { toast(res.error, false); return; }
  toast('Item saved');
  closeItemModal();
  loadItems();
}

async function deleteItem() {
  if (!confirm('Delete this item?')) return;
  const id = document.getElementById('item_id').value;
  await api('delete_item', { id });
  toast('Item deleted');
  closeItemModal();
  loadItems();
}

// ── Settings ──────────────────────────────────────────────────
async function loadSettings() {
  const s = await apiGet('get_settings');

  // Plain text settings (English and Arabic variants).
  const textKeys = [
    'restaurant_name', 'restaurant_name_ar',
    'restaurant_tagline', 'restaurant_tagline_ar',
    'logo_url', 'meta_description',
    'currency_code', 'currency_decimals',
    'default_language',
    // Popup text fields (title/body/button in both languages,
    // plus the media type and URL). Checkbox is handled below.
    'popup_media_type', 'popup_media_url',
    'popup_title_en',   'popup_title_ar',
    'popup_body_en',    'popup_body_ar',
    'popup_button_en',  'popup_button_ar',
    // Showcase popup (menu.latartekw.com)
    'popup_showcase_media_type', 'popup_showcase_media_url',
    'popup_showcase_title_en',   'popup_showcase_title_ar',
    'popup_showcase_body_en',    'popup_showcase_body_ar',
    'popup_showcase_button_en',  'popup_showcase_button_ar',
    // Ordering + email + receipt header
    'whatsapp_number',  'order_prefix',
    'order_email_to',   'order_email_from',
    'abandonment_report_to',
    // Payment gateway
    'order_placement_mode',
    'myfatoorah_token', 'myfatoorah_environment', 'myfatoorah_country',
    'receipt_header_en','receipt_header_ar',
    'receipt_address_en','receipt_address_ar',
    'receipt_phone',
    'receipt_footer_en','receipt_footer_ar'
  ];
  textKeys.forEach(k => {
    const el = document.getElementById('s_' + k);
    if (el) el.value = s[k] || '';
  });

  // Default language has a sensible fallback so the select isn't blank
  // even when the setting row is missing.
  document.getElementById('s_default_language').value = s['default_language'] || 'en';

  // Layout: tick the radio matching the saved value (or editorial as default).
  const layout = s['layout'] || 'editorial';
  const layoutRadio = document.querySelector(`input[name="s_layout"][value="${layout}"]`);
  if (layoutRadio) layoutRadio.checked = true;

  // Checkboxes: treat any truthy value as enabled.
  document.getElementById('s_popup_enabled').checked =
    (s['popup_enabled'] === '1' || s['popup_enabled'] === 1 || s['popup_enabled'] === true);
  document.getElementById('s_popup_showcase_enabled').checked =
    (s['popup_showcase_enabled'] === '1' || s['popup_showcase_enabled'] === 1 || s['popup_showcase_enabled'] === true);
  document.getElementById('s_order_email_enabled').checked =
    (s['order_email_enabled'] === '1' || s['order_email_enabled'] === 1 || s['order_email_enabled'] === true);
  // Payment method checkboxes — default to enabled when setting is missing
  // so admin sees the methods on first load (matches the SQL defaults).
  document.getElementById('s_payment_cash_enabled').checked =
    (s['payment_cash_enabled'] !== '0' && s['payment_cash_enabled'] !== 0);
  document.getElementById('s_payment_card_enabled').checked =
    (s['payment_card_enabled'] !== '0' && s['payment_card_enabled'] !== 0);
  document.getElementById('s_payment_counter_enabled').checked =
    (s['payment_counter_enabled'] !== '0' && s['payment_counter_enabled'] !== 0);

  // Refresh the popup media preview to match the loaded URL.
  refreshPopupPreview();

  // Color pickers + their matching hex text inputs.
  ['primary_color', 'accent_color'].forEach(k => {
    const v = s[k] || '#1a1a1a';
    document.getElementById('s_' + k).value       = v;
    document.getElementById('s_' + k + '_hex').value = v;
  });
}

// Keep the color picker and the hex text input in sync.
['primary_color', 'accent_color'].forEach(k => {
  document.getElementById('s_' + k)?.addEventListener('input', function () {
    document.getElementById('s_' + k + '_hex').value = this.value;
  });
  document.getElementById('s_' + k + '_hex')?.addEventListener('input', function () {
    if (/^#[0-9a-f]{6}$/i.test(this.value)) document.getElementById('s_' + k).value = this.value;
  });
});

// ---- Popup media preview & upload helpers ------------------
// Look at the currently-set media type + URL and show a
// thumbnail (image) or inline <video> preview so the admin
// knows exactly what the customer will see before saving.
function refreshPopupPreview() {
  const type = document.getElementById('s_popup_media_type').value;
  const url  = document.getElementById('s_popup_media_url').value.trim();
  const wrap = document.getElementById('popupPreviewWrap');
  if (!url || type === 'none') { wrap.style.display = 'none'; wrap.innerHTML = ''; return; }
  const safeUrl = url.replace(/"/g, '&quot;');
  wrap.style.display = 'block';
  if (type === 'video') {
    // Muted/autoplay/loop/playsinline replicates the customer view
    // so the admin sees real behaviour, including iOS-compatible
    // autoplay. Portrait videos render with a max-height so a very
    // tall clip doesn't blow out the settings card.
    wrap.innerHTML =
      `<video src="${safeUrl}" autoplay muted loop playsinline
              style="max-width:160px;max-height:240px;border-radius:8px;
                     border:1px solid var(--border);background:#000;display:block"></video>`;
  } else {
    wrap.innerHTML =
      `<img src="${safeUrl}" alt=""
            style="max-width:160px;max-height:240px;border-radius:8px;
                   border:1px solid var(--border);object-fit:cover;display:block"
            onerror="this.style.display='none'">`;
  }
}

// Re-render the preview whenever the URL or type changes.
document.getElementById('s_popup_media_url')?.addEventListener('input', refreshPopupPreview);
document.getElementById('s_popup_media_type')?.addEventListener('change', refreshPopupPreview);

// Upload handler for the popup media file input. We set
// kind=media so the server allows both images and videos.
// The returned URL is written into the URL field (so the
// admin can still edit it), the preview auto-refreshes, and
// the media type is auto-synced based on what was uploaded.
async function uploadPopupMedia() {
  const file = document.getElementById('popup_media_file').files[0];
  if (!file) return;
  const fd = new FormData();
  fd.append('file', file);
  const r = await fetch('api.php?action=upload_photo&kind=media', {
    method: 'POST', body: fd
  });
  const res = await r.json();
  if (res.url) {
    document.getElementById('s_popup_media_url').value = res.url;
    // Sync the media type selector to match what was actually uploaded.
    // res.kind is either 'image' or 'video' (set by the server).
    if (res.kind === 'video' || res.kind === 'image') {
      document.getElementById('s_popup_media_type').value = res.kind;
    }
    refreshPopupPreview();
    toast('Media uploaded');
  } else {
    toast(res.error || 'Upload failed', false);
  }
}

async function saveSettings() {
  // List every setting key we manage. The API upserts any keys we send,
  // so adding more later is just a matter of adding them to this list.
  const keys = [
    'restaurant_name', 'restaurant_name_ar',
    'restaurant_tagline', 'restaurant_tagline_ar',
    'logo_url', 'meta_description',
    'currency_code', 'currency_decimals',
    'default_language',
    'primary_color', 'accent_color',
    // Popup fields
    'popup_media_type', 'popup_media_url',
    'popup_title_en',   'popup_title_ar',
    'popup_body_en',    'popup_body_ar',
    'popup_button_en',  'popup_button_ar',
    // Showcase popup (menu.latartekw.com)
    'popup_showcase_media_type', 'popup_showcase_media_url',
    'popup_showcase_title_en',   'popup_showcase_title_ar',
    'popup_showcase_body_en',    'popup_showcase_body_ar',
    'popup_showcase_button_en',  'popup_showcase_button_ar',
    // Ordering + email + receipt header
    'whatsapp_number',  'order_prefix',
    'order_email_to',   'order_email_from',
    'abandonment_report_to',
    // Payment gateway
    'order_placement_mode',
    'myfatoorah_token', 'myfatoorah_environment', 'myfatoorah_country',
    'receipt_header_en','receipt_header_ar',
    'receipt_address_en','receipt_address_ar',
    'receipt_phone',
    'receipt_footer_en','receipt_footer_ar'
  ];
  const body = {};
  keys.forEach(k => {
    const el = document.getElementById('s_' + k);
    if (el) body[k] = el.value;
  });
  // Checkboxes → "1"/"0"
  body['popup_enabled']          = document.getElementById('s_popup_enabled').checked ? '1' : '0';
  body['popup_showcase_enabled'] = document.getElementById('s_popup_showcase_enabled').checked ? '1' : '0';
  body['order_email_enabled']    = document.getElementById('s_order_email_enabled').checked ? '1' : '0';
  body['payment_cash_enabled']    = document.getElementById('s_payment_cash_enabled').checked ? '1' : '0';
  body['payment_card_enabled']    = document.getElementById('s_payment_card_enabled').checked ? '1' : '0';
  body['payment_counter_enabled'] = document.getElementById('s_payment_counter_enabled').checked ? '1' : '0';

  // Layout: read the currently-checked radio in the layout group.
  const layoutRadio = document.querySelector('input[name="s_layout"]:checked');
  if (layoutRadio) body['layout'] = layoutRadio.value;

  const res = await api('save_settings', body);
  if (res.error) { toast(res.error, false); return; }
  toast('Settings saved');
}

async function changePassword() {
  const cur = document.getElementById('pw_current').value;
  const nw  = document.getElementById('pw_new').value;
  const cf  = document.getElementById('pw_confirm').value;
  if (nw !== cf) { toast('Passwords do not match', false); return; }
  const res = await api('change_password', { current: cur, new: nw });
  if (res.error) { toast(res.error, false); return; }
  toast('Password updated');
  ['pw_current', 'pw_new', 'pw_confirm'].forEach(id => document.getElementById(id).value = '');
}

// Send a test email to whatever's in the recipient field. Shows
// the real result inline (including PHP error detail) so the admin
// can diagnose deliverability issues without placing a fake order.
//
// Workflow: admin fills in recipient, clicks Save Settings to
// persist it, THEN clicks Send test email. The test reads from
// the DB (not the form) so you can't test unsaved values —
// that's by design; it verifies the full end-to-end config.
async function sendTestEmail() {
  const statusEl = document.getElementById('testEmailStatus');
  statusEl.innerHTML = '<span style="color:#888">Sending…</span>';
  try {
    const res = await fetch('api.php?action=test_email', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'same-origin',
      body: '{}',
    });
    const data = await res.json();
    if (data.sent) {
      statusEl.innerHTML = '<span style="color:#16a34a">✓ Sent to ' + (data.to || '') +
        '. Check inbox and spam folder.</span>';
    } else if (data.skipped) {
      statusEl.innerHTML = '<span style="color:#b45309">⚠ Skipped: ' + data.skipped + '</span>';
    } else if (data.error) {
      statusEl.innerHTML = '<span style="color:#b91c1c">✗ Failed: ' + (data.error || 'unknown error') +
        '</span>';
    } else {
      statusEl.innerHTML = '<span style="color:#b91c1c">✗ Unknown response</span>';
    }
  } catch (e) {
    statusEl.innerHTML = '<span style="color:#b91c1c">✗ Request failed: ' + e.message + '</span>';
  }
}

// Verify MyFatoorah credentials work. Calls the admin API which
// in turn does a tiny test payment with the configured token. A
// green ✓ means auth succeeded; red ✗ means the token is wrong
// or the environment/country is mismatched.
//
// Workflow: admin types token, picks env+country, clicks Save,
// THEN clicks Test connection. The test reads from DB (not the
// form) — so unsaved values won't be tested. By design.
async function testMyFatoorah() {
  const statusEl = document.getElementById('mfTestStatus');
  statusEl.innerHTML = '<span style="color:#888">Testing…</span>';
  try {
    const res = await fetch('api.php?action=test_payment_connection', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'same-origin',
      body: '{}',
    });
    const data = await res.json();
    if (data.ok) {
      statusEl.innerHTML = '<span style="color:#16a34a">✓ Connected (' + (data.env || '?') + ' env)</span>';
    } else {
      statusEl.innerHTML = '<span style="color:#b91c1c">✗ ' + (data.error || 'connection failed') + '</span>';
    }
  } catch (e) {
    statusEl.innerHTML = '<span style="color:#b91c1c">✗ Request failed: ' + e.message + '</span>';
  }
}

// ── Close modals on overlay click ────────────────────────────
document.getElementById('catModal').addEventListener('click',  function (e) { if (e.target === this) closeCatModal();  });
document.getElementById('itemModal').addEventListener('click', function (e) { if (e.target === this) closeItemModal(); });

// ============================================================
// BROWSE EXISTING UPLOADS
// ============================================================
// State for the Browse modal. While open, _browseTarget holds
// where the picked URL should land (an input element id, or a
// row id + 'galleryRow' kind). _browseFilters controls what files
// to show.
let _browseTarget = null;
let _browseFiles  = [];   // last-fetched file list
let _browseFilters = { type: 'all', usage: 'all' };

function openBrowseModal(typeFilter, targetId, kind) {
  // typeFilter: 'image' | 'video' | 'all' — restricts what we fetch
  // targetId:   for normal fields, the ID of the URL <input> to fill
  //             for gallery rows, the row's id (we update its inner input)
  // kind:       'galleryRow' for gallery row case, undefined otherwise
  _browseTarget  = { id: targetId, kind: kind || 'simple' };
  _browseFilters = { type: typeFilter || 'all', usage: 'all' };

  // Sync the chip UI to match the requested type filter.
  document.querySelectorAll('#browseModal .browse-chip').forEach(chip => {
    if (chip.dataset.filter === 'type') {
      chip.classList.toggle('active', chip.dataset.value === _browseFilters.type);
    } else if (chip.dataset.filter === 'usage') {
      chip.classList.toggle('active', chip.dataset.value === _browseFilters.usage);
    }
  });

  document.getElementById('browseModal').classList.add('open');
  loadBrowseFiles();
}

function closeBrowseModal() {
  document.getElementById('browseModal').classList.remove('open');
  _browseTarget = null;
}

function setBrowseFilter(filter, value, btn) {
  _browseFilters[filter] = value;
  // Update active chip in the same filter group
  btn.parentElement.querySelectorAll(`.browse-chip[data-filter="${filter}"]`)
    .forEach(c => c.classList.toggle('active', c === btn));
  // Type filter triggers a re-fetch (server-side filter); usage
  // filter is purely client-side, just re-render.
  if (filter === 'type') loadBrowseFiles();
  else                   renderBrowseGrid();
}

async function loadBrowseFiles() {
  const grid = document.getElementById('browseGrid');
  grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#888;padding:40px">Loading...</div>';
  try {
    const url = 'api.php?action=list_uploads' +
                (_browseFilters.type !== 'all' ? `&type=${_browseFilters.type}` : '');
    const r = await fetch(url);
    _browseFiles = await r.json();
    renderBrowseGrid();
  } catch (err) {
    grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#c4362c;padding:40px">Failed to load files</div>';
  }
}

function renderBrowseGrid() {
  const grid = document.getElementById('browseGrid');
  // Apply usage filter client-side.
  let files = _browseFiles;
  if (_browseFilters.usage === 'unused') {
    files = files.filter(f => !f.in_use);
  }

  // Stats line at the top
  const totalSize = files.reduce((s, f) => s + (f.size || 0), 0);
  document.getElementById('browseStats').textContent =
    `${files.length} file${files.length !== 1 ? 's' : ''} · ${formatBytes(totalSize)}`;

  if (files.length === 0) {
    grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#888;padding:40px">No files match the current filter.</div>';
    return;
  }

  grid.innerHTML = files.map(f => {
    const thumb = f.is_video
      ? `<video src="${escAttr(f.url)}" muted></video>`
      : `<img src="${escAttr(f.url)}" alt="" onerror="this.style.background='#fee'; this.removeAttribute('src')">`;
    const usedDot = f.in_use ? '' : 'unused';
    return `
      <div class="browse-tile ${usedDot}" onclick="pickBrowsedFile('${escAttr(f.url)}', ${f.is_video ? 1 : 0})">
        ${thumb}
        <div class="tile-meta">
          <div class="tile-name" title="${escAttr(f.filename)}">${escHtml(f.filename)}</div>
          <div class="tile-size">${formatBytes(f.size)}${f.in_use ? '' : ' · unused'}</div>
        </div>
      </div>`;
  }).join('');
}

function pickBrowsedFile(url, isVideo) {
  if (!_browseTarget) return;
  if (_browseTarget.kind === 'galleryRow') {
    // Gallery row case: update the row's internal input + thumb
    const row = document.getElementById(_browseTarget.id);
    if (row) {
      row.dataset.isVideo = isVideo ? '1' : '0';
      row.querySelector('input[type=url]').value = url;
      refreshPhotoThumb(row);
    }
  } else {
    // Simple input case: fill the input by id, dispatch input event
    // so any preview-refresh listener updates immediately.
    const input = document.getElementById(_browseTarget.id);
    if (input) {
      input.value = url;
      input.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }
  toast('Selected ' + url.split('/').pop());
  closeBrowseModal();
}

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

// Close on overlay click + escape key
document.getElementById('browseModal').addEventListener('click', function (e) {
  if (e.target === this) closeBrowseModal();
});
document.addEventListener('keydown', function (e) {
  if (e.key === 'Escape' && document.getElementById('browseModal').classList.contains('open')) {
    closeBrowseModal();
  }
});

// ============================================================
// DRAG-AND-SORT (SortableJS)
// ============================================================
// Three places where rows can be reordered:
//   1. Categories list  → updates categories.sort_order
//   2. Items list       → updates items.sort_order, but only
//                          within a single category (cross-category
//                          drags are reverted; that's a separate
//                          "change category" action)
//   3. Gallery photos   → updates item_photos.sort_order on save
//
// SortableJS is loaded from CDN above. Its callbacks fire on drop
// and we batch-post the new order to api.php?action=save_sort_orders.

// Initialize Sortable on the categories table after it renders.
// renderCategories() is the entry point; we hook into it to
// (re-)attach Sortable when the table body changes.
let _catSortable = null;
function initCategoriesSortable() {
  const tbody = document.querySelector('#categoriesTable tbody');
  if (!tbody) return;
  if (_catSortable) { _catSortable.destroy(); _catSortable = null; }
  _catSortable = Sortable.create(tbody, {
    handle: '.drag-handle',
    animation: 150,
    ghostClass: 'sortable-ghost',
    chosenClass: 'sortable-chosen',
    onEnd: async () => {
      // Read the new order from the DOM. data-id was set when
      // renderCategories built the row.
      const orders = [...tbody.querySelectorAll('tr[data-id]')].map((tr, idx) => ({
        id: parseInt(tr.dataset.id, 10),
        sort_order: idx + 1,
      }));
      try {
        const r = await fetch('api.php?action=save_sort_orders', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ kind: 'category', orders }),
        });
        const res = await r.json();
        if (res.error) toast(res.error, false);
        else            toast(`Reordered ${res.updated} categories`);
      } catch (err) {
        toast('Reorder failed', false);
      }
    },
  });
}

// Items table — single flat tbody, items grouped by category.
// We use SortableJS but veto cross-category drags via onMove.
// Each row carries data-cat-id, and a move is allowed only if
// source and destination rows belong to the same category.
let _itemSortable = null;
function initItemsSortable() {
  const tbody = document.getElementById('itemTableBody');
  if (!tbody) return;
  if (_itemSortable) { _itemSortable.destroy(); _itemSortable = null; }
  _itemSortable = Sortable.create(tbody, {
    handle: '.drag-handle',
    animation: 150,
    ghostClass: 'sortable-ghost',
    chosenClass: 'sortable-chosen',
    onMove: (evt) => {
      // Block cross-category drops. evt.dragged is the row being
      // dragged; evt.related is the row currently in the target
      // slot. Both must share a category for the move to proceed.
      const fromCat = evt.dragged?.dataset?.catId;
      const toCat   = evt.related?.dataset?.catId;
      if (!fromCat || !toCat) return true;
      return fromCat === toCat;
    },
    onEnd: async (evt) => {
      // Only the dragged row's category needs sort_order recomputed.
      // Walk the tbody and collect rows in that category, in DOM order.
      const catId = evt.item?.dataset?.catId;
      if (!catId) return;
      const orders = [...tbody.querySelectorAll(`tr[data-cat-id="${catId}"]`)]
        .map((tr, idx) => ({
          id: parseInt(tr.dataset.id, 10),
          sort_order: idx + 1,
        }));
      try {
        const r = await fetch('api.php?action=save_sort_orders', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ kind: 'item', orders }),
        });
        const res = await r.json();
        if (res.error) toast(res.error, false);
        else            toast(`Reordered ${res.updated} items`);
      } catch (err) {
        toast('Reorder failed', false);
      }
    },
  });
}

// Gallery photos — Sortable on the photos list inside the item
// edit modal. Order is saved when the item itself is saved
// (Save button), so we don't post anything to the server here —
// just let SortableJS rearrange the DOM. saveItem() reads the
// rows in DOM order and saves their indices.
let _gallerySortable = null;
function initGallerySortable() {
  const list = document.getElementById('photosList');
  if (!list) return;
  if (_gallerySortable) { _gallerySortable.destroy(); _gallerySortable = null; }
  _gallerySortable = Sortable.create(list, {
    handle: '.drag-handle',
    animation: 150,
    ghostClass: 'sortable-ghost',
    chosenClass: 'sortable-chosen',
  });
}

// ============================================================
// COUNTRY-OF-ORIGIN MASTER DATA
// ============================================================
// Small CRUD page for the origins table. Loads on first nav,
// re-renders on every save/delete. Cached in `_origins` so the
// edit modal can look up a row's current values without a re-fetch.
let _origins = [];

async function loadOrigins() {
  _origins = await apiGet('list_origins');
  const tb = document.getElementById('originsTableBody');
  if (!_origins.length) {
    tb.innerHTML = `<tr><td colspan="6" style="text-align:center;color:var(--muted);padding:30px">
      No origin rows yet. Click "+ Add row" to start.
    </td></tr>`;
    return;
  }
  tb.innerHTML = _origins.map(o => `
    <tr>
      <td style="font-weight:500">${escHtml(o.item_en)}</td>
      <td style="font-weight:500;direction:rtl;text-align:right">${escHtml(o.item_ar)}</td>
      <td>${escHtml(o.country_en)}</td>
      <td style="direction:rtl;text-align:right">${escHtml(o.country_ar)}</td>
      <td>${o.sort_order}</td>
      <td><button class="btn btn-sm edit-origin-btn" data-id="${o.id}">Edit</button></td>
    </tr>`).join('');
  tb.querySelectorAll('.edit-origin-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      const id = parseInt(btn.dataset.id, 10);
      const row = _origins.find(x => x.id == id);
      if (row) openOriginModal(row);
    });
  });
}

function openOriginModal(row = null) {
  document.getElementById('originModal').classList.add('open');
  document.getElementById('originModalTitle').textContent = row ? 'Edit origin' : 'Add origin';
  document.getElementById('origin_id').value         = row ? row.id : '';
  document.getElementById('origin_item_en').value    = row ? row.item_en    : '';
  document.getElementById('origin_item_ar').value    = row ? row.item_ar    : '';
  document.getElementById('origin_country_en').value = row ? row.country_en : '';
  document.getElementById('origin_country_ar').value = row ? row.country_ar : '';
  // Default sort_order for new rows: one higher than the current max
  const defaultSort = row ? row.sort_order
                          : (_origins.reduce((m, x) => Math.max(m, x.sort_order), 0) + 1);
  document.getElementById('origin_sort_order').value = defaultSort;
  document.getElementById('deleteOriginBtn').style.display = row ? 'inline-flex' : 'none';
}

function closeOriginModal() {
  document.getElementById('originModal').classList.remove('open');
}

async function saveOrigin() {
  const payload = {
    id:         parseInt(document.getElementById('origin_id').value, 10) || 0,
    item_en:    document.getElementById('origin_item_en').value.trim(),
    item_ar:    document.getElementById('origin_item_ar').value.trim(),
    country_en: document.getElementById('origin_country_en').value.trim(),
    country_ar: document.getElementById('origin_country_ar').value.trim(),
    sort_order: parseInt(document.getElementById('origin_sort_order').value, 10) || 0,
  };
  const res = await api('save_origin', payload);
  if (res.error) { toast(res.error, false); return; }
  toast('Saved');
  closeOriginModal();
  loadOrigins();
}

async function deleteOrigin() {
  const id = parseInt(document.getElementById('origin_id').value, 10);
  if (!id) return;
  if (!confirm('Delete this origin row?')) return;
  const res = await api('delete_origin', { id });
  if (res.error) { toast(res.error, false); return; }
  toast('Deleted');
  closeOriginModal();
  loadOrigins();
}

// Close modal on overlay click
document.getElementById('originModal').addEventListener('click', function (e) {
  if (e.target === this) closeOriginModal();
});

// ============================================================
// BRANCH MANAGEMENT  (super admin only)
// ============================================================
// CRUD for branches. _branches is cached so the user-management
// modal and (later) the item editor can populate branch dropdowns
// without re-fetching.
let _branches = [];

async function loadBranches() {
  _branches = await apiGet('list_branches');
  const tb = document.getElementById('branchesTableBody');
  if (!_branches.length) {
    tb.innerHTML = `<tr><td colspan="7" style="text-align:center;color:var(--muted);padding:30px">
      No branches yet. Click "+ Add branch".</td></tr>`;
    return;
  }
  tb.innerHTML = _branches.map(b => `
    <tr>
      <td style="font-weight:500">${escHtml(b.name)}</td>
      <td style="direction:rtl;text-align:right">${b.name_ar ? escHtml(b.name_ar) : '<span style="color:var(--muted)">—</span>'}</td>
      <td style="color:var(--muted)"><code>${escHtml(b.slug)}</code></td>
      <td>${b.phone ? escHtml(b.phone) : '<span style="color:var(--muted)">—</span>'}</td>
      <td>${b.sort_order}</td>
      <td><span class="pill ${b.is_active == 1 ? 'pill-green' : 'pill-gray'}">${b.is_active == 1 ? 'Active' : 'Hidden'}</span></td>
      <td><button class="btn btn-sm edit-branch-btn" data-id="${b.id}">Edit</button></td>
    </tr>`).join('');
  tb.querySelectorAll('.edit-branch-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      const b = _branches.find(x => x.id == parseInt(btn.dataset.id, 10));
      if (b) openBranchModal(b);
    });
  });
  // Keep the user-modal branch dropdown in sync with the latest list.
  populateBranchDropdown();
}

// Fill the branch <select> in the user modal. "All branches" is
// the empty-value default (for super admins / unscoped users).
function populateBranchDropdown() {
  const sel = document.getElementById('user_branch_id');
  if (!sel) return;
  const current = sel.value;
  sel.innerHTML = '<option value="">All branches</option>' +
    _branches.map(b => `<option value="${b.id}">${escHtml(b.name)}</option>`).join('');
  sel.value = current;
}

function openBranchModal(b = null) {
  document.getElementById('branchModal').classList.add('open');
  document.getElementById('branchModalTitle').textContent = b ? 'Edit branch' : 'Add branch';
  document.getElementById('branch_id').value         = b ? b.id : '';
  document.getElementById('branch_name').value       = b ? b.name : '';
  document.getElementById('branch_name_ar').value    = b ? (b.name_ar || '') : '';
  document.getElementById('branch_slug').value       = b ? b.slug : '';
  document.getElementById('branch_phone').value      = b ? (b.phone || '') : '';
  document.getElementById('branch_address').value    = b ? (b.address || '') : '';
  document.getElementById('branch_address_ar').value = b ? (b.address_ar || '') : '';
  document.getElementById('branch_sort_order').value = b ? b.sort_order
    : (_branches.reduce((m, x) => Math.max(m, x.sort_order), 0) + 1);
  document.getElementById('branch_is_active').checked = b ? b.is_active == 1 : true;
  document.getElementById('deleteBranchBtn').style.display = b ? 'inline-flex' : 'none';
}

function closeBranchModal() {
  document.getElementById('branchModal').classList.remove('open');
}

async function saveBranch() {
  const payload = {
    id:          parseInt(document.getElementById('branch_id').value, 10) || 0,
    name:        document.getElementById('branch_name').value.trim(),
    name_ar:     document.getElementById('branch_name_ar').value.trim(),
    slug:        document.getElementById('branch_slug').value.trim(),
    phone:       document.getElementById('branch_phone').value.trim(),
    address:     document.getElementById('branch_address').value.trim(),
    address_ar:  document.getElementById('branch_address_ar').value.trim(),
    sort_order:  parseInt(document.getElementById('branch_sort_order').value, 10) || 0,
    is_active:   document.getElementById('branch_is_active').checked ? 1 : 0,
  };
  if (!payload.name) { toast('Branch name required', false); return; }
  const res = await api('save_branch', payload);
  if (res.error) { toast(res.error, false); return; }
  toast('Branch saved');
  closeBranchModal();
  loadBranches();
}

async function deleteBranch() {
  const id = parseInt(document.getElementById('branch_id').value, 10);
  if (!id) return;
  if (!confirm('Delete this branch? This cannot be undone.')) return;
  const res = await api('delete_branch', { id });
  if (res.error) { toast(res.error, false); return; }
  toast('Branch deleted');
  closeBranchModal();
  loadBranches();
}

document.getElementById('branchModal').addEventListener('click', function (e) {
  if (e.target === this) closeBranchModal();
});

// ============================================================
// USER MANAGEMENT  (super admin only)
// ============================================================
// CRUD for admin_users. The server enforces super-admin access;
// this UI is only reachable when window.ADMIN_PERMS.users is true
// (the nav tab is server-side conditional).
let _users = [];

async function loadUsers() {
  _users = await apiGet('list_users');
  // Need the branch list to show each user's branch name.
  if (!_branches.length) {
    _branches = await apiGet('list_branches');
  }
  const tb = document.getElementById('usersTableBody');
  if (!_users.length) {
    tb.innerHTML = `<tr><td colspan="6" style="text-align:center;color:var(--muted);padding:30px">
      No users yet.</td></tr>`;
    return;
  }
  tb.innerHTML = _users.map(u => {
    // Build a readable access summary.
    let access;
    if (u.is_super == 1) {
      access = '<span class="pill pill-green">Super Admin</span>';
    } else {
      const parts = [];
      if (u.perm_menu == 1)     parts.push('Menu');
      if (u.perm_orders == 1)   parts.push('Orders');
      if (u.perm_settings == 1) parts.push('Settings');
      access = parts.length
        ? parts.map(p => `<span class="pill pill-gray">${p}</span>`).join(' ')
        : '<span style="color:var(--muted)">No access</span>';
    }
    const status = u.is_active == 1
      ? '<span class="pill pill-green">Active</span>'
      : '<span class="pill pill-gray">Disabled</span>';
    // Branch name — "All branches" when branch_id is null.
    let branchLabel;
    if (u.branch_id == null) {
      branchLabel = '<span style="color:var(--muted)">All branches</span>';
    } else {
      const b = _branches.find(x => x.id == u.branch_id);
      branchLabel = b ? escHtml(b.name)
                      : '<span style="color:var(--muted)">#' + u.branch_id + '</span>';
    }
    return `
      <tr>
        <td style="font-weight:500">${escHtml(u.username)}</td>
        <td>${u.display_name ? escHtml(u.display_name) : '<span style="color:var(--muted)">—</span>'}</td>
        <td>${branchLabel}</td>
        <td>${access}</td>
        <td>${status}</td>
        <td><button class="btn btn-sm edit-user-btn" data-id="${u.id}">Edit</button></td>
      </tr>`;
  }).join('');
  tb.querySelectorAll('.edit-user-btn').forEach(btn => {
    btn.addEventListener('click', () => {
      const u = _users.find(x => x.id == parseInt(btn.dataset.id, 10));
      if (u) openUserModal(u);
    });
  });
}

async function openUserModal(user = null) {
  document.getElementById('userModal').classList.add('open');
  document.getElementById('userModalTitle').textContent = user ? 'Edit user' : 'Add user';
  document.getElementById('user_id').value           = user ? user.id : '';
  document.getElementById('user_username').value     = user ? user.username : '';
  document.getElementById('user_display_name').value = user ? (user.display_name || '') : '';
  document.getElementById('user_password').value     = '';
  // Password hint differs for add vs edit.
  document.getElementById('userPwHint').textContent = user
    ? '(leave blank to keep current password)'
    : '(required)';
  document.getElementById('user_perm_menu').checked     = user ? user.perm_menu == 1     : false;
  document.getElementById('user_perm_orders').checked   = user ? user.perm_orders == 1   : false;
  document.getElementById('user_perm_settings').checked = user ? user.perm_settings == 1 : false;
  document.getElementById('user_is_super').checked      = user ? user.is_super == 1      : false;
  document.getElementById('user_is_active').checked     = user ? user.is_active == 1     : true;
  document.getElementById('deleteUserBtn').style.display = user ? 'inline-flex' : 'none';

  // Make sure the branch dropdown is populated. The user might open
  // this modal before ever visiting the Branches tab, so load the
  // branch list on demand if we don't have it yet.
  if (!_branches.length) {
    _branches = await apiGet('list_branches');
  }
  populateBranchDropdown();
  document.getElementById('user_branch_id').value =
    (user && user.branch_id != null) ? String(user.branch_id) : '';

  onSuperToggle();  // sync the disabled-state of section checkboxes + branch
}

function closeUserModal() {
  document.getElementById('userModal').classList.remove('open');
}

// When "Super Admin" is checked, the per-section checkboxes are
// implied — we check and disable them. The branch dropdown is
// also forced to "All branches" and disabled, since a super admin
// always has cross-branch access.
function onSuperToggle() {
  const isSuper = document.getElementById('user_is_super').checked;
  ['user_perm_menu', 'user_perm_orders', 'user_perm_settings'].forEach(id => {
    const cb = document.getElementById(id);
    if (isSuper) { cb.checked = true; cb.disabled = true; }
    else         { cb.disabled = false; }
  });
  const branchSel = document.getElementById('user_branch_id');
  if (branchSel) {
    if (isSuper) { branchSel.value = ''; branchSel.disabled = true; }
    else         { branchSel.disabled = false; }
  }
}

async function saveUser() {
  const payload = {
    id:            parseInt(document.getElementById('user_id').value, 10) || 0,
    username:      document.getElementById('user_username').value.trim(),
    display_name:  document.getElementById('user_display_name').value.trim(),
    password:      document.getElementById('user_password').value,
    perm_menu:     document.getElementById('user_perm_menu').checked ? 1 : 0,
    perm_orders:   document.getElementById('user_perm_orders').checked ? 1 : 0,
    perm_settings: document.getElementById('user_perm_settings').checked ? 1 : 0,
    is_super:      document.getElementById('user_is_super').checked ? 1 : 0,
    is_active:     document.getElementById('user_is_active').checked ? 1 : 0,
    branch_id:     document.getElementById('user_branch_id').value,  // '' = all branches
  };
  if (!payload.username) { toast('Username required', false); return; }
  if (!payload.id && !payload.password) {
    toast('Password required for a new user', false); return;
  }
  const res = await api('save_user', payload);
  if (res.error) { toast(res.error, false); return; }
  toast('User saved');
  closeUserModal();
  loadUsers();
}

async function deleteUser() {
  const id = parseInt(document.getElementById('user_id').value, 10);
  if (!id) return;
  if (!confirm('Delete this user? This cannot be undone.')) return;
  const res = await api('delete_user', { id });
  if (res.error) { toast(res.error, false); return; }
  toast('User deleted');
  closeUserModal();
  loadUsers();
}

// Close user modal on overlay click
document.getElementById('userModal').addEventListener('click', function (e) {
  if (e.target === this) closeUserModal();
});

// ── Init ──────────────────────────────────────────────────────
loadDashboard();
</script>
</body>
</html>
