:root{
  --bg:#f4f5f7; --panel:#fff; --ink:#16181d; --muted:#6b7280; --line:#e3e6eb;
  --brand:#c2410c; --brand-ink:#fff; --accent:#0f766e;
  --ok:#15803d; --warn:#b45309; --danger:#b91c1c;
  --r:10px; --shadow:0 1px 2px rgba(16,20,30,.06),0 8px 24px rgba(16,20,30,.06);
  --top:56px;
}
*{box-sizing:border-box}
/* The `hidden` attribute must always win. Any rule that sets `display` on an
   element (e.g. .modal-back{display:grid}) has the same specificity as the UA's
   [hidden] rule and would otherwise keep it on screen. */
[hidden]{display:none !important}
html,body{height:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font:14px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,sans-serif;
  -webkit-font-smoothing:antialiased;overflow:hidden;
}
button,input,select,textarea{font:inherit;color:inherit}
h2{margin:0 0 4px;font-size:20px}
h3{margin:0 0 10px;font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
/* Flex, not float: a floated child here would intrude into the scroll container
   below it (an overflow:auto box is a BFC and narrows to avoid floats). */
.panel h3{display:flex;justify-content:space-between;align-items:center;gap:10px}
hr{border:0;border-top:1px solid var(--line);margin:18px 0}
kbd{font:10px/1 ui-monospace,monospace;border:1px solid rgba(0,0,0,.15);border-bottom-width:2px;
  border-radius:4px;padding:2px 4px;opacity:.6;margin-left:5px}
.muted{color:var(--muted)}
.small{font-size:12px}
.mt{margin-top:12px}

/* ---------- top bar ---------- */
.topbar{
  height:var(--top);display:flex;align-items:center;gap:18px;padding:0 16px;
  background:var(--panel);border-bottom:1px solid var(--line);position:relative;z-index:5;
}
.brand{display:flex;align-items:center;gap:10px;min-width:190px}
/* The full lockup is unreadable this small, so the top bar wears the three-ball
   mark on its own — the part of the logo that still reads at 30px. */
.logo{height:30px;width:auto;max-width:62px;object-fit:contain;display:block;flex:none}
.brand b{display:block;font-size:14px;line-height:1.1;max-width:170px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.brand small{display:block;color:var(--muted);font-size:11px}
.tabs{display:flex;gap:2px;flex:1;min-width:0}
.tabs button{
  background:none;border:0;padding:8px 13px;border-radius:8px;cursor:pointer;color:var(--muted);font-weight:500;
}
.tabs button:hover{background:var(--bg)}
.tabs button.active{background:var(--ink);color:#fff}
.tabs button.active kbd{border-color:rgba(255,255,255,.3)}
.topmeta{display:flex;align-items:center;gap:10px;color:var(--muted);font-variant-numeric:tabular-nums}
.pill{background:var(--accent);color:#fff;padding:4px 11px;border-radius:20px;font-weight:600}

/* ---------- views ---------- */
main{height:calc(100vh - var(--top));overflow:hidden}
.view{display:none;height:100%}
.view.active{display:block}
.pad{padding:20px;height:100%;overflow:auto}

/* ---------- POS ---------- */
/* minmax(0,…) + min-height:0 pin both panes to the viewport. Without them the
   catalogue's tall column layout stretches the row and pushes the Payment button
   off the bottom of the screen. */
.pos{display:grid;grid-template-columns:minmax(0,1fr) 380px;grid-template-rows:minmax(0,1fr);height:100%}
.catalogue{display:flex;flex-direction:column;min-width:0;min-height:0;border-right:1px solid var(--line)}
.cat-toolbar{display:flex;gap:10px;padding:12px 16px 8px;align-items:center}
#itemSearch{
  flex:1;padding:10px 12px;border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
}
#itemSearch:focus{outline:2px solid var(--brand);outline-offset:-1px}
.group-switch,.seg{display:inline-flex;background:#e7e9ee;border-radius:9px;padding:3px}
.group-switch button,.seg button{
  border:0;background:none;padding:7px 14px;border-radius:7px;cursor:pointer;color:var(--muted);font-weight:600;font-size:13px
}
.group-switch button.active,.seg button.active{background:var(--panel);color:var(--ink);box-shadow:0 1px 2px rgba(0,0,0,.12)}
.seg.small button{padding:5px 11px}

.chips{display:flex;gap:7px;padding:6px 16px 10px;overflow-x:auto;flex-wrap:nowrap}
.chip{
  white-space:nowrap;border:1px solid var(--line);background:var(--panel);color:var(--muted);
  padding:6px 12px;border-radius:20px;cursor:pointer;font-size:13px
}
.chip.active{background:var(--ink);border-color:var(--ink);color:#fff}

/* Newspaper columns: each section is a block, blocks flow down and across, so the
   menu reads left-to-right like the printed one — Starters, then Mains, then the rest. */
/* The scrolling lives on the wrapper, NOT on the column list. A multi-column box
   with its own height turns extra content into columns off to the right, which
   `overflow-x:hidden` then swallows — items you can never reach. Left to its
   natural height the columns just grow downwards and the wrapper scrolls. */
.item-scroll{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:4px 16px 20px}
.item-grid{column-width:268px;column-gap:14px}
.cat-block{
  break-inside:avoid;-webkit-column-break-inside:avoid;
  margin:0 0 14px;border:1px solid var(--line);border-radius:10px;
  background:var(--panel);overflow:hidden
}
.cat-block h4{
  margin:0;padding:9px 13px;background:var(--c, var(--ink));color:#fff;
  font-size:12.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase
}
.item{
  position:relative;display:flex;align-items:center;gap:8px;width:100%;
  padding:13px 13px;border:0;border-bottom:1px solid var(--line);
  background:var(--panel);cursor:pointer;text-align:left;font:inherit
}
.item:last-child{border-bottom:0}
.item:hover{background:#f7f8fa}
.item:active{background:#eef0f4}
.item .nm{flex:1;font-weight:600;font-size:15px;line-height:1.3;min-width:0}
.item .pr{
  color:var(--accent);font-weight:700;font-size:15px;font-variant-numeric:tabular-nums;
  white-space:nowrap;flex:none
}
.item .pr i{font-style:normal;color:var(--muted);font-weight:600}
/* One fixed marker slot on the left: the veg square normally, the quantity while
   the item is in the cart. Nothing is added or removed, so rows never reflow. */
.item .lead{width:22px;height:22px;flex:none;position:relative;display:grid;place-items:center}
.item .dot{width:12px;height:12px;border-radius:2px;border:1.5px solid var(--ok);flex:none}
.item .dot::after{content:"";display:block;width:5px;height:5px;border-radius:50%;background:var(--ok);margin:2px auto}
.item .dot.nonveg{border-color:var(--danger)}
.item .dot.nonveg::after{background:var(--danger)}
.item.out{opacity:.4;pointer-events:none}
.item .qtybadge{
  position:absolute;inset:0;background:var(--brand);color:#fff;border-radius:50%;
  display:grid;place-items:center;font-size:12px;font-weight:700
}
.item .qtybadge.empty{display:none}
.item.inCart{background:#fff7f3}
.item.inCart .dot{display:none}
.empty{padding:50px 10px;text-align:center;color:var(--muted)}
.cart-lines .empty{padding:22px 10px}

/* ---------- cart ---------- */
.cart{display:flex;flex-direction:column;background:var(--panel);min-width:0;min-height:0}
.cart-head{padding:12px 14px;border-bottom:1px solid var(--line);display:grid;gap:9px}
.cart-meta{display:grid;grid-template-columns:1fr 1fr;gap:7px}
.cart-meta select,.cart-meta input{padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:var(--panel);min-width:0}
/* Dine-in without a table chosen: quietly flagged, loudly flashed on submit. */
#tableSel.required{border-color:var(--warn);background:#fffbeb}
#tableSel.needs{border-color:var(--danger);background:#fef2f2;box-shadow:0 0 0 3px rgba(185,28,28,.15)}
.cart-meta select{grid-column:1/-1}
/* min-height:0, not 64px. The list has to be able to give up ALL of its space
   when the screen is short, otherwise it holds its ground and pushes the totals
   and the Payment button off the bottom with no way to scroll to them. */
.cart-lines{flex:1 1 0;min-height:0;overflow-y:auto;padding:4px 0}
.line{display:grid;grid-template-columns:1fr auto;gap:2px 10px;padding:9px 14px;border-bottom:1px solid var(--line)}
.line .l-nm{font-weight:600;font-size:13.5px}
.line .l-amt{font-weight:700;font-variant-numeric:tabular-nums;text-align:right}
.line .l-ctl{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:12px}
.stepper{display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:7px;overflow:hidden}
.stepper button{width:26px;height:26px;border:0;background:var(--panel);cursor:pointer;color:var(--muted);font-size:15px;line-height:1}
.stepper button:hover{background:var(--bg);color:var(--ink)}
.stepper span{min-width:28px;text-align:center;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.l-rm{border:0;background:none;color:var(--danger);cursor:pointer;opacity:.6;font-size:12px}
.l-rm:hover{opacity:1}
.l-note{border:0;background:none;color:var(--muted);cursor:pointer;font-size:12px;text-decoration:underline dotted}
.note-txt{grid-column:1/-1;color:var(--warn);font-size:12px;font-style:italic}

/* Discount, taxes, total and the buttons are always fully visible — they never
   scroll. When the order gets long it is the list of items that shrinks. */
.cart-foot{
  border-top:1px solid var(--line);padding:10px 14px 12px;background:var(--panel);
  display:flex;flex-direction:column;flex:none
}
.cart-sums{flex:none}
/* Clear and Payment share a row, the way Hold and KOT do — one less row of
   chrome, which is a couple more bill lines on screen. */
.cart-actions{grid-template-columns:1fr 1fr}
.cart-actions{flex:none}
.disc-row{display:flex;align-items:center;gap:8px;margin-bottom:7px}
.disc-row label{color:var(--muted);font-size:13px;flex:1}
.disc-row input{width:88px;padding:6px 9px;border:1px solid var(--line);border-radius:7px;text-align:right}
.totals{display:grid;gap:4px;margin-bottom:4px;font-variant-numeric:tabular-nums}
.totals div{display:flex;justify-content:space-between;color:var(--muted);font-size:13px}
.cart-foot .grand{
  display:flex;justify-content:space-between;align-items:baseline;flex:none;
  color:var(--ink);font-size:21px;font-weight:800;font-variant-numeric:tabular-nums;
  border-top:1px dashed var(--line);padding-top:7px;margin:3px 0 8px
}
.cart-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px}
.cart-actions.three{grid-template-columns:repeat(3,1fr);margin-bottom:7px}
.cart-actions.three .btn{padding:9px 4px;font-size:13px}
/* The breakdown is the one part worth losing first: it yields its height and
   scrolls, so Total and Payment can never be pushed off the screen. */
.cart-foot .totals{overflow-y:auto;min-height:0}
.btn{border:1px solid transparent;border-radius:9px;padding:10px 12px;cursor:pointer;font-weight:600;background:var(--bg)}
.btn:hover{filter:brightness(.97)}
.btn.ghost{background:var(--panel);border-color:var(--line);color:var(--muted)}
.btn.ghost:hover{color:var(--ink);border-color:var(--muted)}
.btn.primary{background:var(--brand);color:#fff}
.btn.danger{color:var(--danger)}
.btn.danger.ghost:hover{border-color:var(--danger);color:var(--danger)}
.btn.big{padding:14px;font-size:16px}
.btn[disabled]{opacity:.45;pointer-events:none}
.btnrow{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.btnrow input{padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:var(--panel)}

/* ---------- tables ---------- */
.table-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));margin-top:16px}
/* What the night is worth: running tables, settled bills, and the two together. */
.kpi.prior b{color:var(--muted)}
.kpi.combined{background:var(--ink);border-color:var(--ink);color:#fff}
.kpi.combined span,.kpi.combined .muted{color:rgba(255,255,255,.72)}

/* One bill settled across more than one method. */
.split-rows{display:grid;gap:8px}
.split-row{display:grid;grid-template-columns:70px 1fr;align-items:center;gap:10px;margin:0}
.split-row span{font-weight:600;color:var(--muted);font-size:13px}
.split-left{margin-top:10px;font-weight:700;text-align:right}
.split-left.ok{color:var(--ok)}
.split-left.bad{color:var(--danger)}

/* Money that has been billed but not collected. */
.kpi.owed b{color:var(--warn)}
.tag.owed{background:#fef3c7;color:#92400e}
.pay-grid button.pending{background:#fffbeb;border-color:var(--warn);color:#92400e}
.pay-grid button.pending.active{background:var(--warn);color:#fff}

/* The per-line price: tappable, and marked when it is above the menu. */
.l-price{border:0;background:none;font:inherit;color:inherit;cursor:pointer;padding:2px 5px;
  border-radius:6px;text-decoration:underline dotted;text-underline-offset:3px}
.l-price:hover{background:#eef2f7}
.l-price.up{color:var(--accent);font-weight:700;text-decoration:none;background:#ecfdf5}
.warn-text{color:var(--danger)!important}

/* A table sharing another table's bill: occupied, but nothing of its own. */
.tcard.merged{opacity:.85;border-style:dashed}
.tcard.merged .amt{color:var(--muted);font-weight:600}

/* Moving a guest to another table, or pushing two together. */
.tcard-move{border:0;background:#eef2f7;color:var(--ink);font-weight:600;font-size:12px;
  padding:6px 0;cursor:pointer;border-top:1px solid var(--line)}
.tcard-move:hover{background:#e2e8f0}
.move-grid{display:grid;gap:8px;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));margin:12px 0}
.movecard{display:grid;gap:2px;padding:11px 8px;border:1px solid var(--line);border-radius:9px;
  background:var(--panel);cursor:pointer;text-align:left;font:inherit}
.movecard:hover{border-color:var(--brand)}
.movecard.busy{background:#fff7ed;border-color:var(--warn)}

/* Money taken, by how it was paid — the numbers counted against the drawer. */
.kpi.pay b{color:var(--accent)}

/* Trusted machines, and the code a new till shows while it waits. */
.devices{display:grid;gap:8px;margin-top:6px}
.devrow{display:flex;justify-content:space-between;align-items:center;gap:12px;
  border:1px solid var(--line);border-radius:9px;padding:9px 12px;background:var(--panel)}
.devrow.waiting{border-color:var(--warn);background:#fffbeb}
.approval-code{font:700 34px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.16em;text-align:center;margin:14px 0;color:var(--brand)}

.tally{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin-top:16px}
.tally-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  padding:13px 15px;display:grid;gap:2px;box-shadow:var(--shadow)}
.tally-label{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)}
.tally-card b{font-size:25px;font-variant-numeric:tabular-nums;line-height:1.15}
.tally-card.is-total{background:var(--ink);border-color:var(--ink);color:#fff}
.tally-card.is-total .tally-label,.tally-card.is-total .muted{color:rgba(255,255,255,.72)}
.tcard{
  background:var(--panel);border:1px solid var(--line);border-left:4px solid var(--line);
  border-radius:var(--r);text-align:left;box-shadow:var(--shadow);overflow:hidden;
  display:flex;flex-direction:column
}
.tcard-open{
  flex:1;background:none;border:0;padding:14px;cursor:pointer;text-align:left;font:inherit;color:inherit
}
.tcard-open:hover{background:var(--bg)}
.tcard-free{
  border:0;border-top:1px solid var(--line);background:var(--panel);color:var(--danger);
  padding:7px;cursor:pointer;font-size:12px;font-weight:600
}
.tcard-free:hover{background:#fef2f2}
.tcard.busy{border-left-color:var(--brand)}
.tcard b{display:block;font-size:16px;margin-bottom:3px}
.tcard .amt{color:var(--accent);font-weight:800;font-size:18px;font-variant-numeric:tabular-nums}

/* ---------- panels / tables ---------- */
.row-between{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;flex-wrap:wrap;margin-bottom:14px}
/* minmax(0,…) + min-width:0 let these columns shrink; without it the tables
   push the grid wider than the screen and get clipped instead of scrolling. */
.split{display:grid;grid-template-columns:minmax(0,330px) minmax(0,1fr);gap:16px;align-items:start}
.split > *{min-width:0}
.table-wrap{overflow-x:auto;margin:0 -4px;padding:0 4px}
.nowrap{white-space:nowrap}
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:16px;box-shadow:var(--shadow)}
.panel.grow{min-width:0}
/* Menu screen: the item list is the point of the page, so it goes first and full
   width. Categories are a short reference list that sits under it. */
.menu-stack{display:grid;grid-template-columns:minmax(0,1fr);gap:16px}
.menu-stack > *{min-width:0}
@media (min-width:1100px){
  .menu-stack .panel:not(.grow){max-width:560px}
}
.inline-search{text-transform:none;letter-spacing:0;padding:5px 9px;border:1px solid var(--line);border-radius:7px;min-width:0;max-width:220px}
table.grid{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums}
table.grid th{
  text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);
  padding:8px 10px;border-bottom:1px solid var(--line);white-space:nowrap;position:sticky;top:0;background:var(--panel)
}
table.grid td{padding:9px 10px;border-bottom:1px solid var(--line);vertical-align:middle}
table.grid tr:last-child td{border-bottom:0}
table.grid .r{text-align:right}
table.grid td.nm{white-space:nowrap}
table.grid td.veg,table.grid td.code{white-space:nowrap}
.vlist{display:inline-block;text-align:right;line-height:1.6;font-size:12.5px}

/* On a narrow screen drop the columns the owner rarely reads, so Edit/Delete
   stay on screen instead of hiding behind a horizontal scroll. */
@media (max-width:1000px){
  .col-code,.col-gst{display:none}
}
@media (max-width:820px){
  .col-type{display:none}
}
table.grid tbody tr:hover{background:var(--bg)}
.tag{display:inline-block;padding:2px 8px;border-radius:20px;font-size:11px;font-weight:700;background:var(--bg);color:var(--muted)}
.tag.paid{background:#dcfce7;color:var(--ok)}
.tag.void{background:#fee2e2;color:var(--danger)}
.tag.off{background:#fef3c7;color:var(--warn)}
.mini{border:0;background:none;cursor:pointer;color:var(--muted);padding:3px 5px;border-radius:5px}
.mini:hover{background:var(--bg);color:var(--ink)}
.mini.del:hover{color:var(--danger)}
.mini.go{background:var(--brand);color:#fff;font-weight:600}
.mini.go:hover{background:var(--brand);color:#fff;filter:brightness(.93)}

/* ---------- forms ---------- */
.form{display:grid;gap:11px}
.form label{display:grid;gap:4px;font-size:12px;color:var(--muted);font-weight:600}
.form input,.form select,.form textarea{
  padding:9px 11px;border:1px solid var(--line);border-radius:8px;background:var(--panel);width:100%
}
.form .two{display:grid;grid-template-columns:1fr 1fr;gap:11px}
.form .check{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink);font-weight:500}
.form .check input{width:auto}

/* ---------- report cards ---------- */
.kpis{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin-bottom:18px}
.kpi{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:14px 16px;box-shadow:var(--shadow)}
.kpi span{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.kpi b{display:block;font-size:24px;margin-top:5px;font-variant-numeric:tabular-nums}
.cols{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;align-items:start}
.cols > *{min-width:0}
.bar{height:6px;border-radius:4px;background:var(--brand);min-width:2px}

/* ---------- modal ---------- */
.modal-back{position:fixed;inset:0;background:rgba(16,20,30,.45);display:grid;place-items:center;z-index:50;padding:20px}
.modal{background:var(--panel);border-radius:14px;box-shadow:0 24px 60px rgba(0,0,0,.28);
  width:min(560px,100%);max-height:88vh;overflow:auto;padding:22px}
.modal h3{font-size:17px;text-transform:none;letter-spacing:0;color:var(--ink);margin-bottom:14px}
.modal .btnrow{justify-content:flex-end;margin-top:18px}
.pay-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:12px 0}
.pay-grid button{padding:15px;border:1px solid var(--line);background:var(--panel);border-radius:10px;cursor:pointer;font-weight:700}
.pay-grid button.active{background:var(--ink);color:#fff;border-color:var(--ink)}
.due{font-size:34px;font-weight:800;text-align:center;padding:14px;background:var(--bg);border-radius:10px;font-variant-numeric:tabular-nums}
.change{text-align:center;font-weight:700;color:var(--ok);margin-top:8px;min-height:20px}

/* ---------- toasts ---------- */
.toast-wrap{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);display:grid;gap:8px;z-index:99}
.toast{background:var(--ink);color:#fff;padding:11px 18px;border-radius:9px;box-shadow:var(--shadow);
  animation:pop .25s ease}
.toast.err{background:var(--danger)}
@keyframes pop{from{opacity:0;transform:translateY(8px)}}

#printArea{display:none}

/* The Menu list is the widest table in the app — code, item, category, price, GST,
   type, stock, status and three buttons. It gets the full width on anything short
   of a large desktop. Report panels are narrow and stay two-up much longer. */
@media (max-width:1600px){
  .split{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:1000px){
  .cols{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:1100px){
  .pos{grid-template-columns:minmax(0,1fr) 340px}
}

/* Short screens (a 600px-tall netbook, or a browser with lots of toolbars).
   Tighten the bill panel just enough that the Payment button always fits. */
@media (max-height:700px){
  .cart-head{padding:8px 12px;gap:6px}
  .cart-meta select,.cart-meta input{padding:6px 9px}
  .cart-lines{min-height:0}
  .cart-actions.three .btn{padding:7px 3px;font-size:12px}
  .cart-foot .totals{max-height:88px}
  .cart-foot{padding:8px 12px 10px}
  .disc-row{margin-bottom:5px}
  .disc-quick button{padding:5px 2px}
  .disc-quick{margin-bottom:6px}
  .totals div{font-size:12px}
  .cart-foot .grand{font-size:18px;padding-top:5px;margin:2px 0 6px}
  .btn.big{padding:10px;font-size:15px}
  .cart-actions{gap:5px}
  .cat-credit{padding:4px 16px;font-size:9px}
}

/* Tablet — the common counter setup. Keep both panes, shed the chrome. */
@media (max-width:900px){
  .topbar{gap:10px;padding:0 10px}
  .brand{min-width:0}
  .brand b{max-width:110px;font-size:13px}
  .brand small{display:none}
  .tabs button{padding:8px 9px;font-size:13px}
  .tabs kbd{display:none}
  #clock{display:none}
  .pos{grid-template-columns:minmax(0,1fr) 310px}
  .item-grid{column-width:230px;column-gap:10px}
  .item-scroll{padding:4px 10px 16px}
  .cat-toolbar,.chips{padding-left:10px;padding-right:10px}
  .line .l-ctl{flex-wrap:wrap;gap:6px}
  .pad{padding:14px}
  table.grid th,table.grid td{padding:7px 6px;font-size:12.5px}
}

/* Phone — cart drops below the catalogue and the page scrolls as one column. */
@media (max-width:640px){
  /* `clip` rather than `hidden`: it stops a stray wide child dragging the whole
     page sideways without turning the body into a scroll container, which would
     break the sticky top bar. A backstop — the real widths are fixed below. */
  html,body{overflow-x:clip}
  body{overflow-y:auto}
  main{height:auto;overflow:visible}

  /* Two rows: identity and money on top, the six tabs across the full width
     underneath. Every tab must be reachable without scrolling or turning the
     phone sideways — losing Settings behind an off-screen edge is how a manager
     gets stuck with no way back. */
  .topbar{position:sticky;top:0;flex-wrap:wrap;height:auto;padding:6px 8px;gap:6px}
  .brand{flex:1 1 auto;min-width:0;gap:7px}
  .brand b{max-width:none;font-size:13px}
  .logo{height:26px;max-width:46px}
  .topmeta{gap:6px;min-width:0}
  /* flex-basis, not width: the base rule's `flex:1` sets a basis of 0, which a
     plain width:100% cannot beat — the bar collapsed into a narrow column. */
  .tabs{order:3;flex:1 1 100%;width:100%;flex-wrap:nowrap;gap:3px;overflow:visible}
  /* 40px tall: a thumb on a phone misses a 31px target often enough to matter
     when the person tapping is behind a bar at 2am. */
  .tabs button{flex:1 1 auto;min-width:0;padding:0 4px;min-height:40px;font-size:12px;
    display:flex;align-items:center;justify-content:center}

  /* The account menu — sign out and change password live behind it, and on a
     phone there is no Settings tab for a manager to fall back on. */
  .sync{display:inline-block!important;max-width:38vw;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap;font-size:11px;padding:4px 8px}
  .pill{font-size:12px;padding:3px 9px}

  .pos{grid-template-columns:minmax(0,1fr);grid-template-rows:auto;height:auto}
  .catalogue,.cart{min-width:0}
  .catalogue{border-right:0;border-bottom:1px solid var(--line)}

  /* The category switch is wider than a phone; let it scroll on its own rather
     than stretching the page. */
  .cat-toolbar{flex-wrap:wrap;gap:8px}
  #itemSearch{flex:1 1 100%}
  .group-switch{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}
  .group-switch button{white-space:nowrap}

  .item-scroll{max-height:56vh}
  .cart-lines{max-height:40vh}
  .cart-foot{position:sticky;bottom:0}

  /* Dialogs must sit inside the screen, not run off the right edge. */
  .modal-back{padding:10px}
  .modal{width:100%;max-width:100%;padding:16px;max-height:92vh}
  .move-grid{grid-template-columns:repeat(auto-fill,minmax(96px,1fr))}
  .varrow{grid-template-columns:1fr 70px 62px auto;row-gap:4px}
  .form .two{grid-template-columns:1fr}
  .table-grid{grid-template-columns:repeat(auto-fill,minmax(132px,1fr))}
  .tally{grid-template-columns:1fr}
  .devrow{flex-wrap:wrap}
}

/* ---------- variants, discount presets, help ---------- */

.variant-grid{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));margin:14px 0 4px}
.variant-grid button{
  position:relative;display:grid;gap:3px;padding:16px 14px;text-align:left;cursor:pointer;
  border:1px solid var(--line);border-radius:10px;background:var(--panel)
}
.variant-grid button:hover{border-color:var(--brand)}
.variant-grid button b{font-size:15px}
.variant-grid button span:last-child{color:var(--accent);font-weight:800;font-size:16px}
.variant-grid .dot{position:absolute;top:10px;right:10px;width:11px;height:11px;border-radius:2px;border:1.5px solid var(--ok)}
.variant-grid .dot::after{content:"";display:block;width:5px;height:5px;border-radius:50%;background:var(--ok);margin:1.5px auto}
.variant-grid .dot.nonveg{border-color:var(--danger)}
.variant-grid .dot.nonveg::after{background:var(--danger)}

.disc-quick{display:grid;grid-template-columns:repeat(4,1fr);gap:5px;margin-bottom:8px}
.disc-quick button{
  border:1px solid var(--line);background:var(--panel);border-radius:7px;padding:7px 2px;
  cursor:pointer;font-size:12px;font-weight:600;color:var(--muted)
}
.disc-quick button:hover{border-color:var(--muted);color:var(--ink)}
.disc-quick button.active{background:var(--ink);border-color:var(--ink);color:#fff}

.help-btn{
  width:24px;height:24px;border-radius:50%;border:1px solid var(--line);background:var(--panel);
  color:var(--muted);cursor:pointer;font-weight:700;line-height:1
}
.help-btn:hover{border-color:var(--brand);color:var(--brand)}
.help p{margin:0 0 11px}
.help b{color:var(--ink)}

.variant-grid.hours button{text-align:center;place-items:center}
.variant-grid.hours button b{font-size:16px}
.varbox{border:1px dashed var(--line);border-radius:9px;padding:11px;display:grid;gap:9px}
.varrow{display:grid;grid-template-columns:1fr 82px 72px auto auto auto auto;gap:6px;align-items:center}
/* The first row is the headline — its price is what the billing button shows. */
.varrow.is-head{background:#f0fdf4;border-radius:7px;padding:3px;margin:-3px}
.varrow.is-head .v-l{font-weight:700}
.mini.rec{border:1px solid var(--line);border-radius:6px;padding:3px 7px;font-size:11px;white-space:nowrap}
.mini.rec:hover{border-color:var(--brand);color:var(--brand)}
.recrows{display:grid;gap:8px;margin:10px 0}
.recrow{display:grid;grid-template-columns:1fr 110px 52px auto;gap:8px;align-items:center}
.recrow select,.recrow input{padding:8px 10px;border:1px solid var(--line);border-radius:8px;min-width:0}
.recrow input{text-align:right}
.variant-grid button.out{opacity:.45}
.varmove{display:flex;gap:2px}
.varmove .mini{padding:2px 5px;line-height:1;font-size:10px}
.varmove .mini[disabled]{opacity:.25;cursor:default}
.varrow input[type=number]{text-align:right}
/* the version the save refused — point straight at the empty box */
.varrow.bad .v-p{border-color:#dc2626;background:#fef2f2;box-shadow:0 0 0 2px #fecaca}
/* the amount is in the Recipe, not here — say so quietly instead of looking unfilled */
.varrow .v-u:disabled{background:#f1f2f5;color:var(--muted);border-style:dashed;cursor:not-allowed}
.small-btn{padding:6px 11px;font-size:13px;justify-self:start}

/* ---------- category colours ---------- */
/* Kept deliberately light: a stripe on the tile and a dot on the chip, so the eye
   can jump to "the green ones are veg starters" without the screen turning loud. */
.chip{display:inline-flex;align-items:center;gap:7px}
.chip::before{
  content:"";width:8px;height:8px;border-radius:50%;background:var(--c);flex:none
}
.chip[data-cat="all"]::before{display:none}
.chip.active{background:var(--c, var(--ink));border-color:var(--c, var(--ink));color:#fff}
.chip.active::before{background:rgba(255,255,255,.85)}

.swatch{
  display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:7px;
  vertical-align:1px;flex:none
}
.swatches{display:flex;flex-wrap:wrap;gap:6px}
.swatches button{
  width:26px;height:26px;border-radius:6px;border:2px solid transparent;cursor:pointer;padding:0
}
.swatches button.active{border-color:var(--ink);box-shadow:0 0 0 2px var(--panel) inset}

/* The service-charge line doubles as its own control. No button, no "optional"
   label — staff tap the line, a guest just sees a total. */
.totals div.sc{cursor:pointer;border-radius:5px;margin:0 -5px;padding:0 5px}
.totals div.sc:hover{background:var(--bg);color:var(--ink)}
.totals div.sc.off{opacity:.55;font-style:italic}

/* ---------- sync status ---------- */
.sync{
  font-size:11px;font-weight:700;padding:3px 9px;border-radius:20px;white-space:nowrap;
  border:1px solid transparent
}
.sync.ok{background:#dcfce7;color:var(--ok)}
.sync.busy{background:#fef3c7;color:var(--warn)}
.sync.off{background:var(--bg);color:var(--muted);border-color:var(--line)}
.sync.click{cursor:pointer}
.sync.click:hover{border-color:var(--brand);color:var(--brand)}
@media (max-width:900px){ .sync{display:none} }

/* ---------- sign-in gate ---------- */
/* While the sign-in box is up the app behind it is hidden, not merely covered —
   so nothing shows the menu, the takings or the day's bills to a stranger. */
body.signin-required main,
body.signin-required .tabs,
body.signin-required #todayTotal,
body.signin-required #syncState,
body.signin-required #btnHelp{ visibility:hidden }
body.signin-required .modal-back{ background:rgba(16,20,30,.82) }
.modal.locked{ box-shadow:0 24px 70px rgba(0,0,0,.45) }
.signin-error{
  background:#fef2f2;border:1px solid #fecaca;color:var(--danger);
  padding:8px 11px;border-radius:8px;font-size:13px;margin-bottom:4px
}

/* ---------- boot splash ---------- */
/* The mark racks up, a shine sweeps across it, then the credit settles in —
   about 1.5s, which is roughly how long a cold server takes to answer anyway. */
#splash{
  position:fixed;inset:0;z-index:200;display:grid;place-content:center;justify-items:center;
  gap:14px;background:var(--bg);
}
.splash-logo{position:relative;display:block;overflow:hidden;border-radius:12px}
.splash-logo img{
  display:block;width:190px;height:auto;
  animation:blRack .78s cubic-bezier(.2,1.5,.35,1) both;
}
.splash-logo .shine{
  position:absolute;top:-40%;left:-70%;width:45%;height:180%;pointer-events:none;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.55),transparent);
  transform:skewX(-18deg);
  animation:blShine .9s .55s ease-out both;
}
.splash-note{
  font-size:13px;color:var(--muted);min-height:18px;
  animation:blFade .4s .5s both;
}
.splash-credit{
  font-size:11.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);
  opacity:.75;animation:blFade .6s 1s both;
}
@keyframes blRack{
  0%  {opacity:0;transform:scale(.62) rotate(-9deg)}
  60% {opacity:1}
  100%{opacity:1;transform:scale(1) rotate(0)}
}
@keyframes blShine{ from{left:-70%} to{left:120%} }
@keyframes blFade{ from{opacity:0;transform:translateY(6px)} to{opacity:.75;transform:none} }

body:not(.booting) #splash{
  animation:blSplashOut .45s ease forwards;
  pointer-events:none;
}
@keyframes blSplashOut{ to{opacity:0;visibility:hidden} }
/* The splash covers everything, so the app underneath can render as it likes. */
body.booting .modal-back{display:none !important}

/* Sits below the menu on the billing screen and never scrolls away, so the credit
   is on screen the whole time someone is working. */
.cat-credit{
  flex:none;border-top:1px solid var(--line);background:var(--panel);
  padding:6px 16px;text-align:center;
  font-size:10px;font-weight:600;letter-spacing:.11em;text-transform:uppercase;
  color:var(--muted);opacity:.75;white-space:nowrap;overflow:hidden;text-overflow:ellipsis
}
.cat-credit b{color:var(--ink);font-weight:800;opacity:.85}

.warn-note{
  background:#fffbeb;border:1px solid #fde68a;color:var(--warn);
  padding:9px 12px;border-radius:8px;font-size:12.5px;margin:0 0 12px
}
.warn-note b{color:var(--ink)}

/* Rows for things in stock that still have no price — part of the bar, not yet sellable. */
tr.needs-price{background:#fffbeb}
tr.needs-price:hover{background:#fef3c7}
tr.needs-price td{border-bottom-color:#fde68a}

.credit-line{
  margin-top:14px;padding-top:12px;border-top:1px solid var(--line);
  font-size:11.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--muted)
}
.credit-line b{color:var(--ink);font-weight:700}

@media (prefers-reduced-motion:reduce){
  .splash-logo img,.splash-logo .shine,.splash-note,.splash-credit,body:not(.booting) #splash{
    animation-duration:.01ms !important;animation-delay:0ms !important
  }
}
