<?php
declare(strict_types=1);

try {
  require_once __DIR__ . '/Includes.php';
  require_once __DIR__ . '/pos_core.php';
  pos_ensure_schema($pdo);

$requiredWorkspace = isset($requestedWorkspace) && in_array($requestedWorkspace, ['tuckshop', 'produce'], true) ? $requestedWorkspace : null;
$user = pos_require_login($requiredWorkspace);
$workspace = (string)$user['workspace'];
pos_migrate_legacy_sales($pdo, $workspace);
$isManager = (string)$user['role'] === 'manager';
if (!empty($managerOnly) && !$isManager) {
  header('Location: cashier_pos.php');
  exit;
}

$meta = pos_workspace_meta($workspace);
$pageUrl = basename((string)($_SERVER['SCRIPT_NAME'] ?? ($workspace === 'produce' ? 'produce_desktop.php' : 'tuckshop_desktop.php')));
$settingPrefix = 'pos_' . $workspace . '_';
$supportedCurrencies = supported_currencies();
$fxRates = [];
foreach ($supportedCurrencies as $currencyCode) {
  $fxRates[$currencyCode] = get_currency_rate_to_usd($pdo, $currencyCode);
}
if (!isset($fxRates['USD']) || (float)$fxRates['USD'] <= 0) $fxRates['USD'] = 1.0;

$storeName = trim(get_app_setting($pdo, $settingPrefix . 'store_name', (string)$meta['store_name']));
$storePhone = trim(get_app_setting($pdo, $settingPrefix . 'store_phone', '+263 77 000 0000'));
$storeTagline = trim(get_app_setting($pdo, $settingPrefix . 'store_tagline', (string)$meta['tagline']));
$receiptFooter = trim(get_app_setting($pdo, $settingPrefix . 'receipt_footer', 'Thank you for supporting our school.'));
$defaultTaxRate = (float)get_app_setting($pdo, $settingPrefix . 'default_tax_rate', '0');
$reorderPhone = trim(get_app_setting($pdo, $settingPrefix . 'reorder_phone', ''));

function pos_page_flash(string $type, string $text): void {
  $_SESSION['pos_flash'][] = ['type' => $type, 'text' => $text];
}
function pos_page_redirect(string $pageUrl, string $suffix = ''): void {
  header('Location: ' . $pageUrl . $suffix);
  exit;
}
function pos_action_error(Throwable $e): string {
  if ($e instanceof RuntimeException || $e instanceof InvalidArgumentException) return $e->getMessage();
  return mavela_exception_detail($e);
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  try {
    if (isset($_POST['checkout_cart'])) {
      $receipt = pos_checkout($pdo, $user, $_POST, $fxRates);
      pos_page_flash('success', 'Sale ' . $receipt['receipt_no'] . ' completed successfully.');
      $_SESSION['pos_clear_cart'] = true;
      pos_page_redirect($pageUrl, '?receipt=' . (int)$receipt['transaction_id']);
    }

    if (isset($_POST['hold_order'])) {
      $holdRef = pos_hold_order($pdo, $user, $_POST);
      pos_page_flash('success', 'Order ' . $holdRef . ' was held and can be resumed later.');
      $_SESSION['pos_clear_cart'] = true;
      pos_page_redirect($pageUrl, '#held-orders');
    }

    if (isset($_POST['cancel_hold'])) {
      $holdId = (int)($_POST['hold_id'] ?? 0);
      $sql = "UPDATE tp_held_orders SET status='cancelled', cancelled_at=NOW() WHERE id=? AND workspace=? AND status='active'";
      $params = [$holdId, $workspace];
      if (!$isManager) {
        $sql .= ' AND held_by=?';
        $params[] = (int)$user['id'];
      }
      $stmt = $pdo->prepare($sql);
      $stmt->execute($params);
      pos_page_flash($stmt->rowCount() ? 'success' : 'error', $stmt->rowCount() ? 'Held order cancelled.' : 'The held order could not be cancelled.');
      pos_page_redirect($pageUrl, '#held-orders');
    }

    if (isset($_POST['void_transaction'])) {
      pos_void_transaction($pdo, $user, (int)($_POST['transaction_id'] ?? 0), (string)($_POST['void_reason'] ?? ''));
      pos_page_flash('success', 'Transaction voided and stock restored.');
      pos_page_redirect($pageUrl, '#transactions');
    }

    if (isset($_POST['open_shift'])) {
      pos_open_shift($pdo, (int)$user['id'], $workspace, max(0, (float)($_POST['opening_float'] ?? 0)), (string)($_POST['shift_currency'] ?? 'USD'));
      pos_page_flash('success', 'Register shift opened.');
      pos_page_redirect($pageUrl, '#register');
    }

    if (isset($_POST['close_shift'])) {
      pos_close_shift($pdo, (int)($_POST['shift_id'] ?? 0), (int)$user['id'], max(0, (float)($_POST['closing_cash'] ?? 0)), trim((string)($_POST['shift_notes'] ?? '')));
      pos_page_flash('success', 'Register shift closed and cash variance recorded.');
      pos_page_redirect($pageUrl, '#register');
    }

    if ($isManager && isset($_POST['save_product'])) {
      $productId = (int)($_POST['product_id'] ?? 0);
      $name = trim((string)($_POST['product_name'] ?? ''));
      $category = trim((string)($_POST['category'] ?? ''));
      $sku = strtoupper(trim((string)($_POST['sku'] ?? '')));
      $barcode = trim((string)($_POST['barcode'] ?? ''));
      $unit = trim((string)($_POST['unit_label'] ?? 'unit'));
      $buying = max(0, (float)($_POST['buying_price'] ?? 0));
      $selling = max(0, (float)($_POST['selling_price'] ?? 0));
      $stock = max(0, (float)($_POST['stock_qty'] ?? 0));
      $reorder = max(0, (float)($_POST['reorder_level'] ?? 0));
      $tax = max(0, min(100, (float)($_POST['product_tax_rate'] ?? 0)));
      $supplier = trim((string)($_POST['supplier_name'] ?? ''));
      $trackStock = isset($_POST['track_stock']) ? 1 : 0;
      $allowFractional = isset($_POST['allow_fractional']) ? 1 : 0;
      if ($name === '' || $category === '') throw new RuntimeException('Product name and category are required.');
      if ($selling <= 0) throw new RuntimeException('Selling price must be greater than zero.');
      if ($sku !== '') {
        $dup = $pdo->prepare('SELECT id FROM tp_products WHERE workspace=? AND sku=? AND id<>? LIMIT 1');
        $dup->execute([$workspace, $sku, $productId]);
        if ($dup->fetch()) throw new RuntimeException('That SKU is already used in this workspace.');
      }
      if ($barcode !== '') {
        $dup = $pdo->prepare('SELECT id FROM tp_products WHERE workspace=? AND barcode=? AND id<>? LIMIT 1');
        $dup->execute([$workspace, $barcode, $productId]);
        if ($dup->fetch()) throw new RuntimeException('That barcode is already used in this workspace.');
      }
      if ($productId > 0) {
        $stmt = $pdo->prepare("UPDATE tp_products SET product_name=?, category=?, sku=?, barcode=?, unit_label=?, buying_price=?, selling_price=?,
          reorder_level=?, tax_rate=?, supplier_name=?, track_stock=?, allow_fractional=? WHERE id=? AND workspace=?");
        $stmt->execute([$name, $category, $sku ?: null, $barcode ?: null, $unit ?: 'unit', $buying, $selling, $reorder, $tax, $supplier ?: null, $trackStock, $allowFractional, $productId, $workspace]);
        pos_page_flash('success', 'Product updated successfully.');
      } else {
        $stmt = $pdo->prepare("INSERT INTO tp_products
          (workspace, category, product_name, sku, barcode, unit_label, buying_price, selling_price, stock_qty, reorder_level, tax_rate, supplier_name, track_stock, allow_fractional, is_active)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)");
        $stmt->execute([$workspace, $category, $name, $sku ?: null, $barcode ?: null, $unit ?: 'unit', $buying, $selling, $stock, $reorder, $tax, $supplier ?: null, $trackStock, $allowFractional]);
        $newId = (int)$pdo->lastInsertId();
        if ($stock > 0 && $trackStock) {
          $move = $pdo->prepare("INSERT INTO tp_stock_movements (workspace, product_id, movement_type, quantity_change, balance_after, unit_cost_usd, reference_no, reason, created_by)
            VALUES (?, ?, 'opening_stock', ?, ?, ?, ?, 'Initial product stock', ?)");
          $move->execute([$workspace, $newId, $stock, $stock, $buying, pos_ref('STK'), (int)$user['id']]);
        }
        pos_page_flash('success', 'New product added to the catalogue.');
      }
      pos_page_redirect($pageUrl, '#inventory');
    }

    if ($isManager && isset($_POST['adjust_stock'])) {
      $productId = (int)($_POST['product_id'] ?? 0);
      $mode = (string)($_POST['adjustment_mode'] ?? 'add');
      $qtyInput = (float)($_POST['adjustment_qty'] ?? 0);
      $reason = trim((string)($_POST['adjustment_reason'] ?? ''));
      if ($productId <= 0 || $reason === '') throw new RuntimeException('Choose a product and enter an adjustment reason.');
      $pdo->beginTransaction();
      $lock = $pdo->prepare('SELECT * FROM tp_products WHERE id=? AND workspace=? FOR UPDATE');
      $lock->execute([$productId, $workspace]);
      $product = $lock->fetch();
      if (!$product) throw new RuntimeException('Product not found.');
      $oldStock = (float)$product['stock_qty'];
      if ($mode === 'set') $newStock = max(0, $qtyInput);
      else $newStock = max(0, $oldStock + $qtyInput);
      $change = round($newStock - $oldStock, 3);
      $update = $pdo->prepare('UPDATE tp_products SET stock_qty=? WHERE id=?');
      $update->execute([$newStock, $productId]);
      $move = $pdo->prepare("INSERT INTO tp_stock_movements (workspace, product_id, movement_type, quantity_change, balance_after, unit_cost_usd, reference_no, reason, created_by)
        VALUES (?, ?, 'adjustment', ?, ?, ?, ?, ?, ?)");
      $move->execute([$workspace, $productId, $change, $newStock, (float)$product['buying_price'], pos_ref('ADJ'), $reason, (int)$user['id']]);
      $pdo->commit();
      pos_page_flash('success', 'Stock adjusted. New balance: ' . number_format($newStock, 3) . ' ' . $product['unit_label'] . '.');
      pos_page_redirect($pageUrl, '#inventory');
    }

    if ($isManager && isset($_POST['toggle_product'])) {
      $productId = (int)($_POST['product_id'] ?? 0);
      $stmt = $pdo->prepare('UPDATE tp_products SET is_active=IF(is_active=1,0,1) WHERE id=? AND workspace=?');
      $stmt->execute([$productId, $workspace]);
      pos_page_flash('success', 'Product availability changed.');
      pos_page_redirect($pageUrl, '#inventory');
    }

    if ($isManager && isset($_POST['save_pos_settings'])) {
      $newStoreName = trim((string)($_POST['store_name'] ?? ''));
      if ($newStoreName === '') throw new RuntimeException('Store name is required.');
      $settings = [
        'store_name' => $newStoreName,
        'store_phone' => trim((string)($_POST['store_phone'] ?? '')),
        'store_tagline' => trim((string)($_POST['store_tagline'] ?? '')),
        'receipt_footer' => trim((string)($_POST['receipt_footer'] ?? '')),
        'default_tax_rate' => (string)max(0, min(100, (float)($_POST['default_tax_rate'] ?? 0))),
        'reorder_phone' => trim((string)($_POST['reorder_phone'] ?? ''))
      ];
      foreach ($settings as $key => $value) {
        set_app_setting($pdo, $settingPrefix . $key, $value, (int)$user['id']);
      }
      pos_page_flash('success', 'POS and receipt settings saved.');
      pos_page_redirect($pageUrl, '#settings');
    }
  } catch (Throwable $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    pos_page_flash('error', pos_action_error($e));
    pos_page_redirect($pageUrl);
  }
}

$flashes = $_SESSION['pos_flash'] ?? [];
unset($_SESSION['pos_flash']);
$clearCartOnLoad = !empty($_SESSION['pos_clear_cart']);
unset($_SESSION['pos_clear_cart']);

$productsStmt = $pdo->prepare('SELECT * FROM tp_products WHERE workspace=? ' . ($isManager ? '' : 'AND is_active=1 ') . 'ORDER BY is_active DESC, category, product_name');
$productsStmt->execute([$workspace]);
$products = $productsStmt->fetchAll();
$activeProducts = array_values(array_filter($products, static fn(array $p): bool => (int)$p['is_active'] === 1));
$categories = array_values(array_unique(array_map(static fn(array $p): string => (string)$p['category'], $activeProducts)));
sort($categories);

$todaySummaryStmt = $pdo->prepare("SELECT COUNT(*) AS tx_count, COALESCE(SUM(total_amount_usd),0) AS sales_usd,
  COALESCE(SUM(discount_amount_usd),0) AS discounts_usd, COALESCE(SUM(tax_amount_usd),0) AS tax_usd
  FROM tp_transactions WHERE workspace=? AND status='completed' AND DATE(sold_at)=CURDATE()");
$todaySummaryStmt->execute([$workspace]);
$todaySummary = $todaySummaryStmt->fetch() ?: ['tx_count'=>0,'sales_usd'=>0,'discounts_usd'=>0,'tax_usd'=>0];

$profitStmt = $pdo->prepare("SELECT COALESCE(SUM(s.total_amount_usd - (p.buying_price*s.quantity)),0)
  FROM tp_sales s JOIN tp_products p ON p.id=s.product_id
  WHERE s.workspace=? AND s.status='completed' AND DATE(s.sold_at)=CURDATE()");
$profitStmt->execute([$workspace]);
$todayProfit = (float)$profitStmt->fetchColumn();

$voidTodayStmt = $pdo->prepare("SELECT COUNT(*) FROM tp_transactions WHERE workspace=? AND status='voided' AND DATE(voided_at)=CURDATE()");
$voidTodayStmt->execute([$workspace]);
$voidToday = (int)$voidTodayStmt->fetchColumn();

$txStatus = (string)($_GET['status'] ?? 'all');
if (!in_array($txStatus, ['all','completed','voided'], true)) $txStatus = 'all';
$txFrom = (string)($_GET['from'] ?? date('Y-m-d', strtotime('-7 days')));
$txTo = (string)($_GET['to'] ?? date('Y-m-d'));
$txSearch = trim((string)($_GET['q'] ?? ''));
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $txFrom)) $txFrom = date('Y-m-d', strtotime('-7 days'));
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $txTo)) $txTo = date('Y-m-d');
$txSql = "SELECT t.*, u.full_name AS cashier_name FROM tp_transactions t LEFT JOIN tp_users u ON u.id=t.sold_by
  WHERE t.workspace=? AND DATE(t.sold_at) BETWEEN ? AND ?";
$txParams = [$workspace, $txFrom, $txTo];
if ($txStatus !== 'all') { $txSql .= ' AND t.status=?'; $txParams[] = $txStatus; }
if ($txSearch !== '') {
  $txSql .= ' AND (t.sale_ref LIKE ? OR t.customer_name LIKE ? OR t.customer_phone LIKE ? OR u.full_name LIKE ?)';
  $like = '%' . $txSearch . '%';
  array_push($txParams, $like, $like, $like, $like);
}
$txSql .= ' ORDER BY t.sold_at DESC LIMIT 250';
$transactionsStmt = $pdo->prepare($txSql);
$transactionsStmt->execute($txParams);
$transactions = $transactionsStmt->fetchAll();

$heldSql = "SELECT h.*, u.full_name AS held_by_name FROM tp_held_orders h LEFT JOIN tp_users u ON u.id=h.held_by WHERE h.workspace=? AND h.status='active'";
$heldParams = [$workspace];
if (!$isManager) { $heldSql .= ' AND h.held_by=?'; $heldParams[] = (int)$user['id']; }
$heldSql .= ' ORDER BY h.created_at DESC LIMIT 100';
$heldStmt = $pdo->prepare($heldSql);
$heldStmt->execute($heldParams);
$heldOrders = $heldStmt->fetchAll();

$lowStock = array_values(array_filter($activeProducts, static fn(array $p): bool => (int)($p['track_stock'] ?? 1) === 1 && (float)$p['stock_qty'] <= (float)$p['reorder_level']));
$stockMoveStmt = $pdo->prepare("SELECT m.*, p.product_name, p.unit_label, u.full_name AS user_name
  FROM tp_stock_movements m JOIN tp_products p ON p.id=m.product_id LEFT JOIN tp_users u ON u.id=m.created_by
  WHERE m.workspace=? ORDER BY m.created_at DESC LIMIT 80");
$stockMoveStmt->execute([$workspace]);
$stockMovements = $stockMoveStmt->fetchAll();

$paymentBreakdownStmt = $pdo->prepare("SELECT p.payment_method, COALESCE(SUM(p.amount_usd),0) AS amount_usd, COUNT(DISTINCT p.transaction_id) AS tx_count
  FROM tp_sale_payments p JOIN tp_transactions t ON t.id=p.transaction_id
  WHERE t.workspace=? AND t.status='completed' AND DATE(t.sold_at) BETWEEN DATE_SUB(CURDATE(), INTERVAL 6 DAY) AND CURDATE()
  GROUP BY p.payment_method ORDER BY amount_usd DESC");
$paymentBreakdownStmt->execute([$workspace]);
$paymentBreakdown = $paymentBreakdownStmt->fetchAll();

$topProductsStmt = $pdo->prepare("SELECT p.product_name, SUM(s.quantity) AS qty, SUM(s.total_amount_usd) AS revenue
  FROM tp_sales s JOIN tp_products p ON p.id=s.product_id
  WHERE s.workspace=? AND s.status='completed' AND DATE(s.sold_at) BETWEEN DATE_SUB(CURDATE(), INTERVAL 29 DAY) AND CURDATE()
  GROUP BY s.product_id, p.product_name ORDER BY revenue DESC LIMIT 8");
$topProductsStmt->execute([$workspace]);
$topProducts = $topProductsStmt->fetchAll();

$dailyTrendStmt = $pdo->prepare("SELECT DATE(sold_at) AS sale_day, SUM(total_amount_usd) AS revenue, COUNT(*) AS tx_count
  FROM tp_transactions WHERE workspace=? AND status='completed' AND DATE(sold_at) BETWEEN DATE_SUB(CURDATE(), INTERVAL 6 DAY) AND CURDATE()
  GROUP BY DATE(sold_at) ORDER BY sale_day");
$dailyTrendStmt->execute([$workspace]);
$dailyTrendRows = $dailyTrendStmt->fetchAll();
$dailyMap = [];
foreach ($dailyTrendRows as $row) $dailyMap[(string)$row['sale_day']] = $row;
$dailyTrend = [];
for ($i = 6; $i >= 0; $i--) {
  $day = date('Y-m-d', strtotime('-' . $i . ' days'));
  $dailyTrend[] = ['sale_day'=>$day, 'revenue'=>(float)($dailyMap[$day]['revenue'] ?? 0), 'tx_count'=>(int)($dailyMap[$day]['tx_count'] ?? 0)];
}
$maxDailyRevenue = max(1, ...array_map(static fn(array $r): float => (float)$r['revenue'], $dailyTrend));

$currentShift = pos_current_shift($pdo, (int)$user['id'], $workspace);
$expectedCash = $currentShift ? pos_shift_expected_cash($pdo, (int)$currentShift['id']) : 0.0;

$receipt = null;
$receiptId = (int)($_GET['receipt'] ?? 0);
if ($receiptId > 0) $receipt = pos_get_receipt($pdo, $receiptId, $workspace);

$productsForJs = array_map(static function(array $p): array {
  return [
    'id'=>(int)$p['id'], 'name'=>(string)$p['product_name'], 'category'=>(string)$p['category'],
    'sku'=>(string)($p['sku'] ?? ''), 'barcode'=>(string)($p['barcode'] ?? ''), 'unit'=>(string)$p['unit_label'],
    'price_usd'=>(float)$p['selling_price'], 'stock'=>(float)$p['stock_qty'], 'track_stock'=>(int)($p['track_stock'] ?? 1),
    'allow_fractional'=>(int)($p['allow_fractional'] ?? 0), 'reorder'=>(float)$p['reorder_level'], 'tax_rate'=>(float)($p['tax_rate'] ?? 0)
  ];
}, $activeProducts);
$holdsForJs = [];
foreach ($heldOrders as $hrow) {
  $holdsForJs[(int)$hrow['id']] = [
    'id'=>(int)$hrow['id'], 'cart'=>json_decode((string)$hrow['cart_json'], true) ?: [],
    'customer_name'=>(string)($hrow['customer_name'] ?? ''), 'customer_phone'=>(string)($hrow['customer_phone'] ?? ''),
    'currency_code'=>(string)$hrow['currency_code'], 'discount_type'=>(string)$hrow['discount_type'],
    'discount_value'=>(float)$hrow['discount_value'], 'tax_rate'=>(float)$hrow['tax_rate'], 'notes'=>(string)($hrow['notes'] ?? '')
  ];
}
?>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title><?= h($storeName) ?> | Modern POS</title>
  <style>
    :root{
      --brown:#4a2c1a;--brown-2:#6a4024;--gold:#d4a72c;--gold-2:#f1d47a;--red:#a61b1b;--red-2:#7d1212;
      --cream:#fbf7ef;--paper:#fffdf9;--ink:#25170f;--muted:#725f52;--line:#e7d9c8;--green:#237a45;--shadow:0 16px 42px rgba(74,44,26,.12)
    }
    *{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:linear-gradient(135deg,#f8f1e5,#fffaf3 46%,#f3e7d6);color:var(--ink);font-family:Inter,"Segoe UI",system-ui,sans-serif}
    button,input,select,textarea{font:inherit}button{cursor:pointer}.app{min-height:100vh}.topbar{position:sticky;top:0;z-index:40;background:rgba(74,44,26,.97);color:#fff;border-bottom:4px solid var(--gold);box-shadow:0 8px 28px rgba(37,23,15,.22)}
    .topbar-inner{width:min(1540px,100%);margin:auto;padding:12px 18px;display:flex;align-items:center;gap:16px;justify-content:space-between}.brand{display:flex;align-items:center;gap:12px;min-width:0}.brand-mark{width:46px;height:46px;border-radius:14px;display:grid;place-items:center;background:linear-gradient(145deg,var(--gold),#f6df8d);color:var(--brown);font-size:1.45rem;box-shadow:inset 0 0 0 2px rgba(255,255,255,.32)}
    .brand h1{font-size:1.05rem;margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.brand p{margin:2px 0 0;color:#f0dfc8;font-size:.78rem}.top-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}.pill,.top-link{border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.1);color:#fff;padding:8px 11px;border-radius:999px;text-decoration:none;font-weight:750;font-size:.78rem}.pill.open{background:rgba(35,122,69,.3);border-color:rgba(122,228,163,.45)}
    .nav{width:min(1540px,100%);margin:auto;display:flex;gap:4px;padding:0 18px 9px;overflow:auto}.nav a{color:#f7ead8;text-decoration:none;padding:8px 12px;border-radius:9px;font-size:.82rem;font-weight:800;white-space:nowrap}.nav a:hover{background:rgba(255,255,255,.12);color:#fff}.wrap{width:min(1540px,100%);margin:auto;padding:18px}.alerts{display:grid;gap:8px;margin-bottom:14px}.alert{padding:12px 14px;border-radius:12px;border:1px solid;font-weight:700}.alert.success{background:#edf9f1;color:#176338;border-color:#bde3c9}.alert.error{background:#fff0f0;color:#8c1717;border-color:#f0bcbc}
    .stats{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin-bottom:14px}.stat{background:var(--paper);border:1px solid var(--line);border-radius:16px;padding:15px;box-shadow:0 7px 20px rgba(74,44,26,.06)}.stat small{display:block;color:var(--muted);font-weight:750;margin-bottom:5px}.stat strong{font-size:1.3rem}.stat.alert-stat{border-color:#e9a4a4;background:#fff8f7}.panel{background:var(--paper);border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow)}.panel-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 18px;border-bottom:1px solid var(--line)}.panel-head h2{font-size:1.02rem;margin:0}.panel-head p{margin:3px 0 0;color:var(--muted);font-size:.78rem}.panel-body{padding:16px 18px}
    .pos-grid{display:grid;grid-template-columns:minmax(0,1.55fr) minmax(360px,.82fr);gap:14px;align-items:start}.catalog-toolbar{display:grid;grid-template-columns:minmax(260px,1fr) auto;gap:10px;padding:14px 16px}.searchbox{position:relative}.searchbox input{width:100%;padding:13px 14px 13px 42px;border:1px solid var(--line);border-radius:13px;background:#fff;font-weight:650;outline:none}.searchbox input:focus{border-color:var(--gold);box-shadow:0 0 0 4px rgba(212,167,44,.15)}.searchbox span{position:absolute;left:14px;top:12px;font-size:1.1rem}.category-row{display:flex;gap:7px;overflow:auto;padding:0 16px 14px}.category-btn{border:1px solid var(--line);background:#fff;color:var(--brown);padding:8px 11px;border-radius:999px;font-size:.77rem;font-weight:800;white-space:nowrap}.category-btn.active{background:var(--brown);color:#fff;border-color:var(--brown)}
    .product-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(155px,1fr));gap:10px;padding:0 16px 16px;max-height:650px;overflow:auto}.product-card{position:relative;text-align:left;border:1px solid var(--line);background:linear-gradient(160deg,#fff,#fbf4e9);border-radius:14px;padding:13px;min-height:132px;transition:.15s;box-shadow:0 4px 12px rgba(74,44,26,.04)}.product-card:hover{transform:translateY(-2px);border-color:var(--gold);box-shadow:0 9px 20px rgba(74,44,26,.12)}.product-card.low{border-color:#e49b9b}.product-card.out{opacity:.55}.product-card .cat{font-size:.68rem;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);font-weight:850}.product-card .name{display:block;font-weight:850;margin:7px 0 4px;line-height:1.2}.product-card .sku{font-size:.68rem;color:var(--muted)}.product-card .price{position:absolute;left:13px;bottom:12px;color:var(--brown);font-size:1rem;font-weight:900}.product-card .stock{position:absolute;right:10px;bottom:10px;padding:4px 7px;border-radius:999px;background:#edf8f0;color:#1e6b3c;font-size:.67rem;font-weight:850}.product-card.low .stock{background:#fff0ef;color:var(--red)}
    .cart-panel{position:sticky;top:126px;overflow:hidden}.cart-head{background:linear-gradient(135deg,var(--brown),var(--brown-2));color:#fff;padding:15px 17px;display:flex;justify-content:space-between;align-items:center}.cart-head h2{margin:0;font-size:1.02rem}.cart-head button{border:0;background:rgba(255,255,255,.12);color:#fff;border-radius:9px;padding:7px 9px;font-weight:800}.cart-list{padding:8px 13px;max-height:285px;overflow:auto}.cart-empty{padding:26px 12px;text-align:center;color:var(--muted);border:1px dashed var(--line);border-radius:12px;margin:4px}.cart-line{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px;align-items:center;padding:10px 2px;border-bottom:1px solid #efe4d6}.cart-line .line-name{font-weight:800;font-size:.83rem}.cart-line .line-meta{font-size:.7rem;color:var(--muted);margin-top:2px}.qty-box{display:flex;align-items:center;border:1px solid var(--line);border-radius:9px;overflow:hidden}.qty-box button{border:0;background:#f7efe4;width:28px;height:28px;font-weight:900;color:var(--brown)}.qty-box input{width:48px;border:0;text-align:center;font-size:.78rem;font-weight:800;outline:none}.line-total{min-width:74px;text-align:right;font-weight:850;font-size:.82rem}.remove-line{border:0;background:none;color:var(--red);font-weight:900;padding:3px}
    .customer-grid,.checkout-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:0 14px 10px}.field{display:grid;gap:5px}.field.full{grid-column:1/-1}.field label{font-size:.7rem;color:var(--muted);font-weight:850;text-transform:uppercase;letter-spacing:.04em}.field input,.field select,.field textarea{width:100%;border:1px solid var(--line);border-radius:9px;padding:9px 10px;background:#fff;outline:none}.field textarea{min-height:58px;resize:vertical}.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--gold);box-shadow:0 0 0 3px rgba(212,167,44,.12)}
    .totals{padding:10px 15px;background:#fbf5eb;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.total-row{display:flex;justify-content:space-between;gap:10px;padding:4px 0;font-size:.82rem}.total-row.grand{font-size:1.17rem;font-weight:950;color:var(--brown);padding-top:8px;border-top:1px dashed #d6c0a6;margin-top:4px}.checkout-actions{display:grid;grid-template-columns:1fr 1.6fr;gap:8px;padding:12px 14px 15px}.btn{border:0;border-radius:11px;padding:11px 13px;font-weight:900}.btn-primary{background:linear-gradient(135deg,var(--gold),#edca61);color:var(--brown)}.btn-danger{background:var(--red);color:#fff}.btn-brown{background:var(--brown);color:#fff}.btn-soft{background:#f3e9dc;color:var(--brown);border:1px solid var(--line)}.btn-green{background:var(--green);color:#fff}.btn:disabled{opacity:.5;cursor:not-allowed}.shortcut{font-size:.67rem;opacity:.7;margin-left:5px}
    .split-box{display:none;grid-column:1/-1;border:1px solid var(--line);background:#fffaf3;border-radius:10px;padding:8px}.split-box.active{display:block}.split-row{display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:5px;margin-bottom:5px}.split-row button{border:0;background:#f8dfdf;color:var(--red);border-radius:7px;font-weight:900}.mini-btn{border:1px solid var(--line);background:#fff;padding:7px 9px;border-radius:8px;font-size:.75rem;font-weight:800;color:var(--brown)}
    .section{margin-top:16px;scroll-margin-top:145px}.two-col{display:grid;grid-template-columns:1fr 1fr;gap:14px}.three-col{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}.toolbar{display:flex;align-items:end;gap:8px;flex-wrap:wrap}.toolbar .field{min-width:145px}.toolbar .field.search{min-width:240px;flex:1}.table-wrap{overflow:auto}.data-table{width:100%;border-collapse:collapse;min-width:820px}.data-table th,.data-table td{padding:10px 12px;border-bottom:1px solid #eee3d6;text-align:left;font-size:.79rem;vertical-align:middle}.data-table th{position:sticky;top:0;background:#f7efe4;color:var(--brown);text-transform:uppercase;letter-spacing:.04em;font-size:.68rem}.data-table tr:hover td{background:#fffaf2}.status{display:inline-flex;padding:4px 8px;border-radius:999px;font-size:.68rem;font-weight:900;text-transform:uppercase}.status.completed{background:#e6f6ec;color:#17633a}.status.voided{background:#ffe7e7;color:#8d1717}.status.inactive{background:#efe7df;color:#6d5a4c}.actions{display:flex;gap:6px;flex-wrap:wrap}.link-btn{border:1px solid var(--line);background:#fff;color:var(--brown);border-radius:8px;padding:6px 8px;text-decoration:none;font-size:.72rem;font-weight:850}.link-btn.danger{color:var(--red);border-color:#e8bbbb;background:#fff8f8}
    .low-list{display:grid;gap:7px}.low-item{display:flex;justify-content:space-between;gap:10px;border:1px solid #efcccc;background:#fff8f7;padding:9px 10px;border-radius:10px;font-size:.78rem}.bar-list{display:grid;gap:10px}.bar-row{display:grid;grid-template-columns:minmax(100px,1fr) 2fr auto;gap:10px;align-items:center;font-size:.78rem}.bar-track{height:9px;background:#eee1d2;border-radius:999px;overflow:hidden}.bar-fill{height:100%;background:linear-gradient(90deg,var(--brown),var(--gold));border-radius:999px}.trend{display:grid;grid-template-columns:repeat(7,1fr);gap:8px;align-items:end;height:190px;padding-top:15px}.trend-col{display:grid;grid-template-rows:1fr auto auto;gap:5px;align-items:end;text-align:center}.trend-bar{width:75%;max-width:42px;margin:auto;background:linear-gradient(180deg,var(--gold),var(--brown));border-radius:7px 7px 2px 2px;min-height:3px}.trend-col small{font-size:.65rem;color:var(--muted)}.trend-col strong{font-size:.68rem}
    .form-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.check-row{display:flex;gap:14px;align-items:center;flex-wrap:wrap}.check-row label{display:flex;align-items:center;gap:6px;font-size:.78rem;font-weight:800}.register-card{display:grid;grid-template-columns:1fr 1fr;gap:12px}.register-summary{background:linear-gradient(135deg,#fff7e5,#f8ead2);border:1px solid var(--gold-2);border-radius:14px;padding:15px}.register-summary strong{font-size:1.35rem;display:block;margin-top:4px}
    .modal{position:fixed;inset:0;background:rgba(37,23,15,.62);display:none;align-items:center;justify-content:center;padding:18px;z-index:100}.modal.open{display:flex}.modal-card{width:min(620px,100%);max-height:90vh;overflow:auto;background:var(--paper);border-radius:18px;box-shadow:0 26px 80px rgba(0,0,0,.3)}.modal-head{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:15px 18px;border-bottom:1px solid var(--line)}.modal-head h3{margin:0}.modal-close{border:0;background:#f3e8db;width:34px;height:34px;border-radius:50%;font-weight:900}.modal-body{padding:17px 18px}.receipt{width:340px;max-width:100%;margin:auto;background:#fff;color:#111;padding:18px;font-family:"Courier New",monospace;font-size:12px}.receipt h2{text-align:center;margin:0 0 4px}.receipt .center{text-align:center}.receipt hr{border:0;border-top:1px dashed #444}.receipt-row{display:flex;justify-content:space-between;gap:10px;padding:2px 0}.receipt .item{margin:6px 0}.receipt .item small{display:flex;justify-content:space-between}.receipt .void-mark{border:3px solid #a00;color:#a00;font-size:1.4rem;font-weight:900;text-align:center;padding:6px;transform:rotate(-4deg);margin:12px 0}
    .hint{color:var(--muted);font-size:.75rem}.kbd{display:inline-block;border:1px solid #d2c0ab;background:#fff;padding:1px 5px;border-radius:5px;box-shadow:0 1px 0 #c3ad95;font-size:.68rem}.empty-state{text-align:center;color:var(--muted);padding:26px}.hidden{display:none!important}
    @media(max-width:1120px){.stats{grid-template-columns:repeat(3,1fr)}.pos-grid{grid-template-columns:1fr}.cart-panel{position:static}.product-grid{max-height:520px}.three-col{grid-template-columns:1fr}.form-grid{grid-template-columns:repeat(2,1fr)}}
    @media(max-width:760px){.topbar-inner{align-items:flex-start}.brand p{display:none}.top-actions .pill.user{display:none}.wrap{padding:11px}.stats{grid-template-columns:1fr 1fr}.stat{padding:12px}.stat strong{font-size:1.05rem}.two-col,.register-card{grid-template-columns:1fr}.product-grid{grid-template-columns:repeat(2,minmax(0,1fr));padding:0 10px 10px}.catalog-toolbar{grid-template-columns:1fr;padding:10px}.category-row{padding:0 10px 10px}.customer-grid,.checkout-grid{grid-template-columns:1fr}.field.full{grid-column:auto}.form-grid{grid-template-columns:1fr}.split-row{grid-template-columns:1fr 1fr}.split-row .split-ref{grid-column:1/-1}.nav{padding-left:10px}.panel-head{align-items:flex-start;flex-direction:column}.toolbar{width:100%}.toolbar .field,.toolbar .field.search{width:100%;min-width:0}.checkout-actions{grid-template-columns:1fr}.trend{height:150px}.bar-row{grid-template-columns:1fr}.bar-track{order:3}.top-link.switch{display:none}}
    @media print{body *{visibility:hidden!important}.receipt-print,.receipt-print *{visibility:visible!important}.receipt-print{position:absolute!important;left:0;top:0;width:100%!important;background:#fff!important}.receipt{width:80mm!important;padding:4mm!important}.modal{position:static!important;background:#fff!important;padding:0!important}.modal-card{box-shadow:none!important;max-height:none!important}.modal-head,.receipt-actions{display:none!important}}
  </style>
</head>
<body>
<div class="app">
  <header class="topbar">
    <div class="topbar-inner">
      <div class="brand"><div class="brand-mark"><?= h((string)$meta['emoji']) ?></div><div><h1><?= h($storeName) ?></h1><p><?= h($storeTagline) ?></p></div></div>
      <div class="top-actions">
        <span class="pill user"><?= h((string)$user['name']) ?> · <?= h(ucfirst((string)$user['role'])) ?></span>
        <span class="pill <?= $currentShift ? 'open' : '' ?>"><?= $currentShift ? '● Register open' : '○ Register closed' ?></span>
        <?php if ($isManager): ?><a class="top-link switch" href="tuckshop_projects_logout.php">Change workspace</a><?php endif; ?>
        <a class="top-link" href="tuckshop_projects_logout.php">Logout</a>
      </div>
    </div>
    <nav class="nav"><a href="#sell">Sell</a><a href="#held-orders">Held (<?= count($heldOrders) ?>)</a><a href="#transactions">Transactions</a><a href="#inventory">Inventory</a><a href="#reports">Reports</a><a href="#register">Register</a><?php if ($isManager): ?><a href="#settings">Settings</a><?php endif; ?></nav>
  </header>

  <main class="wrap" id="sell">
    <?php if ($flashes): ?><div class="alerts"><?php foreach ($flashes as $flash): ?><div class="alert <?= h((string)$flash['type']) ?>"><?= h((string)$flash['text']) ?></div><?php endforeach; ?></div><?php endif; ?>

    <section class="stats">
      <article class="stat"><small>Sales today</small><strong>$<?= number_format((float)$todaySummary['sales_usd'],2) ?></strong></article>
      <article class="stat"><small>Transactions</small><strong><?= number_format((int)$todaySummary['tx_count']) ?></strong></article>
      <article class="stat"><small>Estimated profit</small><strong>$<?= number_format($todayProfit,2) ?></strong></article>
      <article class="stat"><small>Held orders</small><strong><?= count($heldOrders) ?></strong></article>
      <article class="stat <?= $lowStock ? 'alert-stat' : '' ?>"><small>Low-stock items</small><strong><?= count($lowStock) ?></strong></article>
    </section>

    <section class="pos-grid">
      <article class="panel">
        <div class="panel-head"><div><h2>Product catalogue</h2><p>Scan a barcode or tap an item. Search with <span class="kbd">F2</span>.</p></div><button class="mini-btn" type="button" id="refreshStockBtn">Refresh stock</button></div>
        <div class="catalog-toolbar">
          <div class="searchbox"><span>⌕</span><input id="productSearch" autocomplete="off" placeholder="Scan barcode, SKU or search product…"></div>
          <select id="saleCurrencyTop" class="mini-btn" aria-label="Sale currency"><?php foreach ($supportedCurrencies as $code): ?><option value="<?= h($code) ?>"><?= h($code) ?></option><?php endforeach; ?></select>
        </div>
        <div class="category-row"><button class="category-btn active" type="button" data-category="all">All products</button><?php foreach ($categories as $category): ?><button class="category-btn" type="button" data-category="<?= h($category) ?>"><?= h($category) ?></button><?php endforeach; ?></div>
        <div class="product-grid" id="productGrid"></div>
      </article>

      <aside class="panel cart-panel">
        <div class="cart-head"><h2>Current sale <span id="cartCountBadge">(0)</span></h2><button type="button" id="clearCartBtn">Clear</button></div>
        <div class="cart-list" id="cartList"><div class="cart-empty">Your cart is empty.<br>Tap a product or scan its barcode.</div></div>
        <div class="customer-grid">
          <div class="field"><label>Customer name</label><input id="customerName" placeholder="Optional / required for credit"></div>
          <div class="field"><label>Phone</label><input id="customerPhone" placeholder="Optional"></div>
        </div>
        <div class="checkout-grid">
          <div class="field"><label>Discount</label><select id="discountType"><option value="none">No discount</option><option value="percent">Percentage %</option><option value="fixed">Fixed amount</option></select></div>
          <div class="field"><label>Discount value</label><input id="discountValue" type="number" min="0" step="0.01" value="0"></div>
          <div class="field"><label>Tax rate</label><input id="taxRate" type="number" min="0" max="100" step="0.01" value="<?= h((string)$defaultTaxRate) ?>"></div>
          <div class="field"><label>Currency</label><select id="saleCurrency"><?php foreach ($supportedCurrencies as $code): ?><option value="<?= h($code) ?>"><?= h($code) ?></option><?php endforeach; ?></select></div>
          <div class="field"><label>Payment method</label><select id="paymentMethod"><option value="cash">Cash</option><option value="ecocash">EcoCash</option><option value="mobile_money">Other mobile money</option><option value="card">Card</option><option value="bank_transfer">Bank transfer</option><option value="credit">Credit / account</option><option value="split">Split payment</option></select></div>
          <div class="field"><label>Amount tendered</label><input id="amountTendered" type="number" min="0" step="0.01" placeholder="0.00"></div>
          <div class="field full" id="referenceField"><label>Payment reference</label><input id="paymentReference" placeholder="Transaction/reference number"></div>
          <div class="split-box" id="splitBox"><div id="splitRows"></div><button class="mini-btn" type="button" id="addSplitBtn">+ Add payment</button></div>
          <div class="field full"><label>Sale note</label><textarea id="saleNotes" placeholder="Optional note for this transaction"></textarea></div>
        </div>
        <div class="totals">
          <div class="total-row"><span>Subtotal</span><span id="subtotalText">$0.00</span></div>
          <div class="total-row"><span>Discount</span><span id="discountText">$0.00</span></div>
          <div class="total-row"><span>Tax</span><span id="taxText">$0.00</span></div>
          <div class="total-row grand"><span>Total</span><span id="totalText">$0.00</span></div>
          <div class="total-row"><span>Change</span><span id="changeText">$0.00</span></div>
        </div>
        <div class="checkout-actions"><button class="btn btn-soft" type="button" id="holdBtn">Hold <span class="shortcut">F8</span></button><button class="btn btn-primary" type="button" id="payBtn">Complete sale <span class="shortcut">F4</span></button></div>
      </aside>
    </section>

    <form method="post" id="saleForm" class="hidden">
      <input type="hidden" name="cart_json" id="formCartJson"><input type="hidden" name="customer_name" id="formCustomerName"><input type="hidden" name="customer_phone" id="formCustomerPhone">
      <input type="hidden" name="currency_code" id="formCurrency"><input type="hidden" name="discount_type" id="formDiscountType"><input type="hidden" name="discount_value" id="formDiscountValue">
      <input type="hidden" name="tax_rate" id="formTaxRate"><input type="hidden" name="payment_method" id="formPaymentMethod"><input type="hidden" name="amount_tendered" id="formTendered">
      <input type="hidden" name="payment_reference" id="formPaymentReference"><input type="hidden" name="payments_json" id="formPaymentsJson"><input type="hidden" name="notes" id="formNotes"><input type="hidden" name="hold_id" id="formHoldId">
      <button name="checkout_cart" id="checkoutSubmit"></button><button name="hold_order" id="holdSubmit"></button>
    </form>

    <section class="section panel" id="held-orders">
      <div class="panel-head"><div><h2>Held orders</h2><p>Park an unfinished sale and resume it later without losing the cart.</p></div><span class="status completed"><?= count($heldOrders) ?> active</span></div>
      <div class="table-wrap"><table class="data-table"><thead><tr><th>Hold reference</th><th>Time</th><th>Customer</th><th>Held by</th><th>Currency</th><th>Actions</th></tr></thead><tbody>
      <?php foreach ($heldOrders as $held): ?><tr><td><strong><?= h((string)$held['hold_ref']) ?></strong></td><td><?= h(date('d M Y H:i',strtotime((string)$held['created_at']))) ?></td><td><?= h((string)($held['customer_name'] ?: 'Walk-in')) ?></td><td><?= h((string)($held['held_by_name'] ?: 'Unknown')) ?></td><td><?= h((string)$held['currency_code']) ?></td><td><div class="actions"><button type="button" class="link-btn resume-hold" data-hold-id="<?= (int)$held['id'] ?>">Resume</button><form method="post" onsubmit="return confirm('Cancel this held order?');"><input type="hidden" name="hold_id" value="<?= (int)$held['id'] ?>"><button class="link-btn danger" name="cancel_hold">Cancel</button></form></div></td></tr><?php endforeach; ?>
      <?php if (!$heldOrders): ?><tr><td colspan="6" class="empty-state">No held orders.</td></tr><?php endif; ?></tbody></table></div>
    </section>

    <section class="section panel" id="transactions">
      <div class="panel-head"><div><h2>Transactions and voids</h2><p>Search, reprint or void completed sales. Voiding restores stock and keeps a complete audit record.</p></div></div>
      <div class="panel-body"><form method="get" class="toolbar">
        <div class="field"><label>From</label><input type="date" name="from" value="<?= h($txFrom) ?>"></div><div class="field"><label>To</label><input type="date" name="to" value="<?= h($txTo) ?>"></div>
        <div class="field"><label>Status</label><select name="status"><option value="all" <?= $txStatus==='all'?'selected':'' ?>>All</option><option value="completed" <?= $txStatus==='completed'?'selected':'' ?>>Completed</option><option value="voided" <?= $txStatus==='voided'?'selected':'' ?>>Voided</option></select></div>
        <div class="field search"><label>Search</label><input name="q" value="<?= h($txSearch) ?>" placeholder="Receipt, customer, phone or cashier"></div><button class="btn btn-brown">Apply filters</button>
      </form></div>
      <div class="table-wrap"><table class="data-table"><thead><tr><th>Receipt</th><th>Date</th><th>Cashier</th><th>Customer</th><th>Payment</th><th>Total</th><th>Status</th><th>Actions</th></tr></thead><tbody>
      <?php foreach ($transactions as $tx): ?><tr><td><strong><?= h((string)$tx['sale_ref']) ?></strong></td><td><?= h(date('d M Y H:i',strtotime((string)$tx['sold_at']))) ?></td><td><?= h((string)($tx['cashier_name'] ?: 'Unknown')) ?></td><td><?= h((string)($tx['customer_name'] ?: 'Walk-in')) ?></td><td><?= h(ucwords(str_replace('_',' ',(string)$tx['payment_method']))) ?></td><td><?= h(pos_currency_symbol((string)$tx['currency_code'])) ?><?= number_format((float)$tx['total_amount'],2) ?></td><td><span class="status <?= h((string)$tx['status']) ?>"><?= h((string)$tx['status']) ?></span></td><td><div class="actions"><a class="link-btn" href="?receipt=<?= (int)$tx['id'] ?>#transactions">Receipt</a><?php if ((string)$tx['status']==='completed'): ?><button class="link-btn danger void-btn" type="button" data-id="<?= (int)$tx['id'] ?>" data-ref="<?= h((string)$tx['sale_ref']) ?>">Void</button><?php endif; ?></div></td></tr><?php endforeach; ?>
      <?php if (!$transactions): ?><tr><td colspan="8" class="empty-state">No transactions match the selected filters.</td></tr><?php endif; ?></tbody></table></div>
    </section>

    <section class="section" id="inventory">
      <div class="two-col">
        <?php if ($isManager): ?><article class="panel"><div class="panel-head"><div><h2>Add or edit product</h2><p>Use SKU and barcode fields for faster checkout.</p></div><button class="mini-btn" type="button" id="resetProductBtn">New product</button></div><div class="panel-body">
          <form method="post" id="productForm"><input type="hidden" name="product_id" id="productId" value="0"><div class="form-grid">
            <div class="field"><label>Product name</label><input name="product_name" id="productName" required></div><div class="field"><label>Category</label><input name="category" id="productCategory" list="categoryOptions" required><datalist id="categoryOptions"><?php foreach ($categories as $category): ?><option value="<?= h($category) ?>"><?php endforeach; ?></datalist></div>
            <div class="field"><label>SKU</label><input name="sku" id="productSku"></div><div class="field"><label>Barcode</label><input name="barcode" id="productBarcode"></div>
            <div class="field"><label>Unit</label><input name="unit_label" id="productUnit" value="unit"></div><div class="field"><label>Buying price USD</label><input name="buying_price" id="productBuying" type="number" min="0" step="0.01" value="0"></div>
            <div class="field"><label>Selling price USD</label><input name="selling_price" id="productSelling" type="number" min="0" step="0.01" required></div><div class="field"><label>Opening stock</label><input name="stock_qty" id="productStock" type="number" min="0" step="0.001" value="0"></div>
            <div class="field"><label>Reorder level</label><input name="reorder_level" id="productReorder" type="number" min="0" step="0.001" value="5"></div><div class="field"><label>Tax rate %</label><input name="product_tax_rate" id="productTax" type="number" min="0" max="100" step="0.01" value="0"></div>
            <div class="field"><label>Supplier</label><input name="supplier_name" id="productSupplier"></div>
          </div><div class="check-row" style="margin:12px 0"><label><input type="checkbox" name="track_stock" id="productTrack" checked> Track stock</label><label><input type="checkbox" name="allow_fractional" id="productFractional"> Allow fractional quantity</label></div><button class="btn btn-brown" name="save_product">Save product</button>
          </form></div></article>
          <article class="panel"><div class="panel-head"><div><h2>Stock adjustment</h2><p>Record deliveries, corrections, waste or damaged items with a reason.</p></div></div><div class="panel-body"><form method="post"><div class="field"><label>Product</label><select name="product_id" required><option value="">Select product</option><?php foreach ($products as $p): ?><option value="<?= (int)$p['id'] ?>"><?= h((string)$p['product_name']) ?> (<?= number_format((float)$p['stock_qty'],3) ?> <?= h((string)$p['unit_label']) ?>)</option><?php endforeach; ?></select></div><div class="two-col" style="margin-top:10px"><div class="field"><label>Mode</label><select name="adjustment_mode"><option value="add">Add or subtract</option><option value="set">Set exact balance</option></select></div><div class="field"><label>Quantity</label><input name="adjustment_qty" type="number" step="0.001" required placeholder="Use negative number to subtract"></div></div><div class="field" style="margin-top:10px"><label>Reason</label><textarea name="adjustment_reason" required placeholder="e.g. Supplier delivery INV-102, damaged stock, stock count correction"></textarea></div><button class="btn btn-brown" name="adjust_stock" style="margin-top:10px">Record adjustment</button></form></div></article><?php endif; ?>
      </div>

      <article class="panel section"><div class="panel-head"><div><h2>Inventory catalogue</h2><p><?= count($products) ?> products · <?= count($lowStock) ?> at or below reorder level.</p></div></div><div class="table-wrap"><table class="data-table"><thead><tr><th>Product</th><th>SKU / Barcode</th><th>Cost</th><th>Price</th><th>Margin</th><th>Stock</th><th>Reorder</th><th>Status</th><?php if ($isManager): ?><th>Actions</th><?php endif; ?></tr></thead><tbody>
      <?php foreach ($products as $p): $margin=(float)$p['selling_price']-(float)$p['buying_price']; ?><tr><td><strong><?= h((string)$p['product_name']) ?></strong><br><small><?= h((string)$p['category']) ?> · <?= h((string)$p['unit_label']) ?></small></td><td><?= h((string)($p['sku'] ?: '—')) ?><br><small><?= h((string)($p['barcode'] ?: 'No barcode')) ?></small></td><td>$<?= number_format((float)$p['buying_price'],2) ?></td><td>$<?= number_format((float)$p['selling_price'],2) ?></td><td>$<?= number_format($margin,2) ?></td><td><strong><?= number_format((float)$p['stock_qty'],3) ?></strong></td><td><?= number_format((float)$p['reorder_level'],3) ?></td><td><span class="status <?= (int)$p['is_active']===1?'completed':'inactive' ?>"><?= (int)$p['is_active']===1?'Active':'Inactive' ?></span></td><?php if ($isManager): ?><td><div class="actions"><button type="button" class="link-btn edit-product" data-product='<?= h(json_encode($p,JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP)) ?>'>Edit</button><form method="post"><input type="hidden" name="product_id" value="<?= (int)$p['id'] ?>"><button class="link-btn" name="toggle_product"><?= (int)$p['is_active']===1?'Disable':'Enable' ?></button></form></div></td><?php endif; ?></tr><?php endforeach; ?>
      <?php if (!$products): ?><tr><td colspan="9" class="empty-state">No products have been added yet.</td></tr><?php endif; ?></tbody></table></div></article>

      <div class="two-col section">
        <article class="panel"><div class="panel-head"><div><h2>Low-stock alerts</h2><p>Products that need replenishment.</p></div></div><div class="panel-body low-list"><?php foreach ($lowStock as $p): ?><div class="low-item"><span><strong><?= h((string)$p['product_name']) ?></strong><br><small>Reorder at <?= number_format((float)$p['reorder_level'],3) ?></small></span><strong><?= number_format((float)$p['stock_qty'],3) ?> <?= h((string)$p['unit_label']) ?></strong></div><?php endforeach; ?><?php if (!$lowStock): ?><div class="empty-state">All tracked products are above reorder levels.</div><?php endif; ?></div></article>
        <article class="panel"><div class="panel-head"><div><h2>Recent stock movements</h2><p>Sale, void and adjustment audit trail.</p></div></div><div class="table-wrap" style="max-height:390px"><table class="data-table"><thead><tr><th>Time</th><th>Product</th><th>Type</th><th>Change</th><th>Balance</th></tr></thead><tbody><?php foreach ($stockMovements as $move): ?><tr><td><?= h(date('d M H:i',strtotime((string)$move['created_at']))) ?></td><td><?= h((string)$move['product_name']) ?></td><td><?= h(ucwords(str_replace('_',' ',(string)$move['movement_type']))) ?></td><td><strong><?= (float)$move['quantity_change']>=0?'+':'' ?><?= number_format((float)$move['quantity_change'],3) ?></strong></td><td><?= number_format((float)$move['balance_after'],3) ?></td></tr><?php endforeach; ?><?php if (!$stockMovements): ?><tr><td colspan="5" class="empty-state">No stock movements recorded.</td></tr><?php endif; ?></tbody></table></div></article>
      </div>
    </section>

    <section class="section" id="reports">
      <div class="three-col">
        <article class="panel"><div class="panel-head"><div><h2>7-day sales trend</h2><p>Completed transaction revenue in USD.</p></div></div><div class="panel-body"><div class="trend"><?php foreach ($dailyTrend as $day): $height=max(2,((float)$day['revenue']/$maxDailyRevenue)*100); ?><div class="trend-col"><div class="trend-bar" style="height:<?= number_format($height,1,'.','') ?>%" title="$<?= number_format((float)$day['revenue'],2) ?>"></div><strong>$<?= number_format((float)$day['revenue'],0) ?></strong><small><?= h(date('D',strtotime((string)$day['sale_day']))) ?></small></div><?php endforeach; ?></div></div></article>
        <article class="panel"><div class="panel-head"><div><h2>Payment mix</h2><p>Last 7 days.</p></div></div><div class="panel-body bar-list"><?php $maxPay=max(1,...array_map(static fn(array $r):float=>(float)$r['amount_usd'],$paymentBreakdown)); foreach ($paymentBreakdown as $pay): ?><div class="bar-row"><span><?= h(ucwords(str_replace('_',' ',(string)$pay['payment_method']))) ?></span><div class="bar-track"><div class="bar-fill" style="width:<?= number_format(((float)$pay['amount_usd']/$maxPay)*100,1,'.','') ?>%"></div></div><strong>$<?= number_format((float)$pay['amount_usd'],2) ?></strong></div><?php endforeach; ?><?php if (!$paymentBreakdown): ?><div class="empty-state">No payment data yet.</div><?php endif; ?></div></article>
        <article class="panel"><div class="panel-head"><div><h2>Top products</h2><p>Last 30 days by revenue.</p></div></div><div class="panel-body bar-list"><?php $maxProd=max(1,...array_map(static fn(array $r):float=>(float)$r['revenue'],$topProducts)); foreach ($topProducts as $top): ?><div class="bar-row"><span><?= h((string)$top['product_name']) ?></span><div class="bar-track"><div class="bar-fill" style="width:<?= number_format(((float)$top['revenue']/$maxProd)*100,1,'.','') ?>%"></div></div><strong>$<?= number_format((float)$top['revenue'],2) ?></strong></div><?php endforeach; ?><?php if (!$topProducts): ?><div class="empty-state">No product sales yet.</div><?php endif; ?></div></article>
      </div>
      <div class="stats section"><article class="stat"><small>Today discounts</small><strong>$<?= number_format((float)$todaySummary['discounts_usd'],2) ?></strong></article><article class="stat"><small>Today tax</small><strong>$<?= number_format((float)$todaySummary['tax_usd'],2) ?></strong></article><article class="stat alert-stat"><small>Voids today</small><strong><?= $voidToday ?></strong></article></div>
    </section>

    <section class="section panel" id="register">
      <div class="panel-head"><div><h2>Cash register shift</h2><p>Track opening float, expected cash, closing cash and variance by cashier.</p></div></div><div class="panel-body register-card">
        <div class="register-summary"><small>Current register status</small><strong><?= $currentShift ? 'OPEN' : 'CLOSED' ?></strong><?php if ($currentShift): ?><p class="hint">Opened <?= h(date('d M Y H:i',strtotime((string)$currentShift['opened_at']))) ?> · Opening float <?= h(pos_currency_symbol((string)$currentShift['currency_code'])) ?><?= number_format((float)$currentShift['opening_float'],2) ?></p><p>Expected cash now: <strong style="display:inline;font-size:1rem"><?= h(pos_currency_symbol((string)$currentShift['currency_code'])) ?><?= number_format($expectedCash,2) ?></strong></p><?php else: ?><p class="hint">Open a shift to record an opening float. A zero-float shift is opened automatically on the first sale.</p><?php endif; ?></div>
        <?php if ($currentShift): ?><form method="post"><input type="hidden" name="shift_id" value="<?= (int)$currentShift['id'] ?>"><div class="field"><label>Counted closing cash</label><input name="closing_cash" type="number" min="0" step="0.01" required></div><div class="field" style="margin-top:9px"><label>Closing notes</label><input name="shift_notes" placeholder="Optional note"></div><button class="btn btn-danger" name="close_shift" style="margin-top:10px">Close shift</button></form><?php else: ?><form method="post"><div class="two-col"><div class="field"><label>Opening float</label><input name="opening_float" type="number" min="0" step="0.01" value="0"></div><div class="field"><label>Currency</label><select name="shift_currency"><?php foreach ($supportedCurrencies as $code): ?><option value="<?= h($code) ?>"><?= h($code) ?></option><?php endforeach; ?></select></div></div><button class="btn btn-green" name="open_shift" style="margin-top:10px">Open shift</button></form><?php endif; ?>
      </div>
    </section>

    <?php if ($isManager): ?><section class="section panel" id="settings"><div class="panel-head"><div><h2>POS settings</h2><p>Store identity, receipt details, tax default and reorder contact.</p></div></div><div class="panel-body"><form method="post"><div class="form-grid"><div class="field"><label>Store name</label><input name="store_name" value="<?= h($storeName) ?>" required></div><div class="field"><label>Phone</label><input name="store_phone" value="<?= h($storePhone) ?>"></div><div class="field"><label>Tagline</label><input name="store_tagline" value="<?= h($storeTagline) ?>"></div><div class="field"><label>Default tax %</label><input name="default_tax_rate" type="number" min="0" max="100" step="0.01" value="<?= h((string)$defaultTaxRate) ?>"></div><div class="field"><label>Reorder WhatsApp</label><input name="reorder_phone" value="<?= h($reorderPhone) ?>" placeholder="+263…"></div><div class="field full"><label>Receipt footer</label><input name="receipt_footer" value="<?= h($receiptFooter) ?>"></div></div><button class="btn btn-brown" name="save_pos_settings" style="margin-top:12px">Save settings</button></form></div></section><?php endif; ?>
  </main>
</div>

<div class="modal" id="voidModal" aria-hidden="true"><div class="modal-card"><div class="modal-head"><h3>Void transaction <span id="voidRef"></span></h3><button class="modal-close" type="button" data-close-modal>×</button></div><div class="modal-body"><p class="hint">This action will mark the sale as voided, restore all stock quantities, and record who performed the void. The audit record cannot be deleted.</p><form method="post"><input type="hidden" name="transaction_id" id="voidTransactionId"><div class="field"><label>Void reason</label><textarea name="void_reason" required minlength="5" placeholder="Explain why this transaction must be voided"></textarea></div><button class="btn btn-danger" name="void_transaction" style="margin-top:12px">Confirm void and restore stock</button></form></div></div></div>

<?php if ($receipt): ?>
<div class="modal open receipt-print" id="receiptModal"><div class="modal-card" style="width:min(430px,100%)"><div class="modal-head"><h3>Receipt <?= h((string)$receipt['sale_ref']) ?></h3><button class="modal-close" type="button" data-close-modal>×</button></div><div class="modal-body"><div class="receipt">
  <h2><?= h($storeName) ?></h2><div class="center"><?= h($storeTagline) ?><br><?= h($storePhone) ?></div><hr><div>Receipt: <?= h((string)$receipt['sale_ref']) ?></div><div>Date: <?= h(date('d M Y H:i',strtotime((string)$receipt['sold_at']))) ?></div><div>Cashier: <?= h((string)($receipt['cashier_name'] ?: 'POS User')) ?></div><?php if (!empty($receipt['customer_name'])): ?><div>Customer: <?= h((string)$receipt['customer_name']) ?></div><?php endif; ?><hr>
  <?php foreach ($receipt['items'] as $item): ?><div class="item"><strong><?= h((string)$item['product_name']) ?></strong><small><span><?= number_format((float)$item['quantity'],3) ?> × <?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$item['unit_price'],2) ?></span><span><?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$item['line_total'],2) ?></span></small></div><?php endforeach; ?><hr>
  <div class="receipt-row"><span>Subtotal</span><span><?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$receipt['subtotal'],2) ?></span></div><div class="receipt-row"><span>Discount</span><span>-<?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$receipt['discount_amount'],2) ?></span></div><div class="receipt-row"><span>Tax</span><span><?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$receipt['tax_amount'],2) ?></span></div><div class="receipt-row" style="font-size:15px;font-weight:bold"><span>TOTAL</span><span><?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$receipt['total_amount'],2) ?></span></div><hr>
  <div>Payment: <?= h(ucwords(str_replace('_',' ',(string)$receipt['payment_method']))) ?></div><div>Tendered: <?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$receipt['amount_tendered'],2) ?></div><div>Change: <?= h(pos_currency_symbol((string)$receipt['currency_code'])) ?><?= number_format((float)$receipt['change_due'],2) ?></div><?php if ((string)$receipt['status']==='voided'): ?><div class="void-mark">VOID</div><div>Reason: <?= h((string)$receipt['void_reason']) ?></div><?php endif; ?><hr><div class="center"><?= h($receiptFooter) ?></div>
</div><div class="receipt-actions" style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px"><button class="btn btn-brown" type="button" onclick="window.print()">Print receipt</button><a class="btn btn-soft" style="text-align:center;text-decoration:none" href="<?= h($pageUrl) ?>">Close</a></div></div></div></div>
<?php endif; ?>

<script>
(() => {
  'use strict';
  const PRODUCTS = <?= json_encode($productsForJs,JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT) ?>;
  const FX = <?= json_encode($fxRates,JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT) ?>;
  const HOLDS = <?= json_encode($holdsForJs,JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT) ?>;
  const STORAGE_KEY = <?= json_encode('mavela_pos_cart_'.$workspace.'_'.(int)$user['id']) ?>;
  const CLEAR_ON_LOAD = <?= $clearCartOnLoad ? 'true' : 'false' ?>;
  let cart = {};
  let selectedCategory = 'all';
  let activeHoldId = 0;

  const el = id => document.getElementById(id);
  const escapeHtml = value => String(value ?? '').replace(/[&<>'"]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;',"'":'&#039;','"':'&quot;'}[c]));
  const currency = () => el('saleCurrency').value;
  const rate = code => Number(FX[code] || 1) || 1;
  const symbol = code => code === 'RAND' ? 'R' : (code === 'ZIG' ? 'ZiG ' : '$');
  const money = (amount, code = currency()) => symbol(code) + Number(amount || 0).toFixed(2);
  const inCurrency = usd => Number(usd || 0) / rate(currency());

  function saveCart() {
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify({cart, holdId:activeHoldId})); } catch (_) {}
  }
  function restoreCart() {
    try {
      const saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
      if (saved.cart && typeof saved.cart === 'object') cart = saved.cart;
      activeHoldId = Number(saved.holdId || 0);
    } catch (_) { cart = {}; }
    Object.keys(cart).forEach(id => {
      const product = PRODUCTS.find(p => p.id === Number(id));
      if (!product) delete cart[id];
      else cart[id] = {...cart[id], ...product, qty:Number(cart[id].qty || 0)};
    });
  }
  function totals() {
    const subtotalUsd = Object.values(cart).reduce((sum, item) => sum + item.price_usd * item.qty, 0);
    const subtotal = inCurrency(subtotalUsd);
    const discountType = el('discountType').value;
    const discountValue = Math.max(0, Number(el('discountValue').value || 0));
    let discount = discountType === 'percent' ? subtotal * Math.min(100, discountValue) / 100 : (discountType === 'fixed' ? Math.min(subtotal, discountValue) : 0);
    const taxable = Math.max(0, subtotal - discount);
    const tax = taxable * Math.max(0, Math.min(100, Number(el('taxRate').value || 0))) / 100;
    const total = taxable + tax;
    const tendered = Math.max(0, Number(el('amountTendered').value || 0));
    const change = ['cash','split'].includes(el('paymentMethod').value) ? Math.max(0, tendered - total) : 0;
    return {subtotal, discount, tax, total, change};
  }
  function renderProducts() {
    const query = el('productSearch').value.trim().toLowerCase();
    const filtered = PRODUCTS.filter(p => (selectedCategory === 'all' || p.category === selectedCategory) && (!query || [p.name,p.category,p.sku,p.barcode].join(' ').toLowerCase().includes(query)));
    el('productGrid').innerHTML = filtered.length ? filtered.map(p => {
      const low = p.track_stock && p.stock <= 0 ? 'out' : (p.track_stock && p.stock <= p.reorder ? 'low' : '');
      return `<button type="button" class="product-card ${low}" data-product-id="${p.id}" ${p.track_stock && p.stock <= 0 ? 'disabled' : ''}><span class="cat">${escapeHtml(p.category)}</span><span class="name">${escapeHtml(p.name)}</span><span class="sku">${escapeHtml(p.sku || p.barcode || 'No code')}</span><span class="price">$${Number(p.price_usd).toFixed(2)}</span><span class="stock">${p.track_stock ? Number(p.stock).toFixed(p.allow_fractional?3:0)+' '+escapeHtml(p.unit) : 'Unlimited'}</span></button>`;
    }).join('') : '<div class="empty-state" style="grid-column:1/-1">No products match your search.</div>';
  }
  function renderCart() {
    const items = Object.values(cart).filter(item => item.qty > 0);
    el('cartCountBadge').textContent = `(${items.reduce((s,i)=>s+i.qty,0).toFixed(0)})`;
    el('cartList').innerHTML = items.length ? items.map(item => `<div class="cart-line"><div><div class="line-name">${escapeHtml(item.name)}</div><div class="line-meta">${money(inCurrency(item.price_usd))} / ${escapeHtml(item.unit)} · ${item.track_stock ? Number(item.stock).toFixed(item.allow_fractional?3:0)+' available' : 'not stock tracked'}</div></div><div class="qty-box"><button type="button" data-cart-action="minus" data-id="${item.id}">−</button><input data-qty-id="${item.id}" type="number" min="${item.allow_fractional?0.001:1}" step="${item.allow_fractional?0.001:1}" value="${Number(item.qty).toFixed(item.allow_fractional?3:0)}"><button type="button" data-cart-action="plus" data-id="${item.id}">+</button></div><div><div class="line-total">${money(inCurrency(item.price_usd*item.qty))}</div><button class="remove-line" type="button" data-cart-action="remove" data-id="${item.id}">Remove</button></div></div>`).join('') : '<div class="cart-empty">Your cart is empty.<br>Tap a product or scan its barcode.</div>';
    let t = totals();
    if (['ecocash','mobile_money','card','bank_transfer','credit'].includes(el('paymentMethod').value)) {
      el('amountTendered').value = t.total.toFixed(2);
      t = totals();
    }
    el('subtotalText').textContent = money(t.subtotal); el('discountText').textContent = '-' + money(t.discount); el('taxText').textContent = money(t.tax); el('totalText').textContent = money(t.total); el('changeText').textContent = money(t.change);
    el('payBtn').disabled = !items.length; el('holdBtn').disabled = !items.length;
    saveCart();
  }
  function addProduct(id, qty=1) {
    const p = PRODUCTS.find(x => x.id === Number(id)); if (!p) return;
    const current = cart[p.id] ? Number(cart[p.id].qty) : 0;
    const next = current + Number(qty);
    if (p.track_stock && next > p.stock + 0.0001) { alert(`Only ${p.stock} ${p.unit} of ${p.name} is available.`); return; }
    cart[p.id] = {...p, qty:p.allow_fractional ? Math.round(next*1000)/1000 : Math.round(next)};
    renderCart();
  }
  function updateQty(id, qty) {
    const item = cart[id]; if (!item) return;
    qty = item.allow_fractional ? Math.round(Number(qty)*1000)/1000 : Math.round(Number(qty));
    if (qty <= 0) delete cart[id]; else if (item.track_stock && qty > item.stock) { alert(`Only ${item.stock} ${item.unit} is available.`); item.qty=item.stock; } else item.qty=qty;
    renderCart();
  }
  function clearCart(force=false) {
    if (!force && Object.keys(cart).length && !confirm('Clear the current cart?')) return;
    cart={}; activeHoldId=0; ['customerName','customerPhone','saleNotes','paymentReference'].forEach(id=>el(id).value=''); el('discountType').value='none'; el('discountValue').value='0'; el('amountTendered').value=''; renderCart();
  }
  function syncCurrency(code) {
    el('saleCurrency').value=code; el('saleCurrencyTop').value=code; renderCart();
  }
  function fillForm() {
    const items = Object.values(cart).map(i=>({id:i.id,qty:i.qty}));
    el('formCartJson').value=JSON.stringify(items); el('formCustomerName').value=el('customerName').value; el('formCustomerPhone').value=el('customerPhone').value; el('formCurrency').value=currency(); el('formDiscountType').value=el('discountType').value; el('formDiscountValue').value=el('discountValue').value; el('formTaxRate').value=el('taxRate').value; el('formPaymentMethod').value=el('paymentMethod').value; el('formTendered').value=el('amountTendered').value; el('formPaymentReference').value=el('paymentReference').value; el('formNotes').value=el('saleNotes').value; el('formHoldId').value=activeHoldId || '';
    const splits = [...document.querySelectorAll('.split-row')].map(row=>({method:row.querySelector('.split-method').value,amount:Number(row.querySelector('.split-amount').value||0),reference:row.querySelector('.split-ref').value})).filter(p=>p.amount>0); el('formPaymentsJson').value=JSON.stringify(splits);
  }
  function addSplitRow(method='cash', amount='', reference='') {
    const row=document.createElement('div'); row.className='split-row'; row.innerHTML=`<select class="split-method"><option value="cash">Cash</option><option value="ecocash">EcoCash</option><option value="mobile_money">Mobile money</option><option value="card">Card</option><option value="bank_transfer">Bank transfer</option></select><input class="split-amount" type="number" min="0" step="0.01" placeholder="Amount"><input class="split-ref" placeholder="Reference"><button type="button">×</button>`; row.querySelector('.split-method').value=method; row.querySelector('.split-amount').value=amount; row.querySelector('.split-ref').value=reference; row.querySelector('button').onclick=()=>row.remove(); row.querySelector('.split-amount').addEventListener('input',()=>{ el('amountTendered').value=[...document.querySelectorAll('.split-amount')].reduce((s,i)=>s+Number(i.value||0),0).toFixed(2); renderCart(); }); el('splitRows').appendChild(row);
  }
  function paymentUi() {
    const method=el('paymentMethod').value; el('splitBox').classList.toggle('active',method==='split'); el('referenceField').classList.toggle('hidden',method==='cash'||method==='split');
    if (method!=='cash' && method!=='split') el('amountTendered').value=totals().total.toFixed(2);
    if (method==='split' && !el('splitRows').children.length) { addSplitRow('cash'); addSplitRow('ecocash'); }
    renderCart();
  }
  function resumeHold(id) {
    const hold=HOLDS[id]; if (!hold) return; clearCart(true); hold.cart.forEach(line=>addProduct(Number(line.id),Number(line.qty))); activeHoldId=Number(id); el('customerName').value=hold.customer_name; el('customerPhone').value=hold.customer_phone; syncCurrency(hold.currency_code); el('discountType').value=hold.discount_type; el('discountValue').value=hold.discount_value; el('taxRate').value=hold.tax_rate; el('saleNotes').value=hold.notes; renderCart(); window.scrollTo({top:0,behavior:'smooth'});
  }

  el('productGrid').addEventListener('click',e=>{const btn=e.target.closest('[data-product-id]'); if(btn)addProduct(Number(btn.dataset.productId));});
  el('productSearch').addEventListener('input',renderProducts);
  el('productSearch').addEventListener('keydown',e=>{if(e.key==='Enter'){e.preventDefault();const q=e.currentTarget.value.trim();const exact=PRODUCTS.find(p=>p.barcode===q||p.sku.toLowerCase()===q.toLowerCase());if(exact){addProduct(exact.id);e.currentTarget.value='';renderProducts();}}});
  document.querySelectorAll('.category-btn').forEach(btn=>btn.addEventListener('click',()=>{document.querySelectorAll('.category-btn').forEach(b=>b.classList.remove('active'));btn.classList.add('active');selectedCategory=btn.dataset.category;renderProducts();}));
  el('cartList').addEventListener('click',e=>{const btn=e.target.closest('[data-cart-action]');if(!btn)return;const id=Number(btn.dataset.id),item=cart[id];if(!item)return;if(btn.dataset.cartAction==='plus')updateQty(id,item.qty+(item.allow_fractional ? 0.1 : 1));if(btn.dataset.cartAction==='minus')updateQty(id,item.qty-(item.allow_fractional ? 0.1 : 1));if(btn.dataset.cartAction==='remove')updateQty(id,0);});
  el('cartList').addEventListener('change',e=>{if(e.target.matches('[data-qty-id]'))updateQty(Number(e.target.dataset.qtyId),Number(e.target.value));});
  ['discountType','discountValue','taxRate','amountTendered'].forEach(id=>el(id).addEventListener('input',renderCart));
  el('saleCurrency').addEventListener('change',e=>syncCurrency(e.target.value)); el('saleCurrencyTop').addEventListener('change',e=>syncCurrency(e.target.value)); el('paymentMethod').addEventListener('change',paymentUi); el('addSplitBtn').addEventListener('click',()=>addSplitRow()); el('clearCartBtn').addEventListener('click',()=>clearCart()); el('refreshStockBtn').addEventListener('click',()=>location.reload());
  el('payBtn').addEventListener('click',()=>{if(!Object.keys(cart).length)return;const t=totals();const method=el('paymentMethod').value;if(method==='credit'&&!el('customerName').value.trim()){alert('Enter the customer name for a credit sale.');return;}if(method==='cash'&&Number(el('amountTendered').value||0)<t.total){alert('Amount tendered is less than the total.');el('amountTendered').focus();return;}if(method==='split'){const splitTotal=[...document.querySelectorAll('.split-amount')].reduce((sum,input)=>sum+Number(input.value||0),0);if(Math.abs(splitTotal-t.total)>0.01){alert(`Split payments must equal ${money(t.total)} exactly.`);return;}}if(!confirm(`Complete this sale for ${money(t.total)}?`))return;fillForm();el('checkoutSubmit').click();});
  el('holdBtn').addEventListener('click',()=>{if(!Object.keys(cart).length)return;fillForm();el('holdSubmit').click();});
  document.querySelectorAll('.resume-hold').forEach(btn=>btn.addEventListener('click',()=>resumeHold(Number(btn.dataset.holdId))));
  document.querySelectorAll('.void-btn').forEach(btn=>btn.addEventListener('click',()=>{el('voidTransactionId').value=btn.dataset.id;el('voidRef').textContent=btn.dataset.ref;el('voidModal').classList.add('open');}));
  document.querySelectorAll('[data-close-modal]').forEach(btn=>btn.addEventListener('click',()=>btn.closest('.modal').classList.remove('open')));
  document.querySelectorAll('.modal').forEach(modal=>modal.addEventListener('click',e=>{if(e.target===modal)modal.classList.remove('open');}));
  document.addEventListener('keydown',e=>{if(e.key==='F2'){e.preventDefault();el('productSearch').focus();el('productSearch').select();}if(e.key==='F4'){e.preventDefault();el('payBtn').click();}if(e.key==='F8'){e.preventDefault();el('holdBtn').click();}if(e.key==='Escape')document.querySelectorAll('.modal.open').forEach(m=>m.classList.remove('open'));});

  <?php if ($isManager): ?>
  const resetProduct=()=>{el('productForm').reset();el('productId').value='0';el('productUnit').value='unit';el('productReorder').value='5';el('productBuying').value='0';el('productTax').value='0';el('productTrack').checked=true;el('productStock').disabled=false;};
  el('resetProductBtn').addEventListener('click',resetProduct);
  document.querySelectorAll('.edit-product').forEach(btn=>btn.addEventListener('click',()=>{const p=JSON.parse(btn.dataset.product);el('productId').value=p.id;el('productName').value=p.product_name;el('productCategory').value=p.category;el('productSku').value=p.sku||'';el('productBarcode').value=p.barcode||'';el('productUnit').value=p.unit_label;el('productBuying').value=p.buying_price;el('productSelling').value=p.selling_price;el('productStock').value=p.stock_qty;el('productStock').disabled=true;el('productReorder').value=p.reorder_level;el('productTax').value=p.tax_rate||0;el('productSupplier').value=p.supplier_name||'';el('productTrack').checked=Number(p.track_stock)!==0;el('productFractional').checked=Number(p.allow_fractional)===1;document.getElementById('inventory').scrollIntoView({behavior:'smooth'});}));
  <?php endif; ?>

  if (CLEAR_ON_LOAD) { try { localStorage.removeItem(STORAGE_KEY); } catch (_) {} cart = {}; activeHoldId = 0; }
  restoreCart(); renderProducts(); renderCart(); paymentUi();
})();
</script>
</body>
</html>

<?php
} catch (Throwable $e) {
  $supportCode = strtoupper(substr(hash('sha256', get_class($e) . '|' . $e->getMessage() . '|' . $e->getFile() . '|' . $e->getLine()), 0, 12));
  error_log('Modern POS startup failure [' . $supportCode . ']: ' . get_class($e) . ': ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
  if (!headers_sent()) {
    http_response_code(500);
    header('Content-Type: text/html; charset=UTF-8');
  }
  $safeMessage = $e instanceof RuntimeException
    ? $e->getMessage()
    : 'The POS could not finish loading because the server or database setup is incomplete.';
?>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>POS setup required</title>
  <style>
    *{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;padding:24px;background:linear-gradient(135deg,#f8f1e5,#fffaf3);font-family:"Segoe UI",Arial,sans-serif;color:#25170f}.card{width:min(760px,100%);background:#fffdf9;border:1px solid #e7d9c8;border-top:7px solid #a61b1b;border-radius:18px;box-shadow:0 20px 60px rgba(74,44,26,.16);padding:26px}.badge{display:inline-block;background:#fff0ef;color:#8b1717;border:1px solid #efc0bd;padding:6px 10px;border-radius:999px;font-weight:800;font-size:.78rem}h1{margin:14px 0 8px;color:#4a2c1a}p{line-height:1.6;color:#655247}.steps{margin:18px 0;background:#fbf5eb;border:1px solid #ead9c2;border-radius:12px;padding:15px 18px}.steps li{margin:8px 0}.code{display:inline-block;background:#4a2c1a;color:#fff;padding:6px 9px;border-radius:8px;font-family:Consolas,monospace}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:18px}.actions a{display:inline-block;text-decoration:none;background:#d4a72c;color:#3b2515;font-weight:900;padding:10px 14px;border-radius:10px}.actions a.secondary{background:#4a2c1a;color:#fff}</style>
</head>
<body>
  <main class="card">
    <span class="badge">Modern POS startup check</span>
    <h1>The POS database upgrade needs attention</h1>
    <p><?= htmlspecialchars($safeMessage, ENT_QUOTES, 'UTF-8') ?></p>
    <div class="steps">
      <strong>Corrective steps</strong>
      <ol>
        <li>Upload the hotfix files <b>pos_core.php</b> and <b>pos_workspace.php</b> together.</li>
        <li>In phpMyAdmin, select the Mavela database and import <b>DB/modern_pos_hotfix.sql</b>.</li>
        <li>Confirm the database user has SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER and INDEX permissions.</li>
        <li>Reload this page after the import completes.</li>
      </ol>
    </div>
    <p>Support code: <span class="code"><?= htmlspecialchars($supportCode, ENT_QUOTES, 'UTF-8') ?></span></p>
    <div class="actions"><a href="tuckshop_projects_login.php">Return to POS login</a><a class="secondary" href="javascript:location.reload()">Retry</a></div>
  </main>
</body>
</html>
<?php
}
?>
