/* NGON POS — tokens straight off the Style system board */
:root{
  /* --ground is the page. --cream stays what it always was: the light ink on navy. */
  --ground:#FFFFFF;
  --cream:#F9F4EA; --surface:#FCF9F3; --white:#fff; --sidebar:#FBF7F0;
  --peach:#FCE8D8; --peach-2:#FBE3CE; --well:#F3EADC; --line:#F0E7D9; --line-2:#EFE6D8; --line-3:#E3D6C2;
  --navy:#133755; --navy-2:#234F70; --navy-ink:#16232E;
  --fill:#133755;   /* the navy SOLID: chips, toast, an ordered table */
  /* grey TEXT: the old #7E8C99..#A3AFBA ramp read 2.3-3.4:1 on white, so every text grey
     is now the one that clears 4.5:1. The light values live on only where nothing has to
     be read: --lgt-line for a border, --ph for a placeholder. */
  --sec:#5D6E7D; --mut:#5D6E7D; --sub:#5D6E7D; --plc:#5D6E7D; --lgt:#5D6E7D;
  --lgt-line:#A3AFBA; --ph:#98A5B1;
  --orange:#F0521B; --orange-2:#FCA13A; --grad:linear-gradient(135deg,#FCA13A,#F0521B);
  /* --action fills anything with words on it (Send, Save, the qty badge); --accent-ink is
     flat orange text. Both are the brand's own gradient and orange (the owner's choice,
     2026-09-30). Set again on body below, so each theme's --grad / --orange carries through. */
  --action:var(--grad); --action-2:var(--grad);
  --accent-ink:var(--orange); --accent-ink-2:var(--orange);
  /* the tap effects, as bare channels because a keyframe needs to add its own alpha.
     Keep these in step with --orange / --orange-2 in every theme that changes them. */
  --fx-rgb:240,82,27; --fx-2-rgb:252,161,58;
  --edge:#F0521B;   /* the selected border. Warmed in dark — see body.dark */
  --pick:#FEF0E6;   /* the wash behind a chosen option. NEVER set via the `background` shorthand */
  --gold:#E0A34D; --gold-ink:#B37519; --red:#F4552B; --green:#2F6B4A;
  /* the two washes an audit screen needs: something to look at, and something wrong */
  --warn-bg:#FBEAD2; --bad-bg:#FBE0DA; --bad-ink:#9E2F18;
  /* ---- shape and type. A theme is allowed to change these too, not just the colours:
     a coffee house gets thick outlines and round corners, a bar gets square ones. The
     values here ARE the current look; every rule below reads them instead of a number. */
  --font:Inter,-apple-system,'Helvetica Neue',Arial,sans-serif;
  --font-display:var(--font);
  --r-xs:4px; --r-sm:8px; --r:12px; --r-lg:15px; --r-xl:22px; --r-pill:999px;
  --bw-thin:1px; --bw:1.5px; --bw-thick:2px;
  --lift:none;          /* a resting box */
  --lift-on:none;       /* a chosen one */
  --on-accent:#fff;     /* text on the accent gradient */
  --paper:#FFFFFF;      /* real white in EVERY theme: a QR code or a receipt preview sits on paper, not on the theme */
}
/* the themes set --grad / --orange on body, so the aliases resolve there too */
body{--action:var(--grad); --action-2:var(--grad); --accent-ink:var(--orange); --accent-ink-2:var(--orange)}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{font-family:var(--font);background:var(--ground);color:var(--navy);
  -webkit-font-smoothing:antialiased;overflow:hidden}
button{font:inherit;color:inherit;border:0;background:none;cursor:pointer}
/* 100% of the body, not 100vh: percent heights follow the layout viewport, which is
   what shrinks when the keyboard opens. 100vh does not, so the app stays taller than the
   visible screen and the browser scrolls the document to reach the field. */
#app{display:flex;height:100%;padding-top:var(--alerts-h,0px)}

/* sidebar */
.side{width:212px;flex-shrink:0;background:var(--ground);border-right:var(--bw-thin) solid var(--line-2);
  display:flex;flex-direction:column;padding:22px 14px}
