WFDASH-WEBAPP/public/pos/pos.html
2026-08-31 01:42:24 +02:00

393 lines
28 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, user-scalable=no">
<meta name="theme-color" content="#ff385c">
<title>New sale</title>
<link rel="manifest" href="manifest.json">
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='7' fill='%23ff385c'/><text x='16' y='22' font-family='-apple-system,sans-serif' font-size='17' font-weight='700' text-anchor='middle' fill='white'>W</text></svg>">
<style>
:root{
--bg:#ffffff;--surface:#fff7f8;--fg:#222222;--muted:#dddddd;--border:#ffe3e8;--accent:#ff385c;
--ok:#0f8a3f;--warn:#b14a00;--danger:#c92a2a;
--shadow-up:0 -1px 0 var(--muted), 0 -8px 24px rgba(34,34,34,.06);
--font:'Inter',system-ui,-apple-system,Segoe UI,Helvetica Neue,Arial,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{height:100%;background:var(--bg);color:var(--fg);font:15px/1.45 var(--font);-webkit-font-smoothing:antialiased;overscroll-behavior:none;overflow-x:hidden}
body{display:flex;flex-direction:column;min-height:100dvh;max-width:480px;margin:0 auto;background:var(--bg);padding-bottom:env(safe-area-inset-bottom)}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
button:focus-visible,input:focus-visible,select:focus-visible{outline:0;box-shadow:0 0 0 3px rgba(255,56,92,.30);border-radius:10px}
.topbar .back:focus-visible,.topbar .theme-btn:focus-visible{box-shadow:0 0 0 3px rgba(255,56,92,.30);border-radius:50%}
input{font:inherit;color:inherit}
/* ---- Topbar ---- */
.topbar{display:flex;align-items:center;gap:10px;padding:14px 16px 10px;background:var(--bg);position:sticky;top:0;z-index:10;border-bottom:1px solid transparent;transition:border-color .15s}
.topbar.scrolled{border-bottom-color:var(--muted)}
.topbar .back{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;color:var(--fg)}
.topbar .back:active{background:var(--surface)}
.topbar h1{font-size:17px;font-weight:600;letter-spacing:-.01em;flex:1}
.topbar .netpill{font-size:11px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;color:#717171;padding:4px 8px;border:1px solid var(--muted);border-radius:999px}
.topbar .netpill.off{color:var(--danger);border-color:var(--danger);background:#fff5f5}
/* ---- Search ---- */
.search{padding:6px 16px 10px;background:var(--bg);position:sticky;top:60px;z-index:9}
.search-box{display:flex;align-items:center;gap:10px;padding:11px 14px;border:1px solid var(--muted);border-radius:12px;background:#fff;box-shadow:0 1px 2px rgba(34,34,34,.02)}
.search-box:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.12)}
.search-box svg{width:18px;height:18px;color:#717171;flex:0 0 auto;stroke-width:1.7}
.search-box input{flex:1;border:0;outline:0;background:transparent;font-size:15px;min-width:0}
.search-box input::placeholder{color:#9a9a9a}
/* ---- Category dropdown ---- */
.cat-row{display:flex;align-items:center;gap:10px;padding:4px 16px 12px;background:var(--bg);position:sticky;top:118px;z-index:8}
.cat-trigger{display:flex;align-items:center;gap:8px;padding:10px 14px;border:1px solid var(--muted);border-radius:10px;background:#fff;font-size:14px;font-weight:500;color:var(--fg);min-height:42px;max-width:65%;letter-spacing:-.005em}
.cat-trigger:active{background:var(--surface)}
.cat-trigger .cat-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cat-trigger .cat-chev{width:16px;height:16px;flex:0 0 auto;color:#717171;transition:transform .18s}
.cat-trigger[aria-expanded="true"] .cat-chev{transform:rotate(180deg)}
.cat-count{font-size:12px;color:#717171;letter-spacing:.01em;font-variant-numeric:tabular-nums}
.cat-menu{position:fixed;left:16px;right:16px;top:auto;background:#fff;border:1px solid var(--muted);border-radius:14px;box-shadow:0 12px 40px rgba(34,34,34,.18);z-index:60;max-width:448px;margin:0 auto;overflow:hidden;transform-origin:top center;animation:catIn .15s ease}
@keyframes catIn{from{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}
.cat-menu[hidden]{display:none}
.cat-menu-head{max-height:60dvh;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:4px 0}
.cat-item{display:flex;align-items:center;gap:12px;padding:12px 16px;width:100%;text-align:left;font-size:14px;color:var(--fg);font-weight:500;letter-spacing:-.005em;border-bottom:1px solid var(--muted);background:none;min-height:44px}
.cat-item:last-child{border-bottom:0}
.cat-item:active{background:var(--surface)}
.cat-item .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cat-item .ct{font-size:12px;color:#717171;font-variant-numeric:tabular-nums;letter-spacing:.02em;flex:0 0 auto}
.cat-item.active{background:var(--surface);color:var(--accent)}
.cat-item.active .ct{color:var(--accent)}
.cat-item.active::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--accent);flex:0 0 auto}
.cat-backdrop{position:fixed;inset:0;background:transparent;z-index:55}
.cat-backdrop[hidden]{display:none}
/* ---- Catalog list ---- */
.catalog{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:0 16px 220px}
.catalog .meta{padding:12px 0 6px;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#717171;display:flex;justify-content:space-between}
.catalog .empty{padding:60px 20px;text-align:center;color:#9a9a9a}
.catalog .empty h3{font-size:16px;font-weight:600;color:var(--fg);margin-bottom:6px;letter-spacing:-.01em}
.catalog .empty p{font-size:13px;line-height:1.5}
.prod{display:flex;align-items:center;gap:12px;padding:12px 0;border-bottom:1px solid var(--muted);min-height:60px;background:none;border-left:0;border-right:0;border-top:0;width:100%;text-align:left}
.prod:active{background:var(--surface)}
.prod .ic{width:40px;height:40px;border-radius:10px;background:var(--surface);border:1px solid var(--border);display:grid;place-items:center;color:var(--accent);font-size:12px;font-weight:700;letter-spacing:.04em;flex:0 0 auto}
.prod .body{flex:1;min-width:0;padding-right:8px}
.prod .name{font-size:14px;font-weight:500;line-height:1.3;letter-spacing:-.005em;color:var(--fg);overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.prod .sub{font-size:11px;color:#717171;margin-top:2px;letter-spacing:.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.prod .price{font-size:14px;font-weight:600;letter-spacing:-.005em;color:var(--fg);font-variant-numeric:tabular-nums;white-space:nowrap}
.prod .price small{font-size:11px;color:#717171;font-weight:500;margin-left:2px}
/* ---- Cart bottom sheet ---- */
.cart-bar{position:fixed;left:0;right:0;bottom:0;background:#fff;border-top:1px solid var(--muted);padding:12px 16px calc(12px + env(safe-area-inset-bottom));z-index:20;display:flex;align-items:center;gap:12px;box-shadow:var(--shadow-up);max-width:480px;margin:0 auto;transform:translateY(100%);transition:transform .22s cubic-bezier(.2,.8,.2,1)}
.cart-bar.show{transform:translateY(0)}
.cart-bar .count{display:flex;flex-direction:column;line-height:1.15}
.cart-bar .count b{font-size:20px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.cart-bar .count span{font-size:11px;color:#717171;letter-spacing:.04em;text-transform:uppercase}
.cart-bar .total{margin-left:auto;font-size:20px;font-weight:700;letter-spacing:-.02em;color:var(--fg);font-variant-numeric:tabular-nums}
.cart-bar .checkout{padding:14px 22px;background:var(--accent);color:#fff;border-radius:12px;font-weight:600;font-size:15px;letter-spacing:-.005em;min-height:48px;display:flex;align-items:center;gap:6px}
.cart-bar .checkout:active{background:#e5324f}
.cart-bar .checkout svg{width:18px;height:18px;stroke-width:2}
/* ---- Cart drawer ---- */
.drawer{position:fixed;inset:0;background:rgba(34,34,34,.5);z-index:50;opacity:0;pointer-events:none;transition:opacity .2s}
.drawer.show{opacity:1;pointer-events:auto}
.sheet{position:absolute;left:0;right:0;bottom:0;background:#fff;border-radius:18px 18px 0 0;max-height:88dvh;display:flex;flex-direction:column;transform:translateY(100%);transition:transform .25s cubic-bezier(.2,.8,.2,1);max-width:480px;margin:0 auto;padding-bottom:env(safe-area-inset-bottom)}
.drawer.show .sheet{transform:translateY(0)}
.sheet-head{display:flex;align-items:center;padding:18px 20px 8px;border-bottom:1px solid var(--muted)}
.sheet-head h2{font-size:18px;font-weight:700;letter-spacing:-.01em;flex:1}
.sheet-head .x{width:32px;height:32px;border-radius:50%;background:var(--surface);display:grid;place-items:center;color:var(--fg)}
.sheet-body{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:4px 0}
.line{display:flex;align-items:center;gap:12px;padding:14px 20px;border-bottom:1px solid var(--muted)}
.line .nm{flex:1;min-width:0;font-size:14px;font-weight:500;line-height:1.3;letter-spacing:-.005em}
.line .nm small{display:block;font-size:11px;color:#717171;margin-top:2px;letter-spacing:.01em}
.qty{display:flex;align-items:center;border:1px solid var(--muted);border-radius:10px;overflow:hidden}
.qty button{width:34px;height:34px;display:grid;place-items:center;color:var(--fg);font-size:16px;font-weight:600}
.qty button:active{background:var(--surface)}
.qty .v{width:30px;text-align:center;font-size:14px;font-weight:600;font-variant-numeric:tabular-nums}
.line .pr{width:78px;text-align:right;font-size:14px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--fg)}
.line .rm{width:32px;height:32px;border-radius:50%;color:#9a9a9a;display:grid;place-items:center}
.line .rm:active{background:#fff0f0;color:var(--danger)}
.sheet-foot{padding:14px 20px 18px;border-top:1px solid var(--muted);background:#fff}
.totals{display:flex;justify-content:space-between;padding:6px 0;font-size:14px;color:#717171;letter-spacing:.01em}
.totals b{color:var(--fg);font-variant-numeric:tabular-nums}
.totals.grand{padding-top:12px;margin-top:8px;border-top:1px solid var(--muted);font-size:17px;color:var(--fg);font-weight:700;letter-spacing:-.01em}
/* ---- Payment sheet ---- */
.pay-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:8px 20px 16px}
.pay-tile{padding:18px 14px;border:1.5px solid var(--muted);border-radius:14px;background:#fff;text-align:left;min-height:92px;display:flex;flex-direction:column;justify-content:space-between}
.pay-tile:active{background:var(--surface)}
.pay-tile .lab{font-size:14px;font-weight:600;letter-spacing:-.01em}
.pay-tile .sub{font-size:11px;color:#717171;margin-top:2px;letter-spacing:.01em}
.pay-tile .ic{width:32px;height:32px;border-radius:8px;background:var(--surface);color:var(--accent);display:grid;place-items:center;margin-bottom:8px}
.pay-tile .ic svg{width:18px;height:18px;stroke-width:1.7}
.pay-tile.selected{border-color:var(--accent);background:#fff8fa}
.pay-tile.selected .ic{background:var(--accent);color:#fff}
.cash-block{padding:0 16px 20px;display:none}
.cash-block.show{display:block}
.cash-row{display:flex;gap:8px;margin-bottom:10px;min-width:0}
.cash-row .field{flex:1 1 0;min-width:0;display:flex;flex-direction:column}
.cash-row label{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:#717171;margin-bottom:4px}
.cash-row input{width:100%;box-sizing:border-box;padding:12px 10px;border:1px solid var(--muted);border-radius:10px;font-size:16px;font-weight:600;text-align:right;font-variant-numeric:tabular-nums;outline:0;background:#fff;min-width:0}
.cash-row input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.12)}
.quick{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px}
.quick button{padding:9px 13px;border:1px solid var(--muted);border-radius:999px;font-size:13px;font-weight:500;background:#fff;color:var(--fg);min-height:36px}
.quick button:active{background:var(--surface);border-color:#bbb}
.change-out{padding:14px;border-radius:12px;background:var(--surface);border:1px solid var(--border);text-align:center;min-height:64px;display:flex;flex-direction:column;justify-content:center;opacity:0;max-height:0;padding-top:0;padding-bottom:0;overflow:hidden;transition:opacity .15s, max-height .2s, padding .2s, border-width .2s;border-width:0}
.change-out.show{opacity:1;max-height:120px;padding:14px;border-width:1px}
.change-out .lbl{font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#717171}
.change-out .amt{font-size:32px;font-weight:700;letter-spacing:-.02em;color:var(--ok);font-variant-numeric:tabular-nums;margin-top:4px}
.change-out.short .amt{color:var(--danger)}
.cust-block{padding:0 16px 16px;display:none}
.cust-block.show{display:block}
.cust-block .search-row{display:flex;gap:8px;margin-bottom:10px;min-width:0}
.cust-block input{flex:1 1 0;width:100%;box-sizing:border-box;min-width:0;padding:12px 10px;border:1px solid var(--muted);border-radius:10px;font-size:14px;outline:0;background:#fff}
.cust-block input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.12)}
.cust-results{border:1px solid var(--muted);border-radius:10px;max-height:160px;overflow-y:auto;background:#fff}
.cust-results:empty{display:none}
.cust-results div{padding:10px 14px;border-bottom:1px solid var(--muted);font-size:14px;display:flex;align-items:center;gap:8px;cursor:pointer}
.cust-results div:last-child{border-bottom:0}
.cust-results div:active{background:var(--surface)}
.cust-results small{color:#717171;font-size:11px;margin-left:auto;letter-spacing:.02em}
.cust-picked{padding:10px 12px;background:var(--surface);border:1px solid var(--border);border-radius:10px;font-size:13px;display:none;align-items:center;gap:8px;margin-bottom:8px}
.cust-picked.show{display:flex}
.cust-picked b{flex:1;font-weight:600}
.cust-picked button{color:var(--danger);font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}
.final-cta{width:calc(100% - 40px);margin:0 20px 18px;padding:16px;background:var(--accent);color:#fff;border-radius:14px;font-size:16px;font-weight:600;letter-spacing:-.01em;min-height:54px;display:flex;align-items:center;justify-content:center;gap:8px}
.final-cta:active{background:#e5324f}
.final-cta:disabled{background:#e0e0e0;color:#999}
.final-cta svg{width:20px;height:20px;stroke-width:2}
/* ---- theme toggle ---- */
.theme-btn{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;color:var(--fg);flex:0 0 auto;background:transparent;border:0;cursor:pointer;position:relative}
.theme-btn:active{background:var(--surface)}
.theme-btn svg{width:18px;height:18px}
.theme-btn .i-moon{display:none}
:root[data-theme="dark"] .theme-btn .i-sun{display:none}
:root[data-theme="dark"] .theme-btn .i-moon{display:block}
:root[data-theme="auto"] .theme-btn .i-moon{display:none}
:root[data-theme="auto"] .theme-btn .i-sun{display:block}
/* ---- dark theme (auto follows prefers-color-scheme) ---- */
:root[data-theme="dark"]{
--bg:#0f0f0f; --surface:#1c1416; --fg:#f0f0f0; --muted:#2a2a2a; --border:#3a2429;
--shadow-up:0 -1px 0 var(--muted), 0 -8px 24px rgba(0,0,0,.4);
}
:root[data-theme="dark"] body{background:var(--bg);color:var(--fg)}
:root[data-theme="dark"] .topbar{background:var(--bg);border-bottom-color:var(--muted)}
:root[data-theme="dark"] .search-box{background:#181818;border-color:var(--muted)}
:root[data-theme="dark"] .search-box:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.2)}
:root[data-theme="dark"] .search-box svg{color:#888}
:root[data-theme="dark"] .search-box input{color:var(--fg)}
:root[data-theme="dark"] .search-box input::placeholder{color:#666}
:root[data-theme="dark"] .chip{background:#181818;border-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .chip.active{background:var(--fg);color:var(--bg);border-color:var(--fg)}
:root[data-theme="dark"] .cat-trigger{background:#181818;border-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .cat-trigger .cat-chev{color:#888}
:root[data-theme="dark"] .cat-count{color:#888}
:root[data-theme="dark"] .cat-menu{background:#181818;border-color:var(--muted);box-shadow:0 12px 40px rgba(0,0,0,.5)}
:root[data-theme="dark"] .cat-item{color:var(--fg);border-bottom-color:var(--muted)}
:root[data-theme="dark"] .cat-item:active{background:var(--surface)}
:root[data-theme="dark"] .cat-item .ct{color:#888}
:root[data-theme="dark"] .cat-item.active{background:var(--surface);color:var(--accent)}
:root[data-theme="dark"] .prod{border-bottom-color:var(--muted)}
:root[data-theme="dark"] .prod:active{background:var(--surface)}
:root[data-theme="dark"] .prod .ic{background:var(--surface);border-color:var(--border);color:var(--accent)}
:root[data-theme="dark"] .prod .name{color:var(--fg)}
:root[data-theme="dark"] .prod .sub{color:#888}
:root[data-theme="dark"] .prod .price{color:var(--fg)}
:root[data-theme="dark"] .prod .price small{color:#888}
:root[data-theme="dark"] .cart-bar{background:#181818;border-top-color:var(--muted);box-shadow:var(--shadow-up)}
:root[data-theme="dark"] .cart-bar .count span{color:#888}
:root[data-theme="dark"] .cart-bar .total{color:var(--fg)}
:root[data-theme="dark"] .drawer{background:rgba(0,0,0,.7)}
:root[data-theme="dark"] .sheet{background:#181818}
:root[data-theme="dark"] .sheet-head{border-bottom-color:var(--muted)}
:root[data-theme="dark"] .sheet-head .x{background:var(--surface);color:var(--fg)}
:root[data-theme="dark"] .line{border-bottom-color:var(--muted)}
:root[data-theme="dark"] .line .nm{color:var(--fg)}
:root[data-theme="dark"] .line .nm small{color:#888}
:root[data-theme="dark"] .qty{border-color:var(--muted)}
:root[data-theme="dark"] .qty button{color:var(--fg)}
:root[data-theme="dark"] .qty button:active{background:var(--surface)}
:root[data-theme="dark"] .line .pr{color:var(--fg)}
:root[data-theme="dark"] .line .rm{color:#666}
:root[data-theme="dark"] .line .rm:active{background:#3a2429;color:var(--accent)}
:root[data-theme="dark"] .sheet-foot{background:#181818;border-top-color:var(--muted)}
:root[data-theme="dark"] .totals{color:#888}
:root[data-theme="dark"] .totals b{color:var(--fg)}
:root[data-theme="dark"] .totals.grand{border-top-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .empty{color:#666}
:root[data-theme="dark"] .empty h3{color:var(--fg)}
:root[data-theme="dark"] .empty p{color:#888}
:root[data-theme="dark"] .netpill{background:transparent;color:#888;border-color:var(--muted)}
:root[data-theme="dark"] .netpill.off{color:#ff6680;border-color:#ff6680;background:#2a1a1a}
:root[data-theme="dark"] .back:active{background:var(--surface)}
:root[data-theme="dark"] .pay-tile{background:#181818;border-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .pay-tile:active{background:var(--surface)}
:root[data-theme="dark"] .pay-tile .ic{background:var(--surface);color:var(--accent)}
:root[data-theme="dark"] .pay-tile.selected{border-color:var(--accent);background:#2a1a1a}
:root[data-theme="dark"] .pay-tile.selected .ic{background:var(--accent);color:#fff}
:root[data-theme="dark"] .cash-row input{background:#181818;border-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .cash-row input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.2)}
:root[data-theme="dark"] .cash-row input[readonly]{background:#222;color:#aaa}
:root[data-theme="dark"] .cash-row label{color:#888}
:root[data-theme="dark"] .quick button{background:#181818;border-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .quick button:active{background:var(--surface);border-color:#444}
:root[data-theme="dark"] .change-out{background:var(--surface);border-color:var(--border);color:var(--fg)}
:root[data-theme="dark"] .change-out .lbl{color:#888}
:root[data-theme="dark"] .cust-block input{background:#181818;border-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .cust-block input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.2)}
:root[data-theme="dark"] .cust-results{background:#181818;border-color:var(--muted)}
:root[data-theme="dark"] .cust-results div{border-bottom-color:var(--muted);color:var(--fg)}
:root[data-theme="dark"] .cust-results div:active{background:var(--surface)}
:root[data-theme="dark"] .cust-results small{color:#888}
:root[data-theme="dark"] .cust-picked{background:var(--surface);border-color:var(--border);color:var(--fg)}
:root[data-theme="dark"] .final-cta:disabled{background:#2a2a2a;color:#666}
@media (prefers-reduced-motion: reduce){*{transition-duration:0.01ms !important;animation-duration:0.01ms !important}}
</style>
</head>
<body>
<header class="topbar" id="topbar">
<button class="back" data-od-id="back-btn" onclick="if(history.length>1)history.back();else location.href='index.html'" aria-label="Back">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 6l-6 6 6 6"/></svg>
</button>
<h1>New sale</h1>
<span class="netpill" id="netpill">…</span>
<button class="theme-btn" data-theme-toggle data-od-id="theme-toggle" aria-label="Toggle theme" title="Toggle theme" onclick="(window.WFTheme&&window.WFTheme.cycle())||(window.__wfCycle&&window.__wfCycle())">
<svg class="i-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
<svg class="i-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
</header>
<div class="search">
<div class="search-box">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
<input id="q" type="search" placeholder="Search SKU or product" autocomplete="off" inputmode="search" enterkeyhint="search">
</div>
</div>
<div class="cat-row">
<button class="cat-trigger" id="catTrigger" data-od-id="cat-trigger" aria-haspopup="listbox" aria-expanded="false">
<span class="cat-label" id="catLabel">All categories</span>
<svg class="cat-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M6 9l6 6 6-6"/></svg>
</button>
<span class="cat-count" id="catCount">— products</span>
</div>
<div class="cat-menu" id="catMenu" role="listbox" hidden>
<div class="cat-menu-head" id="catMenuItems"></div>
</div>
<div class="cat-backdrop" id="catBackdrop" hidden></div>
<main class="catalog" id="catalog">
<div class="empty" id="empty">
<h3>Loading catalog…</h3>
<p>Fetching products from the register.</p>
</div>
</main>
<div class="cart-bar" id="cartBar" data-od-id="cart-bar">
<button class="back" style="width:44px;height:44px;border-radius:50%;background:var(--surface);border:1px solid var(--border)" onclick="openDrawer()" aria-label="View cart">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M3 6h2l2 12h12l2-9H6"/><circle cx="9" cy="20" r="1.4"/><circle cx="17" cy="20" r="1.4"/></svg>
</button>
<div class="count"><b id="cartCount">0</b><span>items</span></div>
<div class="total" id="cartTotal">R 0.00</div>
<button class="checkout" data-od-id="checkout-btn" onclick="openPayment()">
Charge
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
</button>
</div>
<!-- Cart drawer -->
<div class="drawer" id="cartDrawer">
<div class="sheet">
<div class="sheet-head">
<h2>Cart</h2>
<button class="x" onclick="closeDrawer()" aria-label="Close">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 6l12 12M18 6L6 18"/></svg>
</button>
</div>
<div class="sheet-body" id="cartLines"></div>
<div class="sheet-foot">
<div class="totals"><span>Subtotal</span><b id="subTotal">R 0.00</b></div>
<div class="totals"><span>VAT 15%</span><b id="vatTotal">R 0.00</b></div>
<div class="totals grand"><span>Total (incl. VAT)</span><b id="grandTotal">R 0.00</b></div>
<button class="final-cta" data-od-id="cart-checkout" onclick="closeDrawer();openPayment()">
Take payment
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
</button>
</div>
</div>
</div>
<!-- Payment drawer -->
<div class="drawer" id="payDrawer">
<div class="sheet">
<div class="sheet-head">
<h2>Take payment</h2>
<button class="x" onclick="closePayment()" aria-label="Close">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 6l12 12M18 6L6 18"/></svg>
</button>
</div>
<div class="sheet-body">
<div class="totals" style="padding:10px 20px 0"><span>Subtotal</span><b id="paySub">R 0.00</b></div>
<div class="totals" style="padding:0 20px"><span>VAT 15%</span><b id="payVat">R 0.00</b></div>
<div class="totals grand" style="padding:14px 20px"><span>Total due</span><b id="payTotal">R 0.00</b></div>
<div class="pay-grid" id="payGrid">
<button class="pay-tile" data-od-id="pay-cash" data-meth="cash" onclick="pickMethod('cash')">
<div><div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="6" width="18" height="12" rx="2"/><circle cx="12" cy="12" r="2.5"/></svg></div><div class="lab">Cash</div><div class="sub">Calculate change</div></div>
</button>
<button class="pay-tile" data-od-id="pay-card" data-meth="card" onclick="pickMethod('card')">
<div><div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="6" width="18" height="12" rx="2"/><path d="M3 10h18"/></svg></div><div class="lab">Card</div><div class="sub">No change</div></div>
</button>
<button class="pay-tile" data-od-id="pay-eft" data-meth="eft" onclick="pickMethod('eft')">
<div><div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 7h16M4 12h16M4 17h10"/></svg></div><div class="lab">EFT</div><div class="sub">Instant transfer</div></div>
</button>
<button class="pay-tile" data-od-id="pay-account" data-meth="account" onclick="pickMethod('account')">
<div><div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M19 8v6M22 11h-6"/></svg></div><div class="lab">Account</div><div class="sub">Print delivery note</div></div>
</button>
</div>
<div class="cash-block" id="cashBlock">
<div class="cash-row">
<div class="field"><label>Total due</label><input id="dueIn" type="text" readonly tabindex="-1"></div>
<div class="field"><label>Cash given</label><input id="givenIn" type="text" inputmode="decimal" placeholder="0.00"></div>
</div>
<div class="quick" id="quick"></div>
<div class="change-out" id="changeOut">
<div class="lbl">Change to give</div>
<div class="amt" id="changeAmt">R 0.00</div>
</div>
</div>
<div class="cust-block" id="custBlock">
<div class="cust-picked" id="custPicked"><b></b><button onclick="clearCust()">Remove</button></div>
<div class="search-row">
<input id="custQ" placeholder="Search customer" autocomplete="off">
</div>
<div class="cust-results" id="custResults"></div>
</div>
</div>
<div style="padding:0 20px 18px">
<button class="final-cta" id="confirmBtn" data-od-id="confirm-pay" disabled onclick="confirmSale()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12l5 5 9-11"/></svg>
Complete sale
</button>
</div>
</div>
</div>
<script src="pos-config.js"></script>
<script src="theme.js"></script>
<script src="pos-app.js"></script>
<script>if("serviceWorker" in navigator){navigator.serviceWorker.register("sw.js").catch(function(){});}</script>
</body>
</html>