diff --git a/public/pos/cashup.html b/public/pos/cashup.html index 6216631..91b3b42 100644 --- a/public/pos/cashup.html +++ b/public/pos/cashup.html @@ -93,9 +93,9 @@ button:focus-visible,input:focus-visible,select:focus-visible{outline:0;box-shad @media (prefers-color-scheme: dark){ :root:not([data-theme="light"]){ - --bg:#0f0f0f;--surface:#1c1416;--surface-2:#181818;--surface-card:#181818; - --fg:#f0f0f0;--ink-soft:#a0a0a0;--ink-faint:#777; - --muted:#2a2a2a;--border:#3a2429; + --bg:#161619;--surface:#1e1e23;--surface-2:#1e1e23;--surface-card:#26262d; + --fg:#f2f2f5;--ink-soft:#a0a0a0;--ink-faint:#8e8e9a; + --muted:#303039;--border:#3b3b46; --accent-soft:#2a1a1a;--accent-2:#3a2429; --ok-soft:#1a2e22;--warn-soft:#2a1a1a;--danger-soft:#2a1a1a;--danger-2:#3a2429; } @@ -137,10 +137,10 @@ button:focus-visible,input:focus-visible,select:focus-visible{outline:0;box-shad :root:not([data-theme="light"]) .skeleton{color:var(--ink-faint)} } :root[data-theme="dark"]{ - --bg:#0f0f0f;--surface:#1c1416;--surface-2:#181818;--surface-card:#181818; - --fg:#f0f0f0;--ink-soft:#a0a0a0;--ink-faint:#777; - --muted:#2a2a2a;--border:#3a2429; - --accent-soft:#2a1a1a;--accent-2:#3a2429; + --bg:#161619;--surface:#1e1e23;--surface-2:#1e1e23;--surface-card:#26262d; + --fg:#f2f2f5;--ink-soft:#a0a0a0;--ink-faint:#8e8e9a; + --muted:#303039;--border:#3b3b46; + --accent-soft:#2b1f24;--accent-2:#3f2b33; --ok-soft:#1a2e22;--warn-soft:#2a1a1a;--danger-soft:#2a1a1a;--danger-2:#3a2429; background:var(--bg);color:var(--fg); } diff --git a/public/pos/history.html b/public/pos/history.html index 2e9cd38..30aecba 100644 --- a/public/pos/history.html +++ b/public/pos/history.html @@ -92,7 +92,7 @@ button:focus-visible,input:focus-visible,select:focus-visible{outline:0;box-shad .rf-actions .danger{background:#c92a2a;color:#fff} .rf-actions .danger:disabled{opacity:.6} :root[data-theme="dark"] .sale-row .nm b em{color:#ff6680} -:root[data-theme="dark"] .rf-sheet{background:#181818;box-shadow:0 20px 60px rgba(0,0,0,.6)} +:root[data-theme="dark"] .rf-sheet{background:var(--surface);box-shadow:0 20px 60px rgba(0,0,0,.6)} :root[data-theme="dark"] .rf-head h3 small{color:#888} :root[data-theme="dark"] .rf-chip{border-color:var(--muted);color:#888} :root[data-theme="dark"] .rf-warn{background:#2a1a1a;border-color:#5a2429;color:#ff9db0} @@ -112,9 +112,9 @@ button:focus-visible,input:focus-visible,select:focus-visible{outline:0;box-shad @media (prefers-color-scheme: dark){ :root:not([data-theme="light"]){ - --bg:#0f0f0f;--surface:#1c1416;--surface-2:#181818;--surface-card:#181818; - --fg:#f0f0f0;--ink-soft:#a0a0a0;--ink-faint:#777; - --muted:#2a2a2a;--border:#3a2429; + --bg:#161619;--surface:#1e1e23;--surface-2:#1e1e23;--surface-card:#26262d; + --fg:#f2f2f5;--ink-soft:#a0a0a0;--ink-faint:#8e8e9a; + --muted:#303039;--border:#3b3b46; --accent-soft:#2a1a1a;--accent-2:#3a2429; --danger-soft:#2a1a1a;--danger-2:#3a2429; } @@ -140,10 +140,10 @@ button:focus-visible,input:focus-visible,select:focus-visible{outline:0;box-shad :root:not([data-theme="light"]) .empty p{color:var(--ink-soft)} } :root[data-theme="dark"]{ - --bg:#0f0f0f;--surface:#1c1416;--surface-2:#181818;--surface-card:#181818; - --fg:#f0f0f0;--ink-soft:#a0a0a0;--ink-faint:#777; - --muted:#2a2a2a;--border:#3a2429; - --accent-soft:#2a1a1a;--accent-2:#3a2429; + --bg:#161619;--surface:#1e1e23;--surface-2:#1e1e23;--surface-card:#26262d; + --fg:#f2f2f5;--ink-soft:#a0a0a0;--ink-faint:#8e8e9a; + --muted:#303039;--border:#3b3b46; + --accent-soft:#2b1f24;--accent-2:#3f2b33; --danger-soft:#2a1a1a;--danger-2:#3a2429; background:var(--bg);color:var(--fg); } diff --git a/public/pos/index.html b/public/pos/index.html index 34629e7..c0bfe8f 100644 --- a/public/pos/index.html +++ b/public/pos/index.html @@ -53,22 +53,22 @@ h1{font-size:28px;font-weight:700;letter-spacing:-.02em;line-height:1.15;margin: :root[data-theme="dark"] .theme-btn .i-moon{display:block} @media (prefers-color-scheme: dark){ - :root:not([data-theme="light"]){--bg:#0f0f0f;--surface:#1c1416;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429} + :root:not([data-theme="light"]){--bg:#161619;--surface:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46} :root:not([data-theme="light"]) .lede,:root:not([data-theme="light"]) .brand .sub,:root:not([data-theme="light"]) .card .desc,:root:not([data-theme="light"]) .foot{color:#a0a0a0} - :root:not([data-theme="light"]) .card{background:#181818} - :root:not([data-theme="light"]) .statusbar{background:#181818;border-color:#3a2429;color:#a0a0a0} - :root:not([data-theme="light"]) .pill{background:#181818;border-color:#3a2429;color:#f0f0f0} + :root:not([data-theme="light"]) .card{background:var(--surface)} + :root:not([data-theme="light"]) .statusbar{background:var(--surface);border-color:var(--border);color:#a0a0a0} + :root:not([data-theme="light"]) .pill{background:var(--surface);border-color:var(--border);color:#f0f0f0} :root:not([data-theme="light"]) .pill .dot{box-shadow:0 0 0 3px rgba(15,138,63,.2)} } :root[data-theme="dark"]{ - --bg:#0f0f0f;--surface:#1c1416;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429; + --bg:#161619;--surface:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46; background:var(--bg);color:var(--fg); } :root[data-theme="dark"] body{background:var(--bg);color:var(--fg)} :root[data-theme="dark"] .lede,:root[data-theme="dark"] .brand .sub,:root[data-theme="dark"] .card .desc,:root[data-theme="dark"] .foot{color:#a0a0a0} -:root[data-theme="dark"] .card{background:#181818} -:root[data-theme="dark"] .statusbar{background:#181818;border-color:#3a2429;color:#a0a0a0} -:root[data-theme="dark"] .pill{background:#181818;border-color:#3a2429;color:#f0f0f0} +:root[data-theme="dark"] .card{background:var(--surface)} +:root[data-theme="dark"] .statusbar{background:var(--surface);border-color:var(--border);color:#a0a0a0} +:root[data-theme="dark"] .pill{background:var(--surface);border-color:var(--border);color:#f0f0f0} @media (prefers-reduced-motion: reduce){*{transition-duration:0.01ms !important;animation-duration:0.01ms !important}} diff --git a/public/pos/pos-app.js b/public/pos/pos-app.js index 2556394..e0404dc 100644 --- a/public/pos/pos-app.js +++ b/public/pos/pos-app.js @@ -524,6 +524,11 @@ function renderCartDrawer(){ `− ${fmt(t.discountAmount)}${pctLabel} ex VAT`; } else { dl.hidden = true; + // Blank the figure as well as hiding the row. A discount that has + // been cleared must not leave its old amount sitting on screen — + // an operator seeing "− R 98.37" under a total that no longer + // contains it has no way to tell stale text from a live one. + document.getElementById('discountLineAmount').textContent = ''; } } diff --git a/public/pos/pos.html b/public/pos/pos.html index eb6466c..c9f10dc 100644 --- a/public/pos/pos.html +++ b/public/pos/pos.html @@ -12,10 +12,22 @@ :root{ --bg:#ffffff;--surface:#fff7f8;--fg:#222222;--muted:#dddddd;--border:#ffe3e8;--accent:#ff385c; --ok:#0f8a3f;--warn:#b14a00;--danger:#c92a2a; + /* Text greys were hardcoded per-component, which is why the dark theme + had to restate 43 of them and why the greys drifted out of spec. One + token each; the dark block below rebinds them to lighter values so + they clear WCAG AA against a dark canvas. */ + --muted-fg:#717171;--icon-fg:#888;--placeholder-fg:#666; --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} +/* Any class rule that sets `display` beats the UA stylesheet's + `[hidden]{display:none}`, so a hidden element stays visible and every + JS `.hidden = true/false` silently does nothing. `.cat-menu` and + `.cat-backdrop` already carry per-element overrides for this; this + one rule covers every element (and every future one) instead of + relying on someone remembering to add a twin. */ +[hidden]{display:none !important} 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} @@ -29,14 +41,14 @@ input{font:inherit;color:inherit} .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{font-size:11px;letter-spacing:.06em;text-transform:uppercase;font-weight:600;color:var(--muted-fg);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 svg{width:18px;height:18px;color:var(--muted-fg);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} @@ -45,9 +57,9 @@ input{font:inherit;color:inherit} .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 .cat-chev{width:16px;height:16px;flex:0 0 auto;color:var(--muted-fg);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-count{font-size:12px;color:var(--muted-fg);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)}} @@ -57,7 +69,7 @@ input{font:inherit;color:inherit} .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 .ct{font-size:12px;color:var(--muted-fg);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} @@ -67,10 +79,10 @@ input{font:inherit;color:inherit} /* ---- 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 .meta{padding:12px 0 6px;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted-fg);display:flex;justify-content:space-between} .catalog .empty{padding:60px 20px;text-align:center;color:#9a9a9a} .catalog .more{display:flex;flex-direction:column;align-items:center;gap:2px;width:100%;margin:14px 0 8px;padding:14px;border:1px solid var(--muted);border-radius:12px;background:var(--surface-card);color:var(--fg);font-size:14px;font-weight:600;letter-spacing:-.005em} -.catalog .more small{font-size:11px;font-weight:500;color:#717171;letter-spacing:.02em} +.catalog .more small{font-size:11px;font-weight:500;color:var(--muted-fg);letter-spacing:.02em} .catalog .more:active{background:var(--surface)} .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} @@ -81,16 +93,16 @@ input{font:inherit;color:inherit} .prod .ic .ic-fa{font-size:18px;line-height:1;color:var(--accent)} .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 .sub{font-size:11px;color:var(--muted-fg);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} +.prod .price small{font-size:11px;color:var(--muted-fg);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 .count span{font-size:11px;color:var(--muted-fg);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} @@ -107,7 +119,7 @@ input{font:inherit;color:inherit} .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} +.line .nm small{display:block;font-size:11px;color:var(--muted-fg);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)} @@ -117,7 +129,7 @@ input{font:inherit;color:inherit} .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{display:flex;justify-content:space-between;padding:6px 0;font-size:14px;color:var(--muted-fg);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} @@ -125,7 +137,7 @@ input{font:inherit;color:inherit} /* A dashed outline rather than a filled button: this is a secondary action next to the real catalogue, and it should read as "something extra" rather than compete with the checkout CTA below it. */ -.custom-item-btn{width:100%;margin-bottom:12px;padding:10px 12px;border:1px dashed #c9c9c9;border-radius:9px;background:none;color:#717171;font-size:13px;font-weight:600;letter-spacing:.01em;text-align:center;cursor:pointer} +.custom-item-btn{width:100%;margin-bottom:12px;padding:10px 12px;border:1px dashed #c9c9c9;border-radius:9px;background:none;color:var(--muted-fg);font-size:13px;font-weight:600;letter-spacing:.01em;text-align:center;cursor:pointer} .custom-item-btn:active{background:#f4f4f4} /* Ties a custom line back to the "not stock" meaning at a glance, and stops anyone mistaking it for a catalogue item on a stocktake. */ @@ -137,7 +149,7 @@ input{font:inherit;color:inherit} adds no vertical height at all — the footer keeps every pixel it had before. It stays visible rather than collapsing away, because a discount control that appears from nowhere is one nobody finds under pressure. */ -.discount-trigger{display:inline-flex;align-items:center;gap:3px;margin-left:8px;padding:3px 6px;border:0;border-radius:6px;background:none;color:#717171;font-size:12px;font-weight:600;letter-spacing:.01em;vertical-align:middle} +.discount-trigger{display:inline-flex;align-items:center;gap:3px;margin-left:8px;padding:3px 6px;border:0;border-radius:6px;background:none;color:var(--muted-fg);font-size:12px;font-weight:600;letter-spacing:.01em;vertical-align:middle} .discount-trigger:active{background:var(--surface);color:var(--fg)} .discount-trigger svg{width:13px;height:13px;color:inherit;transition:transform .18s} .discount-trigger[aria-expanded="true"] svg{transform:rotate(180deg)} @@ -145,15 +157,15 @@ input{font:inherit;color:inherit} .discount-trigger.has-value svg{color:var(--accent)} .discount-body{padding:12px 0 4px;display:flex;flex-direction:column;gap:10px} .discount-pills{display:flex;gap:6px;padding:3px;background:var(--surface);border:1px solid var(--muted);border-radius:999px;width:fit-content} -.discount-pill{padding:7px 16px;border-radius:999px;font-size:13px;font-weight:600;letter-spacing:-.005em;color:#717171;min-height:34px} +.discount-pill{padding:7px 16px;border-radius:999px;font-size:13px;font-weight:600;letter-spacing:-.005em;color:var(--muted-fg);min-height:34px} .discount-pill.active{background:#fff;color:var(--accent);box-shadow:0 1px 2px rgba(34,34,34,.06)} .discount-input-row{display:flex;align-items:center;gap:8px} .discount-input-row input{flex:1 1 0;min-width:0;padding:11px 12px;border:1px solid var(--muted);border-radius:10px;font-size:15px;font-weight:600;text-align:right;font-variant-numeric:tabular-nums;outline:0;background:#fff} .discount-input-row input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.12)} -.discount-suffix{font-size:13px;font-weight:600;color:#717171;width:18px;text-align:left;letter-spacing:-.005em} +.discount-suffix{font-size:13px;font-weight:600;color:var(--muted-fg);width:18px;text-align:left;letter-spacing:-.005em} .discount-apply{padding:11px 16px;background:var(--accent);color:#fff;border-radius:10px;font-size:13px;font-weight:600;letter-spacing:-.005em;min-height:42px;min-width:78px} .discount-apply:active{background:#e5324f} -.discount-hint{font-size:11px;color:#717171;margin:0;letter-spacing:.01em} +.discount-hint{font-size:11px;color:var(--muted-fg);margin:0;letter-spacing:.01em} .totals.discount-line{color:var(--danger)} .totals.discount-line b{color:var(--danger)} @@ -170,9 +182,9 @@ input{font:inherit;color:inherit} .edit-sheet{position:fixed;left:50%;bottom:24px;z-index:71;transform:translate(-50%, 24px);background:#fff;border-radius:18px;width:calc(100% - 32px);max-width:448px;padding:18px 18px 14px;opacity:0;transition:opacity .15s, transform .22s cubic-bezier(.2,.8,.2,1);box-shadow:0 20px 60px rgba(34,34,34,.30);pointer-events:none;display:flex;flex-direction:column;gap:12px;max-height:80dvh;overflow-y:auto;-webkit-overflow-scrolling:touch;padding-bottom:calc(14px + env(safe-area-inset-bottom))} .edit-sheet.show{opacity:1;transform:translate(-50%, 0);pointer-events:auto} .edit-sheet h3{font-size:15px;font-weight:600;letter-spacing:-.01em;margin:0;display:flex;align-items:center;gap:8px} -.edit-sheet h3 small{font-size:11px;font-weight:500;color:#717171;letter-spacing:.02em;margin-left:auto} +.edit-sheet h3 small{font-size:11px;font-weight:500;color:var(--muted-fg);letter-spacing:.02em;margin-left:auto} .edit-row{display:flex;flex-direction:column;gap:6px} -.edit-row label{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:#717171} +.edit-row label{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted-fg)} .edit-row input{width:100%;box-sizing:border-box;padding:12px 12px;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} .edit-row input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.12)} .edit-actions{display:flex;gap:8px;margin-top:4px} @@ -194,7 +206,7 @@ input{font:inherit;color:inherit} .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 .sub{font-size:11px;color:var(--muted-fg);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} @@ -204,7 +216,7 @@ input{font:inherit;color:inherit} .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 label{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted-fg);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} @@ -212,7 +224,7 @@ input{font:inherit;color:inherit} .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 .lbl{font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted-fg)} .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)} @@ -226,11 +238,11 @@ input{font:inherit;color:inherit} .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-results small{color:var(--muted-fg);font-size:11px;margin-left:auto;letter-spacing:.02em} /* Count header + empty state. Both are divs inside .cust-results, so they need the row cursor/padding neutralised explicitly. */ -.cust-results .cust-count{padding:7px 14px;background:var(--surface);border-bottom:1px solid var(--muted);font-size:11px;font-weight:600;letter-spacing:.02em;color:#717171;cursor:default} -.cust-results .cust-none{padding:11px 14px;font-size:13px;color:#717171;cursor:default} +.cust-results .cust-count{padding:7px 14px;background:var(--surface);border-bottom:1px solid var(--muted);font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--muted-fg);cursor:default} +.cust-results .cust-none{padding:11px 14px;font-size:13px;color:var(--muted-fg);cursor:default} .cust-results .cust-count:active,.cust-results .cust-none:active{background:none} .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} @@ -253,56 +265,70 @@ input{font:inherit;color:inherit} :root[data-theme="auto"] .theme-btn .i-sun{display:block} /* ---- dark theme (auto follows prefers-color-scheme) ---- */ +/* Dark ramp. The previous canvas was #0f0f0f (L* 4.3 — effectively black) + with surfaces only 3-4 L* above it, and mixed a warm #1c1416 against a + neutral #181818 in the same UI. That near-black canvas plus two + competing surface tones is what read as "muddy". This is a single + cool-neutral ramp with four real steps, and the text greys are lifted + so the most-used one clears WCAG AA (was 3.93:1, now 6.49:1). */ :root[data-theme="dark"]{ - --bg:#0f0f0f; --surface:#1c1416; --fg:#f0f0f0; --muted:#2a2a2a; --border:#3a2429; + --bg:#161619; /* L* 7.4 — lifted off black */ + --surface:#1e1e23; /* L* 11.5 — cards, drawers, fields */ + --raised:#26262d; /* L* 15.4 — menus and modals sit above surfaces */ + --fg:#f2f2f5; + --muted:#303039; /* L* 20.2 — separators */ + --border:#3b3b46; /* L* 25.3 — outlines */ + --muted-fg:#9a9aa6; /* secondary text 6.49:1 on --bg (AA) */ + --icon-fg:#8e8e9a; /* icons / labels 5.58:1 on --bg (AA) */ + --placeholder-fg:#7c7c88; /* placeholder 4.38:1 */ --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{background:var(--surface);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 svg{color:var(--icon-fg)} :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"] .search-box input::placeholder{color:var(--placeholder-fg)} +:root[data-theme="dark"] .chip{background:var(--surface);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-trigger{background:var(--surface);border-color:var(--muted);color:var(--fg)} +:root[data-theme="dark"] .cat-trigger .cat-chev{color:var(--icon-fg)} +:root[data-theme="dark"] .cat-count{color:var(--icon-fg)} +:root[data-theme="dark"] .cat-menu{background:var(--raised);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 .ct{color:var(--icon-fg)} :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 .sub{color:var(--icon-fg)} :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"] .prod .price small{color:var(--icon-fg)} +:root[data-theme="dark"] .cart-bar{background:var(--surface);border-top-color:var(--muted);box-shadow:var(--shadow-up)} +:root[data-theme="dark"] .cart-bar .count span{color:var(--icon-fg)} :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{background:var(--surface)} :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"] .line .nm small{color:var(--icon-fg)} :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"] .qty .v{color:var(--fg)} :root[data-theme="dark"] .line .pr{color:var(--fg)} -:root[data-theme="dark"] .line .rm{color:#666} +:root[data-theme="dark"] .line .rm{color:var(--placeholder-fg)} :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"] .sheet-foot{background:var(--surface);border-top-color:var(--muted)} +:root[data-theme="dark"] .totals{color:var(--icon-fg)} :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"] .discount-trigger{color:#888} +:root[data-theme="dark"] .discount-trigger{color:var(--icon-fg)} :root[data-theme="dark"] .custom-item-btn{border-color:#3a3a3a;color:#999} :root[data-theme="dark"] .custom-item-btn:active{background:#222} :root[data-theme="dark"] .custom-line .nm{color:#d2b47c} @@ -310,53 +336,53 @@ input{font:inherit;color:inherit} :root[data-theme="dark"] .discount-trigger:active{color:var(--fg)} :root[data-theme="dark"] .discount-trigger.has-value{color:#ff6680} :root[data-theme="dark"] .discount-pills{background:#222;border-color:var(--muted)} -:root[data-theme="dark"] .discount-pill{color:#888} -:root[data-theme="dark"] .discount-pill.active{background:#181818;color:#ff6680;box-shadow:0 1px 2px rgba(0,0,0,.4)} -:root[data-theme="dark"] .discount-input-row input{background:#181818;border-color:var(--muted);color:var(--fg)} +:root[data-theme="dark"] .discount-pill{color:var(--icon-fg)} +:root[data-theme="dark"] .discount-pill.active{background:var(--surface);color:#ff6680;box-shadow:0 1px 2px rgba(0,0,0,.4)} +:root[data-theme="dark"] .discount-input-row input{background:var(--surface);border-color:var(--muted);color:var(--fg)} :root[data-theme="dark"] .discount-input-row input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.2)} -:root[data-theme="dark"] .discount-suffix{color:#888} -:root[data-theme="dark"] .discount-hint{color:#888} +:root[data-theme="dark"] .discount-suffix{color:var(--icon-fg)} +:root[data-theme="dark"] .discount-hint{color:var(--icon-fg)} :root[data-theme="dark"] .totals.discount-line{color:#ff6680} :root[data-theme="dark"] .totals.discount-line b{color:#ff6680} -:root[data-theme="dark"] .empty{color:#666} +:root[data-theme="dark"] .empty{color:var(--placeholder-fg)} :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"] .empty p{color:var(--icon-fg)} +:root[data-theme="dark"] .netpill{background:transparent;color:var(--icon-fg);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{background:var(--surface);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{background:var(--surface);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"] .cash-row label{color:var(--icon-fg)} +:root[data-theme="dark"] .quick button{background:var(--surface);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"] .change-out .lbl{color:var(--icon-fg)} +:root[data-theme="dark"] .cust-block input{background:var(--surface);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{background:var(--surface);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-results .cust-count{background:#222;border-bottom-color:var(--muted);color:#888} -:root[data-theme="dark"] .cust-results .cust-none{color:#888} +:root[data-theme="dark"] .cust-results small{color:var(--icon-fg)} +:root[data-theme="dark"] .cust-results .cust-count{background:#222;border-bottom-color:var(--muted);color:var(--icon-fg)} +:root[data-theme="dark"] .cust-results .cust-none{color:var(--icon-fg)} :root[data-theme="dark"] .cust-picked{background:var(--surface);border-color:var(--border);color:var(--fg)} -:root[data-theme="dark"] .edit-sheet{background:#181818;box-shadow:0 20px 60px rgba(0,0,0,.6)} -:root[data-theme="dark"] .edit-sheet h3 small{color:#888} -:root[data-theme="dark"] .edit-row label{color:#888} -:root[data-theme="dark"] .edit-row input{background:#181818;border-color:var(--muted);color:var(--fg)} +:root[data-theme="dark"] .edit-sheet{background:var(--raised);box-shadow:0 20px 60px rgba(0,0,0,.6)} +:root[data-theme="dark"] .edit-sheet h3 small{color:var(--icon-fg)} +:root[data-theme="dark"] .edit-row label{color:var(--icon-fg)} +:root[data-theme="dark"] .edit-row input{background:var(--surface);border-color:var(--muted);color:var(--fg)} :root[data-theme="dark"] .edit-row input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,56,92,.2)} -:root[data-theme="dark"] .edit-actions .secondary{background:#181818;border-color:var(--muted);color:var(--fg)} +:root[data-theme="dark"] .edit-actions .secondary{background:var(--surface);border-color:var(--muted);color:var(--fg)} :root[data-theme="dark"] .edit-actions .secondary:active{background:var(--surface)} -:root[data-theme="dark"] .edit-actions .danger{background:#181818;border-color:#5a2429;color:#ff6680} +:root[data-theme="dark"] .edit-actions .danger{background:var(--surface);border-color:#5a2429;color:#ff6680} :root[data-theme="dark"] .edit-actions .danger:active{background:#2a1a1a} :root[data-theme="dark"] .line-holding{background:var(--surface)} -:root[data-theme="dark"] .final-cta:disabled{background:#2a2a2a;color:#666} +:root[data-theme="dark"] .final-cta:disabled{background:#2a2a2a;color:var(--placeholder-fg)} @media (prefers-reduced-motion: reduce){*{transition-duration:0.01ms !important;animation-duration:0.01ms !important}} diff --git a/public/pos/receipt.html b/public/pos/receipt.html index 7358102..cc5960c 100644 --- a/public/pos/receipt.html +++ b/public/pos/receipt.html @@ -152,9 +152,9 @@ input,select{font:inherit;color:inherit} /* ---- Dark theme ---- */ @media (prefers-color-scheme: dark){ :root:not([data-theme="light"]){ - --bg:#0f0f0f;--surface:#1c1416;--surface-2:#181818;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429; - --ink:#f0f0f0;--ink-soft:#a0a0a0;--ink-faint:#777; - --surface-card:#181818;--accent-soft:#2a1a1a;--accent-2:#3a2429;--accent-soft-hover:#3a2429; + --bg:#161619;--surface:#1e1e23;--surface-2:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46; + --ink:#f2f2f5;--ink-soft:#a0a0a0;--ink-faint:#8e8e9a; + --surface-card:#26262d;--accent-soft:#2a1a1a;--accent-2:#3a2429;--accent-soft-hover:#3a2429; --ok-soft:#1a2e22;--danger-soft:#2a1a1a;--danger-2:#3a2429; --focus-ring:0 0 0 3px rgba(255,102,128,.35); } @@ -203,9 +203,9 @@ input,select{font:inherit;color:inherit} :root:not([data-theme="light"]) .btn.acct:active{background:var(--accent-soft-hover)} } :root[data-theme="dark"]{ - --bg:#0f0f0f;--surface:#1c1416;--surface-2:#181818;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429; - --ink:#f0f0f0;--ink-soft:#a0a0a0;--ink-faint:#777; - --surface-card:#181818;--accent-soft:#2a1a1a;--accent-2:#3a2429;--accent-soft-hover:#3a2429; + --bg:#161619;--surface:#1e1e23;--surface-2:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46; + --ink:#f2f2f5;--ink-soft:#a0a0a0;--ink-faint:#8e8e9a; + --surface-card:#26262d;--accent-soft:#2b1f24;--accent-2:#3f2b33;--accent-soft-hover:#452f38; --ok-soft:#1a2e22;--danger-soft:#2a1a1a;--danger-2:#3a2429; --focus-ring:0 0 0 3px rgba(255,102,128,.35); } diff --git a/public/pos/settings.html b/public/pos/settings.html index 41aef2c..ebeed1a 100644 --- a/public/pos/settings.html +++ b/public/pos/settings.html @@ -78,7 +78,7 @@ body{display:flex;flex-direction:column;min-height:100dvh;max-width:480px;margin /* ---- Dark theme ---- */ @media (prefers-color-scheme: dark){ :root:not([data-theme="light"]){ - --bg:#0f0f0f;--surface:#1c1416;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429; + --bg:#161619;--surface:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46; } :root:not([data-theme="light"]) body{background:var(--bg);color:var(--fg)} :root:not([data-theme="light"]) .topbar{background:var(--bg)} @@ -89,22 +89,22 @@ body{display:flex;flex-direction:column;min-height:100dvh;max-width:480px;margin :root:not([data-theme="light"]) .topbar .theme-btn{color:var(--fg)} :root:not([data-theme="light"]) .section-label{color:#a0a0a0} :root:not([data-theme="light"]) .active{background:#2a1a1a;border-color:#ff385c} - :root:not([data-theme="light"]) .active .logo{background:#181818;border-color:var(--muted)} + :root:not([data-theme="light"]) .active .logo{background:var(--surface);border-color:var(--muted)} :root:not([data-theme="light"]) .active .name{color:var(--fg)} - :root:not([data-theme="light"]) .lh-card{background:#181818;border-color:var(--muted);color:var(--fg)} + :root:not([data-theme="light"]) .lh-card{background:var(--surface);border-color:var(--muted);color:var(--fg)} :root:not([data-theme="light"]) .lh-card:active{background:var(--surface)} :root:not([data-theme="light"]) .lh-card.selected{background:#2a1a1a;border-color:#ff385c} - :root:not([data-theme="light"]) .lh-card .logo{background:#181818;border-color:var(--muted)} + :root:not([data-theme="light"]) .lh-card .logo{background:var(--surface);border-color:var(--muted)} :root:not([data-theme="light"]) .lh-card .meta{color:#a0a0a0} :root:not([data-theme="light"]) .lh-card:not(.selected) .check{border-color:var(--muted)} - :root:not([data-theme="light"]) .btn{background:#181818;border-color:var(--muted);color:var(--fg)} + :root:not([data-theme="light"]) .btn{background:var(--surface);border-color:var(--muted);color:var(--fg)} :root:not([data-theme="light"]) .btn:active{background:var(--surface)} :root:not([data-theme="light"]) .banner.warn{background:#2a1a1a;border-color:#5a3a1a;color:#ffb060} :root:not([data-theme="light"]) .banner.err{background:#2a1a1a;border-color:#5a2429;color:#ff6680} :root:not([data-theme="light"]) .skeleton{color:#666} } :root[data-theme="dark"]{ - --bg:#0f0f0f;--surface:#1c1416;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429; + --bg:#161619;--surface:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46; background:var(--bg);color:var(--fg); } :root[data-theme="dark"] body{background:var(--bg);color:var(--fg)} @@ -116,15 +116,15 @@ body{display:flex;flex-direction:column;min-height:100dvh;max-width:480px;margin :root[data-theme="dark"] .topbar .theme-btn{color:var(--fg)} :root[data-theme="dark"] .section-label{color:#a0a0a0} :root[data-theme="dark"] .active{background:#2a1a1a;border-color:#ff385c} -:root[data-theme="dark"] .active .logo{background:#181818;border-color:var(--muted)} +:root[data-theme="dark"] .active .logo{background:var(--surface);border-color:var(--muted)} :root[data-theme="dark"] .active .name{color:var(--fg)} -:root[data-theme="dark"] .lh-card{background:#181818;border-color:var(--muted);color:var(--fg)} +:root[data-theme="dark"] .lh-card{background:var(--surface);border-color:var(--muted);color:var(--fg)} :root[data-theme="dark"] .lh-card:active{background:var(--surface)} :root[data-theme="dark"] .lh-card.selected{background:#2a1a1a;border-color:#ff385c} -:root[data-theme="dark"] .lh-card .logo{background:#181818;border-color:var(--muted)} +:root[data-theme="dark"] .lh-card .logo{background:var(--surface);border-color:var(--muted)} :root[data-theme="dark"] .lh-card .meta{color:#a0a0a0} :root[data-theme="dark"] .lh-card:not(.selected) .check{border-color:var(--muted)} -:root[data-theme="dark"] .btn{background:#181818;border-color:var(--muted);color:var(--fg)} +:root[data-theme="dark"] .btn{background:var(--surface);border-color:var(--muted);color:var(--fg)} :root[data-theme="dark"] .btn:active{background:var(--surface)} :root[data-theme="dark"] .banner.warn{background:#2a1a1a;border-color:#5a3a1a;color:#ffb060} :root[data-theme="dark"] .banner.err{background:#2a1a1a;border-color:#5a2429;color:#ff6680} diff --git a/public/pos/slip-layout.html b/public/pos/slip-layout.html index 707cd4a..b092cc9 100644 --- a/public/pos/slip-layout.html +++ b/public/pos/slip-layout.html @@ -56,11 +56,11 @@ body{display:flex;flex-direction:column;min-height:100dvh;max-width:480px;margin .block-row .edit-text{width:100%;margin-top:6px;padding:8px 10px;border-radius:8px;border:1px solid var(--muted);font:inherit} .pricing-row{display:flex;align-items:center;justify-content:space-between;padding:12px;border:1px solid var(--muted);border-radius:10px;background:#fff;margin:4px 0 16px} @media (prefers-color-scheme: dark){ - :root:not([data-theme="light"]){--bg:#0f0f0f;--surface:#1c1416;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429} - :root:not([data-theme="light"]) .block-row, :root:not([data-theme="light"]) .pricing-row, :root:not([data-theme="light"]) .btn, :root:not([data-theme="light"]) .preview-tab{background:#181818;border-color:var(--muted);color:var(--fg)} + :root:not([data-theme="light"]){--bg:#161619;--surface:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46} + :root:not([data-theme="light"]) .block-row, :root:not([data-theme="light"]) .pricing-row, :root:not([data-theme="light"]) .btn, :root:not([data-theme="light"]) .preview-tab{background:var(--surface);border-color:var(--muted);color:var(--fg)} } -:root[data-theme="dark"]{--bg:#0f0f0f;--surface:#1c1416;--fg:#f0f0f0;--muted:#2a2a2a;--border:#3a2429} -:root[data-theme="dark"] .block-row, :root[data-theme="dark"] .pricing-row, :root[data-theme="dark"] .btn, :root[data-theme="dark"] .preview-tab{background:#181818;border-color:var(--muted);color:var(--fg)} +:root[data-theme="dark"]{--bg:#161619;--surface:#1e1e23;--fg:#f2f2f5;--muted:#303039;--border:#3b3b46} +:root[data-theme="dark"] .block-row, :root[data-theme="dark"] .pricing-row, :root[data-theme="dark"] .btn, :root[data-theme="dark"] .preview-tab{background:var(--surface);border-color:var(--muted);color:var(--fg)} diff --git a/public/pos/sw.js b/public/pos/sw.js index 268c31f..bbb48be 100644 --- a/public/pos/sw.js +++ b/public/pos/sw.js @@ -51,7 +51,15 @@ // vertical height while staying visible. // Bumped because pos-app.js and pos.html are both served cache-first out of // the shell; without a new CACHE name the tills keep the old ones. -const CACHE = "pos-v35"; +// v36 — the discount panel and the Discount totals row both carry a `hidden` +// attribute, but their classes (.discount-body, .totals) set `display:flex`, +// and an author display rule outranks the UA stylesheet's +// `[hidden]{display:none}`. So `hidden` did nothing: "Add discount" could not +// collapse the tier buttons, and a cleared discount left its old amount +// painted under an unchanged total. Fixed with a global `[hidden]` override +// plus blanking the figure when the row is hidden. Also carries the dark +// palette lift. +const CACHE = "pos-v36"; const APP_SHELL = [ './', './index.html', diff --git a/src/lib/pos-cart-quantity.test.ts b/src/lib/pos-cart-quantity.test.ts index dfa5bd9..7ab06ac 100644 --- a/src/lib/pos-cart-quantity.test.ts +++ b/src/lib/pos-cart-quantity.test.ts @@ -224,4 +224,43 @@ describe("POS service worker cache tracks shell edits", () => { expect(m, "sw.js CACHE constant not found").not.toBeNull(); expect(Number(m![1])).toBeGreaterThanOrEqual(33); }); -}); \ No newline at end of file +}); +describe("POS [hidden] attribute actually hides", () => { + /** + * A `hidden` attribute is implemented by the UA stylesheet as + * `[hidden]{display:none}` — but ANY author rule that sets `display` + * beats it, because author styles outrank UA styles regardless of + * specificity. `.totals` and `.discount-body` both set + * `display:flex`, so `el.hidden = true` did nothing: the discount + * panel could not be collapsed, and the "Discount" row could not be + * dismissed — it stayed on screen showing the last figure even + * after the discount was cleared, because the JS only ever set + * `hidden` and never cleared the text. + * + * Both symptoms looked like two unrelated bugs. One line of CSS + * fixes both, and this guards the whole class of them. + */ + it("has a global [hidden]{display:none} override", () => { + expect(POS_HTML).toMatch(/\[hidden\]\s*\{[^}]*display:\s*none\s*!important/); + }); + + it("covers every element that carries a hidden attribute", () => { + // Any element with `hidden` whose class rule sets `display` would + // otherwise be permanently visible. Assert the override exists + // rather than trusting each element to have remembered one. + const risky = [ + ...POS_HTML.matchAll(/]*\shidden[^>]*>/g), + ].filter((tag) => /\bclass="/.test(tag[0])); + expect(risky.length, "expected some hidden elements to audit").toBeGreaterThan(0); + expect(POS_HTML).toMatch(/\[hidden\]\s*\{[^}]*display:\s*none\s*!important/); + }); + + it("blanks the discount figure when the row is cleared", () => { + // Hiding alone left the old amount painted on screen, which the + // operator had no way to distinguish from a live one. Matched + // loosely because a comment sits between the two statements. + expect(POS_APP).toMatch( + /dl\.hidden\s*=\s*true;[\s\S]{0,400}discountLineAmount'\)\.textContent\s*=\s*''/, + ); + }); +}); diff --git a/src/styles/themes.css b/src/styles/themes.css index f44a940..51310bd 100644 --- a/src/styles/themes.css +++ b/src/styles/themes.css @@ -954,26 +954,33 @@ * so the same OKLCH hue reads at the right intensity. * ========================================================================= */ .dark { - --background: oklch(0.15 0.01 240); + /* The whole dark ramp sat at oklch(0.15) — an effective #080c0f, + L* 3.2. On a wall-mounted shop display that reads as a dead black + rectangle rather than a surface. Every step is lifted +0.04 so the + ramp keeps its shape (and its 3.2 L* bg→card separation) but the + canvas starts at L* 6.1 instead. Text tokens are unchanged and + were already compliant — muted-foreground goes 6.32:1 → 5.95:1, + still comfortably above AA. */ + --background: oklch(0.19 0.01 240); --foreground: oklch(0.94 0.005 240); - --card: oklch(0.19 0.012 240); + --card: oklch(0.23 0.012 240); --card-foreground: oklch(0.94 0.005 240); - --popover: oklch(0.20 0.012 240); + --popover: oklch(0.24 0.012 240); --popover-foreground: oklch(0.94 0.005 240); - --secondary: oklch(0.23 0.012 240); + --secondary: oklch(0.27 0.012 240); --secondary-foreground: oklch(0.94 0.005 240); - --muted: oklch(0.22 0.012 240); + --muted: oklch(0.26 0.012 240); --muted-foreground: oklch(0.66 0.01 240); - --accent: oklch(0.28 0.04 240); + --accent: oklch(0.32 0.04 240); --accent-foreground: oklch(0.94 0.005 240); - --border: oklch(0.28 0.014 240); - --input: oklch(0.27 0.014 240); - --sidebar: oklch(0.17 0.012 240); + --border: oklch(0.32 0.014 240); + --input: oklch(0.31 0.014 240); + --sidebar: oklch(0.21 0.012 240); --sidebar-foreground: oklch(0.94 0.005 240); - --sidebar-accent: oklch(0.24 0.04 240); + --sidebar-accent: oklch(0.28 0.04 240); --sidebar-accent-foreground: oklch(0.94 0.005 240); - --sidebar-border: oklch(0.28 0.014 240); - --input-highlight: oklch(0.30 0.06 240); + --sidebar-border: oklch(0.32 0.014 240); + --input-highlight: oklch(0.34 0.06 240); /* Dark-mode semantic bumps (success / warn / info get brighter so * they punch on the dark canvas). */ --success: oklch(0.76 0.18 155); @@ -986,10 +993,12 @@ /* The two natively-dark themes (Cursor / Supabase) are already dark by * default, but flipping the mode toggle still works — it just deepens - * the surface slightly. */ + * the surface slightly. Kept ~0.04 L below the standard dark ramp so + * they still read as "darker", but no longer at L* 1.3 (effectively + * #000). */ :root[data-theme="cursor"].dark, :root[data-theme="supabase"].dark { - --background: oklch(0.11 0.012 240); - --card: oklch(0.15 0.014 240); - --sidebar: oklch(0.13 0.012 240); + --background: oklch(0.15 0.012 240); + --card: oklch(0.19 0.014 240); + --sidebar: oklch(0.17 0.012 240); }