.brand{display:flex;align-items:center;gap:9px;padding:0 8px 22px;font-size:17px;font-weight:800;letter-spacing:.02em}
.brand i{width:26px;height:26px;border-radius:var(--r-sm);background:var(--grad);display:grid;place-items:center;flex-shrink:0}
.nav{display:flex;flex-direction:column;gap:2px}
.nav a{display:flex;align-items:center;gap:11px;padding:11px 12px;border-radius:var(--r);font-size:14px;font-weight:500;color:var(--sec);text-decoration:none}
.nav a.on{background:var(--peach-2);color:var(--navy);font-weight:700}
.nav .badge{margin-left:auto;background:var(--red);color:#fff;border-radius:var(--r-pill);min-width:19px;height:19px;font-size:12px;font-weight:700;display:grid;place-items:center;padding:0 5px}
.hr{height:1px;background:var(--line);margin:16px 8px}
.grow{flex-grow:1}
.synced{background:#F4EDE3;border-radius:var(--r-lg);padding:14px;font-size:12px;line-height:1.45;color:var(--mut)}
.synced b{display:block;font-size:14px;color:var(--navy);margin-bottom:5px}

/* shell */
/* min-height:0 so the row below it can be shorter than its contents. Without this a
   flex child refuses to shrink past its content, every panel inside grows to fit, and
   overflow:auto never has anything to scroll — the bug that ate two rounds on Settings
   and two more on History. */
.main{flex-grow:1;display:flex;flex-direction:column;min-width:0;min-height:0}
.head{height:84px;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0 22px;gap:20px}
.h1{font-size:25px;font-weight:700;letter-spacing:-.02em;line-height:1.15}
.h2{font-size:12.5px;color:var(--sub);margin-top:3px}
.body{flex-grow:1;display:flex;align-items:stretch;min-height:0}
.col{flex-grow:1;display:flex;flex-direction:column;min-width:0;min-height:0;overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  padding:0 14px 22px 22px;gap:13px}
.panel{width:340px;flex-shrink:0;min-height:0;overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain;background:var(--ground);border-left:var(--bw-thin) solid var(--line-2);
  border-radius:var(--r-xl) 0 0 0;display:flex;flex-direction:column;padding:16px}

/* atoms */
.pill{height:40px;border-radius:var(--r-pill);display:inline-flex;align-items:center;gap:8px;padding:0 16px;
  background:var(--white);border:var(--bw-thin) solid var(--line);font-size:13px;font-weight:600;color:var(--sec);white-space:nowrap;box-shadow:var(--lift)}
.pill.on{background:var(--fill);border-color:var(--fill);color:var(--cream);font-weight:700}
.pill.go{background:var(--action);border:0;color:#fff;font-weight:700}
.pill[disabled]{opacity:.4;cursor:not-allowed;box-shadow:none}
.btn{height:52px;border-radius:var(--r-pill);display:flex;align-items:center;justify-content:center;gap:9px;
  font-size:15px;font-weight:700;background:var(--white);color:var(--sec);box-shadow:var(--lift)}
.btn.go{background:var(--action);color:#fff}
.btn.dark{background:var(--fill);color:var(--cream)}
.btn[disabled]{opacity:.5;cursor:not-allowed}
.card{background:var(--surface);border:var(--bw-thin) solid var(--line-2);border-radius:var(--r-lg);box-shadow:var(--lift)}
.row{display:flex;align-items:center;gap:8px}
.muted{color:var(--mut)} .sub{color:var(--sub)} .b{font-weight:700} .bb{font-weight:800}
.tag{background:var(--peach-2);border-radius:var(--r-pill);padding:4px 11px;font-size:12px;font-weight:700;color:var(--accent-ink-2)}

/* floor list */
/* fixed row height: with 1fr a room with four tables stretched them to fill the page */
.tiles{flex-grow:1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:168px;align-content:start;gap:14px;min-height:0;overflow:auto}
.tile{background:var(--surface);border:var(--bw) solid var(--line-3);border-radius:var(--r-lg);padding:15px;display:flex;flex-direction:column;justify-content:space-between;cursor:pointer;text-align:left;box-shadow:var(--lift)}
.tile .n{font-size:27px;font-weight:800;letter-spacing:-.02em;line-height:1}
.tile.ordered{background:var(--fill);border-color:var(--fill);color:var(--cream)}
.tile.seated{border-color:var(--edge)}
.tile.bill_requested{background:#FDF3E2;border-color:var(--gold)}
.tile.to_clear{background:#F6F1E7;border:1.5px dashed var(--lgt-line);color:var(--sub)}

/* menu grid */
.menu{flex-grow:1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:200px;gap:13px;overflow:auto;align-content:start;padding-right:4px}
.item{background:var(--white);border:var(--bw) solid var(--line-3);border-radius:var(--r-lg);padding:9.5px;
  display:flex;flex-direction:column;cursor:pointer;text-align:left;
  box-shadow:0 1px 2px rgba(19,55,85,.04);transition:border-color .12s,box-shadow .12s,transform .12s}
.item:hover{border-color:var(--orange-2);box-shadow:0 4px 12px rgba(19,55,85,.09);transform:translateY(-1px)}
.item.has{border:var(--bw-thick) solid var(--edge);padding:9px;box-shadow:0 2px 8px rgba(240,82,27,.14)}
.item .ph{height:84px;flex-shrink:0;border-radius:var(--r);background:var(--well);display:grid;place-items:center;color:#C6B49B;font-size:12px;letter-spacing:.06em}
/* A card is 200px tall and, on a 1024 till, ~97px wide. Everything is budgeted to fit it:
   the name gets the full width for two lines (hyphenated, then an ellipsis), the price its
   own line under it, and the Thai name + hint share one footer line, the Thai name giving
   way. Name and price side by side left the name a few letters wide ("Vietn/ames"). */
.item .nm{flex-shrink:0;margin-top:8px;display:flex;flex-direction:column;gap:1px;font-size:13.5px;font-weight:700;line-height:1.25}
.item .nmt{min-height:2.5em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:break-word;hyphens:auto}
.item .pr{color:var(--accent-ink);flex-shrink:0}
.item .ft{flex-shrink:0;margin-top:auto;padding-top:4px;display:flex;align-items:center;justify-content:space-between;gap:6px;font-size:12px;color:var(--plc);white-space:nowrap}
.item .ft>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis}
.item.out{opacity:.6;border-style:dashed;cursor:not-allowed}
.cats{display:flex;gap:4px;overflow:auto;height:58px;align-items:center;background:var(--white);border:var(--bw-thin) solid var(--line);border-radius:var(--r-lg);padding:0 8px;flex-shrink:0}
.cat{padding:8px 13px;font-size:13.5px;font-weight:500;color:var(--sec);white-space:nowrap;border-radius:var(--r-pill)}
.cat.on{color:var(--accent-ink);font-weight:700}

/* ticket */
.tk{flex-grow:1;display:flex;flex-direction:column;gap:8px;min-height:0;overflow:auto;margin-bottom:12px}
.ln{background:var(--white);border:var(--bw) solid var(--line-3);border-radius:var(--r-lg);padding:10px;
  display:flex;align-items:center;gap:11px;
  box-shadow:0 1px 2px rgba(19,55,85,.04);transition:border-color .12s,box-shadow .12s,transform .12s}
.ln:hover{border-color:var(--orange-2);box-shadow:0 4px 12px rgba(19,55,85,.09)}
button.ln:hover{transform:translateY(-1px)}
.ln.sel{border-color:var(--edge);box-shadow:0 3px 10px rgba(240,82,27,.13)}
.ln.sel .nm{color:var(--accent-ink)}
.ln.new{border-left:var(--bw-thick) solid var(--edge)}
.ln .th{width:42px;height:42px;border-radius:var(--r);background:var(--well);flex-shrink:0}
.ln .av{width:42px;height:42px;border-radius:var(--r);flex-shrink:0;display:grid;place-items:center;
  background:linear-gradient(135deg,#FDEEDF,#FBDCC3);color:var(--accent-ink-2);font-size:16px;font-weight:800;
  border:var(--bw-thin) solid var(--peach-2)}
.ln.off .av{background:var(--well);color:var(--lgt);border-color:var(--line-3)}
.ln .tag{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  background:var(--well);color:var(--sec);border-radius:var(--r-pill);padding:2px 8px}
.ln .tag.off{background:#FDE7E0;color:var(--red)}
.ln .nm{flex-grow:1;min-width:0;font-size:13.5px;font-weight:700;line-height:1.3}
/* the sub-lines were flowing inline, which is why these rows read as one grey smear */
.ln .md{display:block;font-size:12px;color:var(--sub);font-weight:500;margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ln .pr{font-size:13px;font-weight:700;color:var(--accent-ink)}
.stp{display:flex;align-items:center;gap:7px;border:var(--bw-thin) solid var(--line);border-radius:var(--r-pill);padding:2px 7px;font-size:12px;font-weight:700}
/* the live stepper: each of − and + is a full 44px thumb target with 8px between them,
   drawn as two round keys either side of the count rather than glyphs inside a pill */
.stp.live{gap:8px;border:0;padding:0}
.stp.live .q{min-width:18px;text-align:center;font-size:14px;font-variant-numeric:tabular-nums}
.stp button{width:44px;height:44px;flex-shrink:0;display:grid;place-items:center;font-size:20px;line-height:1;color:var(--navy);
  background:var(--white);border:var(--bw-thin) solid var(--line-3);border-radius:var(--r-pill)}
.stp button:active{background-color:var(--pick)}
.sect{font-size:12px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--sub);padding:2px}
.sect.hot{color:var(--accent-ink)}
.tot{background:var(--white);border-radius:var(--r);padding:12px 13px;display:flex;flex-direction:column;gap:7px;flex-shrink:0;margin-bottom:12px;font-size:12.5px}
.tot .r{display:flex;justify-content:space-between;align-items:baseline}
.tot .big{font-size:19px;font-weight:700;color:var(--accent-ink);letter-spacing:-.02em}
.dash{border-top:1px dashed #EBDFCE;margin:2px 0}

/* modal */
.scrim{position:fixed;inset:0;background:rgba(19,55,85,.58);display:grid;place-items:center;z-index:50;padding:24px}
.modal{background:var(--surface);border-radius:var(--r-xl);padding:24px;width:min(660px,100%);max-height:90vh;overflow:auto;
  box-shadow:0 14px 34px rgba(19,55,85,.13);display:flex;flex-direction:column;gap:16px}
.modal h3{margin:0;font-size:23px;font-weight:700;letter-spacing:-.02em}
.opts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
/* a dialog's ✕ (xBtn in app.js): a whole thumb, never a 38px corner */
.xbtn{width:44px;height:44px;padding:0;justify-content:center;flex-shrink:0}
/* the till's own confirm/prompt sits over whatever dialog asked it */
.sheet-scrim{z-index:55}
.sheetfld{display:flex;flex-direction:column;gap:6px;font-size:14px;font-weight:700;color:var(--navy)}
.sheetfld .inp{font-size:16px;height:48px}   /* 16px: smaller and a phone zooms the page to it */
/* destructive: a fixed deep red, white on it 6.6:1 in every theme */
.btn.danger{background:#B42318;color:#fff}
.btn.danger:active{background:#8F1C13}

/* ── Sale Session ──────────────────────────────────────────────────────────
   Five full-width bands instead of a column and a rail. The rail used to hold
   exceptions, the drawer and the roster together because the layout had a slot
   for them, not because they belong to one another. */
.col.session{padding:22px 24px 26px;gap:18px}
.sesshead{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;flex-shrink:0}
.closehint{font-size:12px;color:var(--sub);margin-top:7px;max-width:240px;margin-left:auto;line-height:1.45}
.sstatus{display:inline-flex;align-items:center;gap:7px;background:var(--pick);border-radius:var(--r-pill);
  padding:5px 13px;font-size:12px;font-weight:700;color:var(--accent-ink-2);margin-top:9px}
.sstatus i{width:7px;height:7px;border-radius:50%;background:var(--orange);display:block;flex-shrink:0}
.sstatus.done{background:var(--well);color:var(--sec)}
.sstatus.done i{background:var(--sec)}
.band{display:flex;flex-direction:column;gap:10px;flex-shrink:0}
.band .sect{display:flex;align-items:center;gap:0}
.band .bn{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--well);
  color:var(--sec);font-size:12px;margin-right:8px;letter-spacing:0;flex-shrink:0}
.band .hint{font-weight:500;letter-spacing:0;text-transform:none;color:var(--lgt);font-size:12px;margin-left:7px}
.card.sess{background:var(--surface);border:var(--bw-thin) solid var(--line-2);border-radius:var(--r-lg);padding:16px 17px}
.sessgrid{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:14px;align-items:start}

/* 1 — the tie */
.tie{display:grid;grid-template-columns:repeat(3,minmax(0,1fr)) auto;align-items:stretch}
.tie .cell{padding:4px 20px 4px 0;min-width:0}
.tie .cell+.cell{padding-left:20px;border-left:var(--bw-thin) solid var(--line)}
.tie .k{font-size:12px;color:var(--mut);font-weight:600}
.tie .v{font-size:30px;font-weight:700;letter-spacing:-.025em;line-height:1.15;margin-top:3px;font-variant-numeric:tabular-nums}
.tie .v.owed{color:var(--gold-ink)}
.tie .s{font-size:12px;color:var(--sub);margin-top:2px}
.tie .proof{display:flex;align-items:center;gap:9px;padding-left:20px;border-left:var(--bw-thin) solid var(--line);min-width:200px}
.tie .ok{width:30px;height:30px;border-radius:50%;background:var(--pick);color:var(--accent-ink-2);display:grid;place-items:center;
  font-size:15px;font-weight:800;flex-shrink:0}
.tie .ok.bad{background:var(--bad-bg);color:var(--red)}
.tie .t{font-size:12.5px;font-weight:700;line-height:1.35}
.tie .t span{display:block;font-weight:500;color:var(--sub);font-size:12px;margin-top:1px}

/* 2 — tenders */
.tndr{display:grid;grid-template-columns:1fr auto auto;gap:14px;align-items:center;padding:9px 0;font-size:13.5px}
.tndr+.tndr{border-top:var(--bw-thin) solid var(--line)}
.tndr:first-child{padding-top:0}
.tndr .n{color:var(--sub);font-size:12px;text-align:right;min-width:62px;font-variant-numeric:tabular-nums}
.tndr .a{font-weight:700;text-align:right;min-width:92px;font-variant-numeric:tabular-nums}
.tndr.tot{border-top:var(--bw) solid var(--navy);margin-top:3px;padding-top:11px}
.chip{display:inline-block;background:var(--well);border-radius:var(--r-pill);padding:3px 10px;font-size:12px;font-weight:700;color:var(--sec);margin-left:6px}
.chip.warn{background:var(--warn-bg);color:var(--gold-ink)}
.share{height:5px;border-radius:var(--r-pill);background:var(--well);overflow:hidden;margin-top:9px;display:flex}
.share i{display:block;height:100%}
.slegend{display:flex;gap:14px;margin-top:8px;font-size:12px;color:var(--sub);flex-wrap:wrap}
.slegend span{display:flex;align-items:center;gap:5px}
.slegend i{width:8px;height:8px;border-radius:2px;display:block;flex-shrink:0}
.hbars{display:flex;align-items:flex-end;gap:4px;height:58px;margin-top:11px}
.hbars .h{flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;gap:4px;height:100%;min-width:0}
.hbars .h i{width:100%;border-radius:4px 4px 0 0;background:var(--orange-2);display:block}
.hbars .h i.mark{background:var(--gold)}
.hbars .h span{font-size:12px;color:var(--lgt)}

/* 2 — the drawer */
.skv{display:flex;justify-content:space-between;gap:12px;padding:6px 0;font-size:13px}
.skv .v{font-weight:700;font-variant-numeric:tabular-nums;flex-shrink:0}
.varamt{font-size:24px;font-weight:700;font-variant-numeric:tabular-nums}

/* Manage Access: a row you can pick up by the handle and nowhere else, so the list
   still scrolls under a finger that lands anywhere on a name */
.ln.urow{padding:0;gap:0;align-items:stretch;overflow:hidden}
.urow .grip{width:44px;flex-shrink:0;display:grid;place-items:center;color:var(--lgt);
  cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;border-right:var(--bw-thin) solid var(--line)}
.urow .grip:active{cursor:grabbing;color:var(--accent-ink);background:var(--pick)}
.urow-main{flex-grow:1;min-width:0;display:flex;align-items:center;gap:11px;padding:10px;text-align:left}
.urow.uslot{border:2px dashed var(--line-2);background:transparent;box-shadow:none}
.urow.uslot > *{visibility:hidden}
/* the press shrink sticks to whichever row the held one slid past — nothing is being pressed there */
.udrag .urow:active{transform:none}
.ughost{position:fixed;z-index:60;margin:0;pointer-events:none;opacity:.94;will-change:transform;
  box-shadow:0 4px 12px rgba(19,55,85,.12);transition:opacity .15s,box-shadow .15s}
.ughost.up{opacity:.88;box-shadow:0 16px 36px rgba(19,55,85,.24)}
.ughost .grip{cursor:grabbing;color:var(--orange);background:var(--pick)}

/* the drawer: four movements, their total, then the count against it */
.drawersum{display:flex;justify-content:space-between;gap:12px;align-items:baseline;margin-top:9px;padding-top:10px;
  border-top:var(--bw) solid var(--navy);font-size:13.5px;font-weight:700;font-variant-numeric:tabular-nums}
.drawerresult{background:var(--well);border-radius:var(--r);padding:11px 13px;margin-top:11px}
.varrow{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-top:5px;padding-top:8px;
  border-top:var(--bw-thin) dashed var(--line-3)}
.drawerbtn{width:100%;margin-top:12px}
/* the four movements are secondary to counting, so they sit below it behind a rule */
.drawerpills{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-top:12px;padding-top:12px;
  border-top:var(--bw-thin) solid var(--line)}
.drawerpills .pill{width:100%;justify-content:center;padding:0 10px}

/* 3 — the exception report */
.exgrid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:9px}
.exbox{background:var(--well);border-radius:var(--r);padding:11px 12px;min-width:0}
.exbox.hot{background:var(--warn-bg)}
.exbox .v{font-size:19px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.exbox .k{font-size:12px;color:var(--sec);margin-top:3px;line-height:1.35}
.exbox .m{font-size:12px;color:var(--mut);margin-top:3px}
.extable{overflow-x:auto;margin-top:13px}
.extable table{width:100%;border-collapse:collapse;min-width:620px}
.extable th{font-size:12px;letter-spacing:.07em;text-transform:uppercase;color:var(--mut);text-align:left;font-weight:700;padding:0 10px 7px 0;white-space:nowrap}
.extable td{font-size:13px;padding:8px 10px 8px 0;border-top:var(--bw-thin) solid var(--line);vertical-align:top}
.extable td.r,.extable th.r{text-align:right;padding-right:0;font-variant-numeric:tabular-nums}
.extable .when{color:var(--sub);font-variant-numeric:tabular-nums;white-space:nowrap}
.xtag{display:inline-block;border-radius:var(--r-pill);padding:2px 9px;font-size:12px;font-weight:700;white-space:nowrap}
.xtag.void{background:var(--bad-bg);color:var(--bad-ink)}
.xtag.canc{background:var(--well);color:var(--sec)}
.xtag.comp{background:var(--warn-bg);color:var(--gold-ink)}
.xtag.disc{background:var(--pick);color:var(--accent-ink-2)}

/* 4 and 5 — rows that open a bill */
.warnbar{background:var(--warn-bg);border-radius:var(--r);padding:11px 13px;font-size:12.5px;color:var(--gold-ink);line-height:1.5;flex-shrink:0}
.ln.sessrow{width:100%;text-align:left}
.ln.sessrow .tblno{width:48px;flex-shrink:0;font-size:15px;font-weight:800}
@media (max-width:1100px){
  .sessgrid{grid-template-columns:1fr}
  .exgrid{grid-template-columns:repeat(3,minmax(0,1fr))}
  .tie{grid-template-columns:repeat(2,minmax(0,1fr))}
  .tie .proof{grid-column:1/-1;border-left:0;padding-left:0;margin-top:12px;border-top:var(--bw-thin) solid var(--line);padding-top:12px}
}

/* several tenders on one bill: what is in so far, under the amount still to pay, and
   the amount box a card or QR keys into when it is not taking all of it */
.sofar{margin-top:10px;display:flex;flex-direction:column;gap:4px}
.sofar div{display:flex;gap:10px;font-size:13px;align-items:center}
.sofar .m{font-weight:700;min-width:130px}
.sofar .ok{color:#9FE0B6;font-weight:800}
.amtbox{background:var(--white);border:var(--bw) solid var(--line-3);border-radius:var(--r-lg);padding:12px 16px;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}
.amtbox .k{font-size:12px;color:var(--sub);font-weight:600}
.amtbox .v{font-size:26px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.amtbox.edit{border-color:var(--edge)}
.tot .r.paid{color:var(--green);font-weight:700}

/* split bill: the bills across the top, the ticket's dishes below. A chosen bill wears
   the same orange edge and wash as a chosen option anywhere else in the till. */
.modal.split{width:min(980px,100%)}
.sbills{display:flex;gap:10px;overflow-x:auto;padding:2px;flex-shrink:0;scroll-snap-type:x proximity}
.sbill{flex:1 0 210px;max-width:280px;min-height:190px;scroll-snap-align:start;display:flex;flex-direction:column;gap:8px;text-align:left;
  background:var(--white);border:var(--bw) solid var(--line-3);border-radius:var(--r-lg);padding:12px;box-shadow:var(--lift)}
.sbill.on{background-color:var(--pick);border:var(--bw-thick) solid var(--edge);padding:11.5px;box-shadow:0 2px 8px rgba(240,82,27,.14)}
.sbill .sx{width:26px;height:26px;border-radius:var(--r-pill);display:grid;place-items:center;font-size:12px;color:var(--sub);background:var(--well)}
.sbill .sl{display:flex;flex-direction:column;gap:5px;min-height:0;overflow:auto;max-height:180px}
.sbill .sln{display:flex;justify-content:space-between;gap:8px;font-size:12.5px;font-weight:600;padding:5px 7px;border-radius:var(--r-sm);background:var(--surface);border:var(--bw-thin) solid var(--line)}
.sbill .sln:hover{border-color:var(--orange-2)}
.sbill .sln .pr{color:var(--accent-ink);flex-shrink:0}
.spool{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;max-height:34vh;overflow:auto;padding:2px}
.spool .ln{cursor:pointer;text-align:left}
.spool .ct{width:34px;height:34px;border-radius:var(--r);background:var(--fill);color:var(--cream);display:grid;place-items:center;font-size:14px;font-weight:800;flex-shrink:0}
@media (max-width:820px){.spool{grid-template-columns:repeat(2,minmax(0,1fr))}}
.opt{background:var(--white);border:var(--bw) solid var(--line-2);border-radius:var(--r);padding:11px 13px;display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:13px;font-weight:500;color:var(--sec);cursor:pointer;text-align:left;box-shadow:var(--lift)}
.opt.on{background-color:var(--pick);border:var(--bw-thick) solid var(--edge);color:var(--navy);font-weight:700}
.opt.out{opacity:.5;text-decoration:line-through;cursor:not-allowed}
.opt .d{font-size:12.5px;font-weight:700;color:var(--accent-ink)}
.opt .ct{font-size:12px;font-weight:800;color:var(--accent-ink);margin-left:2px}
.optwrap{display:flex;gap:6px;min-width:0}
.optwrap .opt{flex:1;min-width:0}
.optminus{width:38px;flex-shrink:0;background:var(--white);border:var(--bw) solid var(--line-2);border-radius:var(--r);
  font-size:17px;font-weight:700;color:var(--sec);cursor:pointer;display:grid;place-items:center}
.optminus:active{background-color:var(--pick)}
.grid8{display:grid;grid-template-columns:repeat(8,minmax(0,1fr));gap:8px}
.num{height:62px;background:var(--white);border:var(--bw) solid var(--line-2);border-radius:var(--r);display:grid;place-items:center;font-size:21px;font-weight:700;color:var(--mut);cursor:pointer}
.num.on{background:var(--action);border:0;color:#fff;font-size:23px;font-weight:800}
.lbl{font-size:14px;font-weight:700;margin-bottom:9px;display:flex;align-items:center;gap:9px}
.req{background-color:var(--pick);border-radius:var(--r-pill);padding:3px 9px;font-size:12px;font-weight:700;color:var(--accent-ink-2)}
.ok{color:var(--green);font-size:12px;font-weight:700}

/* receipt */
.kot{background:#fff;color:#111;font-family:'JetBrains Mono',ui-monospace,Menlo,monospace;width:272px;padding:16px;margin:0 auto}
.kot .c{text-align:center} .kot .rule{border-top:var(--bw-thick) solid #111;margin:11px 0}
.kot .dash{border-top:1px dashed #111;margin:11px 0}
.kot .inv{background:#111;color:#fff;text-align:center;font-weight:700;letter-spacing:.08em;padding:5px 0;font-size:12.5px;margin:11px 0 9px}
.kot .it{display:flex;gap:10px;margin-bottom:9px}
.kot .it b{font-size:19px} .kot .it .en{font-size:16px;font-weight:700;line-height:1.2}
.kot .it .th{font-size:13px;font-weight:700;line-height:1.2}
.kot .it .mo{font-size:12px;margin-top:2px}
.kot .void .en,.kot .void .th{text-decoration:line-through}
.toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%);background:var(--fill);color:var(--cream);
  padding:13px 22px;border-radius:var(--r-sm);font-size:13.5px;font-weight:600;z-index:80;box-shadow:0 8px 22px rgba(19,55,85,.16)}
.err{white-space:pre-wrap;font-variant-numeric:tabular-nums;background:#FEF0E6;border:var(--bw-thin) solid #F7C9AC;color:#A33F13;border-radius:var(--r);padding:11px 13px;font-size:12px;line-height:1.5}

/* --- added: cart highlight, edit mode, inputs, numpad --- */
.item.on{border:var(--bw-thick) solid var(--edge);padding:9px}
.item .ph{position:relative}
.item .qty{position:absolute;top:8px;right:8px;background:var(--action);color:#fff;border-radius:var(--r-pill);
  min-width:24px;height:24px;display:grid;place-items:center;font-size:12.5px;font-weight:800;letter-spacing:0}
.tile{position:relative}
.del{position:absolute;width:26px;height:26px;border-radius:var(--r-pill);background:var(--red);color:#fff;
  display:grid;place-items:center;font-size:13px;font-weight:700;box-shadow:0 2px 6px rgba(19,55,85,.25);z-index:5;cursor:pointer}
.del.off{background:#D8CBB6;color:#8593A0;cursor:not-allowed}
.inp{width:100%;height:46px;background:#fff;border:var(--bw) solid var(--line-2);border-radius:var(--r);
  padding:0 14px;font:inherit;font-size:14px;font-weight:600;color:var(--navy);box-shadow:var(--lift)}
.inp:focus{border-color:var(--edge)}
.inp::placeholder{font-weight:400;color:var(--ph)}
.pad{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:9px;flex-shrink:0;max-width:420px}
/* on the settle page the pad takes the whole column, as wide as the tender cards above it */
.col>.pad{max-width:none}
.key{height:62px;background:var(--surface);border:var(--bw-thin) solid #F2EADE;border-radius:var(--r-lg);
  font-size:24px;font-weight:700;color:var(--navy);display:grid;place-items:center;box-shadow:var(--lift)}
.key:active{background:var(--peach-2)}

/* ✕ sits inside the tile (the list scrolls, so a negative offset gets clipped)
   and just outside a map table, which is round */
.tile .del{top:10px;right:10px}
.tiles{padding:2px}
.szbtn{width:38px;height:38px;flex-shrink:0;background:#fff;border:var(--bw) solid var(--line-2);border-radius:var(--r-sm);
  font-size:20px;font-weight:700;color:var(--navy);display:grid;place-items:center}
.szbtn[disabled]{color:#C9D2DA;background:#F4F1EB;cursor:not-allowed}
.szval{flex-grow:1;height:38px;background:#fff;border:var(--bw) solid var(--edge);border-radius:var(--r-sm);
  display:flex;align-items:center;justify-content:center;gap:3px;font-size:15px;font-weight:800}
.tile.sel{outline:3px solid var(--edge);outline-offset:-1px}
.ln[data-line]{cursor:pointer}
.ln[data-line]:hover{outline:2px solid var(--edge);outline-offset:-1px}
.ln.dead{opacity:.6}
.ln.dead .nm,.ln.dead .pr{text-decoration:line-through}
/* comped prices are red now — see SIGN BEATS BRAND at the end of this file */
@media print{
  /* 80mm roll, and NO fixed page height — a receipt is as long as it needs to be.
     Without this the browser assumes A4 and pads a ticket out to a full page. */
  @page{size:80mm auto;margin:0}

  /* Dark mode must not follow the paper. Light text on white paper prints nothing at
     all, and the first anyone would know is an empty slip in a customer's hand. */
  body,body.dark{
    background:#fff!important; color:#111!important;
    --ground:#fff; --surface:#fff; --white:#fff; --well:#fff; --pick:#fff;
    --navy:#111; --cream:#fff; --fill:#111; --line:#ccc; --line-2:#ccc; --line-3:#999;
    --sec:#333; --mut:#333; --sub:#333; --lgt:#666;
  }
  body{overflow:visible}
  .side,.head,.panel,.col,.toast,.btn,.pill{display:none!important}
  .scrim{position:static;background:#fff;padding:0;display:block}
  .modal{box-shadow:none;padding:0;max-height:none;width:auto;background:#fff}
  .kot,.paper{width:76mm;padding:2mm;margin:0;background:#fff;color:#111;border:0}
  /* gradient text is invisible on paper — put the ink back */
  *{background-image:none!important;-webkit-text-fill-color:currentColor!important}
}
.tg{width:50px;height:29px;border-radius:var(--r-pill);background:var(--line-3);display:flex;align-items:center;padding:3px;flex-shrink:0;transition:background-color .13s}
/* a settings row that IS its switch — the whole line is the target, not the pill */
.swrow{width:100%;text-align:left;padding:0}
.swrow:active .tg{transform:scale(.94)}
.swrow .tg{transition:background-color .13s,transform .13s}
.tg span{width:23px;height:23px;border-radius:var(--r-pill);background:#fff;transition:transform .12s}
.tg.on{background:var(--grad);justify-content:flex-end}
.trainbar{position:fixed;top:0;left:0;right:0;height:26px;background:var(--gold);color:#3B2A0A;
  display:grid;place-items:center;font-size:12px;font-weight:800;letter-spacing:.1em;z-index:90}
body.training #app{padding-top:calc(26px + var(--alerts-h,0px))}

/* The warn bars, above whatever screen is up. #app is padded by the strip's height
   (--alerts-h, measured in paint()), so it pushes the screen down and never covers it. */
.alerts{position:fixed;top:0;left:0;right:0;z-index:80;max-height:40vh;overflow:auto;
  display:flex;flex-direction:column;gap:6px;padding:8px 12px;background:var(--ground);
  border-bottom:var(--bw-thin) solid var(--line-2)}
.alerts .qrs-bars{padding:0}
body.training .alerts{top:26px}
body.training .kot::before{content:"*** TRAINING — NOT A REAL BILL ***";display:block;text-align:center;
  font-weight:700;font-size:12px;margin-bottom:10px;letter-spacing:.06em}
.setrow{display:flex;align-items:center;gap:15px;padding:17px 18px;text-align:left;width:100%;cursor:pointer;box-shadow:var(--lift)}
.setrow:hover{border-color:var(--edge)}
.seticon{width:44px;height:44px;flex-shrink:0;border-radius:var(--r);background:var(--peach-2);display:grid;place-items:center}
/* the Settings index: groups of tiles, as many across as fit */
.setgroup{font-size:11.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--mut);margin:20px 4px 9px}
.setgroup:first-child{margin-top:4px}
.setgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px}
.settile{flex-direction:column;align-items:flex-start;gap:12px;height:100%}
.printonly{display:none}
@media print{ .printonly{display:block} }




/* the gradient stays where there are no words on it; a button with a label is solid */
.btn.go,.pill.go{background:var(--action);border:0;color:#fff}
.btn.go:active,.pill.go:active{background:var(--action-2)}
.brand i{background:var(--grad)}
.item .qty{background:var(--action)}

/* One ring, for a keyboard or a switch, never for a finger (that is :focus-visible's job).
   A dialog takes focus itself when it opens so Tab starts inside it; the box needs no ring. */
:focus-visible{outline:3px solid var(--edge);outline-offset:2px}
.modal:focus{outline:none}
.search:focus-within{outline:3px solid var(--edge);outline-offset:2px}

/* money in, money off — the same rule the dashboard uses */
.money-in{color:var(--green)}
.money-off{color:var(--red)}

/* switching a table: only the legal targets stay lit */
.swapbar{display:flex;align-items:center;gap:10px;background:var(--peach);border:var(--bw-thin) solid var(--peach-2);
  border-radius:var(--r);padding:11px 14px;margin-bottom:11px;font-size:13px;color:var(--navy-ink);flex-shrink:0}
.swapbar .dot{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;
  background:var(--action);color:#fff;font-size:12px;font-weight:700;flex-shrink:0}
.swapbar b{font-weight:700}
.tile.swapno{opacity:.3;pointer-events:none}
.tile.swapok{outline:2px solid var(--edge);outline-offset:2px}
.tile.swapfrom{outline:2px dashed var(--fill);outline-offset:2px}

/* ============================================================
   DARK MODE
   The whole app is token-driven, so this is mostly one palette
   swap. What follows the tokens is the short list of places that
   had a colour baked in — each one is here because it would
   otherwise be dark-on-dark or light-on-light.
   ============================================================ */
body.dark{
  --action:var(--grad); --action-2:var(--grad); --accent-ink:var(--orange); --accent-ink-2:var(--orange);
  --edge:#FCA13A;           /* the same red-orange reads RED on black — warm it */
  --warn-bg:#3B3018; --bad-bg:#3E2019; --bad-ink:#F0A08C;
  --pick:#3A2418;
  --ground:#0E1E2C;          /* the page */
  --surface:#152836;         /* cards, modals, tables */
  --white:#1A2F3F;           /* things that were pure white */
  --sidebar:#0E1E2C;
  --well:#1D3345;
  --peach:#263B4E; --peach-2:#2F4759;
  --line:#243849; --line-2:#2B4155; --line-3:#3A5468;

  --navy:#E6EEF4;            /* the ink, now light */
  --navy-2:#BACCD9; --navy-ink:#F2F7FA;
  --fill:#2F5A7C;            /* the navy solid, lifted so it reads on a dark ground */
  --cream:#EAF2F7;           /* ink on that solid */

  --sec:#A7B9C6; --mut:#8DA1B0; --sub:#8DA1B0; --plc:#8DA1B0; --lgt:#8DA1B0;   /* 4.9:1+ on every dark surface */
  --lgt-line:#63788A; --ph:#728696;

  /* orange survives the swap untouched — it is the brand and it reads on both.
     green and red do not: both are too dark to see on a dark ground. */
  --green:#4CBF8B; --red:#FF7B5E;
  --gold:#E0A34D; --gold-ink:#F0C489;
  --paper:#FFFFFF;
}

/* --- floor --- */
body.dark .tile.bill_requested{background:#33291A}
body.dark .tile.to_clear{background:#182936}

/* --- inputs and controls that were literal white --- */
body.dark .inp,body.dark .szbtn,body.dark .szval{background:var(--white)}
body.dark .szbtn[disabled]{background:#16293A;color:#4C6376}
body.dark .key{border-color:var(--line-2)}
body.dark .tg span{background:#F4F8FB}
body.dark .del.off{background:#33495D;color:var(--lgt)}

/* --- the warm peach washes --- */
body.dark .ln .tag.off{background-color:var(--pick)}
body.dark .err{background:#3A1E16;border-color:#7A3A22;color:#FFB39B}
body.dark .ln .av{background:linear-gradient(135deg,#33241B,#402C1E);border-color:#4A3423}
body.dark .synced{background:#152836}
body.dark .dash{border-top-color:var(--line-2)}
body.dark .item .ph{color:#5E7286}
body.dark .swapbar{background:#2A1D14;border-color:#4A3423;color:var(--navy)}

/* --- shadows read as light on a dark ground, so soften them to real shadow --- */
body.dark .item,body.dark .ln{box-shadow:0 1px 2px rgba(0,0,0,.30)}
body.dark .item:hover,body.dark .ln:hover{box-shadow:0 4px 14px rgba(0,0,0,.42)}
body.dark .modal{box-shadow:0 14px 40px rgba(0,0,0,.55)}
body.dark .scrim{background:rgba(4,12,20,.66)}

/* --- a bill is paper in both modes: a receipt preview that goes dark is a
       receipt you cannot check against the one in your hand --- */
.paper{background:#fff;color:#111;border:var(--bw-thin) solid var(--line-2)}
body.dark .paper{border-color:#000}


/* ============================================================
   GRADIENT BORDERS
   The thing you just picked gets the brand gradient around it,
   not a flat orange. Two background layers: the inner one is the
   element's own fill clipped to the padding box, the outer is the
   gradient clipped to the border box — so the gradient shows only
   in the border itself, and it follows the rounded corners.
   Each rule sets --inner to whatever it sits on, or the border
   turns into a solid gradient block.
   ============================================================ */
.item.on,.item.has,.opt.on,.ln.sel,.card.picked,.tile.seated,.setrow:hover{
  border-color:transparent;
  background-image:linear-gradient(var(--inner),var(--inner)),var(--grad);
  background-origin:border-box;
  background-clip:padding-box,border-box;
}
.item.on,.item.has{--inner:var(--white)}
.ln.sel{--inner:var(--white)}
.card.picked,.tile.seated,.setrow:hover{--inner:var(--surface)}
.opt.on{--inner:var(--pick)}

/* the border has to be thick enough for a gradient to be legible as one */
.item.on,.item.has{border:var(--bw-thick) solid transparent;padding:8.5px}
.ln.sel{border:var(--bw-thick) solid transparent;padding:9.5px}
.opt.on{border:var(--bw-thick) solid transparent}
.card.picked{border:var(--bw-thick) solid transparent}
.tile.seated{border:var(--bw) solid transparent}
.setrow:hover{border:var(--bw-thin) solid transparent}

/* the glow under a picked tile follows the gradient too, warmer in dark */
.item.has,.item.on{box-shadow:0 3px 12px rgba(240,82,27,.16)}
.ln.sel{box-shadow:0 3px 10px rgba(240,82,27,.13)}
body.dark .item.has,body.dark .item.on{box-shadow:0 3px 14px rgba(252,161,58,.22)}
body.dark .ln.sel{box-shadow:0 3px 12px rgba(252,161,58,.18)}

/* outlines cannot take a gradient, so they use the warmed flat orange instead —
   these are transient states (dragging, switching), not a settled choice */
body.dark .tile.sel,body.dark .tile.swapok{outline-color:var(--edge)}

/* ============================================================
   ACCENT TEXT
   The brand gradient clipped to the glyphs. Its light end is about
   2:1 on white — the owner chose the brand look over the contrast
   guideline (2026-09-30), so it stays.
   ============================================================ */
.gx,
.item .pr,
.cat.on,
.ln.sel .nm,
.ln .pr,
.sect.hot,
.tot .big,
.opt .d{
  color:var(--edge);
  background-image:var(--grad);
  -webkit-background-clip:text;
  background-clip:text;
  -webkit-text-fill-color:transparent;
}

/* These carry their own pill background, so clipping to text would eat the pill.
   They take the warmed flat orange instead — at small sizes a gradient reads as nothing. */
.tag,.req,.ln .av,.ln .tag{color:var(--edge)}
.chip{color:var(--edge)}

/* the accent needs some weight behind it to read as one */
.item .pr,.ln .pr,.tot .big,.cat.on,.ln.sel .nm{font-weight:800}

/* ============================================================
   SIGN BEATS BRAND
   These come last on purpose. Gradient text works by clipping a
   background to the glyphs and setting -webkit-text-fill-color
   to transparent — so a later `color:` alone would paint nothing.
   Anything that carries a sign has to switch BOTH back off.
   ============================================================ */
.money-in,.money-off,
.ln.dead .pr,.ln.comped .pr{
  background-image:none;
  -webkit-text-fill-color:currentColor;
}
.money-in{color:var(--green)}
.money-off{color:var(--red)}

/* a comped or voided line took money off the bill — it is not a brand moment */
.ln.dead .pr,.ln.comped .pr{color:var(--red)}

/* ============================================================
   TOUCH FEEDBACK
   A ring of light on whatever was pressed.

   Drawn in #fx — a fixed layer outside #app — because a tap replaces the
   entire app in one innerHTML write, which would kill an animation
   attached to the element that was tapped.

   A ripple was tried alongside this and dropped: on a real till the ring
   said everything the ripple did, and two effects at once was noise.
   ============================================================ */
#fx-under,#fx-over{position:fixed;top:0;right:0;bottom:0;left:0;pointer-events:none;overflow:hidden}
#fx-under{z-index:40}   /* below .scrim (50) — plays out behind a dialog that just opened */
#fx-over {z-index:90}   /* above it — for taps made inside a dialog */
/* the scrim is see-through, so an effect behind it still showed as an after-image around the
   dialog it opened. Whatever came up covers it completely instead. */
body:has(.scrim, .drawer-scrim) #fx-under{visibility:hidden}

/* the ring follows the shape of whatever was tapped, so a round table stays round */
.fx-pulse{position:absolute;pointer-events:none;animation-duration:var(--fx-gs,.7s);
  animation-timing-function:ease-out;animation-fill-mode:forwards}
.fx-pulse.g-pulse{animation-name:fx-pulse}
.fx-pulse.g-halo {animation-name:fx-halo}
/* the colour is the theme's accent, not a fixed orange — Coffee House pulses in its own */
@keyframes fx-pulse{0%{box-shadow:0 0 0 0 rgba(var(--fx-rgb),.5)}100%{box-shadow:0 0 0 18px rgba(var(--fx-rgb),0)}}
@keyframes fx-halo{0%{box-shadow:0 0 0 rgba(var(--fx-2-rgb),0)}
  35%{box-shadow:0 6px 26px rgba(var(--fx-2-rgb),.8),0 0 0 2px rgba(var(--fx-rgb),.5)}
  100%{box-shadow:0 0 0 rgba(var(--fx-2-rgb),0)}}

/* A copy of what was pressed, animated in the overlay. The live element is destroyed
   by the redraw a few milliseconds later, so the copy is the only way these finish. */
/* the ghost is a copy of the pressed thing; in a theme with no borders that copy is a
   white box on a white box, so it always carries a faint accent ring of its own */
.fx-ghost{position:absolute;pointer-events:none;margin:0;transform-origin:center;outline:2px solid rgba(var(--fx-rgb),.55);outline-offset:-2px;
  animation-fill-mode:forwards}
.fx-ghost.g-jelly {animation-name:fx-jelly;animation-timing-function:ease-out}
.fx-ghost.g-absorb{animation-name:fx-absorb;animation-timing-function:cubic-bezier(.4,0,.2,1)}
@keyframes fx-jelly{0%{transform:scale(1,1)}22%{transform:scale(1.1,.88)}45%{transform:scale(.92,1.08)}
  68%{transform:scale(1.04,.97)}100%{transform:scale(1);opacity:0}}
@keyframes fx-absorb{0%{transform:scale(1);opacity:.9}100%{transform:scale(.55);opacity:0}}

/* Scattered from the fingertip. The colour is set per particle in app.js — the theme's
   two accent oranges alternate, which reads better at 5px than a gradient does. */
.fx-dot{position:absolute;pointer-events:none;border-radius:50%}
/* one tap's worth of effect, moved as one when the button it belongs to moves */
.fx-group{position:absolute;left:0;top:0;pointer-events:none;will-change:transform}

/* No 300ms wait for a possible double-tap. This is the single biggest
   improvement to how the till feels, and it is one line. */
html{touch-action:manipulation}
button,a,.item,.tile,.ln,.opt,.key,.num,.pill,.btn,.cat,.card{
  touch-action:manipulation;-webkit-tap-highlight-color:transparent}

/* Hover states stick on a touch screen: tap a dish and it stays highlighted as though
   the finger were still on it. Only give them to devices with a real pointer. */
@media (hover:none){
  .item:hover,.ln:hover,.setrow:hover,.rg:hover{
    border-color:inherit;box-shadow:none;transform:none}
  .item:hover{border-color:var(--line-3);box-shadow:0 1px 2px rgba(19,55,85,.04)}
  .ln:hover{border-color:var(--line-3);box-shadow:0 1px 2px rgba(19,55,85,.04)}
}

/* the press itself: instant, and it survives the redraw because it is :active */
.item:active,.tile:active,.ln:active,.key:active,.num:active,.opt:active{
  transform:scale(.96)}
.btn:active,.pill:active,.nav a:active{transform:scale(.975)}
.nav a:active{background:var(--peach)}
.item,.tile,.ln,.key,.num,.opt,.btn,.pill,.nav a{transition:transform .13s cubic-bezier(.3,1.3,.5,1),background-color .13s}

/* ============================================================
   MAKE IT STOP FEELING LIKE A BROWSER

   Everything below removes a behaviour Chrome gives a web page that an
   app would never do. Individually each is small; together they are the
   difference between "a website on a till" and "the till".
   ============================================================ */

/* 1. Pull-to-refresh. Scroll up at the top of the dish list and Chrome reloads
      the page — mid-order, on a machine holding a bill. This is the big one. */
html,body{overscroll-behavior:none}

/* 2. Scroll chaining. Reach the bottom of the dish grid and the page itself
      starts moving underneath. A panel should stop when it runs out. */
.menu,.tiles,.tk,.col,.panel,.cats,.tablewrap,.modal,.opts{overscroll-behavior:contain}

/* 3. Long-press selecting text and raising a context menu. Native apps do not
      do this. Inputs are exempted below — those genuinely need selecting. */
body{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
input,textarea,.kot,.paper,[contenteditable]{-webkit-user-select:text;user-select:text;-webkit-touch-callout:default}

/* 4. Scrollbars. A till is touched, not pointed at; the bar is one more thing
      that says "browser". Scrolling itself is untouched. */
.menu,.tiles,.tk,.col,.panel,.cats,.tablewrap,.modal{scrollbar-width:none;-ms-overflow-style:none}
.menu::-webkit-scrollbar,.tiles::-webkit-scrollbar,.tk::-webkit-scrollbar,.col::-webkit-scrollbar,
.panel::-webkit-scrollbar,.cats::-webkit-scrollbar,.tablewrap::-webkit-scrollbar,
.modal::-webkit-scrollbar{width:0;height:0;display:none}

/* 5. Scroll anchoring. When a redraw changes what is above your finger, Chrome
      helpfully shifts the view to compensate — which reads as the list twitching. */
.menu,.tiles,.tk,.col,.panel{overflow-anchor:none}

/* 6. Momentum. Without this, older Android scrolls a panel like a spreadsheet:
      it stops dead the moment your finger leaves the glass. */
.menu,.tiles,.tk,.col,.panel,.cats,.tablewrap,.modal{-webkit-overflow-scrolling:touch}

/* Room for the notch and the gesture bar, once installed to the home screen. */
@supports (padding:env(safe-area-inset-left)){
  #app{padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}
}

/* A newer version is on the server. Offered, never forced — a screen that vanished
   mid-order would be worse than being a few minutes behind. */
.updbar{position:fixed;left:0;right:0;bottom:0;z-index:70;display:flex;align-items:center;gap:14px;
  justify-content:space-between;background:var(--fill);color:var(--cream);
  padding:12px 18px;font-size:13px;box-shadow:0 -6px 20px rgba(19,55,85,.22)}
.updbar b{color:#fff}
.updbar .pill{height:34px;background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.25);color:#fff}
.updbar .pill.go{background:var(--action);border:0}


/* ============================================================
   Coffee House.
   The first style that changes shape as well as colour: everything looks drawn with one
   marker — thick bone-brown outlines, big soft corners, a hard offset shadow under every
   box like a sticker, and Nunito's round letters. The selection cue is no longer a
   gradient border but a box lifted on an orange shadow. Accent stays the customer's.
   ============================================================ */
body.doodle{
  --action:var(--grad); --action-2:var(--grad); --accent-ink:var(--orange); --accent-ink-2:var(--orange);
  --font:Nunito,"Varela Round","Hiragino Maru Gothic ProN",-apple-system,sans-serif;
  --font-display:var(--font);
  --ground:#FBF4E8; --cream:#FFF8EE; --surface:#FFFDF8; --white:#FFFDF8; --sidebar:#F6E9D6;
  --peach:#FFE9B8; --peach-2:#FFE0A6; --well:#F1E1CB;
  --line:#E9D9C2;            /* faint dividers stay faint */
  --line-2:#3A2A20; --line-3:#3A2A20;   /* box outlines become ink */
  --navy:#3A2A20; --navy-2:#5A463A; --navy-ink:#2A1C14; --fill:#3A2A20;
  --sec:#6E5846; --mut:#6E5846; --sub:#6E5846; --plc:#6E5846; --lgt:#6E5846;
  --lgt-line:#B5A493; --ph:#A08C7A;
  --orange:#D9822B; --orange-2:#F2A54A; --grad:linear-gradient(135deg,#F2A54A,#D9822B);
  --fx-rgb:217,130,43; --fx-2-rgb:242,165,74;
  --edge:#3A2A20; --pick:#FFE3BF;
  --gold:#E0A83A; --gold-ink:#6B4A0A; --red:#D64B3A; --green:#3E8A4E;
  --warn-bg:#FBE9C8; --bad-bg:#FADCD4; --bad-ink:#93301B;
  --r-xs:6px; --r-sm:12px; --r:16px; --r-lg:20px; --r-xl:26px; --r-pill:999px;
  --bw-thin:2px; --bw:2.4px; --bw-thick:3px;
  --lift:3px 3px 0 var(--navy);
  --lift-on:3px 3px 0 var(--orange);
  --on-accent:#3A2A20;
  --paper:#FFFFFF;
}
body.doodle{font-weight:600}
body.doodle .bb,body.doodle .h1,body.doodle .b{font-weight:800}
/* selection: an ink outline lifted on orange, instead of the gradient border */
body.doodle .item.on,body.doodle .item.has,body.doodle .opt.on,body.doodle .ln.sel,body.doodle .card.picked,body.doodle .tile.seated,body.doodle .setrow:hover{
  background-image:none;border-color:var(--navy);box-shadow:var(--lift-on)}
body.doodle .opt.on span,body.doodle .item.on .nm{background-image:none;background-color:transparent;-webkit-text-fill-color:currentColor;color:var(--navy)}
body.doodle .ln,body.doodle .item{box-shadow:var(--lift)}
body.doodle .ln:hover,body.doodle .item:hover{transform:none;box-shadow:var(--lift)}
body.doodle .btn.go,body.doodle .pill.go{color:var(--on-accent);border:var(--bw) solid var(--navy)}
/* white on this orange is 2.9:1; every other label on --action takes the ink too */
body.doodle .item .qty,body.doodle .num.on,body.doodle .swapbar .dot,body.doodle .se-tile{color:var(--on-accent)}
body.doodle .btn.dark,body.doodle .pill.on,body.doodle .toast{box-shadow:var(--lift)}
body.doodle .brand i{border:2px solid var(--navy);box-shadow:2px 2px 0 var(--navy)}
body.doodle .inp{background:var(--white)}
body.doodle .side{border-right-width:var(--bw)}
body.doodle .panel{border-left-width:var(--bw)}
body.doodle .modal{border:var(--bw) solid var(--navy);box-shadow:6px 6px 0 var(--navy)}
body.doodle .err{border:var(--bw) solid var(--red);background:#FFE6E0;color:#8A2A16}
body.doodle .tile.ordered{box-shadow:var(--lift)}

/* ============================================================
   Paper.
   No borders anywhere — every box is lifted off a sage ground by a soft shadow instead.
   Big corners, Quicksand's round letters, a sea-teal accent, and the chosen thing glows
   teal rather than growing a border. Gold, green and red keep their jobs.
   ============================================================ */
body.paper{
  --action:var(--grad); --action-2:var(--grad); --accent-ink:var(--orange); --accent-ink-2:var(--orange);
  --font:Quicksand,Nunito,-apple-system,sans-serif;
  --font-display:var(--font);
  --ground:#F1F4EE; --cream:#F3F7F2; --surface:#FFFFFF; --white:#FFFFFF; --sidebar:#E9EEE5;
  --peach:#FFF3D6; --peach-2:#FFEBBF; --well:#E3E9DF;
  --line:#E4E9E0;                       /* faint dividers inside a box */
  --line-2:transparent; --line-3:transparent;   /* box edges: none — the shadow is the edge */
  --navy:#26332A; --navy-2:#3E5044; --navy-ink:#1B261F; --fill:#26332A;
  --sec:#5E6E63; --mut:#56655B; --sub:#56655B; --plc:#56655B; --lgt:#56655B;
  --lgt-line:#A8B4AB; --ph:#98A59B;
  --orange:#159A8C; --orange-2:#3FBFAF; --grad:linear-gradient(135deg,#3FBFAF,#159A8C);
  --fx-rgb:21,154,140; --fx-2-rgb:63,191,175;
  --edge:#159A8C; --pick:#DFF3F0;
  --gold:#D6A531; --gold-ink:#7E5F0C; --red:#D9452A; --green:#2F7A4E;
  --warn-bg:#FBEAD2; --bad-bg:#FBE0DA; --bad-ink:#9E2F18;
  --r-xs:6px; --r-sm:10px; --r:16px; --r-lg:20px; --r-xl:26px; --r-pill:999px;
  --bw-thin:1px; --bw:1px; --bw-thick:1.5px;
  --lift:0 6px 16px -10px rgba(38,51,42,.35),0 1px 0 rgba(38,51,42,.06);
  --lift-on:0 8px 18px -10px rgba(21,154,140,.65),0 0 0 1.5px #159A8C;
  --on-accent:#fff;
  --paper:#FFFFFF;
}
body.paper{font-weight:500}
body.paper .bb,body.paper .h1,body.paper .b{font-weight:700}
/* selection: a teal glow, not a border */
body.paper .item.on,body.paper .item.has,body.paper .opt.on,body.paper .ln.sel,body.paper .card.picked,body.paper .tile.seated,body.paper .setrow:hover{
  background-image:none;border-color:transparent;box-shadow:var(--lift-on)}
body.paper .ln,body.paper .item{box-shadow:var(--lift)}
body.paper .ln:hover,body.paper .item:hover{box-shadow:var(--lift)}
/* things that were only a border need another way to be seen */
body.paper .inp{background:var(--white);border-color:var(--line);box-shadow:var(--lift)}
body.paper .inp:focus{border-color:var(--edge)}
body.paper .side{border-right:0}
body.paper .panel{border-left:0;background:var(--sidebar)}
body.paper .modal{box-shadow:0 30px 60px -30px rgba(38,51,42,.5)}
body.paper .err{border-color:transparent;background:#FFE9E4;box-shadow:var(--lift)}
/* :not(.on):not(.go) — `body.paper .pill` outranks `.pill.on`, and a chosen pill would
   otherwise be cream letters on a white box */
body.paper .pill:not(.on):not(.go){background:var(--white)}
body.paper .pill.on,body.paper .btn.dark,body.paper .toast{box-shadow:var(--lift)}
body.paper .tile.ordered,body.paper .tile.bill_requested{box-shadow:var(--lift)}
/* An ordered table has to be the loudest tile on the floor. Paper's --fill is nearly
   black, and on a pale sage page that reads as a hole punched in it — so here, and only
   here, the ordered tile gets a deep teal of its own: same family as the accent, same
   weight as the slab it replaces. */
body.paper .tile.ordered{background-color:#0E6F66;border-color:#0E6F66;color:#EAF7F4}
body.paper .tile.ordered .pill.go{background:rgba(255,255,255,.18);color:#fff}

/* ============================================================
   Green Grounds.
   After the café POS of the same name: a cream page, pure white boxes, and ONE colour —
   a deep leaf green — doing every job the gradient and the navy used to do. Every box
   wears a 1px green hairline instead of a shadow; corners are big and soft; Montserrat
   with Noto Sans Thai so the Thai names sit at the same weight. The chosen thing gets
   a 2px green edge, nothing else. Money in is green like everything else, so money off
   is the only red on the page.
   ============================================================ */
body.grounds{
  --action:var(--grad); --action-2:var(--grad); --accent-ink:var(--orange); --accent-ink-2:var(--orange);
  --font:Montserrat,"Noto Sans Thai",Inter,-apple-system,sans-serif;
  --font-display:var(--font);
  --ground:#F4F2E6; --cream:#FFFFFF; --surface:#FFFFFF; --white:#FFFFFF; --sidebar:#FFFFFF;
  --peach:#DDEBE1; --peach-2:#CFE3D5; --well:#F0EEE3;
  --line:#E3E0D3;                              /* faint dividers stay faint */
  --line-2:#0B5A34; --line-3:#0B5A34;          /* box edges are the green hairline */
  --navy:#171717; --navy-2:#3D3D3D; --navy-ink:#111111; --fill:#0B5A34;
  --sec:#5E5E5E; --mut:#5E5E5E; --sub:#5E5E5E; --plc:#5E5E5E; --lgt:#5E5E5E;
  --lgt-line:#B5B5B5; --ph:#A5A5A5;
  --orange:#0B5A34; --orange-2:#0E6B3E; --grad:linear-gradient(135deg,#0E6B3E,#0B5A34);
  --fx-rgb:11,90,52; --fx-2-rgb:14,107,62;
  --edge:#0B5A34; --pick:#DDEBE1;
  --gold:#C9A24E; --gold-ink:#7A5C14; --red:#E05252; --green:#0B5A34;
  --warn-bg:#F6E7C6; --bad-bg:#F7DCD8; --bad-ink:#8C2F22;
  --r-xs:6px; --r-sm:12px; --r:16px; --r-lg:22px; --r-xl:28px; --r-pill:999px;
  --bw-thin:1px; --bw:1px; --bw-thick:2px;
  --lift:none; --lift-on:none;
  --on-accent:#fff;
  --paper:#FFFFFF;
}
body.grounds{font-weight:500}
body.grounds .bb,body.grounds .h1,body.grounds .b{font-weight:700}
/* the hairline is the edge, so nothing floats */
body.grounds .item,body.grounds .ln,body.grounds .item:hover,body.grounds .ln:hover,body.grounds .item.has,body.grounds .item.on,body.grounds .ln.sel{box-shadow:none;transform:none}
body.grounds .item:hover,body.grounds .ln:hover{border-color:var(--orange-2)}
body.grounds .side{border-right-color:var(--line)}
body.grounds .panel{border-left-color:var(--line)}
body.grounds .cats{border-color:var(--line-3)}
body.grounds .nav a.on{background:var(--fill);color:var(--cream)}
body.grounds .nav a.on .badge{background:#fff;color:var(--fill)}
body.grounds .item .qty{background:var(--white);color:var(--fill);border:var(--bw) solid var(--fill)}
body.grounds .tag{background:var(--pick);color:var(--fill)}
body.grounds .synced{background:var(--white);border:var(--bw) solid var(--line)}
body.grounds .toast{box-shadow:0 8px 22px rgba(0,0,0,.14)}
body.grounds .modal{box-shadow:0 30px 60px -30px rgba(0,0,0,.35)}
body.grounds .err{background:#FDECEC;border-color:#F3B9B9;color:#9E2B2B}
body.grounds .key{border-color:var(--line)}
body.grounds .btn.dark{background:var(--white);color:var(--fill);border:var(--bw) solid var(--fill)}
/* Montserrat runs wide: a long dish name must not spill over the line below it */
body.grounds .item .nm{overflow:hidden}

/* ============================================================
   Grounds layout (Settings → Screen layout). A second axis, independent of the look:
   the order screen gains a search bar, category cards with a count and a sold-out
   pill, photo tiles with a round +, and thumbnails on the ticket. Every rule reads the
   tokens, so it takes whichever look the till is wearing.
   ============================================================ */
.search{height:48px;border-radius:var(--r-pill);background:var(--white);border:var(--bw) solid var(--line-3);
  display:flex;align-items:center;gap:10px;padding:0 16px;flex-shrink:0;box-shadow:var(--lift)}
.search svg{width:18px;height:18px;flex-shrink:0;color:var(--navy)}
.search input{flex-grow:1;min-width:0;border:0;background:none;font:inherit;font-size:14px;font-weight:500;color:var(--navy);outline:none}
.search input::placeholder{color:var(--ph);font-weight:400}
.search .k{font-size:12px;color:var(--sub);border:1px solid var(--line);border-radius:6px;padding:2px 7px;flex-shrink:0}
.catstrip{display:flex;gap:10px;overflow-x:auto;overflow-y:hidden;flex-shrink:0;padding:2px 2px 6px;scrollbar-width:none}
.catstrip::-webkit-scrollbar{display:none}
.catcard{position:relative;flex-shrink:0;width:168px;height:92px;border-radius:var(--r-lg);background:var(--white);
  border:var(--bw) solid var(--line-3);padding:11px 13px;display:flex;flex-direction:column;justify-content:space-between;
  overflow:hidden;text-align:left;color:var(--navy);box-shadow:var(--lift)}
.catcard.on{background:var(--fill);border-color:var(--fill);color:var(--cream);box-shadow:var(--lift-on)}
.catcard .st{display:inline-flex;align-self:flex-start;height:22px;align-items:center;padding:0 8px;border-radius:var(--r-pill);
  border:1px solid currentColor;font-size:12px;font-weight:600;white-space:nowrap;position:relative;z-index:1}
.catcard.on .st{border-color:rgba(255,255,255,.7)}
.catcard .st.out{background:var(--red);border-color:var(--red);color:#fff}
.catcard .nm{display:block;font-size:13.5px;font-weight:700;line-height:1.1;position:relative;z-index:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.catcard .ct{display:block;font-size:12px;font-weight:500;opacity:.72;margin-top:2px;position:relative;z-index:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.catcard .art{position:absolute;right:-16px;bottom:-14px;width:84px;height:84px;opacity:.14;color:currentColor}
.catcard.on .art{opacity:.3}
.catcard .art svg{width:100%;height:100%}
.menu.pics{grid-auto-rows:222px}
.item .pic{height:118px;flex-shrink:0;border-radius:var(--r);background:var(--well);overflow:hidden;position:relative;
  display:grid;place-items:center;color:#C6B49B;font-size:12px;letter-spacing:.06em}
/* the word sits behind the photo, so a path that leads nowhere shows the placeholder, not a broken icon */
.item .pic::before{content:"PHOTO";position:absolute;inset:0;display:grid;place-items:center}
.item .pic img{width:100%;height:100%;object-fit:cover;display:block;position:relative;z-index:1}
.item .pic .qty{padding:0 9px;white-space:nowrap;letter-spacing:0;z-index:2}   /* above the photo, which sits above the placeholder */
.item.out .pic::after{content:attr(data-out);position:absolute;inset:0;display:grid;place-items:center;
  background:rgba(255,255,255,.55);font-weight:700;font-size:12px;letter-spacing:0;color:var(--navy)}
.item .bot{display:flex;align-items:flex-end;justify-content:space-between;gap:8px;margin-top:8px;flex-grow:1;min-height:0}
.item .bot>span:first-child{min-width:0}
.item .nm2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:13px;font-weight:700;line-height:1.25}
.item .th2{display:block;font-size:12px;color:var(--sub);font-weight:500;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.item .pr2{display:block;font-size:12.5px;font-weight:700;color:var(--accent-ink);margin-top:3px}
.item .add{width:38px;height:38px;border-radius:50%;border:var(--bw) solid var(--edge);background:var(--white);color:var(--edge);
  display:grid;place-items:center;font-size:20px;font-weight:500;flex-shrink:0;line-height:1}
.item.on .add{background-color:var(--edge);color:var(--cream)}
.ln .th{overflow:hidden}
.ln .th img{width:100%;height:100%;object-fit:cover;display:block}

/* ---- Cafe: the frame. No sidebar; a top bar, and the sidebar as a drawer. ---- */
body.ui-cafe #app{flex-direction:column}
body.ui-cafe .side:not(.drawer){display:none}
.topbar{height:66px;flex-shrink:0;display:flex;align-items:center;gap:16px;padding:0 22px;background:var(--ground);border-bottom:var(--bw-thin) solid var(--line)}
.topbar .brand{padding:0;font-size:16px}
.topbar .tdate{font-size:13px;font-weight:600;color:var(--accent-ink);margin-left:6px}
.topbar .tstat{font-size:12.5px;font-weight:600;color:var(--sec)}
.topbar .tmenu{height:44px;border-radius:var(--r-pill);background:var(--white);border:var(--bw) solid var(--line-3);display:inline-flex;align-items:center;gap:8px;padding:0 16px 0 12px;font-size:13px;font-weight:700;color:var(--navy);box-shadow:var(--lift)}
.topbar .tmenu.on{background:var(--fill);border-color:var(--fill);color:var(--cream)}
.drawer-scrim{position:fixed;inset:0;z-index:60;background:rgba(17,17,17,.38)}
.side.drawer{position:fixed;top:0;right:0;bottom:0;z-index:61;width:320px;border-right:0;border-left:var(--bw-thin) solid var(--line-2);
  background:var(--surface);box-shadow:-20px 0 50px rgba(0,0,0,.2);padding-top:26px}
.side.drawer .brand{display:none}
.side.drawer .nav a{padding:13px 14px;font-size:14.5px}
body.ui-cafe .main{min-height:0}
/* bigger category cards: three at a glance, like the board they came from */
body.ui-cafe .catcard{width:248px;height:106px;padding:13px 15px}
body.ui-cafe .catcard .nm{font-size:16px}
body.ui-cafe .catcard .ct{font-size:12px}
body.ui-cafe .catcard .st{height:23px;font-size:12px;padding:0 9px}
body.ui-cafe .catcard .art{width:98px;height:98px;right:-10px;bottom:-14px}
/* the ticket tucks away to a rail, and the grid takes the room */
.pchev{width:34px;height:34px;border-radius:50%;background:var(--white);border:var(--bw) solid var(--line-3);color:var(--navy);font-size:17px;display:grid;place-items:center;flex-shrink:0;box-shadow:var(--lift)}
.panel.mini{width:64px;padding:16px 10px;align-items:center;gap:12px}
.panel.mini .pcount{width:30px;height:30px;border-radius:var(--r-pill);background:var(--fill);color:var(--cream);font-size:13px;font-weight:800;display:grid;place-items:center}
.panel.mini .ptotal{writing-mode:vertical-rl;transform:rotate(180deg);font-size:14px;font-weight:800;color:var(--navy);margin-top:4px}
.menu.pics.wide{grid-template-columns:repeat(5,minmax(0,1fr))}
.seg{display:flex;border:var(--bw) solid var(--line-3);border-radius:var(--r-pill);overflow:hidden;height:38px;flex-shrink:0}
.seg span{flex:1;display:grid;place-items:center;font-size:12px;font-weight:600;color:var(--sec);text-transform:capitalize}
.seg span.on{background:var(--fill);color:var(--cream)}

/* out-of-stock pill: one tap from the Menu tab; green in stock, red out */
.stk{flex:none;align-self:center;border:1.5px solid #BFDCC9;background:#E3F1E8;color:var(--green);border-radius:999px;height:36px;padding:0 12px;font-weight:700;font-size:12.5px;white-space:nowrap}
.stk.out{border-color:#F3C2B5;background:var(--bad-bg);color:var(--bad-ink)}
.stk.sm{height:28px;font-size:12px;padding:0 9px;margin:4px 4px 0 0}
.oos-opts{display:flex;flex-wrap:wrap;margin-top:4px}
.ln .md.oos-why{color:var(--bad-ink);font-weight:700}

/* ---- Stock tab: Receive/Waste/Adjust/Count/Correct, shared with the kitchen phone page
   (app/stock.html), which carries its own copy of these same rules for its own <style>. */
#stock-root{max-width:520px;margin:0 auto;width:100%;padding:4px 0 24px}
.se-tiles{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px}
.se-tile{height:64px;border-radius:var(--r-lg);border:0;background:var(--action);color:#fff;font-weight:700;font-size:16px}
.se-card{background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r);padding:12px 14px;margin-bottom:12px}
.se-row,.se-row-btn{display:flex;justify-content:space-between;padding:8px 0;border-bottom:var(--bw-thin) solid var(--line);width:100%;text-align:left;background:none;border-left:0;border-right:0;border-top:0}
.se-row-btn{background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r);padding:14px;margin-bottom:8px;font-size:16px}
.se-mute{color:var(--sec);font-size:13px}
.se-bad{color:var(--bad-ink);font-weight:700}
.se-link{border:0;background:none;color:var(--navy);font-weight:600}
.se-screen{display:flex;flex-direction:column;gap:10px}
.se-head{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:700}
.se-back{width:40px;height:40px;border-radius:var(--r-sm);border:var(--bw) solid var(--line);background:var(--surface)}
.se-fld{display:flex;flex-direction:column;gap:4px;font-size:13px;color:var(--sec)}
.se-inp{height:46px;border:var(--bw) solid var(--line);border-radius:var(--r-sm);padding:0 12px;font-size:16px;background:var(--white);color:var(--navy)}
.se-line{display:flex;align-items:center;gap:8px;background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r-sm);padding:8px 10px}
.se-line b{flex:1;font-size:14px}
.se-qty{width:90px;text-align:right}
.se-unit{width:90px}
.se-x,.se-skip{border:var(--bw) solid var(--line);background:var(--white);border-radius:var(--r-xs);height:36px;padding:0 10px}
.se-skip.on{background:var(--warn-bg);border-color:var(--gold);color:var(--gold-ink)}
.se-chips{display:flex;gap:6px;flex-wrap:wrap}
.se-chip{height:36px;border-radius:var(--r-pill);border:var(--bw) solid var(--line);background:var(--white);padding:0 12px}
.se-chip.on{background:var(--navy);color:#fff;border-color:var(--navy)}
.se-err{background:var(--bad-bg);color:var(--bad-ink);border-radius:var(--r-sm);padding:10px 12px}
.se-warn{background:var(--warn-bg);color:var(--gold-ink);border-radius:var(--r-sm);padding:10px 12px;font-size:13px}
.se-go{height:52px;border-radius:var(--r);border:0;background:var(--fill);color:#fff;font-weight:700;font-size:16px}
