:root{
  /* ===== The token layer (BeSmart Technology design system, brought in 21 Sep 2026 on MAK's
     decision, brief from the BOH Redesign lane; canvas 2yV7QeTkYAUe7UfMrJnd12). One set of names
     for every mode: surfaces, lines, ink, one brand colour with one job, three status pairs, three
     radii. Dark is the base, Light redefines the same names below, the Solid pair only zeroes the
     radii. The OLD names (--shell, --panel, --text, --navy, --brass ...) stay as aliases of these
     for one release so the whole file follows without a mass rename; every NEW rule uses the new
     names. Untouched on purpose: the till's functional colours --go / --stop / --alert and the
     cheque paper --tape (state reads the same in every mode), the PIN pad's own --pin, the KDS
     ticket ages, #rmFloor and the guest page worlds in order-themes.css. ===== */
  color-scheme:dark;
  --surface:#0f1526; --surface-raised:#171f33; --surface-sunken:#0a0f1c;
  --line:#2a3650; --line-strong:#5f7096;
  --ink:#edf1f8; --ink-muted:#a6b1c6; --ink-faint:#8290aa;
  --brand:#9fb6e6; --brand-strong:#bccbf0; --brand-soft:#1c2b4a; --on-brand:#0f1526;
  --success:#6fd39f; --success-soft:#123626; --warning:#f0b35a; --warning-soft:#3d2a0c; --danger:#f4928a; --danger-soft:#46191a;
  --focus-ring:0 0 0 2px var(--surface),0 0 0 4px var(--brand);
  --radius-sm:4px; --radius-md:6px; --radius-lg:10px; --radius-full:999px;
  /* aliases, the old names */
  --shell:var(--surface); --panel:var(--surface-raised); --panel-2:var(--surface-sunken);
  --text:var(--ink); --text-dim:var(--ink-muted);
  --navy:var(--brand); --navy-2:var(--brand-strong); --brass:var(--brand);
  --tape:#FFFFFF; --tape-line:#DADDE1; /* the cheque paper is plain white (owner, 2026-09-05) */
  --go:#2F7F5B; --stop:#B4402F; --alert:#D4622A;
  /* the PIN pad's own blue: never overridden by an outlet skin (owner, 2026-09-06) */
  --pin:#7C9BE0;
  --ink-on-tape:#191512; /* was --ink: dark text on the white cheque paper, see the .check rules */
  /* Scroll bar thumb/track. The bars themselves are HIDDEN everywhere since 23 Sep 2026, so these
     two paint nothing today; they are kept because the outlet skins in pos-themes.css and
     order-themes.css still set --sb-thumb, and a token that vanishes takes those rules with it. */
  --sb-thumb:#3E5588; --sb-track:transparent;
  --r:var(--radius-lg);
  /* Archivo only (the design system): headings condensed and heavy, labels tracked uppercase,
     money in tabular numerals; the old Space Grotesk, IBM Plex Mono, Fraunces and Manrope are gone. */
  --ui:'Archivo',system-ui,sans-serif;
  --ar:'Noto Kufi Arabic','Archivo',sans-serif;
  --mono:'Archivo',system-ui,sans-serif;
  /* The login screen's own tokens — see the LOGIN / REVENUE CENTRE PICKER section below for why
     these exist separately from --shell/--panel rather than reusing them directly. */
  --login-bg:radial-gradient(ellipse farthest-corner at 50% 0%,#24345c 0%,#1a2846 28%,#131d36 55%,#0c1325 80%,#080d1a 100%);
  --login-card-bg:rgba(22,35,64,.9);
  --login-menu-bg:rgba(22,35,64,.97);
  --login-opt-bg:rgba(255,255,255,.03);
  --login-opt-bg-hover:rgba(255,255,255,.06);
}
/* "Clean slate" light theme — same variable names as the dark palette above, so every rule in
   this file that already reads var(--shell)/var(--text)/etc. picks it up with no other changes.
   --tape/--tape-line/--ink/--go/--stop/--alert are already light-surface-safe (they're either
   already light, or used as solid button/badge backgrounds with fixed light text on top) and
   stay the same in both themes on purpose. --brass is darkened here specifically — the dark
   theme's gold reads fine on a near-black panel but loses too much contrast used as small text
   on a near-white one, so light mode gets a deeper gold instead of reusing the same hex. Applied
   by toggling data-theme on <html> — see /shared/theme.js — never edit this selector by hand
   without checking style.css's other var(--brass)/var(--text-dim) usages still read cleanly. */
:root[data-theme="light"]{
  color-scheme:light;
  --surface:#f4f6f9; --surface-raised:#ffffff; --surface-sunken:#e8ecf2;
  --line:#c3c8d0; --line-strong:#7d8797;
  --ink:#182338; --ink-muted:#5a6577; --ink-faint:#5e687c;
  --brand:#203864; --brand-strong:#172a4d; --brand-soft:#e4eaf5; --on-brand:#ffffff;
  --success:#1e6b47; --success-soft:#dcf3e6; --warning:#8a4b00; --warning-soft:#fdecd2; --danger:#b3261e; --danger-soft:#fbe1df;
  --pin:#2d4a80;
  --sb-thumb:#C3C8D0;
  --login-bg:radial-gradient(ellipse farthest-corner at 50% 0%,#FFFFFF 0%,#F6F7F9 28%,#EEF0F3 55%,#E4E7EB 80%,#DDE1E6 100%);
  --login-card-bg:rgba(255,255,255,.9);
  --login-menu-bg:rgba(255,255,255,.97);
  --login-opt-bg:rgba(0,0,0,.03);
  --login-opt-bg-hover:rgba(0,0,0,.06);
}
/* "Dark Solid" / "Light Solid" (owner, 12 Sep 2026: originally one "Solid" that kept whatever
   theme was active, split same-day into its own dark and light pair). Dark Solid redefines no color at all (base :root above is
   already the dark palette); Light Solid copies the Light theme's colors exactly. Both only add
   --r:0 (the handful of rules already written against the token) plus the broad rule below, which
   covers the other ~160 corners across this file and resmaro.css that predate --r and are
   hardcoded to a pixel/percent value directly. Genuinely round/pill controls (badges, avatars,
   toggle switches, floating action buttons) are excluded on purpose — they're functional shapes,
   not box corners, and forcing them square would make them unreadable as what they are. #rmFloor
   (ResM's whole procedural room drawing — RM_FLOOR_CSS in resmaro-host.js: tables, chairs, sofas,
   zones) is excluded wholesale rather than shape-by-shape: that file's own comment already says
   "the room commits to its own fixed palette like a real drawing — it doesn't follow the app
   theme," so Solid shouldn't touch it at all (adversarial review, 12 Sep 2026: without this, Solid
   was silently squaring every round/oval table and sofa in the floor-plan builder). Add any NEW
   pill/circle element's class to the exclusion list too, or Solid will silently square it. */
:root[data-theme="dark-solid"]{ --radius-sm:0; --radius-md:0; --radius-lg:0; --r:0; }
:root[data-theme="light-solid"]{
  color-scheme:light;
  --surface:#f4f6f9; --surface-raised:#ffffff; --surface-sunken:#e8ecf2;
  --line:#c3c8d0; --line-strong:#7d8797;
  --ink:#182338; --ink-muted:#5a6577; --ink-faint:#5e687c;
  --brand:#203864; --brand-strong:#172a4d; --brand-soft:#e4eaf5; --on-brand:#ffffff;
  --success:#1e6b47; --success-soft:#dcf3e6; --warning:#8a4b00; --warning-soft:#fdecd2; --danger:#b3261e; --danger-soft:#fbe1df;
  --pin:#2d4a80;
  --sb-thumb:#C3C8D0;
  --radius-sm:0; --radius-md:0; --radius-lg:0; --r:0;
  --login-bg:radial-gradient(ellipse farthest-corner at 50% 0%,#FFFFFF 0%,#F6F7F9 28%,#EEF0F3 55%,#E4E7EB 80%,#DDE1E6 100%);
  --login-card-bg:rgba(255,255,255,.9);
  --login-menu-bg:rgba(255,255,255,.97);
  --login-opt-bg:rgba(0,0,0,.03);
  --login-opt-bg-hover:rgba(0,0,0,.06);
}
/* Solid themes square the app through the radius tokens (--radius-sm/md/lg at 0, see the theme
   blocks above); --radius-full stays, so badges, dots and avatars keep their shape. The old
   [data-theme=*-solid] * { border-radius:0 !important } rule and its exclusion list went with
   the sweep of 21 Sep 2026. ResM (resmaro.css) still carries hard coded corners: the PA lane
   applies the same sweep there; until then its cards stay round in Solid. */

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
/* ================= NO SCROLL BARS, ANYWHERE =================
   MAK, 23 Sep 2026: "I hate scroll bars, I want to scroll up and down using mouse wheels and I
   dont want to see scroll bars across all, including resm."

   ONLY THE BAR GOES. Every way of scrolling still works and is untouched: the wheel, a trackpad,
   touch and drag on a phone, the keyboard's arrows, Page Up and Down, Home and End, and a focused
   element being scrolled into view. This hides the indicator, it does not make anything unscrollable.

   Both mechanisms are declared because neither covers everything we ship on:
     scrollbar-width      the standard property. Chromium 121+ (Electron 32 is Chromium 128) and
                          Firefox. This is what does the work in the till, the BOH and the KDS.
     ::-webkit-scrollbar  older WebKit, which is what a guest's phone may still be running on the
                          QR menu and the booking page.
     -ms-overflow-style   old Edge, for the odd Windows machine in a back office.

   THE TRAP, and it is why the rule this replaces could not simply be extended: a non-auto
   scrollbar-color makes every ::-webkit-scrollbar rule on that element INERT on Chromium 121+.
   The old rule set scrollbar-color on the universal selector to theme the bars, so adding a
   ::-webkit-scrollbar hide beside it would have silently done nothing on exactly the builds that
   matter. The colour rule is therefore gone, not disabled: with no bar to paint it has no job.
   --sb-thumb and --sb-track stay defined in the themes so nothing referencing them breaks.

   Universal selector, for the same reason the old rule used one: every pane in these apps is its
   own scroller. :root alone would leave every inner list with its bar. */
*{scrollbar-width:none;-ms-overflow-style:none}
*::-webkit-scrollbar{width:0;height:0;display:none}
html,body{height:100%;margin:0}
body{background:var(--shell);color:var(--text);font-family:var(--ui);overflow:hidden}
button{font-family:inherit;color:inherit;border:0;background:none;cursor:pointer}
/* Type from the design system: headings condensed and heavy, money and quantities in tabular
   numerals so columns line up, one focus ring everywhere. */
h1,h2,h3{font-stretch:80%;font-weight:700;letter-spacing:0}
h1{font-weight:800}
.pr,.totals,.lines,.cheque-tab,.price-cell,.a-code,.item-grid td,.screen-pick-num,.layout-num,.ln-qty{font-variant-numeric:tabular-nums}
:focus-visible{outline:none;box-shadow:var(--focus-ring)}
/* No label ever wraps (MAK, 21 Sep 2026): tabs, chips, badges, buttons, column headers and field
   labels hold one line and take the width of their longest word; a group of buttons wraps between
   buttons, never inside one. */
.a-tab,.a-tabs button,.a-subtabs button,.tabs button,.chip,.a-tag,.btn,.opt,.a-addbtn,.a-actions button,.a-headbtns button,th,.a-field>label,.cat .cat-nm{white-space:nowrap}
/* Native controls follow the mode (color-scheme on :root above), and every one of them gets the
   same frame as a text field, so a select or a date never renders white on dark. */
select,input[type=date],input[type=time],input[type=number],input[type=file],input[type=month],input[type=week]{background:var(--surface);color:var(--ink);border:1px solid var(--line-strong);border-radius:var(--radius-sm);font-family:var(--ui)}
.ar{font-family:var(--ar);direction:rtl}
/* On a French installation the second name is French (see locale.js secondLang): the same
   elements, read left to right in the page's own face. The guest page sets the attribute from
   /api/order/state; the BOH will when its labels follow (27 Sep 2026). */
html[data-second-lang="fr"] .ar,html[data-second-lang="fr"] .nar,html[data-second-lang="fr"] .menu .tile .nar,html[data-second-lang="fr"] .tile .a,html[data-second-lang="fr"] .sub.ar{font-family:inherit;direction:ltr}

.conn-banner{position:fixed;top:0;left:0;right:0;z-index:80;background:var(--alert);color:#fff;text-align:center;font-size:12px;font-weight:600;letter-spacing:.03em;padding:6px}
.conn-banner[hidden]{display:none}
/* Admin's Stop POS services switch: a strip above the New table tabs while counting down and while
   down; the wall only for the last five seconds of the countdown */
.pos-strip{flex:0 0 auto;padding:8px 8px;font-size:12px;font-weight:700;line-height:1.25;text-align:center;color:#fff;background:#b45309;border-bottom:1px solid var(--line)}
.pos-strip.down{background:#991b1b}
.pos-strip.counting{background:#b45309}
/* Admin's Stop POS services switch: the countdown sits over the till, the wall replaces it */
.posdown-wall{position:fixed;inset:0;z-index:95;display:flex;align-items:center;justify-content:center;background:rgba(20,24,32,.92);color:#fff}
.posdown-wall.counting{background:rgba(20,24,32,.55);align-items:flex-start;padding-top:12vh}
.posdown-box{max-width:460px;text-align:center;padding:28px 32px;border-radius:var(--radius-lg);background:#1d2430;box-shadow:0 20px 60px rgba(0,0,0,.5)}
.posdown-box h2{margin:0 0 10px;font-size:22px}
.posdown-box p{margin:0;font-size:15px;line-height:1.5;opacity:.9}
.posdown-box b{font-size:20px}
@media print{.posdown-wall{display:none!important}}

.app{display:flex;flex-direction:column;height:100dvh}
.topbar{display:flex;align-items:center;gap:14px;padding:10px 16px;background:var(--panel);border-bottom:1px solid var(--line);flex:0 0 auto}
.topbar[hidden]{display:none}
/* Left-aligned stack: the outlet name starts under the first letter of the wordmark. */
.brand{display:flex;flex-direction:column;align-items:flex-start;text-align:left;line-height:1.15}
/* The R&B wordmark in the till and BOH headers (MAK, 15 Sep 2026: "the logo is not there inside the
   screen"). The same 480x160 login cut, cropped to the wordmark: the SERVICE WITH RHYTHM / BACK OF
   HOUSE line under it turns to a smudge at 30px, so the box shows rows 16 to 119 and columns 122 to
   357 of the image (measured on all four cuts), scaled to the header height. Dark themes swap to the
   white cuts exactly as the login logos do (rules further down, same specificity order). */
.brand-logo{display:block;width:68.5px;height:30px;background:url("assets/logo-rnb-light.png") no-repeat -35.5px -4.7px/139.8px 46.6px}
.brand-logo-boh{background-image:url("assets/logo-boh-light.png")}
/* BOH keeps a small BOH beside the wordmark: the BACK OF HOUSE line is the part the crop removes. */
.brand-row{display:flex;align-items:center;gap:7px}
/* KDS board header: its own mark (bars, R&B, KITCHEN DISPLAY SCREEN) whole, no crop: the screen is a big
   monitor and the line stays readable at this height. Dark cut under the dark theme, as on its login. */
.brand-logo-kds{display:block;height:38px;width:auto}
:root[data-theme="dark"] .brand-logo-kds{content:url("assets/logo-kds-dark.png")}
.brand-suffix{font-size:12px;letter-spacing:.14em;font-weight:600;color:var(--text-dim)}
.brand b{font-size:15px;letter-spacing:.02em}
.brand span{font-size:10px;color:var(--text-dim);letter-spacing:.14em;text-transform:uppercase}
.open-tables{padding:7px 10px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);color:var(--text);font-family:inherit;font-size:12px;max-width:170px;margin-left:6px}
.open-tables:hover{border-color:var(--brass)}
.btn-newtable{padding:7px 12px;border-radius:var(--radius-md);background:var(--panel-2);border:1px dashed var(--line);font-size:12px;white-space:nowrap;color:var(--text-dim)}
.btn-newtable:hover{border-color:var(--brass);color:var(--brass)}
.btn-cheques{margin-left:auto;padding:7px 12px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);font-size:12px;white-space:nowrap;color:var(--text-dim)}
.btn-cheques:hover{border-color:var(--brass);color:var(--brass)}
/* At least one open cheque, anywhere, has an item sitting unsent for over 7 minutes — see
   anyTableHasOverdue. A glance-able signal for something you're not currently looking at,
   same red/pulse language as checkOverdueBtn (the per-table version of this same alert). */
.btn-cheques.overdue{background:var(--stop);border-color:var(--stop);color:#fff;animation:overdue-pulse 1.6s ease-in-out infinite}
/* BeSmart Admin's topbar has no Cheques button to carry the auto-margin that
   pushes the session-bar right, so give it one directly, scoped to this page only. */
.admin-topbar .session-bar{margin-left:auto}
/* Same reasoning for the KDS board's topbar — no Cheques button there either, so the
   workstation-name tag and Reload button (both now in .session-bar) need their own push right. */
.kds-topbar .session-bar{margin-left:auto}

.session-bar{display:flex;align-items:center;gap:6px}
.session-bar .a-addbtn{margin-top:0;white-space:nowrap}
.session-revenue-centre,.session-user{padding:7px 12px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);font-size:12px;white-space:nowrap}
.session-revenue-centre[hidden]{display:none}
.session-revenue-centre:hover{border-color:var(--brass);color:var(--brass)}
/* .session-revenue-centre is a <button> in the till (opens the RVC picker) but a <select>
   in BeSmart Admin (the RVC switcher) — selects don't inherit font/color/cursor the way
   buttons do, so set them explicitly here for the select case. */
select.session-revenue-centre{color:var(--text);font-family:inherit;cursor:pointer}
.session-user{color:var(--text-dim)}
.session-user:hover{border-color:var(--stop);color:var(--stop)}
/* A plain name display, not a control — both apps now have a dedicated Logout button instead,
   so the red "this logs you out" hover cue would be actively misleading here. */
.session-user.static{cursor:default}
.session-user.static:hover{border-color:var(--line);color:var(--text-dim)}

.main{flex:1;display:flex;min-height:0;position:relative;overflow:hidden}
/* Open cheques as a tab strip on the right edge (owner, 2026-09-05): New table first, then one
   small square per open table. Tapping a tab slides that cheque in over the grid. */
.cheque-tabs-col{flex:0 0 112px;display:flex;flex-direction:column;min-height:0;z-index:31;background:var(--panel);border-left:1px solid var(--line)}
.cheque-tabs{flex:1 1 auto;background:var(--panel);display:flex;flex-direction:column;gap:0;padding:10px 6px 10px 0;overflow-y:auto;min-height:0}
/* Index tabs, like the tabs on a paper file (owner, 2026-09-05): square on the side that touches
   the cheque, rounded on the outer edge; the open one wears the cheque's own paper colour so the
   tab and the sheet read as one piece. */
.cheque-tab{width:100px;height:36px;border-radius:0 var(--radius-lg) var(--radius-lg) 0;background:var(--panel-2);border:1px solid var(--line);border-left:0;font-family:var(--mono);font-weight:700;font-size:14px;color:var(--text);display:flex;align-items:center;justify-content:center;text-align:center;line-height:1.1;flex:0 0 auto;position:relative;box-shadow:2px 2px 6px rgba(0,0,0,.12);margin-bottom:-9px}
/* Stacked like a paper file: each tab sits a little over the one below it (z-index set per tab in
   pos.js so the upper one is on top); the open tab always comes to the front. */
.cheque-tab:last-child{margin-bottom:0}
.cheque-tab.on,.cheque-tab:hover{z-index:60!important}
.cheque-tab:hover{border-color:var(--brass);color:var(--brass)}
.cheque-tab.on{background:var(--tape);border-color:var(--tape-line);color:var(--ink-on-tape);width:106px;box-shadow:3px 3px 8px rgba(0,0,0,.18)}
.cheque-tab.new{background:var(--brand);border-color:var(--brand);color:var(--on-brand);font-family:var(--ui);font-size:11px;white-space:nowrap;font-weight:600;letter-spacing:.02em}
/* Items sitting unsent too long: the table's own tab flashes red (owner, 2026-09-05). */
.cheque-tab.overdue{background:var(--stop);border-color:var(--stop);color:#fff;animation:overdue-pulse 1.6s ease-in-out infinite}
.cheque-tab.overdue.on{background:var(--stop);color:#fff}
/* Closed cheques: pinned at the bottom of the strip, one line, never part of the stack. */
.cheque-tab.closed{margin-top:auto;margin-bottom:0;align-self:center;margin-left:6px;height:36px;width:96px;border-radius:var(--radius-md);border-left:1px solid var(--line);font-family:var(--ui);font-size:11.5px;font-weight:600;white-space:nowrap;box-shadow:none;z-index:1}
.cheque-tab.locked{opacity:.5}
.cheque-tab .cq-lock{position:absolute;right:-2px;bottom:-2px;font-size:9px}
.main[hidden]{display:none}
/* News-style crawl for "order ready" alerts — sits between the topbar and the grid, only takes
   up space while a message is scrolling (see showReadyTicker in pos.js), so it never steals
   room from the grid/check panel the rest of the time. */
.ticker{position:relative;overflow:hidden;height:30px;flex:0 0 auto;background:var(--go);border-bottom:1px solid var(--line)}
/* The cash and waiter strips were removed on 23 Sep 2026 and their colours with them: a guest's
   call lives in the top bar chip and the table's own badge now. Only the kitchen Ready strip and
   the ResM strip are left, and both announce something that already happened. */
.ticker.resm{background:#203864} /* ResM booking notices: BeSmart navy, white text (owner, 16 Sep 2026: green is the kitchen's) */
.ticker-track{position:absolute;top:0;left:100%;z-index:1;white-space:nowrap;line-height:30px;padding:0 16px;font-size:13px;font-weight:700;letter-spacing:.02em;color:#fff}
.ticker-dismiss{position:absolute;top:0;right:0;z-index:2;height:30px;width:34px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.18);border:0;border-left:1px solid rgba(255,255,255,.25);color:#fff;font-size:14px;line-height:1;cursor:pointer}
.ticker-dismiss:hover{background:rgba(0,0,0,.32)}
@keyframes ticker-scroll{from{left:100%}to{left:-100%}}
/* A timed strip (the green order ready bar) reads at once: text from the left, no marquee. */
.ticker.static .ticker-track{left:0;animation:none!important;max-width:calc(100% - 34px);overflow:hidden;text-overflow:ellipsis}
/* .cats-col wraps the category nav plus the Logout button pinned under it — same left-sidebar,
   bottom, white-text placement as BeSmart Admin's own Logout (.a-tab, reused here as-is rather
   than a lookalike copy, so both apps' logout controls are pixel-identical, not just similar). */
.cats-col{flex:0 0 122px;background:var(--panel);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0}
.cats-col .a-tab{margin:0 8px 4px}
.cats-col .ws-name-tag{margin:4px 8px 8px;text-align:center;white-space:normal;line-height:1.3}
/* order.html's QR page uses .cats directly, unwrapped (see .order-app .cats override below) —
   background/border-right stay on the base rule too so that page keeps its look unchanged. */
.cats{flex:1;background:var(--panel);border-right:1px solid var(--line);display:flex;flex-direction:column;padding:10px 8px;gap:6px;overflow-y:auto;min-height:0}
.cats-col .cats{border-right:0}
.cat{padding:13px 10px;border-radius:var(--r);text-align:left;font-size:13px;color:var(--text-dim);border:1px solid transparent}
.cat.on{background:var(--panel-2);color:var(--text);border-color:var(--line)}
.cat small{display:block;font-size:11px;opacity:.6;margin-top:3px;font-family:var(--ar);direction:rtl}
/* The till's own screen list is compact (owner, 21 Sep 2026: the buttons were too big in every
   case, 15 screens on a 17 inch POS and most of them out of sight). Scoped to .cats-col so the
   QR guest page (order.html, .order-app .cat) keeps its roomy horizontal strip: about 37px per
   screen here against 117px before, name and Arabic on two tight lines, 6px clear between
   buttons (MAK, same night: 2px was too little, a large finger lands on the wrong screen).
   The list still scrolls past the pane's height, so a long menu is never cut, just closer. */
.cats-col .cats{padding:8px 6px;gap:6px}
.cats-col #cats .cat{padding:5px 8px;font-size:12.5px;line-height:1.15}
.cats-col #cats .cat small{font-size:10.5px;line-height:1.1;margin-top:1px}
.cat .cat-n{display:none}
.grid-head{display:none}
.tile[hidden]{display:none}

/* grid-auto-rows:min-content is required, not cosmetic. With the default `auto` rows this grid
   resolved every row to the tile's 96px minimum instead of to its contents, so a tile carrying a
   photo (~199px) was laid out inside a 96px row and its picture spilled over the tiles below —
   the reported "pics are over each other", worst on a screen with gaps, where short blank tiles
   share the row. min-content sizes each row to what it actually holds: ~199px where there are
   photos, 96px for a row of text-only tiles or gaps. */
.grid{flex:1;padding:12px;display:grid;gap:10px;overflow-y:auto;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));grid-auto-rows:min-content;align-content:start}
.tile{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:12px;min-height:96px;text-align:left;display:flex;flex-direction:column;justify-content:space-between;transition:transform .08s,border-color .12s;position:relative}
.tile:active{transform:scale(.97);border-color:var(--brass)}
.tile .nm{font-size:13.5px;font-weight:500;line-height:1.25}
.tile .nar{font-size:12px;color:var(--text-dim);margin-top:3px}
.tile .pr{font-family:var(--mono);font-size:13px;color:var(--brass);margin-top:10px}
.tile .flag{position:absolute;top:9px;right:9px;z-index:1;font-size:9px;letter-spacing:.1em;color:#fff;background:rgba(0,0,0,.55);border:1px solid rgba(255,255,255,.2);border-radius:var(--radius-sm);padding:2px 5px}
/* Allergy warning badge on guest QR tiles — top-LEFT (the sizes .flag owns top-right), solid
   ground + z-index so it stays readable over a photo tile. Shown only when the item's allergy
   box is hand-ticked in Admin (never inferred). */
/* The allergy mark, one rule one place (MAK, 21 Sep 2026): a 22px square top right of the tile with the warning sign alone, on the till, the guest QR tile and anywhere a tile draws it. The sizes flag stays top left, the two never meet. */
.tile .allergy-flag{position:absolute;top:8px;right:8px;left:auto;z-index:1;width:22px;height:22px;padding:0;border:0;border-radius:var(--radius-sm);background:var(--warning-soft);color:var(--warning);font-size:13px;line-height:22px;text-align:center;display:inline-flex;align-items:center;justify-content:center}
/* Sub screen tiles (21 Sep 2026): same frame as an item tile (a navy edge read as a black frame, MAK), the ▸ count in the price corner marks it; the back
   tile is the same shape with ◀ and the parent's name. */
.tile-screen .pr,.tile-back .pr{color:var(--navy);font-weight:700}
.tile-back{background:var(--panel-2);border-style:dashed}
.tile-addon{border-style:dashed;border-color:var(--brass)}
.tile-addon .nm::before{content:'+ ';color:var(--brass)}

/* The cheque is a slide-over now (owner, 2026-09-05: "the same as the ResM flyer"): it lives
   over the right side of the grid, slides in when a table is open and hides on Hide / after a
   send, leaving the tab strip to pick the next one. */
.check{position:absolute;top:0;right:112px;bottom:0;width:340px;max-width:calc(100% - 112px);background:var(--tape);color:var(--ink-on-tape);display:flex;flex-direction:column;z-index:30;transform:translateX(calc(100% + 112px));transition:transform .22s;box-shadow:-8px 0 30px rgba(0,0,0,.28)}
.check.open{transform:none}
.check-hd{padding:12px 16px 8px;border-bottom:1px dashed var(--tape-line);display:flex;align-items:baseline;justify-content:space-between}
.check-hd b{font-size:14px}
.check-hd span{font-family:var(--mono);font-size:11px;opacity:.55}
.check-hd-right{display:flex;align-items:baseline;gap:8px;opacity:1}
.check-hd-right>span{opacity:.55}
.check-pax{font-family:var(--ui);font-size:11px;opacity:.75;padding:2px 8px;border-radius:var(--radius-full);background:rgba(0,0,0,.06);border:1px dashed var(--tape-line)}
.check-pax:hover{border-color:var(--go);color:var(--go)}
.check-pax[hidden]{display:none}
/* The loyalty guest pill (#checkGuest, same shape as pax): solid green once the reward is ready. */
/* Readable on the cheque (MAK, 15 Sep 2026: "guest button colour is white, not readable"): the header's own
   dimming used to stack on the pill's, leaving grey on white. */
#checkGuest{opacity:1;color:var(--brass);border:1px solid var(--brass);background:rgba(124,155,224,.14);font-weight:600}
.check-pax.reward,#checkGuest.reward{border-style:solid;border-color:var(--go);color:var(--go);background:rgba(47,127,91,.12);opacity:1;font-weight:600}
.ln-comp{color:var(--go);font-weight:600}
.check-overdue-btn{font-family:var(--ui);font-size:11px;font-weight:600;padding:3px 10px;border-radius:var(--radius-full);background:var(--stop);color:#fff;border:none;animation:overdue-pulse 1.6s ease-in-out infinite}
.check-overdue-btn[hidden]{display:none}
@keyframes overdue-pulse{0%,100%{opacity:1}50%{opacity:.6}}
.overdue-line{color:var(--stop)}
.overdue-line .ln-n::after{content:" · not sent yet";font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.03em}
.lines{flex:1;overflow-y:auto;padding:8px 16px}
/* The cheque paper is white on every theme (--tape), so its bar takes the ink, not the panel thumb. */
.check .lines{--sb-thumb:color-mix(in srgb,var(--ink-on-tape) 30%,transparent)}
.empty{padding:40px 8px;text-align:center;font-size:13px;color:#8a8272;line-height:1.6}
.floor-map{position:relative;width:100%;line-height:0}
.floor-map img{width:100%;height:auto;border-radius:var(--r);display:block}
.fp-marker{position:absolute;transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;justify-content:center;
  width:80px;height:80px;border-radius:var(--radius-full);border:3px solid var(--line);background:var(--panel-2);color:var(--text);
  cursor:pointer;line-height:1.2;padding:0;gap:1px}
.fp-marker.occupied{border-color:var(--go);background:color-mix(in srgb, var(--go) 18%, var(--panel-2))}
.fp-marker.empty{border-style:dashed}
.fp-marker.overdue{border-color:var(--stop);background:color-mix(in srgb, var(--stop) 22%, var(--panel-2))}
.fp-marker.locked{opacity:.6}
.fp-marker .fp-num{font-family:var(--mono);font-size:19px;font-weight:600}
/* Seats/PAX has to be readable at a glance, at arm's length, without tapping in — same reason
   the number itself is large. A small pill (not just dim text) keeps it legible over any
   background photo, busy or plain. */
.fp-marker .fp-seats{font-size:12px;font-weight:600;color:var(--text);background:color-mix(in srgb, var(--panel) 70%, transparent);
  border-radius:var(--radius-md);padding:0 5px;white-space:nowrap}
.fp-marker .fp-lock{position:absolute;bottom:-18px;font-size:9px;white-space:nowrap;color:var(--text-dim)}
.ln{padding:7px 0;border-bottom:1px dotted var(--tape-line);cursor:pointer;border-radius:var(--radius-md)}
.ln:hover{background:rgba(0,0,0,.04)}
.ln:active{background:rgba(0,0,0,.08)}
.ln-extracharge{cursor:default;color:#2e7d32}
.ln-extracharge:hover,.ln-extracharge:active{background:none}
.ln-extracharge .ln-n,.ln-extracharge .ln-p{font-style:italic}
.ln-top{display:flex;gap:8px;align-items:baseline;font-family:var(--mono);font-size:12.5px}
.ln-q{width:26px;flex:0 0 auto}
.ln-n{flex:1;font-family:var(--ui);font-size:13px}
.ln-p{font-variant-numeric:tabular-nums}
.ln-sub{margin:3px 0 0 26px;font-size:11px;color:#6f6857}
.ln-rem{margin:3px 0 0 26px;font-size:11px;color:var(--stop);font-weight:600}
.ln-alg{margin:3px 0 0 26px;font-size:10px;color:#fff;background:var(--stop);display:inline-block;padding:2px 6px;border-radius:var(--radius-sm);letter-spacing:.08em}
.ln-ctl{display:flex;gap:6px;margin:6px 0 0 26px}
.ln-ctl button{width:26px;height:26px;border-radius:var(--radius-md);background:rgba(32,56,100,.12);color:var(--navy);font-size:14px;font-weight:600;line-height:1}
.ln-ctl button.rm{margin-left:auto;background:transparent;color:var(--stop);width:auto;padding:0 6px;font-size:11px}
.ln.sent{opacity:.72}
.ln.sent .ln-n::after{content:'SENT';font-family:var(--mono);font-size:9px;letter-spacing:.1em;background:var(--go);color:#fff;padding:2px 5px;border-radius:var(--radius-sm);margin-left:7px;vertical-align:1px}
.ln.sent .ln-ctl button:not(.rm){display:none}
.btn.fire{background:var(--brand);color:var(--on-brand);font-weight:600}

.kq{display:flex;flex-direction:column;gap:10px}
.kq-empty{padding:26px 8px;text-align:center;color:var(--text-dim);font-size:13px}
.tkt{background:#fff;color:#000;border-radius:var(--radius-md);padding:12px;font-family:var(--mono);font-size:12.5px;line-height:1.5;border-left:5px solid var(--go)}
.tkt.warm{border-left-color:var(--brass)}
.tkt.late{border-left-color:var(--stop)}
.tkt-hd{display:flex;justify-content:space-between;font-weight:600;border-bottom:1px solid #ddd;padding-bottom:5px;margin-bottom:6px}
.tkt-fired{font-size:10.5px;color:#777;margin:-2px 0 6px}
.tkt-el{font-variant-numeric:tabular-nums}
.tkt.late .tkt-el{color:var(--stop)}
.tkt .no{font-weight:700;text-transform:uppercase}
.tkt .plus{padding-left:12px;color:#555}
.tkt .alg{background:#000;color:#fff;text-align:center;padding:4px;font-weight:700;letter-spacing:.08em;margin:-12px -12px 8px;border-radius:var(--radius-md) var(--radius-md) 0 0}
.tkt .paid-tag{background:var(--go);color:#fff;border-radius:var(--radius-sm);padding:1px 6px;font-size:10px;letter-spacing:.05em;margin-left:6px;vertical-align:middle}
.tkt-act{margin-top:8px;width:100%;padding:9px;border-radius:var(--radius-md);background:#111;color:#fff;font-family:var(--ui);font-size:12px}
.tkt.done{opacity:.45}
.tkt.done .tkt-act{background:#888}

/* ================= KDS BOARD (kds.html) =================
   Same .tkt ticket-card CSS as the till's Kitchen Queue modal above — this is only the full-page
   wrapper: a wide, wall-mounted-tablet-friendly grid instead of the modal's single-column list,
   plus the station filter control in the topbar. */
/* Multi-outlet KDS board — one column per assigned Revenue Centre, each tinted from a small
   fixed palette (data-color cycles c0..c5) so 2-3 outlets sharing one physical screen stay
   instantly tellable apart from across a kitchen. Ticket cards inside reuse .tkt as-is. */
.kds-outlets{flex:1;min-height:0;display:flex;overflow-x:auto}
.kds-outlets[hidden]{display:none}
.kds-outlet{flex:1 0 320px;display:flex;flex-direction:column;min-height:0;border-right:1px solid var(--line)}
.kds-outlet:last-child{border-right:0}
.kds-outlet-hd{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 12px 10px 16px;font-weight:700;font-size:15px;letter-spacing:.01em;border-bottom:1px solid rgba(0,0,0,.08)}
.kds-clear-btn{flex:0 0 auto;padding:6px 12px;border-radius:var(--radius-md);border:1px solid rgba(0,0,0,.15);background:rgba(255,255,255,.65);color:inherit;font-family:var(--ui);font-size:11.5px;font-weight:600;letter-spacing:0;cursor:pointer}
.kds-clear-btn:hover{background:rgba(255,255,255,.95)}
.kds-outlet-board{flex:1;min-height:0;overflow-y:auto;padding:14px;display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:12px;align-content:start}
/* KDS boards are fixed pastel tints on every theme (below), so a navy dark-theme thumb would look foreign. */
.kds-outlets,.kds-outlet-board{--sb-thumb:rgba(0,0,0,.28)}
.kds-outlet-board .tkt{font-size:14px}
.kds-outlet-board .kq-empty{grid-column:1/-1;padding:60px 8px;font-size:15px}
.kds-outlet[data-color="c0"]{background:#e3f6e8}
.kds-outlet[data-color="c1"]{background:#fbe4e2}
.kds-outlet[data-color="c2"]{background:#e1eefb}
.kds-outlet[data-color="c3"]{background:#fbf3d9}
.kds-outlet[data-color="c4"]{background:#eee3fa}
.kds-outlet[data-color="c5"]{background:#fbe9d9}
/* Reload/Logout — plain buttons, distinct from the .session-user text-link style, since these
   are meant to read as clearly-tappable controls on a wall-mounted touch screen. */
.topbar .a-addbtn{margin-top:0;padding:7px 12px;font-size:12px}
/* Which physical device this is — see kds-boot.js's showWorkstationName. Same tag look on the
   login screen (centered, above the PIN card's own heading) and in the topbar once logged in. A
   plain rounded-square box, matching every other button/tag's corner radius in this app — not a
   pill, which read as an odd shape mismatched against the square Reload button next to it. */
.ws-name-tag{font-size:11px;letter-spacing:.04em;color:var(--text-dim);background:var(--panel-2);border:1px solid var(--line);border-radius:var(--radius-md);padding:5px 12px;margin-bottom:14px;display:inline-block}
/* In the topbar (next to Reload), not the login card — drop the margin meant to space it from
   the PIN pad below it, and match Reload's own padding/font-size exactly so both sit on the same
   baseline instead of the tag looking slightly low/mismatched next to the button. */
.session-bar .ws-name-tag{margin-bottom:0;padding:7px 12px;font-size:12px}

.totals{padding:10px 16px;border-top:1px dashed var(--tape-line);font-family:var(--mono);font-size:12px}
.tr{display:flex;justify-content:space-between;padding:2px 0}
.tr.grand{font-size:17px;font-weight:600;padding-top:8px;margin-top:6px;border-top:1px solid var(--ink-on-tape)}
.tr.alt{font-size:12px;opacity:.6}
.tr span:last-child{font-variant-numeric:tabular-nums}

.pay{padding:8px 12px 10px;display:flex;flex-direction:column;gap:6px}
.pay-row{display:flex;gap:6px}
/* Cheque buttons in the BeSmart theme (owner, 2026-09-05): light navy by default, full navy for
   the two row-wide actions (Send, Payment). The old beige/brass buttons are gone. */
/* ===== The control set (System sheet of the redesign canvas 3dzm31YGD8sFBmvzD9yQsY, step 1,
   21 Sep 2026): buttons in three sizes, status as a word on a tint, filter and segmented controls,
   the numpad key, the 52px choice, the field, the rail and top bar pieces, the docked side panel
   with tabs and a sticky footer. Written with the tokens so Dark follows. Every rule that the
   till or the BOH already used keeps its name; the look changes, the layout does not. ===== */
/* hidden means gone, whatever display a class gives (the .filt chip and the .btn are inline-flex,
   which used to beat the browser's [hidden] and paint an empty square in the till's top bar
   when the outlet had no serving period, MAK on the Beirut demo, 21 Sep 2026). The PIN error
   is the one exception: it keeps its line so the pad does not jump. */
[hidden]:not(.pin-error){display:none!important}

.btn{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:36px;padding:0 14px;border-radius:var(--radius-md);font-size:14px;line-height:1.2;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background:var(--surface-raised);color:var(--ink);border:1px solid var(--line-strong)}
.btn:active{transform:scale(.98)}
.btn:disabled{opacity:.4;pointer-events:none}
/* Dimmed but still tappable (unlike :disabled) so the tap can toast WHY: used by the till's Print
   while a cheque still has unsent items (see pos.js unsentBlockingPrint). */
.btn.needs-send{opacity:.6}
.btn.primary{background:var(--brand);border-color:var(--brand);color:var(--on-brand)}
.btn.primary:hover{background:var(--brand-strong);border-color:var(--brand-strong)}
.btn.navy{background:var(--brand);border-color:var(--brand);color:var(--on-brand)}
.btn.white{background:var(--surface-raised);color:var(--brand);border:1px solid var(--line-strong)}
.btn.quiet{border-color:transparent;background:transparent;color:var(--brand)}
.btn.danger{border-color:transparent;background:transparent;color:var(--danger)}
.btn.danger:hover{background:var(--danger-soft)}
.btn.ghost{background:transparent;border-color:transparent;color:var(--ink-muted);font-size:13px}
.btn.sm,.btn.small{flex:0 0 auto;min-height:30px;padding:0 10px;font-size:13px}
.btn.lg{min-height:44px;font-size:15px;padding:0 16px}
.btn.big{min-height:56px;font-size:17px;padding:0 18px}
.btn.icon{flex:0 0 36px;width:36px;padding:0}
.btn svg.i,svg.i{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
/* status as a word on a tint, never a colour alone */
.st{white-space:nowrap;display:inline-flex;align-items:center;gap:6px;height:22px;padding:0 8px;border-radius:var(--radius-sm);font-size:12px;line-height:16px;font-weight:500}
.st.ok{background:var(--success-soft);color:var(--success)}
.st.warn{background:var(--warning-soft);color:var(--warning)}
.st.bad{background:var(--danger-soft);color:var(--danger)}
.st.off{background:var(--surface-sunken);color:var(--ink-muted)}
.st.brand{background:var(--brand-soft);color:var(--brand)}
.st i,.sent-chip i{width:6px;height:6px;border-radius:var(--radius-full);background:currentColor;display:inline-block}
.sent-chip{white-space:nowrap;display:inline-flex;align-items:center;gap:5px;height:18px;padding:0 6px;border-radius:var(--radius-sm);font-size:11px;line-height:14px;font-weight:600;background:var(--success-soft);color:var(--success)}
/* filter chip and segmented control */
.filt{white-space:nowrap;display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 10px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-raised);font-size:13px;font-weight:500;color:var(--ink);cursor:pointer}
.filt.on{border-color:var(--brand);background:var(--brand-soft);color:var(--brand)}
.seg{display:inline-flex;border:1px solid var(--line-strong);border-radius:var(--radius-md);overflow:hidden;height:36px}
.seg>span,.seg>button{white-space:nowrap;display:inline-flex;align-items:center;gap:8px;padding:0 14px;font:inherit;font-size:14px;font-weight:500;color:var(--ink-muted);background:var(--surface-raised);border:0;border-right:1px solid var(--line);cursor:pointer}
.seg>span:last-child,.seg>button:last-child{border-right:0}
.seg>.on{background:var(--brand);color:var(--on-brand)}
.seg.lg{height:48px}
.seg.lg>span,.seg.lg>button{font-size:15px;padding:0 18px}
/* the numpad key and the 52px choice */
.key{width:100%;height:64px;border-radius:var(--radius-md);border:1px solid var(--line-strong);background:var(--surface-raised);font:inherit;font-size:22px;font-weight:500;color:var(--ink);font-variant-numeric:tabular-nums;cursor:pointer}
.key.soft{background:var(--surface-sunken);color:var(--ink-muted);font-size:16px}
.key:active{background:var(--brand-soft)}
/* the field: label, control, help */
.fld{display:flex;flex-direction:column;gap:6px;min-width:0}
.fld label,.lbl{white-space:nowrap;font-size:12px;line-height:16px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-muted)}
.fld input,.fld select,.fld textarea,input.search{height:40px;box-sizing:border-box;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 12px;font:inherit;font-size:14px;color:var(--ink);background:var(--surface-raised);width:100%}
.fld textarea{height:auto;padding:10px 12px;resize:none}
.fld .help{font-size:13px;line-height:18px;color:var(--ink-muted)}
.cb{width:16px;height:16px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);background:var(--surface-raised);display:inline-block;box-sizing:border-box;vertical-align:middle;flex-shrink:0}
.cb.on{background:var(--brand);border-color:var(--brand)}
/* headings by class, for markup that cannot carry an h tag */
.h1{margin:0;font-size:28px;line-height:36px;font-weight:700;font-stretch:80%;letter-spacing:-.015em;white-space:nowrap}
.h2{margin:0;font-size:20px;line-height:28px;font-weight:600;font-stretch:80%;letter-spacing:-.01em;white-space:nowrap}
.h3{margin:0;font-size:16px;line-height:24px;font-weight:600;font-stretch:80%;white-space:nowrap}
/* the rail and top bar pieces (the BOH shell, step 6) */
.rail{width:232px;flex-shrink:0;box-sizing:border-box;background:var(--surface-raised);border-right:1px solid var(--line);display:flex;flex-direction:column;padding:20px 12px 12px}
.grp{white-space:nowrap;font-size:11px;line-height:16px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-faint);padding:10px 12px 4px}
.nav{white-space:nowrap;display:flex;align-items:center;gap:10px;height:32px;padding:0 12px;border-radius:var(--radius-md);color:var(--ink);font-size:13px;line-height:20px;font-weight:500;cursor:pointer;background:none;border:0;width:100%;text-align:left;font-family:inherit}
.nav:hover{background:var(--surface-sunken)}
.nav.on{background:var(--brand-soft);color:var(--brand);font-weight:500;box-shadow:inset 3px 0 0 var(--brand)}
.top{height:56px;flex-shrink:0;box-sizing:border-box;border-bottom:1px solid var(--line);background:var(--surface-raised);display:flex;align-items:center;gap:12px;padding:0 24px}
.avatar{width:32px;height:32px;border-radius:var(--radius-full);background:var(--brand);color:var(--on-brand);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;flex-shrink:0}
.tile-k{background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);padding:18px 20px;display:flex;flex-direction:column;gap:4px}
.tile-k .v{font-size:28px;line-height:36px;font-weight:700;font-stretch:80%;letter-spacing:-.015em;font-variant-numeric:tabular-nums;white-space:nowrap}
.tile-k .u{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:13px;line-height:20px;color:var(--ink-muted)}
/* the docked side panel: header, tabs, scrolling body, sticky footer (Delete red on the left,
   Cancel and Save on the right); .modal.side itself is defined with the modal rules */
.modal.side{display:flex;flex-direction:column;padding:0}
.modal.side>h3{padding:20px 20px 4px}
.modal.side>.sub{padding:0 20px}
.modal.side>.a-field,.modal.side>.mgroup,.modal.side>.a-hint,.modal.side>.a-formerr,.modal.side>.a-row2{margin-left:20px;margin-right:20px}
.modal.side>.a-field:first-of-type{margin-top:12px}
.modal.side .panel-tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);padding:0 20px;margin:8px 0 12px}
.modal.side .panel-tabs button{white-space:nowrap;padding:10px 12px;font-size:14px;font-weight:600;color:var(--ink-muted);border-bottom:2px solid transparent;margin-bottom:-1px;background:none;border-top:0;border-left:0;border-right:0}
.modal.side .panel-tabs button.on{color:var(--brand);border-bottom-color:var(--brand)}
.modal.side .modal-foot{position:sticky;bottom:0;margin:auto 0 0;padding:12px 20px;background:var(--surface-raised);border-top:1px solid var(--line);gap:8px}
.modal.side .modal-foot .btn{flex:0 0 auto}
.modal.side .modal-foot .btn.danger{margin-right:auto}
.btn.voice{background:var(--ink-on-tape);color:var(--brass);font-size:12px}
/* Small and square — it sits beside a full-width button, so flex:1 (the .btn default) would
   have it eat half the row for what is a single glyph. */
.btn.mic{flex:0 0 46px;padding:0;height:38px;font-size:17px;line-height:1;background:var(--ink-on-tape);color:#fff;display:flex;align-items:center;justify-content:center}
.btn.mic.busy{opacity:.6}
/* Listening has to be obvious from across a room: a live mic nobody realises is live is the one
   real privacy problem this feature has. */
.btn.mic.on{background:var(--alert);color:#fff;animation:micPulse 1.4s ease-in-out infinite}
@keyframes micPulse{0%,100%{box-shadow:0 0 0 0 rgba(200,60,50,.55)}50%{box-shadow:0 0 0 7px rgba(200,60,50,0)}}
@media (prefers-reduced-motion:reduce){.btn.mic.on{animation:none;outline:2px solid var(--alert);outline-offset:2px}}
.voice-strip{padding:7px 10px;border-radius:var(--r);background:var(--panel-2);color:var(--text-dim);font-size:11.5px;line-height:1.35;text-align:center}
.voice-strip[hidden]{display:none}
.voice-strip.heard{color:var(--ink-on-tape);font-weight:600}
/* A pending settle is the one state where the strip is telling the waiter that money is about to
   move, so it stops looking like a hint and starts looking like a prompt. */
.voice-strip.failed{background:var(--alert);color:#fff}
.voice-strip.confirming{background:var(--alert);color:#fff;font-weight:600}
.btn[disabled]{opacity:.35;pointer-events:none}

/* No dark backdrop behind pop-ups (owner, 2026-09-05): the floating card carries its own shadow. The full-screen layer stays so a tap outside still closes it. */
.scrim{position:fixed;inset:0;background:transparent;display:flex;align-items:center;justify-content:center;padding:18px;z-index:40}
.scrim[hidden]{display:none}
/* Modals must win over her (MAK, 14 Sep 2026): the guest-side language picker renders through
   this same .scrim, and at the default z-index:40 it was rendering BEHIND the digital waiter's
   panel (z-index:60) whenever she was up — invisible and untappable, which stalled her greeting
   entirely since it awaits a choice the guest could never reach. Scoped to while she's on screen
   rather than raised globally, so .scrim's stacking everywhere else in the app is untouched. */
body:has(.ov-panel:not([hidden])) .scrim { z-index: 65; }
/* border-radius:12px unifies this with the rest of the floating-overlay family (login card,
   shutdown box, context menus) — they used to carry five different one-off radii (8/10/12/14/16px)
   with no relation to each other or to the --r:10px token everything else in the app uses. */
/* Every pop-up wears the login card look (owner, 2026-09-05): a translucent floating card with a
   deep shadow, and a sane default width so a two-column list no longer spans half the screen. */
.modal{background:var(--login-card-bg);backdrop-filter:blur(6px);border:1px solid var(--line);border-radius:var(--radius-lg);width:100%;max-width:560px;max-height:88dvh;overflow-y:auto;padding:20px;box-shadow:0 20px 50px rgba(0,0,0,.5)}
.modal.wide{max-width:820px}
/* Every modal used to render at the same fixed 800px regardless of content — a two-line "Log out?"
   confirm stretched into the same box as a 20-field editor form, with huge dead side margins. This
   shrinks it automatically for genuine confirm/alert dialogs (no input/select/textarea and none of
   the richer content wrappers below) while leaving every real form/list/receipt/queue modal at its
   existing width — no JS changes, so it can't drift out of sync the way a hand-toggled class on 70+
   call sites would if a future one forgot to set it. */
.modal:not(:has(input, select, textarea, .receipt, .line-menu, .opts, .mgroup, .lines, .kq, .split-lines, .split-legs, .cheque-list, .calls-list, .layout-grid, .totals, .order-cartrow)){max-width:420px}
/* A modal docked to the right edge as a side panel (BOH Workstations, 21 Sep 2026): the list
   stays in view behind it, the panel takes the full height and scrolls on its own. */
.scrim:has(.modal.side){align-items:stretch;justify-content:flex-end;padding:0}
.modal.side{max-width:420px;width:min(420px,100%);max-height:none;height:100dvh;border-radius:0;border-width:0 0 0 1px;box-shadow:-16px 0 40px rgba(0,0,0,.25)}
.ws-grid td{padding:6px 8px}
.ws-grid .ws-name{background:none;border:0;padding:0;font:inherit;font-weight:600;color:var(--text);cursor:pointer;text-align:left}
.ws-grid .ws-name:hover{color:var(--brass);text-decoration:underline}
.ws-grid tr.inactive td{opacity:.55}
.ws-grid .ws-ip-input{width:100%;max-width:150px}
.modal h3{margin:0 0 2px;font-size:17px}
.modal .sub{margin:0 0 14px;font-size:12px;color:var(--text-dim)}
/* Darker/bolder than .sub on purpose — this is the one line in the order-placed confirmation a
   guest actually needs to act on (keep the tab, or save it), not background detail like the
   ticket number above it. */
.order-stay-note{margin:0 0 14px;font-size:13px;font-weight:600;color:var(--text)}
/* The guest three minute window to change what was just sent (MAK, 22 Sep 2026) */
.order-recall{margin:0 0 14px;padding:12px 14px;border-radius:var(--radius-md);background:var(--warning-soft);color:var(--ink)}
.order-recall-t{display:block;font-size:13px;line-height:18px}
.order-recall-t b{font-variant-numeric:tabular-nums}
.order-recall .order-choice-actions{margin-top:10px}
.order-recall-list{display:flex;flex-direction:column;gap:6px;max-height:46vh;overflow-y:auto;margin:10px 0}
.order-recall-row{display:flex;align-items:center;gap:10px;min-height:48px;padding:0 12px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--panel-2);font-size:14px}
.order-recall-row .ln-n{flex:1;min-width:0}
.order-recall-row .ln-p{font-variant-numeric:tabular-nums;font-weight:600}
.mgroup{margin-bottom:14px}
.mgroup>p{margin:0 0 7px;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--text-dim);display:flex;justify-content:space-between}
/* a hint inside a group reads as a hint, not as the group's label */
.mgroup>p.a-hint,.mgroup>p.sub{font-size:13px;line-height:18px;letter-spacing:0;text-transform:none;color:var(--ink-muted);display:block}
.opts{display:flex;flex-wrap:wrap;gap:7px}
.opt{white-space:nowrap;display:inline-flex;align-items:center;justify-content:space-between;gap:10px;min-height:52px;padding:0 14px;border-radius:var(--radius-md);border:1px solid var(--line-strong);background:var(--surface-raised);font-size:14px;font-weight:500;color:var(--ink)}
.opt.on{border-color:var(--brand);background:var(--brand-soft);color:var(--brand);box-shadow:inset 0 0 0 1px var(--brand)}
.opt small{font-size:13px;font-weight:500;color:var(--ink-muted);font-variant-numeric:tabular-nums}
.opt em{font-style:normal;font-family:var(--mono);font-size:11px;opacity:.7}
.opt .a{font-family:var(--ar);font-size:12px;opacity:.75}
.opt.rem.on{border-color:var(--stop);color:var(--stop);background:rgba(180,64,47,.12);text-decoration:line-through}
.opt.locked{opacity:.4;pointer-events:none}
.line-menu{display:flex;flex-direction:column;gap:8px;margin-bottom:14px}
.line-menu .opt{width:100%;justify-content:flex-start;padding:12px 14px;font-size:14px}
/* The guest book list in the till's Guest dialog (loyaltyFind with nothing or part of a number typed) */
.opts.loy-pick{flex-direction:column;flex-wrap:nowrap;max-height:42vh;overflow:auto}
.opts.loy-pick .opt{width:100%;justify-content:flex-start;padding:11px 14px;font-size:14px}
.opt.danger{color:var(--stop);border-color:rgba(180,64,47,.4)}
/* Armed tap-again-to-confirm state (guest order page's Cash button) — --alert, not --stop/--danger,
   since this isn't an error state, just "one more tap needed." */
.opt.confirming{color:var(--alert);border-color:var(--alert);background:rgba(212,98,42,.12);font-weight:600}
.cheque-list{display:flex;flex-direction:column;gap:8px;margin-bottom:4px}
.cheque-row{width:100%;padding:12px 14px;border-radius:var(--radius-lg);background:var(--panel-2);border:1px solid var(--line);display:flex;justify-content:space-between;align-items:center;gap:10px;text-align:left}
.cheque-row:hover{border-color:var(--brass)}
.cheque-row.overdue-cheque{border-color:var(--stop);background:rgba(180,64,47,.12)}
.cheque-row.overdue-cheque .cq-table{color:var(--stop)}
.cheque-row .cq-main{display:flex;flex-direction:column;gap:2px}
.cheque-row .cq-table{font-size:14px;font-weight:600}
.cheque-row .cq-ref{font-family:var(--mono);font-size:11px;color:var(--text-dim)}
.cheque-row .cq-amt{font-family:var(--mono);font-size:14px;font-variant-numeric:tabular-nums;flex:0 0 auto}
.cheque-empty{padding:14px;text-align:center;color:var(--text-dim);font-size:12px}
.opt.danger:hover{background:rgba(180,64,47,.12)}
.allergy{display:flex;align-items:center;gap:9px;padding:11px;border-radius:var(--radius-md);background:rgba(212,98,42,.12);border:1px solid var(--alert);font-size:12.5px;margin-top:4px}
.allergy input{width:18px;height:18px;accent-color:var(--alert)}
.noteBox{width:100%;min-height:62px;padding:10px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--ui);font-size:13px;resize:vertical;line-height:1.45}
.noteBox:focus{outline:2px solid var(--brass);outline-offset:-1px}
.chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.chip{padding:0 8px;height:24px;display:inline-flex;align-items:center;gap:6px;border-radius:var(--radius-sm);background:var(--surface-sunken);border:0;font-size:12px;line-height:16px;font-weight:600;letter-spacing:.04em;color:var(--text-dim)}
.chip:active{border-color:var(--brass)}
.ln-note{margin:3px 0 0 26px;font-size:11px;color:#5c5647;font-style:italic}
.tkt .note{background:#f2f2f2;border-left:3px solid #000;padding:3px 7px;margin:3px 0;font-style:italic}
.modal-foot{display:flex;gap:8px;margin-top:6px}
.modal-foot .btn{background:var(--surface-raised);color:var(--ink)}
.modal-foot .btn.primary{background:var(--brand);border-color:var(--brand);color:var(--on-brand);font-weight:600}
.modal-foot .btn.danger{background:transparent;border-color:transparent;color:var(--danger)}

.receipt{background:var(--tape);color:var(--ink-on-tape);font-family:var(--mono);font-size:12px;padding:18px;border-radius:var(--radius-lg);line-height:1.55}
.receipt h4{font-family:var(--ui);font-size:15px;margin:0 0 2px;text-align:center}
.receipt .ctr{text-align:center;font-size:11px;opacity:.6;margin-bottom:10px}
.receipt hr{border:0;border-top:1px dashed var(--tape-line);margin:8px 0}
.rl{display:flex;justify-content:space-between;gap:10px}
.rl span:last-child{font-variant-numeric:tabular-nums}

/* Printing a cheque: window.print() today, a real receipt printer later —
   either way only the .receipt itself should hit paper, not the app chrome
   around it. */
@media print{
  #connBanner,.app,.toast,.login-view,.revenue-centre-picker{display:none!important}
  .scrim{position:static!important;inset:auto!important;background:none!important;padding:0!important;display:block!important}
  .modal{box-shadow:none!important;border:none!important;max-width:100%!important;max-height:none!important;padding:0!important;border-radius:0!important;background:#fff!important;overflow:visible!important}
  .modal>*:not(.receipt){display:none!important}
  .receipt{border-radius:0!important;font-size:13px}
}



.tender{display:flex;flex-direction:column;gap:10px}
.tender .quick{display:flex;gap:7px;flex-wrap:wrap}
.tender .quick button{padding:10px 13px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);font-family:var(--mono);font-size:13px}
.tender input{width:100%;padding:12px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:18px}
/* The $+LBP tender's amount + method pairs — input stretches, dropdown keeps its width.
   Deliberately slimmer than the single-tender input (owner: the full-size rows ate the box). */
.tender .mix-row{display:flex;gap:6px;margin-bottom:6px}
.tender .mix-row input{flex:1;min-width:0;padding:7px 10px;font-size:14px}
.tender .mix-ccy{width:84px;padding:7px 6px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:13px}
.tender .mix-qr{flex:0 0 auto;padding:4px 12px;min-height:30px;font-family:var(--mono);font-size:12.5px;letter-spacing:.06em;border:1px solid var(--brass);color:var(--brass);background:transparent;border-radius:var(--radius-md)}
.tip-custom-in{width:100%;padding:10px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:14px;margin-top:8px}
.tip-note{color:var(--text-dim);font-size:11px;font-weight:400}
.change{font-family:var(--mono);font-size:14px;padding:10px;border-radius:var(--radius-md);background:var(--panel-2)}
/* Payment window (owner, 2026-09-05): every control the same height as the Send button, the
   custom-tip box gets air on both sides, and the cash change can be split across both currencies. */
.modal .opt,.modal .quick button,.modal .mix-ccy{padding:4px 10px;min-height:30px;font-size:12.5px;line-height:1.2;box-sizing:border-box}
.modal .tender input,.modal .mix-row input,.modal .change,.modal .tip-custom-in,.modal .ret-row input{padding:5px 10px;min-height:32px;font-size:12.5px;line-height:1.2;box-sizing:border-box}
.modal .tip-custom-in{margin:8px 0}
/* Cancel and the other plain modal buttons in the light navy (owner, 2026-09-05). */
.modal-foot .btn{background:var(--surface-raised);color:var(--ink)}
.modal .tender input{margin:0}
.whish-pay{display:flex;gap:12px;align-items:center;margin-top:8px}
.whish-qr{width:200px;height:200px;object-fit:contain;background:#fff;border:1px solid var(--line);border-radius:var(--radius-md);flex:0 0 auto;cursor:zoom-in}
.whish-pay .change{flex:1}
/* The QR filling the screen for the guest to scan from the tablet (pos.js data-whish-zoom). */
.whish-zoom{position:fixed;inset:0;z-index:200;background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;cursor:pointer}
.whish-zoom img{width:min(78vmin,560px);height:min(78vmin,560px);object-fit:contain}
.whish-zoom-amt{font-family:var(--mono);font-size:34px;font-weight:600;color:#111}
.whish-zoom-hint{font-family:var(--ui);font-size:14px;color:#555}
/* Guest bill: the link button and the folded QR */
.whish-pay-guest{flex-direction:column;align-items:stretch;gap:8px}
.whish-open{display:block;text-align:center;text-decoration:none;padding:14px 16px;font-size:15px}
.whish-qr-details summary{cursor:pointer}
.whish-qr-details .whish-qr{display:block;margin:10px auto 0;width:220px;height:220px}
.ret-row{display:flex;gap:6px;margin-top:6px;align-items:center}
.ret-row label{flex:1;display:flex;flex-direction:column;gap:3px;font-size:11px;color:var(--text-dim);letter-spacing:.04em;text-transform:uppercase}
.ret-row input{width:100%;padding:7px 10px;min-height:36px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:13px;box-sizing:border-box}
.change b{color:var(--brass)}

/* ---------- split payment (pos.js) ---------- */
.split-lines,.split-legs{display:flex;flex-direction:column;gap:8px;margin-bottom:14px;max-height:44vh;overflow-y:auto}
.split-line-row{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);cursor:pointer;font-size:13px}
.split-line-row .pr{font-family:var(--mono);color:var(--brass);margin-left:auto}
.split-assignee{font-size:11px;color:var(--text-dim);min-width:76px;text-align:right}
.split-leg-row{padding:11px 12px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line)}
.split-leg-row .split-leg-hd{display:flex;align-items:center;gap:8px;margin-bottom:9px;font-size:13.5px;font-weight:500}
.split-leg-row .split-leg-hd .pr{font-family:var(--mono);color:var(--brass);margin-left:auto}

/* pointer-events:none because a toast is purely informational — it has no click handler
   anywhere, and while it sat over a button (the guest page's "View order" bar) it silently
   swallowed taps meant for what was underneath. */
.toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:var(--panel-2);border:1px solid var(--brass);padding:11px 18px;border-radius:var(--radius-full);font-size:13px;z-index:60;max-width:88vw;text-align:center;pointer-events:none}
.toast[hidden]{display:none}
/* On the guest page the toast must clear the fixed bottom bar (View order / Make Payment),
   which sits at bottom:14px and stands ~46px tall — "Added X" was landing right on top of it. */
.order-body .toast{bottom:calc(76px + env(safe-area-inset-bottom, 0px))}

.check-toggle{display:none}
@media (max-width:880px){
  /* Phones: the cheque is a bottom sheet, fully hidden until a tab is tapped; the tab strip
     runs along the bottom edge instead of the right. */
  .check{position:fixed;inset:auto 0 56px 0;right:0;width:auto;max-width:none;height:72dvh;z-index:30;border-radius:var(--radius-lg) var(--radius-lg) 0 0;transform:translateY(calc(100% + 60px));transition:transform .22s;box-shadow:0 -8px 30px rgba(0,0,0,.5)}
  .check.open{transform:translateY(0)}
  .cheque-tabs{position:fixed;left:0;right:0;bottom:0;height:56px;flex:none;flex-direction:row;border-left:0;border-top:1px solid var(--line);padding:5px 8px;overflow-x:auto;overflow-y:hidden}
  .cheque-tab{width:68px;height:40px;border-radius:var(--radius-lg) var(--radius-lg) 0 0;border-left:1px solid var(--line);border-bottom:0;margin-bottom:0;margin-right:-10px}
  .cheque-tab:last-child{margin-right:0}
  .cheque-tab.on{width:72px}
  .cheque-tab.closed{margin-top:0;margin-left:auto;margin-right:0;height:40px;width:78px;border-radius:var(--radius-md)}
  /* padding-bottom reserves room for the collapsed check-toggle bar (position:fixed, full
     width, pinned to the bottom) so it doesn't sit on top of whatever's at the bottom of the
     sidebar — Logout, right below Settings — the same overlap .grid's own padding-bottom below
     already exists to avoid for the menu tiles. */
  .cats-col{flex:0 0 96px;padding-bottom:70px}
  .grid{padding-bottom:80px;grid-template-columns:repeat(auto-fill,minmax(128px,1fr))}

  .topbar{flex-wrap:wrap;row-gap:8px;gap:8px;padding:8px 10px}
  /* Scoped to .topbar specifically — order.html's .order-hd reuses the same .brand class for its
     own, differently-structured header (a column flex layout, not a wrapping row), and this same
     rule unscoped used to also apply there: flex-basis:100% on a column child of an auto-height
     container inflated it to ~2.5x its real content height, pushing everything after it (the
     "Just here to pay?" link) down past the header's own box and into the category row below. */
  .topbar .brand{flex:1 0 100%;flex-direction:row;align-items:baseline;gap:6px}
  .open-tables{margin-left:0;max-width:none;flex:1 1 auto;min-width:0}
  .btn-newtable,.btn-cheques{flex:0 0 auto;margin-left:0}
  .session-bar{margin-left:auto}
  .open-tables,.btn-newtable,.btn-cheques,.session-revenue-centre,.session-user,.btn-admin{padding:6px 9px;font-size:11px}
}
@media (max-width:420px){
  .session-revenue-centre{display:none!important}
  /* Scoped to .topbar for the same reason as above — order.html's guests need to keep seeing
     their table number here, it isn't just decorative the way it is on the POS topbar. */
  .topbar .brand span{display:none}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important}}

/* ================= ADMIN ================= */
.admin{flex:1;display:flex;min-height:0}
.a-body{flex:1;min-width:0;display:flex;flex-direction:column;min-height:0}
/* The BOH top bar (step 6): 56px, outlet switcher as a button, scope chip, search, business day. */
.admin-topbar{height:56px;flex:0 0 56px;box-sizing:border-box;border-bottom:1px solid var(--line);background:var(--surface-raised);display:flex;align-items:center;gap:12px;padding:0 24px}
.admin-topbar[hidden]{display:none}
.a-outlet-btn{position:relative;display:inline-flex;align-items:center;height:36px;border:1px solid var(--line-strong);border-radius:var(--radius-md);background:var(--surface-raised);padding:0 8px 0 0;cursor:pointer}
.a-outlet-btn select{appearance:none;-webkit-appearance:none;border:0;background:transparent;height:34px;padding:0 6px 0 14px;font:inherit;font-size:14px;font-weight:700;color:var(--ink);cursor:pointer;min-width:0}
.a-outlet-btn select[hidden]{display:none}
.a-outlet-btn svg{width:16px;height:16px;color:var(--ink-muted);pointer-events:none}
/* The focus ring belongs to the whole button, arrow included, not to the select inside it (MAK,
   27 Sep 2026: "the blue circle around the outlet name should cover the arrow as well"). */
.a-outlet-btn select:focus,.a-outlet-btn select:focus-visible{outline:none;box-shadow:none}
.a-outlet-btn:focus-within{box-shadow:var(--focus-ring)}
.a-top-spacer{flex:1}
.a-top-search{position:relative;display:flex;align-items:center}
.a-top-search svg{position:absolute;left:10px;width:18px;height:18px;color:var(--ink-muted);pointer-events:none}
.a-top-search input.search{width:280px;height:36px;padding-left:36px;border-radius:var(--radius-md)}
.a-top-search input.search:disabled{opacity:.55}
.admin-topbar .chip{height:28px;padding:0 10px;font-size:12px}
.admin-topbar .chip.ok{background:var(--success-soft);color:var(--success)}
.admin-topbar .chip.warn{background:var(--warning-soft);color:var(--warning)}
.admin-topbar .chip i{width:6px;height:6px;border-radius:var(--radius-full);background:currentColor;display:inline-block}
.admin[hidden]{display:none}
/* The rail (step 6): 232px, logo on top, six groups of 32px rows with a 20px line icon, the
   active row on a brand soft fill with a 3px inset bar, the user card pinned at the foot with the
   log out button; the middle scrolls on its own so Settings and the card never leave the screen. */
.a-tabs{flex:0 0 232px;box-sizing:border-box;background:var(--surface-raised);border-right:1px solid var(--line);display:flex;flex-direction:column;padding:12px 12px 12px;min-height:0}
.a-rail-logo{display:block;width:126px;height:42px;object-fit:contain;object-position:left;margin:0 12px 10px}
.a-rail-scroll{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:2px}
.a-grp{white-space:nowrap;font-size:11px;line-height:16px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-faint);padding:6px 12px 2px}
.a-tab{white-space:nowrap;display:flex;align-items:center;gap:10px;height:32px;flex:0 0 32px;padding:0 12px;border-radius:var(--radius-md);color:var(--ink);font-size:13px;line-height:20px;font-weight:500;text-align:left;border:0;transition:background .12s,color .12s}
.a-tab svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0;color:var(--ink-muted)}
.a-tab.on svg{color:var(--brand)}
.a-usercard{display:flex;align-items:center;gap:10px;padding:6px 12px 0;border-top:1px solid var(--line);margin-top:6px;flex:0 0 auto}
.a-usercard .a-uname{flex:1;min-width:0;display:flex;flex-direction:column}
.a-usercard .a-uname b{font-size:14px;line-height:18px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-usercard .a-uname span{font-size:12px;line-height:16px;color:var(--ink-muted);white-space:nowrap}
.a-usercard .btn.icon{flex:0 0 32px;width:32px;min-height:32px;color:var(--ink-muted)}
/* SVG-icon tabs (Clock In / Settings / Logout) — inline SVG instead of Unicode symbol glyphs,
   which can render as tofu boxes on a machine whose fonts don't cover that codepoint. */
.icon-tab{display:flex;align-items:center;gap:8px}
.icon-tab svg{flex:none}
/* The cursor is already a hand (buttons get it globally) — what was missing is any sign the
   thing under the pointer reacts, which is what makes a sidebar feel clickable. */
.a-tab:hover{background:var(--panel-2);color:var(--text);border-color:var(--line)}
.a-tab:hover{background:var(--surface-sunken)}
.a-tab.on{background:var(--brand-soft);color:var(--brand);font-weight:500;box-shadow:inset 3px 0 0 var(--brand)}
.a-tab.on:hover{background:var(--brand-soft)}
.a-subnav{display:flex;gap:8px;margin-bottom:16px}
.a-subtab{padding:8px 14px;border-radius:var(--radius-md);font-size:12.5px;color:var(--text-dim);background:var(--panel);border:1px solid var(--line);transition:color .12s,border-color .12s}
.a-subtab:hover{color:var(--text);border-color:var(--brass)}
.a-subtab.on{background:var(--panel-2);color:var(--brass);border-color:var(--brass)}
/* Reports tab — a second-level nav (by report group) alongside the main tab strip, since ~15
   report types in one flat sub-nav (the pattern every other tab's sub-nav uses) would be
   unusable. Each group gets its own small subnav row rather than one giant flat list. */
.a-report-layout{display:flex;gap:22px;align-items:flex-start}
.a-report-nav{flex:0 0 190px;display:flex;flex-direction:column;gap:14px}
.a-report-group-label{margin:0 0 6px;font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--text-dim)}
.a-report-nav .a-subnav{flex-direction:column;gap:4px;margin-bottom:0}
.a-report-nav .a-subtab{text-align:left}
.a-report-main{flex:1;min-width:0}
.a-report-filters{display:flex;flex-wrap:wrap;align-items:end;gap:14px;margin-bottom:8px}
/* .btn's own base rule is flex:1 (fine for a full-width row of two or three EQUAL actions), which
   in a mixed row like this one — Apply plus the export/print group, squeezed further whenever a
   report adds its own Cheque ref/Cashier filters — divides the leftover space evenly regardless of
   each button's own text length and ellipsis-truncates whichever one needed more of it than its
   equal share ("Export PDF"/"Export Excel" reading as "Export P…"/"Export E…", owner's report, 13
   Sep 2026). flex:0 0 auto here (same idea as the existing .btn.small) keeps every button at its
   own natural width instead; .a-report-filters already wraps, so a genuinely narrow window drops
   the group to its own line rather than clipping the words on it. */
.a-report-filters .btn{flex:0 0 auto}
.a-report-filters label{display:flex;flex-direction:column;gap:4px;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--text-dim)}
.a-nightaudit-panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:16px;margin-bottom:18px}
.a-nightaudit-status{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.a-nightaudit-panel .a-hint{margin:8px 0 0}
.a-nightaudit-panel .mgroup{margin-top:14px;margin-bottom:0}
.a-report-filters input{padding:8px 10px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--ui);font-size:13px;color-scheme:dark}
.a-report-export{display:flex;gap:8px;margin-left:auto}
/* Stale as of 13 Sep 2026 — these two used to compensate for .btn.ghost inheriting .btn's dark
   ink color (meant for tan fills) and vanishing on the dark theme, back when .btn.ghost had no
   color of its own. .btn.ghost now sets color:#fff directly against its own --navy-2 fill (a
   dark/saturated accent in every theme, this one included), which reads fine everywhere on its
   own — but color:var(--text) here has higher specificity and overrides that white with the
   THEME's own text color, which is dark on every light-ground theme (Light, Light Solid): near-black text on a still-dark navy fill, unreadable ("why export
   in black", owner's report). Removed rather than fixed forward, since the base rule already
   does the right thing without a per-context override. */
/* Numeric report columns read right-aligned with lined-up digits, the way ledgers do. */
.a-report-table th.num,.a-report-table td.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:500}
.a-report-title{margin:4px 0 14px;font-size:15px;color:var(--text)}
.a-report-table-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius-md)}
.a-report-table{width:100%;border-collapse:collapse;font-size:14px;line-height:20px;white-space:nowrap}
.a-report-table th,.a-report-table td{padding:10px 16px;text-align:left;border-bottom:1px solid var(--surface-sunken);vertical-align:middle}
.a-report-table th{white-space:nowrap;background:var(--surface-sunken);font-size:12px;line-height:16px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-muted)}
.a-report-table tbody tr:last-child td{border-bottom:0}
.a-report-table tbody tr:hover td{background:var(--surface)}
/* BohReports (redesign 7e): the report list beside the report panel. */
.a-reports{display:grid;grid-template-columns:var(--split,220px) 12px minmax(0,1fr);gap:16px;align-items:start}
/* ================= EACH PANEL SCROLLS INSIDE ITSELF, THE PAGE DOES NOT =================
   MAK, 23 Sep 2026, looking at Reports: "whole page is scrolling, want each section, make sure it
   is like that on all areas that has the same design."

   Four screens share this design and all four behaved the same way: a list panel, a drag handle and
   a working panel, laid out as a grid with align-items:start, so each panel grew to fit its content
   and the PAGE grew with them. Reading a long report scrolled its own heading away, and the report
   list scrolled off the top with it, so the thing you were about to click next left the screen.

   Now the head stays put, the split fills whatever height is left, and each panel scrolls its own
   contents. The two panels are independent: a two hundred row report does not move the list beside
   it, and running down the list does not move the report.

   Applied to the PATTERN rather than to Reports alone, which is what he asked for: Reports, Roles,
   Kitchen displays and the Floor plan. :has() rather than a class on each page, so a fifth screen
   built to this shape gets the behaviour without anyone remembering this rule exists. Chromium 105+
   and every browser we ship on; Electron 32 is Chromium 128.

   The splitter is deliberately left out of the scrolling children: it is a drag handle, it has no
   contents, and giving it a scroll box would let it be dragged out of line with the panels. */
.a-content:has(> .a-reports, > .a-roles, > .a-screens, > .a-fp){
  display:flex;
  flex-direction:column;
  overflow:hidden;      /* the page itself no longer scrolls; its panels do */
  min-height:0;
}
.a-content > .a-reports,
.a-content > .a-roles,
.a-content > .a-screens,
.a-content > .a-fp{
  flex:1 1 auto;
  min-height:0;         /* without this a grid child refuses to shrink and the page scrolls again */
  align-items:stretch;  /* was start, which is what made every panel grow to its content */
}
.a-reports > .a-panel,
.a-roles > .a-panel,
.a-screens > .a-panel,
.a-fp > .a-panel{min-height:0;overflow-y:auto}

/* The report list used to hold itself up with position:sticky and a max-height counted off the
   viewport. That is what a panel does when its parent will not give it a height, and it guessed
   wrong whenever the head above it was a different size. It is a flex child of a real height now,
   so the guess is gone. */
.a-report-nav{padding:6px 8px}
/* A REPORT GROUP HEADING MUST NOT LOOK LIKE SOMETHING YOU CAN PRESS (MAK, 23 Sep 2026: "mark them
   as a heading, it is unclear, make them looks like a tab or something").

   Four groups hold one report named after the group, so the list showed Cashier Balance above
   Cashier Balance, AI Usage above AI Usage, and so on. They were already smaller, uppercase and
   faint, and that was not enough: a label sitting directly above a row of the same words reads as
   two of the same thing, and the only way to tell which one did anything was to click one.

   So the heading gets its own band rather than more type styling. A rule across the full width and
   a tinted strip make it a section break, which is a shape, not a weight; a reader sees the list is
   divided before they read a single word. The rows keep their inset and their rounded corners, so
   pressable and not pressable no longer share a silhouette.
   Tokens only, so it follows every theme including Solid and the outlet skins. */
.a-report-nav .grp{
  padding:7px 12px 6px;
  margin:10px 0 4px;
  border-top:1px solid var(--line);
  background:color-mix(in srgb, var(--ink) 4%, transparent);
  font-size:10.5px;
  letter-spacing:.14em;
  color:var(--ink-faint);
  border-radius:0;
}
/* No rule above the first one: a divider at the very top of a panel is a line to nowhere. */
.a-report-nav .grp:first-child{margin-top:0;border-top:0}
.a-report-nav-row{height:30px;font-size:13px}
.a-report-main{min-width:0}
.a-report-bar{flex-wrap:wrap;row-gap:10px;align-items:flex-end}
.a-report-fields{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap}
.a-report-fields .fld input,.a-report-fields .fld select{height:36px;width:150px}
.a-report-fields .fld select{width:160px}
.a-report-fields .btn{flex:0 0 auto;width:auto}
.a-report-bar .a-headbtns .btn{width:auto}
.a-report-title-line{display:flex;align-items:baseline;gap:10px;padding:14px 20px 6px;flex-wrap:wrap}
.a-report-title-line h3{margin:0;font-size:16px;line-height:24px;font-weight:600;font-stretch:80%;white-space:nowrap}
.a-report-kpis{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;padding:8px 20px 14px}
.a-report-kpis>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.a-report-kpis b{font-size:24px;line-height:28px;font-weight:700;font-stretch:80%;letter-spacing:-.015em;font-variant-numeric:tabular-nums;white-space:nowrap}
.a-report-body{padding:0 20px 20px;min-width:0;overflow-x:auto}
.a-report-body>.a-empty-line{padding-left:0}
.a-report-body .a-nightaudit-panel{background:var(--surface-sunken);border-color:var(--line);border-radius:var(--radius-md);margin-bottom:16px}
.a-nightaudit-status .a-nm{font-weight:600;font-size:14px}
.a-nightaudit-status .btn{width:auto;margin-left:auto}
.a-nightaudit-panel .a-hint{font-size:13px;color:var(--ink-muted)}
.a-nightaudit-panel>.btn{width:auto;margin-right:6px}
/* BohSettings (redesign 7f): the section list beside one panel per section with its own save bar. */
.a-settings{display:grid;grid-template-columns:220px minmax(0,760px);gap:16px;align-items:start}
.a-settings-nav{padding:6px 8px;position:sticky;top:0}
.a-settings-row{height:36px}
.a-settings-main{min-width:0}
.a-settings-main .a-sec{display:none;padding:0}
.a-settings-main .a-sec.on{display:flex}
.a-sec-title{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.a-sec-title h3{white-space:nowrap}
.a-sec-title .a-meta{white-space:normal}
.a-sec-body{padding:20px}
.a-sec-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 20px}
.a-sec-grid .fld{min-width:0}
.a-sec-grid .fld input,.a-sec-grid .fld select{max-width:320px}
.a-sec-foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 20px;border-top:1px solid var(--line);background:var(--surface-sunken)}
.a-sec-foot .btn{width:auto;flex:0 0 auto}
.a-sec-foot .a-meta{margin-right:auto}
.a-pct{position:relative;max-width:320px}
.a-pct input{padding-right:36px;width:100%}
.a-pct span{position:absolute;right:12px;top:0;height:40px;display:flex;align-items:center;color:var(--ink-muted);font-size:14px}
.a-check,.fld label.a-check,.a-field label.a-check{display:flex;align-items:center;gap:8px;min-height:40px;font-size:14px;font-weight:400;letter-spacing:0;text-transform:none;color:var(--ink);white-space:normal}
.a-check input{width:16px;height:16px;margin:0;flex:0 0 16px;accent-color:var(--brand)}
.a-inline{display:flex;align-items:center;gap:10px;min-height:40px;font-size:14px}
.a-inline .btn{width:auto}
.a-value{min-height:40px;display:flex;align-items:center;font-size:14px;color:var(--ink)}
.a-sec-sub{margin-top:20px;padding-top:20px;border-top:1px solid var(--line)}
.a-sec-sub h4{margin:0 0 4px;font-size:15px;font-weight:700;font-stretch:80%}
.a-sec-sub>.a-meta{display:block;margin:0 0 14px;white-space:normal}
.a-whish{display:flex;gap:20px;align-items:flex-start}
.a-whish-qr{width:160px;height:160px;flex:0 0 160px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-sunken);display:flex;align-items:center;justify-content:center;color:var(--ink-faint);font-size:13px;overflow:hidden}
.a-whish-qr.has{background:#fff}
.a-whish-qr img{width:100%;height:100%;object-fit:contain;display:block}
/* The rail logo in the dark themes is the white cut (the navy one sinks into the rail). */
:root:not([data-theme="light"]):not([data-theme="light-solid"]) .a-rail-logo{content:url("assets/logo-boh-dark.png")}
.a-whish-ctl{flex:1;min-width:0;display:flex;flex-direction:column;gap:12px}
.a-whish-ctl .btn{width:auto}
.a-downloads{display:flex;gap:8px;flex-wrap:wrap}
.a-downloads .btn{width:auto;text-decoration:none}
#stModules .a-field{margin:0 0 6px}
#stModules .a-hint{margin:8px 0 0}
/* BohLicensing (redesign 7g): four tiles, Modules beside This machine and Install. */
/* BohKds (round 3): the screens table, the classes strip, the outlets as ordered choice rows. */
.a-kds-table td.nowrap{white-space:nowrap}
.a-kds-table th{overflow:hidden;text-overflow:ellipsis}
.a-class-cell{display:flex;flex-direction:column;gap:2px;padding:12px 16px;border-right:1px solid var(--surface-sunken);min-width:0}
.a-class-cell:last-child{border-right:0}
.a-class-cell b{font-weight:600;font-size:14px}
.a-class-cell .m{font-size:13px;color:var(--ink-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-headbtns a.btn{text-decoration:none;width:auto}
.a-kds-rc{cursor:default}
.a-kds-rc-main{display:inline-flex;align-items:center;gap:10px;min-width:0}
.a-kds-rc-n{font-size:12px;font-weight:700;color:var(--ink-muted);width:14px}
.a-kds-rc-name{display:inline-flex;align-items:center;gap:8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-kds-rc-ctl{display:inline-flex;gap:2px}
.a-kds-rc-ctl .btn.icon{width:32px;height:32px;flex:0 0 32px;color:var(--ink-muted)}
.a-kds-rc-ctl .btn.icon:disabled{opacity:.3}
.a-kds-rc-ctl [data-kds-rc-up] svg{transform:rotate(180deg)}
.a-kds-rc.on .a-screen-grip{color:var(--brand)}
/* BohRewards (round 2): the rewards table, the guest book panel, the guests close. */
.a-rewards{display:grid;grid-template-columns:minmax(0,1fr) 380px;grid-template-rows:auto auto;gap:16px;align-items:start}
.a-rewards>section:first-child{grid-row:1/3}
.a-panel-note{margin:0;padding:12px 20px 14px;font-size:13px;line-height:18px;color:var(--ink-muted);border-top:1px solid var(--surface-sunken)}
.a-guestbook{display:flex;flex-direction:column;gap:10px}
.a-guestbook .a-choice-rows .opt{height:48px;min-height:48px}
.a-guestbook .help{white-space:normal}
.a-rewards-close .a-prow b{white-space:nowrap}
.a-rewards-close .a-prow .m{flex:1}
@media (max-width:1240px){.a-rewards{grid-template-columns:1fr}.a-rewards>section:first-child{grid-row:auto}}
/* BohRoles (round 2): the roles list beside the editor. */
.a-roles{display:grid;grid-template-columns:var(--split,300px) 12px minmax(0,1fr);gap:16px;align-items:start}
.a-roles-list{position:sticky;top:0}
.a-roles-list .a-ph{padding:12px 14px}
.a-roles-rows{min-height:0;overflow-y:auto}
.a-role-row{display:flex;flex-direction:column;gap:2px;width:100%;text-align:left;padding:10px 14px;border:0;border-bottom:1px solid var(--surface-sunken);background:transparent;font:inherit;color:var(--ink);cursor:pointer;position:relative}
.a-role-row:hover{background:var(--surface)}
.a-role-row.on{background:var(--brand-soft)}
.a-role-row.on::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--brand)}
.a-role-row b{font-weight:600;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-role-row .m{font-size:13px;color:var(--ink-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-roles-editor{min-width:0}
.a-roles-head{align-items:center;gap:12px;flex-wrap:wrap}
.a-roles-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1;flex-wrap:wrap}
.a-roles-title h3{margin:0;font-size:16px;line-height:24px;font-weight:600;font-stretch:80%;white-space:nowrap}
.a-roles-name-in{height:36px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 12px;font:inherit;font-size:16px;font-weight:700;color:var(--ink);background:var(--surface-raised);min-width:200px}
.a-roles-head .a-headbtns .btn{width:auto}
.a-roles-body{padding:16px 20px;display:flex;flex-direction:column;gap:16px}
.a-roles-reach{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.a-roles-reach .seg>button{font:inherit;font-size:14px;font-weight:600;cursor:pointer}
.a-roles-reach .sub{font-size:13px;color:var(--ink-muted)}
.a-perm-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px 20px}
.a-perm-col{display:flex;flex-direction:column;gap:8px;min-width:0}
.a-perm-col.off .a-perm-head{opacity:.55}
.a-perm-head{display:flex;align-items:baseline;gap:8px}
.a-perm-head .sub{font-size:12px;color:var(--ink-muted)}
.a-perm-col .a-choice-rows .opt{white-space:nowrap;text-align:left;height:44px;padding:0 14px}
.a-perm-col .a-choice-rows .opt .opt-nm{min-width:0;overflow:hidden;text-overflow:ellipsis}
.a-perm-hint{font-size:13px;line-height:18px;color:var(--ink-muted);min-height:18px;padding:4px 0 0;border-top:1px solid var(--surface-sunken);margin-top:4px;padding-top:10px}
.a-perm-num{display:flex;flex-direction:column;gap:6px}
.a-perm-num label{font-size:14px;font-weight:500;color:var(--ink)}
.a-perm-num .a-pct{max-width:160px}
.a-perm-num .a-pct input{height:40px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 36px 0 12px;font:inherit;font-size:14px;background:var(--surface-raised);color:var(--ink);box-sizing:border-box}
.a-roles-editor .a-sec-foot{position:sticky;bottom:0}
.a-roles-editor .a-sec-foot .a-meta{white-space:normal}
@media (max-width:1240px){.a-perm-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* BohWorkstations (round 2): the setup PIN tile, the default outlet as choice rows. */
.a-pin-tile{background:var(--warning-soft);border-radius:var(--radius-md);padding:12px 14px;display:flex;flex-direction:column;gap:4px}
.a-pin-tile .lbl{color:var(--warning)}
.a-pin-v{font-size:40px;line-height:44px;font-weight:700;font-stretch:80%;font-variant-numeric:tabular-nums;letter-spacing:.04em;color:var(--warning)}
.a-pin-tile .help{color:var(--warning);white-space:normal}
.a-choice-rows{display:flex;flex-direction:column;gap:6px}
.a-og-rows .opt{font-family:inherit;width:100%}
.a-guest-pane .a-choice-rows .opt{font-family:inherit;width:100%}
.modal.side .a-guest-pane.pane.on{display:flex;flex-direction:column;gap:16px}
.a-guest-pane .fld{margin:0}
.a-guest-ingrow{display:flex;align-items:center;gap:12px}
.a-guest-ingrow .btn.sm{flex:0 0 auto;width:auto}
.a-guest-ingrow .help{white-space:normal}
.a-guest-lead{margin:0;font-size:13px;line-height:18px;color:var(--ink-muted)}
.a-qr-actions{display:flex;gap:8px;flex-wrap:wrap}
.a-qr-actions .btn{width:auto;flex:0 0 auto}
.a-qr-sec{display:flex;flex-direction:column;gap:2px;padding-top:8px;border-top:1px solid var(--line)}
.a-qr-sec .help{font-size:13px;line-height:18px;color:var(--ink-muted)}
.a-qr-choice .opt{font-family:inherit;width:100%}
.a-qr-choice .opt:disabled{opacity:.5;cursor:default}
.a-qr-note{margin:0;padding:8px 10px;border-radius:var(--radius-sm);background:var(--warning-soft);color:var(--warning);font-size:13px;line-height:18px}
#qrPane .order-qr-preview{display:flex;justify-content:center;padding:8px 0}
#qrPane .a-hint.mono{font-family:var(--mono);font-size:12px;margin:0;color:var(--ink-muted)}
#qrPane .a-table th,#qrPane .a-table td{padding:6px 8px}
.a-guest-ing{margin:2px 0 0;font-size:13px;line-height:18px;color:var(--ink-muted)}
.a-guest-pane textarea{width:100%;min-height:56px;resize:vertical}
.a-og-rows .opt.dim{opacity:.45}
.a-choice-rows .opt{height:44px;min-height:44px;font-size:14px;font-weight:500;justify-content:space-between;cursor:pointer;font-family:inherit;text-align:left}
.a-choice-rows .opt.on{font-weight:600}
.a-choice-rows .opt .cb{margin-left:10px}
.a-ws-table td.nowrap{white-space:nowrap}
.a-ws-table th{overflow:hidden;text-overflow:ellipsis}
.a-ws-table .a-cell-stack span{font-size:12px}
.tile-k .u .link{background:none;border:0;padding:0;font:inherit;color:var(--brand);cursor:pointer;text-decoration:underline}
/* BohOutlets (round 2): the tiles, the table, the panel with the outlet avatar. */
.a-outlet-avatar{width:56px;height:56px;border-radius:var(--radius-md);font-size:22px;flex:0 0 56px;margin-right:12px}
.a-outlets-table td.nowrap{white-space:nowrap}
.a-outlets-table th{overflow:hidden;text-overflow:ellipsis}
.modal.side .panel-tabs.tight{gap:0;padding:0 12px}
.modal.side .panel-tabs.tight button{padding:10px 8px;font-size:13px}
.a-row-inactive td{opacity:.6}
.a-row-inactive td .st{opacity:1}
.a-two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.a-form-pane .a-pct{max-width:none}
.tile-k .v small{font-size:18px;font-weight:500;color:var(--ink-muted);font-stretch:100%}
.tile-k .v.v-text{font-size:22px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* BohGroups (round 2): the seg of kinds in the filter row, the tables, the option rows in the panel. */
.a-groups-filters{flex-wrap:wrap;row-gap:10px}
.a-groups-filters .seg{flex:0 0 auto}
.a-groups-filters .seg>button{padding:0 12px;font-size:13px}
.a-groups-table td.nowrap{white-space:nowrap}
.a-chiplist{display:flex;flex-wrap:wrap;gap:6px}
.a-chiplist .filt{cursor:default;height:28px;font-size:12px}
.a-chiplist .filt .a-mono{color:var(--ink-muted);font-size:11px;margin-right:6px}
.a-items-list{max-height:60vh;overflow-y:auto}
.a-og-rows{display:flex;flex-direction:column;gap:8px;margin-bottom:8px}
.a-og-row{display:grid;grid-template-columns:118px minmax(0,1fr) 84px 36px;gap:6px;align-items:center;padding-bottom:8px;border-bottom:1px solid var(--surface-sunken)}
.a-og-row>select{grid-column:1;grid-row:1}
.a-og-row>input[data-ogfield=name]{grid-column:2/4;grid-row:1}
.a-og-row>input[data-ogfield=ar]{grid-column:1/3;grid-row:2}
.a-og-row>input[data-ogfield=price],.a-og-row>span{grid-column:3;grid-row:2}
.a-og-row>.btn.icon{grid-column:4;grid-row:1}
.a-og-row select,.a-og-row input{height:36px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 10px;font:inherit;font-size:13px;color:var(--ink);background:var(--surface-raised);min-width:0;width:100%}
.a-og-row .btn.icon{width:36px;height:36px;flex:0 0 36px;color:var(--ink-muted)}
.modal.side .a-form-pane.pane.on{display:flex;flex-direction:column;gap:14px;padding-bottom:16px}
.modal.side .a-form-pane .pane{padding:0;display:none}
.modal.side .a-form-pane .pane.on{display:flex;flex-direction:column;gap:14px}
.a-head>div:first-child p{max-width:72ch}
.a-form-pane .panel-tabs{margin:0 0 4px;padding:0}
.a-form-pane .a-formerr{margin:0}
.a-form-pane .a-hint{margin:0}
.a-form-pane .fld .seg{width:100%;display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}
.a-form-pane .fld .seg>button{justify-content:center;font:inherit;font-size:14px;font-weight:600;cursor:pointer}
.a-form-pane .fld .btn.sm{width:auto;align-self:flex-start}
.a-form-pane .fld>.help{white-space:normal}
.lic-tiles{margin-bottom:16px}
.lic-tiles .v-text{font-size:22px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lic-tiles .lic-v-ok{color:var(--success)}
.lic-tiles .lic-v-warn{color:var(--warning)}
.lic-tiles .lic-v-bad{color:var(--danger)}
.lic-grid{display:grid;grid-template-columns:minmax(0,1fr) 400px;gap:16px;align-items:start}
.lic-side{display:flex;flex-direction:column;gap:16px}
.lic-grid .a-prow .m{flex:1}
.lic-to{white-space:nowrap}
.lic-facts{padding:16px 20px;display:flex;flex-direction:column;gap:12px}
.lic-facts .lic-fact{display:flex;flex-direction:column;gap:2px;padding:0;border:0;font-size:14px}
.lic-facts .lic-fact b{text-align:left;font-weight:500;word-break:break-all}
.lic-facts>.a-meta{margin:4px 0 0;white-space:normal}
.lic-install{padding:16px 20px;display:flex;flex-direction:column;gap:12px;align-items:flex-start}
.lic-install .fld{width:100%}
.lic-install textarea{font-family:ui-monospace,Consolas,monospace;font-size:12px;width:100%}
.lic-install .btn{width:auto}
.lic-install .a-formerr{margin:0}
.a-head+.a-warn,.a-head+.lic-ok{margin-bottom:16px}
.a-report-reprint{display:flex;gap:10px;margin-top:16px}
@media (max-width:880px){
  .a-report-layout{flex-direction:column}
  .a-report-nav{flex-direction:row;flex-wrap:wrap;width:100%}
}
/* AI Assistant tab — a chat, not a report table, so it gets its own small set of rules rather
   than stretching .a-report-* to cover a bubble layout they were never meant for. */
/* BohAi (round 3): the Ask column | divider | the chat */
.a-ai{display:grid;grid-template-columns:var(--split,280px) 12px minmax(0,1fr);gap:16px;align-items:start}
.a-ai-asks{position:sticky;top:0}
.a-ai-asks .a-ph{padding:12px 14px}
.a-ai-asks .a-ph-line{border-top:1px solid var(--line);border-bottom:0}
.a-ai-qs{display:flex;flex-direction:column;padding:4px 8px 8px}
.a-ai-q{min-height:36px;padding:8px 12px;border:0;border-radius:var(--radius-sm);background:transparent;font:inherit;font-size:14px;line-height:20px;color:var(--ink);text-align:left;cursor:pointer}
.a-ai-q:hover{background:var(--surface)}
.a-ai-q:disabled{opacity:.5;cursor:default}
.a-ai-chat{min-width:0;height:calc(100dvh - 190px);min-height:420px}
.a-ai-transcript{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:16px;padding:20px}
.a-ai-empty{margin:auto;text-align:center;max-width:44ch;display:flex;flex-direction:column;align-items:center;gap:8px}
.a-ai-empty p{margin:0;font-size:15px;font-weight:600;color:var(--ink)}
.a-ai-empty p.a-hint{font-weight:400;margin:0}
.a-ai-msg{display:flex;align-items:flex-start;gap:10px}
.a-ai-msg-user{justify-content:flex-end}
.a-ai-bubble{max-width:72%;padding:10px 14px;border-radius:var(--radius-lg);font-size:14px;line-height:20px;background:var(--brand);color:var(--on-brand);white-space:pre-wrap}
.a-ai-avatar{flex:0 0 32px;width:32px;height:32px;border-radius:var(--radius-full);background:var(--brand-soft);color:var(--brand);display:inline-flex;align-items:center;justify-content:center}
.a-ai-avatar.big{width:48px;height:48px;flex-basis:48px}
.a-ai-card{max-width:min(720px,88%);min-width:0;padding:14px 16px;border-radius:var(--radius-md);background:var(--surface-raised);border:1px solid var(--line);box-shadow:0 1px 2px rgba(24,35,56,.08);font-size:14px;line-height:20px;color:var(--ink);display:flex;flex-direction:column;gap:10px}
.a-ai-card-error{border-color:var(--danger);background:var(--danger-soft);color:var(--ink)}
.a-ai-card p{margin:0}
.a-ai-card ul{margin:0;padding-left:18px}
.a-ai-card table,.a-ai-card .a-report-table{width:100%;border-collapse:collapse;font-size:13px;line-height:18px;margin:0}
.a-ai-card .a-report-table-wrap{border:0;border-radius:0;overflow-x:auto}
.a-ai-card th,.a-ai-card td{padding:6px 10px;text-align:left;border-bottom:1px solid var(--surface-sunken);white-space:nowrap}
.a-ai-card th{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-muted);font-weight:600;background:var(--surface-sunken)}
.a-ai-card th.num,.a-ai-card td.num{text-align:right;font-variant-numeric:tabular-nums}
.a-ai-thinking{color:var(--ink-muted);font-style:italic}
.a-ai-bars{display:flex;flex-direction:column;gap:6px;padding:8px 0 2px}
.a-ai-bars .lbl{margin-bottom:2px}
.a-ai-bar-row{display:grid;grid-template-columns:minmax(80px,30%) minmax(0,1fr) auto;gap:10px;align-items:center;font-size:13px;line-height:18px}
.a-ai-bar-lbl{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ink)}
.a-ai-bar-track{display:flex;flex-direction:column;gap:2px;min-width:0}
.a-ai-bar{display:block;height:10px;border-radius:var(--radius-sm);background:var(--brand)}
.a-ai-bar.s1,.a-ai-bar-legend i.s1{background:var(--brand-strong);opacity:.7}
.a-ai-bar.s2,.a-ai-bar-legend i.s2{background:var(--brand-soft)}
.a-ai-bar.s3,.a-ai-bar-legend i.s3{background:var(--ink-faint)}
.a-ai-bar.s4,.a-ai-bar-legend i.s4{background:var(--success)}
.a-ai-bar-v{font-variant-numeric:tabular-nums;font-weight:500;white-space:nowrap;color:var(--ink)}
.a-ai-bar-legend{display:flex;flex-wrap:wrap;gap:12px;font-size:12px;color:var(--ink-muted)}
.a-ai-bar-legend span{display:inline-flex;align-items:center;gap:5px}
.a-ai-bar-legend i{width:10px;height:10px;border-radius:var(--radius-sm);background:var(--brand);display:inline-block}
.a-ai-actions{display:flex;gap:8px;flex-wrap:wrap;padding-top:2px}
.ai-chart-type-picker{display:flex;gap:10px;justify-content:center}
.a-ai-composer{display:flex;gap:10px;align-items:flex-end;padding:12px 16px 16px;border-top:1px solid var(--line);background:var(--surface-raised)}
.a-ai-composer .fld{flex:1;margin:0;min-width:0}
.a-ai-composer textarea{min-height:56px;resize:vertical}
.a-ai-composer .btn.big{height:56px;flex:0 0 auto;min-width:120px;padding:0 24px}
.a-ai-usage{cursor:default;color:var(--ink-muted);font-variant-numeric:tabular-nums}
.a-ai-usage.near{border-color:var(--warning);color:var(--warning);background:var(--warning-soft)}
.a-ai-usage.over{border-color:var(--danger);color:var(--danger);background:var(--danger-soft)}
.a-sr{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* BohBackup (round 3) */
.a-bk-tiles{margin-bottom:16px}
.tile-k .v.ok{color:var(--success)}
.tile-k .v.warn{color:var(--warning)}
.tile-k .v.a-bk-dim{color:var(--ink-muted)}
.tile-k .u a{color:var(--brand);font-weight:600;text-decoration:none}
.tile-k .u a:hover{text-decoration:underline}
.a-bk-panel{margin-bottom:16px}
.a-bk-chip{cursor:default;height:24px;font-size:12px;color:var(--ink-muted)}
.a-bk-table td.a-bk-when{font-weight:600;white-space:nowrap}
.a-bk-table td.a-mono{font-family:var(--mono);font-size:12.5px;color:var(--ink-muted)}
.a-bk-table td.a-bk-act{white-space:nowrap}
.a-bk-table .a-formerr{margin:12px 20px 0}
.a-bk-sched,.a-bk-restore{margin-bottom:16px}
.a-bk-body{padding:16px 20px;display:flex;flex-direction:column;gap:14px}
.a-bk-choice .opt{height:48px;min-height:48px;font-size:14px;font-family:inherit;cursor:pointer;width:100%;text-align:left}
.a-bk-grid{display:grid;grid-template-columns:160px 200px minmax(0,1fr);gap:16px;align-items:start}
.a-bk-grid .fld{margin:0;min-width:0}
.a-bk-unit{display:flex;align-items:center;gap:8px}
.a-bk-unit input{width:100px}
.a-panel.a-bk-restore{border-color:var(--danger-soft);box-shadow:0 0 0 1px var(--danger-soft)}
.a-bk-restore .a-ph{background:var(--danger-soft);border-bottom-color:var(--danger-soft)}
.a-bk-copy{margin:0;font-size:14px;line-height:20px;color:var(--ink);max-width:72ch}
.a-bk-restore .a-bk-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
.a-bk-file{display:flex;align-items:center;gap:8px;min-height:40px;padding:0 6px 0 12px;border:1px solid var(--line-strong);border-radius:var(--radius-md);background:var(--surface-raised)}
.a-bk-filename{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:14px;color:var(--ink)}
.a-bk-filename.empty{color:var(--ink-faint)}
.btn.danger.a-bk-restore-btn{align-self:flex-start;background:var(--danger);border-color:var(--danger);color:#fff}
.btn.danger.a-bk-restore-btn:hover{background:var(--danger);filter:brightness(.92)}
@media (max-width:880px){.a-bk-grid,.a-bk-restore .a-bk-grid{grid-template-columns:1fr}}
@media (max-width:880px){.a-ai{grid-template-columns:1fr}.a-ai>.a-split{display:none}.a-ai-asks{position:static}.a-ai-chat{height:auto;min-height:60dvh}}
.screen-editor{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
.screen-picker{display:flex;flex-direction:column;gap:10px}
.screen-picker input[type=text]{padding:9px 10px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--ui);font-size:13px}
.screen-picker-list{max-height:52vh;overflow-y:auto}
.screen-pick-row{cursor:grab}
.screen-pick-row.a-row-disabled{opacity:.4;pointer-events:none}
/* The item number, shown in the picker and in the placed-entries list — monospace and fixed
   width so the numbers line up into a readable column instead of drifting with name length. */
.screen-pick-num{font-family:var(--mono);font-size:11px;color:var(--text-dim);min-width:34px;display:inline-block;text-align:right;margin-right:8px}
/* From #/To # bulk add — mirrors the item grids' own "+ Add range" row. */
.screen-pick-range{display:flex;align-items:center;gap:6px;margin:8px 0;flex-wrap:wrap}
.screen-pick-range label{font-size:11px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.06em}
.screen-pick-range input{width:72px;padding:6px 8px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:12px}
.screen-pick-range .btn{width:auto;padding:6px 12px;font-size:12px}
/* Both lists here are long — a whole outlet's menu on the left, a whole screen's contents on
   the right — so the rows are deliberately tighter than the standard .a-row/.a-checkrow used
   elsewhere in Admin: more of the menu fits on screen without scrolling, which is the whole
   job of this editor. Scoped to the screen editor so other tabs keep their roomier rows. */
.screen-contents{display:flex;flex-direction:column;gap:4px;min-height:120px;padding:6px;border-radius:var(--r);border:1px dashed var(--line);max-height:52vh;overflow-y:auto}
.screen-entry-row{cursor:grab;padding:5px 10px}
.screen-entry-row .a-nm{font-size:12.5px}
.screen-entry-row .a-meta{font-size:10.5px}
.screen-entry-row .a-actions button{width:26px;padding:3px 0;font-size:11px}
/* Word buttons on a sub screen row (Open, Picture…) take their own width; the 26px is for the arrows and the ✕ (MAK, 21 Sep 2026: "Open button is small"). */
.screen-entry-row .a-actions button[data-open-sub-screen],.screen-entry-row .a-actions button[data-sub-photo-for]{width:auto;padding:3px 10px;white-space:nowrap}
.screen-picker-list .screen-pick-row{padding:4px 8px;margin-bottom:3px}
.screen-picker-list .a-cn{font-size:12.5px}
.screen-picker-list .a-meta{font-size:10.5px}
/* Sits where the old read-only preview used to, at the bottom of the editor — the way into the
   Layout editor, which is now the single place the till grid is both seen and arranged. */
.screen-layout-cta{grid-column:1;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;padding:14px 16px;border-radius:var(--r);border:1px dashed var(--line);background:var(--shell)}
.screen-layout-cta b{display:block;font-size:14px;margin-bottom:3px}
.screen-layout-cta p{margin:0 0 4px;font-size:12px;color:var(--text-dim);max-width:60ch}
.a-content{flex:1;overflow-y:auto;padding:28px 32px 32px}
/* The page header (step 6): one h1 at 32/36 stretched 80 percent, one muted 14px line under it, the
   actions on the right with ONE primary button per view. */
.a-head{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;margin-bottom:20px}
.a-head h2{margin:0;font-size:28px;line-height:36px;font-weight:700;font-stretch:80%;letter-spacing:-.015em;white-space:nowrap}
/* The path above the Screens editor: Screens ▸ Drinks ▸ Cold drinks, every earlier part a click. */
.screen-crumb{background:none;border:0;padding:0;font:inherit;font-size:18px;color:var(--text-dim);cursor:pointer}
.screen-crumb:hover{color:var(--brass);text-decoration:underline}
.screen-crumb-sep{color:var(--text-dim);opacity:.6;font-size:14px}
.screen-crumb-here{color:var(--text)}
.a-head p{margin:4px 0 0;font-size:14px;line-height:20px;color:var(--ink-muted)}
/* Home (step 6): KPI tiles, Needs attention, Sales by outlet, Quick actions, Recent changes. */
.a-home{display:flex;flex-direction:column;gap:20px}
.a-kpis{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px}
.a-home-cols{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:20px;align-items:start}
.a-home-col{display:flex;flex-direction:column;gap:20px;min-width:0}
.a-panel{background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);display:flex;flex-direction:column;overflow:hidden}
.a-ph{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 20px;border-bottom:1px solid var(--line)}
.a-ph h3{margin:0;font-size:16px;line-height:24px;font-weight:600;font-stretch:80%;white-space:nowrap}
.a-ph a,.a-ph button.link{font-size:13px;font-weight:600;white-space:nowrap;color:var(--brand);background:none;border:0;padding:0;cursor:pointer;font-family:inherit}
.a-prow{display:flex;align-items:center;gap:14px;padding:12px 20px;border-bottom:1px solid var(--surface-sunken);font-size:14px;line-height:20px}
.a-prow:last-child{border-bottom:0}
.a-prow b{font-weight:600;white-space:nowrap}
.a-prow .m{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1;color:var(--ink-muted);font-size:13px}
.a-prow.stack{flex-direction:column;align-items:flex-start;gap:2px}
.a-prow.stack .m{white-space:normal}
.a-prow .btn.sm{flex:0 0 auto}
.a-table{border-collapse:collapse;width:100%;font-size:14px;line-height:20px}
.a-table th{white-space:nowrap;text-align:left;padding:10px 16px;background:var(--surface-sunken);font-size:12px;line-height:16px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-muted)}
.a-table td{padding:10px 16px;border-bottom:1px solid var(--surface-sunken);vertical-align:middle}
.a-table tr:last-child td{border-bottom:0}
.a-table .num,.a-table th.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:500;white-space:nowrap}
.a-quick{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;padding:16px 20px}
.a-quick .btn{justify-content:flex-start;min-height:40px;flex:0 0 auto}
.a-empty-line{padding:14px 20px;font-size:13px;color:var(--ink-muted)}
.a-list{display:flex;flex-direction:column;gap:8px}
.a-row{display:flex;align-items:center;gap:10px;padding:11px 14px;border-radius:var(--r);background:var(--panel);border:1px solid var(--line)}
/* Clicking a row opens its editor (see admin.js's row->edit rule) — so say so on hover. Keyed
   off the row actually CONTAINING an Edit button, which is exactly the same condition the JS
   uses, so a row with no editor (Workstations) keeps the normal arrow and stays inert. */
.a-row:has(button[data-edit-serving-period]),
.a-row:has(button[data-edit-family-group]),
.a-row:has(button[data-edit-major-group]),
.a-row:has(button[data-edit-option-group]),
.a-row:has(button[data-edit-item-class]),
.a-row:has(button[data-edit-kds-class]),
.a-row:has(button[data-edit-printer]),
.a-row:has(button[data-edit-kds]),
.a-row:has(button[data-edit-user]),
.a-row:has(button[data-edit-role]),
.a-row:has(button[data-edit-revenue-centre]),
.a-row:has(button[data-open-screen]){cursor:pointer}
.a-row:has(button[data-edit-serving-period]):hover,
.a-row:has(button[data-edit-family-group]):hover,
.a-row:has(button[data-edit-major-group]):hover,
.a-row:has(button[data-edit-option-group]):hover,
.a-row:has(button[data-edit-item-class]):hover,
.a-row:has(button[data-edit-kds-class]):hover,
.a-row:has(button[data-edit-printer]):hover,
.a-row:has(button[data-edit-kds]):hover,
.a-row:has(button[data-edit-user]):hover,
.a-row:has(button[data-edit-role]):hover,
.a-row:has(button[data-edit-revenue-centre]):hover,
.a-row:has(button[data-open-screen]):hover{border-color:var(--brass)}
/* Inside such a row the controls keep their own meaning — a text field must still look typeable
   and a disabled button must not look clickable. */
.a-row input[type=text],.a-row input[type=number]{cursor:text}
.a-row button:disabled{cursor:default}
.a-row.inactive{opacity:.5}
.a-row .a-nm{font-size:13.5px;font-weight:500}
.a-row .a-nar{font-size:12px;color:var(--text-dim);margin-left:6px}
.a-tag{display:inline-block;margin-left:8px;padding:2px 8px;border-radius:var(--radius-full);font-size:10.5px;letter-spacing:.03em}
.a-tag.warn{background:rgba(212,98,42,.15);border:1px solid var(--alert);color:var(--alert)}
.a-tag:not(.warn){background:rgba(184,151,90,.15);border:1px solid var(--brass);color:var(--brass)}
.mgroup-disabled>p{opacity:.55}
.pin-reveal{margin:14px 0;padding:18px;border-radius:var(--r);background:var(--shell);border:1px solid var(--line);text-align:center;font-family:var(--mono);font-size:32px;letter-spacing:.25em;color:var(--pin)}
/* The name column takes the slack, so status, dropdown, IP box and buttons sit at the same x on every
   row regardless of how long the name is (owner, 2026-09-05: Workstations looked staggered). */
.a-row > div:first-child{flex:1 1 auto;min-width:0}
.a-row .a-meta{font-family:var(--mono);font-size:11px;color:var(--text-dim)}
.a-row select{padding:5px 8px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);color:var(--text);font-family:inherit;font-size:11.5px}
.ws-ip-input{width:132px;padding:5px 8px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:11.5px}
.ws-ip-input::placeholder{color:var(--text-dim);opacity:.8}
.ws-ip-input:focus{border-color:var(--brass);outline:none}
/* Always at the right edge, whether or not a row has meta text in the middle (owner, 2026-09-05). */
.a-row .a-actions{display:flex;gap:6px;margin-left:auto}
.a-row .a-actions button{padding:6px 10px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);font-size:11px}
.a-row .a-actions button:hover{border-color:var(--brass);color:var(--brass)}
.a-row .a-actions button.danger:hover{border-color:var(--stop);color:var(--stop)}
.a-row .a-actions button:disabled{opacity:.35;pointer-events:none}
.a-cathd{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--text-dim);margin:16px 0 6px}
.a-cathd:first-child{margin-top:0}
.a-empty{padding:24px;text-align:center;color:var(--text-dim);font-size:13px}
/* Settings tab section rail (owner, 12 Sep 2026: redesign it completely) — same mechanics as
   ResM's own Setup rail (resmaro.css .rm-setup2/.rm-setuprail/.rm-sec), reimplemented under
   admin's own a- prefix and tokens rather than sharing resmaro.css across apps: click a section,
   only it shows, so Settings stops being one long scroll through unrelated fields. */
.a-setup2{display:grid;grid-template-columns:220px minmax(0,760px);gap:24px;align-items:start}
.a-setuprail{position:sticky;top:12px;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:8px;display:flex;flex-direction:column;gap:2px}
.a-setuprail button{display:flex;align-items:center;gap:10px;width:100%;text-align:left;background:none;border:0;border-radius:calc(var(--r) - 4px);padding:10px 14px;font:inherit;font-weight:600;font-size:13.5px;color:var(--text-dim);cursor:pointer}
.a-setuprail button i{width:8px;height:8px;border-radius:var(--radius-full);background:var(--line);flex:none}
.a-setuprail button:hover{background:var(--panel-2);color:var(--text)}
.a-setuprail button.on{background:color-mix(in srgb, var(--navy) 14%, transparent);color:var(--text)}
.a-setuprail button.on i{background:var(--navy)}
.a-secpos{color:var(--text-dim);font-size:13px;margin:6px 0 10px}
.a-sec{display:none;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:6px 0 4px}
.a-sec.on{display:block}
.a-sec h2{margin:0;padding:16px 22px 8px;font-size:18px}
.a-lead{margin:0;padding:0 22px 10px;color:var(--text-dim);font-size:13px}
.a-secrow{display:grid;grid-template-columns:220px 1fr;gap:14px;align-items:start;padding:14px 22px;border-top:1px solid var(--line)}
.a-secrow:first-of-type{border-top:0}
.a-secrow>label{font-weight:700;font-size:13.5px;padding-top:8px;color:var(--text)}
.a-secrow>label small{display:block;font-weight:500;color:var(--text-dim);font-size:12px;margin-top:2px}
.a-secctl{display:flex;flex-wrap:wrap;gap:10px;align-items:center;min-width:0}
/* Same visual treatment as .a-field's inputs (adversarial review, 12 Sep 2026: the Appearance
   select rendered as a bare unstyled native dropdown here, since .a-field's own input/select rule
   never reaches a control sitting inside .a-secctl instead). */
.a-secctl input:not([type=checkbox]),.a-secctl select{width:auto;min-width:140px;margin:0;padding:7px 10px;border-radius:var(--radius-md);background:var(--shell);border:1px solid var(--line);color:var(--text);font-family:var(--ui);font-size:13px}
.a-sechint{flex-basis:100%;color:var(--text-dim);font-size:12.5px}
@media (max-width:900px){.a-setup2{grid-template-columns:1fr}.a-setuprail{position:static;flex-direction:row;flex-wrap:wrap}.a-secrow{grid-template-columns:1fr}}
.a-field{margin-bottom:12px}
.a-field label{display:block;font-size:12px;line-height:16px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-muted);margin-bottom:5px}
.a-field input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.a-field select,.a-field textarea{width:100%;padding:7px 10px;border-radius:var(--radius-sm);background:var(--surface);border:1px solid var(--line-strong);color:var(--ink);font-family:var(--ui);font-size:13px}
.a-field input::placeholder,.a-field textarea::placeholder{color:var(--ink-faint)}
.a-row2{display:flex;gap:10px}
.a-row2[hidden],.a-field[hidden]{display:none}
.a-row2>.a-field{flex:1}

/* ---------- Menu Item spreadsheet grid ---------- */
.item-grid-config{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;padding:12px 14px;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r);margin-bottom:14px}
.item-grid-config .a-field{margin-bottom:0;min-width:180px;flex:1}
/* The search box no longer eats the whole toolbar — it's a fixed, modest width so the add
   buttons and the Family Group picker sit right beside it instead of being pushed to the edge. */
.item-grid-config .a-field-search{flex:0 0 240px;min-width:160px}
.item-grid-range{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;padding:12px 14px;background:var(--panel-2);border:1px dashed var(--line);border-radius:var(--r);margin-bottom:14px}
.item-grid-range .a-field{margin-bottom:0}
.item-grid-range .a-field input{width:110px}
.item-grid-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r)}
/* table-layout:fixed — required for the <colgroup> widths set by manual column resize (see
   itemGridColgroupHtml/the mousedown handler in admin.js) to actually govern column sizing
   instead of just hinting at it. width:100% + a 9th unsized filler <col> (see
   itemGridColgroupHtml) is what lets the table always fill its container: the 8 real columns
   keep the exact literal pixel width they were dragged to, and the filler silently absorbs
   whatever's left — never the browser proportionally re-stretching every column to fill the
   gap, which would undo a manual resize. A total wider than the container still scrolls inside
   .item-grid-wrap's own overflow-x, same as before. */
.item-grid{width:100%;table-layout:fixed;border-collapse:collapse;font-size:12.5px}
.item-grid th{position:relative;text-align:left;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--text-dim);padding:9px 8px;background:var(--panel-2);border-bottom:1px solid var(--line);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.item-grid td{padding:2px 5px;border-bottom:1px solid var(--line);vertical-align:middle;overflow:hidden;text-overflow:ellipsis}
.item-grid tr:last-child td{border-bottom:0}
.item-grid tr.inactive{opacity:.5}
/* Dragged from a header's right edge to resize that column — see the mousedown listener in
   admin.js. The hit area is a wider 8px strip (easy to grab without much precision), but only
   the thin ::after line down its middle is ever drawn, so the boundary itself is always visible
   as a fine separator rather than only appearing once you happen to hover over it. */
.item-grid th .col-resize-handle{position:absolute;top:0;right:0;width:8px;height:100%;cursor:col-resize;z-index:1}
.item-grid th .col-resize-handle::after{content:"";position:absolute;top:0;left:50%;width:1px;height:100%;background:var(--line)}
.item-grid th .col-resize-handle:hover::after,.item-grid th .col-resize-handle.active::after{background:var(--brass);width:2px}
.item-grid input[type=text],.item-grid input[type=number]{width:100%;padding:4px 8px;border-radius:var(--radius-md);background:var(--shell);border:1px solid transparent;color:var(--text);font-family:var(--ui);font-size:12.5px}
.item-grid input[type=text]:focus,.item-grid input[type=number]:focus{border-color:var(--brass);outline:none}
.item-grid input.code-cell,.item-grid input.price-cell{font-family:var(--mono)}
/* Photo column — every menu picture visible straight from the grid, and each thumbnail is the
   button that opens that item's photo editor. Items with no photo of their own show a "+"; an
   outlet item falling back to the catalogue photo is faded so inherited never looks like set. */
.item-grid td.photo-cell{padding:3px 5px}
.item-grid /* Reads as the cell's text, behaves as a control: an option-group set doesn't fit a <select>,
   so the cell itself opens the picker. Underlined on hover so it's discoverably clickable. */
/* Licensing tab: install on the left, what-you-own on the right. Single column on narrow. */
.shutdown-wall{flex:1;display:flex;align-items:center;justify-content:center;padding:40px}
.shutdown-box{max-width:520px;text-align:center;background:var(--panel);border:1px solid var(--stop);border-radius:var(--radius-lg);padding:34px 38px}
.shutdown-box h2{margin:0 0 12px;color:var(--stop)}
.shutdown-box p{font-size:13.5px;line-height:1.6;color:var(--text-dim)}
.unlicensed-badge{background:var(--stop);color:#fff;font-size:10px;font-weight:700;letter-spacing:.12em;padding:4px 9px;border-radius:var(--radius-sm);margin-left:10px;flex:0 0 auto}
.lic-cols{display:grid;grid-template-columns:1fr 1fr;gap:28px;max-width:960px;margin-top:14px}
@media (max-width:900px){.lic-cols{grid-template-columns:1fr}}
.lic-col{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:16px}
.lic-h{margin:0 0 12px;font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:var(--text-dim)}
.lic-ok{padding:9px 12px;border-radius:var(--r);background:rgba(60,140,80,.12);border:1px solid rgba(60,140,80,.4);font-size:12.5px;max-width:960px}
.lic-fact{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px dotted var(--line);font-size:12.5px}
.lic-fact b{text-align:right}
.lic-modules{margin-top:14px;display:flex;flex-direction:column;gap:6px}
.lic-module{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);font-size:13px;opacity:.55}
.lic-module.on{opacity:1;border-color:rgba(60,140,80,.5)}
.lic-module-mark{font-weight:700;width:16px;text-align:center}
.lic-module-exp{margin-left:auto;font-size:11.5px;color:var(--text-dim);font-variant-numeric:tabular-nums}
.lic-module.on .lic-module-mark{color:#3c8c50}
.lic-module:not(.on) .lic-module-mark{color:var(--stop)}
.screen-order-row{cursor:grab}
.screen-order-row:active{cursor:grabbing}
.drag-grip{color:var(--text-dim);font-size:13px;cursor:grab;user-select:none}
.photo-thumb{width:44px;height:44px;padding:0;border-radius:var(--radius-md);overflow:hidden;background:var(--panel-2);border:1px solid var(--line);display:flex;align-items:center;justify-content:center;cursor:pointer}
.item-grid .photo-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.item-grid .photo-thumb span{color:var(--text-dim);font-size:16px;line-height:1}
.item-grid .photo-thumb:hover{border-color:var(--brass)}
.item-grid .photo-thumb.inherited img{opacity:.55}
/* A locked name (sold before, or disabled — see nameCellHtml/assertRenamable): reads as plain
   text rather than an editable field, so it's obvious before you click into it. Hovering shows
   the reason. */
.item-grid input[type=text][readonly]{background:transparent;color:var(--text-dim);cursor:default}
.item-grid input[type=text][readonly]:focus{border-color:transparent}
.item-grid select{width:100%;min-width:0;padding:4px 8px;border-radius:var(--radius-md);background:var(--shell);border:1px solid transparent;color:var(--text);font-family:var(--ui);font-size:12px}
.item-grid select:focus{border-color:var(--brass);outline:none}
/* A <td> must stay a table cell: display:flex here pulled the actions column out of the row
   structure and drew it as its own stack beside the grid (owner, 2026-09-05: "not aligned"). */
.item-grid .item-grid-actions{white-space:nowrap}
.item-grid .item-grid-actions button{margin-right:4px}
.item-grid .item-grid-actions button{padding:5px 8px;font-size:11px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line)}
.item-grid .item-grid-actions button:hover{border-color:var(--brass);color:var(--brass)}
.item-grid .item-grid-actions button.danger:hover{border-color:var(--stop);color:var(--stop)}
.item-grid .item-grid-actions button:disabled{opacity:.35;pointer-events:none}
/* This outlet's own Menu Items grid only (data-context-grid="menuItem") — its More…/Disable
   buttons are tapped constantly on the floor, so they get a larger touch target than Full
   Menu's own single "More…" button, which shares the same base .item-grid-actions styling. */
table[data-context-grid="menuItem"] .item-grid-actions button{padding:6px 12px;font-size:12.5px}
.item-grid .tiers-note{font-family:var(--mono);font-size:11px;color:var(--text-dim);white-space:nowrap}
.item-grid td.major-group-cell{color:var(--text-dim);font-size:12px;white-space:nowrap}
.item-grid td.code-cell{font-family:var(--mono);font-size:12.5px;padding-left:8px;white-space:nowrap;cursor:default}
.item-grid .outlet-chips{display:flex;flex-wrap:wrap;gap:3px;max-width:160px}
.item-grid .outlet-chip{padding:2px 6px;border-radius:var(--radius-lg);background:var(--panel-2);border:1px solid var(--line);font-size:10px;color:var(--text-dim);white-space:nowrap}
.item-grid .outlet-chip.here{border-color:var(--brass);color:var(--brass)}
.item-grid .import-btn{padding:5px 8px;font-size:11px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);white-space:nowrap}
.item-grid .import-btn.on{border-color:var(--brass);color:var(--brass)}
.item-grid .import-btn:hover{border-color:var(--brass);color:var(--brass)}

.ctx-menu{position:fixed;z-index:500;min-width:150px;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:0 8px 24px rgba(0,0,0,.35);padding:5px;font-size:12.5px}
.ctx-menu button{display:block;width:100%;text-align:left;padding:8px 10px;border-radius:var(--radius-md);background:transparent;color:var(--text)}
.ctx-menu button:hover{background:var(--panel)}
.ctx-menu button.danger:hover{color:var(--stop)}
.ctx-menu-insert{position:fixed;z-index:500;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:0 8px 24px rgba(0,0,0,.35);padding:14px;display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;max-width:360px}
.ctx-menu-insert .a-field{margin-bottom:0}
.ctx-menu-insert .a-field input{width:90px}
.ctx-menu-insert p.a-hint{width:100%;margin:0 0 2px}
.a-variant-row,.a-comp-row{display:flex;gap:8px;align-items:center;margin-bottom:6px}
.a-variant-row input{flex:1}
.a-variant-row button,.a-comp-row button{flex:0 0 auto;padding:8px 10px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);font-size:12px}
.a-addbtn{margin-top:4px;padding:6px 12px;border-radius:var(--radius-md);min-height:30px;background:var(--panel-2);border:1px dashed var(--line);font-size:12px;color:var(--text-dim)}
.a-addbtn:hover{border-color:var(--brass);color:var(--brass)}
.a-addbtn:disabled{opacity:.4;cursor:not-allowed}
.a-addbtn:disabled:hover{border-color:var(--line);color:var(--text-dim)}
.a-checkrow{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);margin-bottom:6px}
.a-checkrow input[type=checkbox]{width:16px;height:16px}
.a-checkrow .a-cn{flex:1;font-size:13px}
.a-checkrow .a-removable{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--text-dim)}
.a-checklist{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:0 12px}
.a-warn{padding:10px 12px;border-radius:var(--radius-md);background:rgba(212,98,42,.12);border:1px solid var(--alert);font-size:12.5px;margin-bottom:12px}
.a-formerr{padding:10px 12px;border-radius:var(--radius-md);background:rgba(212,98,42,.12);border:1px solid var(--alert);font-size:12.5px;margin-bottom:12px}
/* Every other .a-formerr is only ever added to the DOM once there's a real message to show — the
   one exception is the Licensing tab's #stLicenseErr, left in the markup empty and filled in later
   on an install failure, which meant an empty box (padding+border+background, no text) sat there
   permanently. :empty catches that case generically, so the same mistake can't quietly reappear
   somewhere else the same way. */
.a-formerr:empty{display:none}
.a-hint{font-size:12px;color:var(--text-dim);margin:0 0 12px}
.a-headbtns{display:flex;gap:8px}
.a-headbtns .a-addbtn{margin-top:0}
.a-code{font-family:var(--mono);font-size:11.5px;color:var(--text-dim);margin-right:8px}

/* ---------- Admin on a phone/small tablet: the 168px text-label sidebar has no room to live
   next to content, so it becomes a horizontal scrollable strip along the top instead (same
   breakpoint the till uses for its own mobile layout, above). Everything else here just
   un-crowds rows/forms/grids that were laid out assuming desktop width. ---------- */
@media (max-width:880px){
  .admin{flex-direction:column}
  .a-tabs{flex:0 0 auto;flex-direction:row;overflow-x:auto;overflow-y:hidden;border-right:0;border-bottom:1px solid var(--line);-webkit-overflow-scrolling:touch}
  .a-tabs .a-tab{flex:0 0 auto;white-space:nowrap}
  .a-tabs .a-tab[data-tab="__exit"]{margin-top:0!important;margin-left:auto!important}
  .a-content{padding:14px 16px 28px}
  .a-head{flex-wrap:wrap;row-gap:10px}
  .a-row{flex-wrap:wrap;row-gap:8px}
  .a-row .a-meta{flex:1 1 100%;margin-left:0;order:2}
  .a-row .a-actions{order:3;flex:1 1 100%;flex-wrap:wrap;justify-content:flex-end}
  .a-row2{flex-direction:column;gap:0}
  .a-subnav{flex-wrap:wrap;row-gap:8px}
  .screen-editor{grid-template-columns:1fr}
}
@media (max-width:480px){
  .a-content{padding:12px 12px 24px}
  .item-grid-config .a-field,.item-grid-config{min-width:0}
  .item-grid-config .a-field{flex:1 1 128px}
}
/* Below 420px the till's own topbar rule (above) hides .session-revenue-centre outright to save
   space — fine there, since the till mostly stays on the RC it was logged into. In Admin it's a
   <select> and the only way a multi-RC admin switches location, so it needs to stay reachable
   even on a small phone; this wins on specificity over that rule despite both using !important. */
@media (max-width:420px){
  .admin-topbar .session-revenue-centre{display:block!important;flex:1 1 auto;min-width:0}
}

/* ================= LOGIN / REVENUE CENTRE PICKER =================
   KDS and ResM still use the old logo-v3.png, transparent and neutral enough to sit on either
   theme's background unchanged. The till/BOH/order screens wear the R&B mark instead (12 Sep
   2026), which needs separate light/dark cuts — see the :root[data-theme="dark"] rule below. This
   gradient just needs to track --shell/--panel the same way the rest of the app does, via the
   --login-* tokens defined in :root above. */
.login-view,.revenue-centre-picker,.workstation-setup{position:fixed;inset:0;z-index:70;background:var(--login-bg);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:32px;padding:24px}
.login-view[hidden],.revenue-centre-picker[hidden],.workstation-setup[hidden]{display:none}

.login-logo{width:min(80vw,440px);height:auto;filter:drop-shadow(0 16px 34px rgba(0,0,0,.55))}
/* R&B logo handover (12 Sep 2026): navy mark for every theme except the two dark ones, which sit
   on the shared --shell dark ground and need the white cut instead. dark-solid has no color rules
   of its own (see :root[data-theme="dark-solid"] above) — it inherits base :root's dark colors and
   only flattens corners — so it needs the dark logo the same as plain dark. */
:root[data-theme="dark"] .login-logo,
:root[data-theme="dark"] .order-logo,
:root[data-theme="dark"] .order-logo-lg,
:root[data-theme="dark-solid"] .login-logo,
:root[data-theme="dark-solid"] .order-logo,
:root[data-theme="dark-solid"] .order-logo-lg{content:url("assets/logo-rnb-dark.png")}
/* BOH handover (12 Sep 2026): same equal-specificity rule as above, so it has to come AFTER it to
   win for BOH's login screens — .login-logo-boh sits alongside .login-logo on the same <img>, not
   instead of it, so the till's rule immediately above would otherwise apply there too. */
:root[data-theme="dark"] .login-logo-boh,
:root[data-theme="dark-solid"] .login-logo-boh{content:url("assets/logo-boh-dark.png")}
:root[data-theme="dark"] .brand-logo,
:root[data-theme="dark-solid"] .brand-logo{background-image:url("assets/logo-rnb-dark.png")}
:root[data-theme="dark"] .brand-logo-boh,
:root[data-theme="dark-solid"] .brand-logo-boh{background-image:url("assets/logo-boh-dark.png")}
/* KDS (13 Sep 2026): same rule shape, but KDS itself only ever stamps "dark" or "light" (no
   picker of its own — see kds.html's inline snippet), so no dark-solid entry is reachable here. */
:root[data-theme="dark"] .login-logo-kds{content:url("assets/logo-kds-dark.png")}
/* ResM (14 Sep 2026): its own mark (the table M with the candle dot, Logo/2026/ResM), same equal-
   specificity rule shape so it has to sit after the till's rule to win on ResM's login. */
/* The white lockup on every dark ground, the default (no data-theme) included; the light themes swap back to the blued one. */
.login-logo-resm{content:url("assets/logo-resm-dark.png")}
:root[data-theme="light"] .login-logo-resm,
:root[data-theme="light-solid"] .login-logo-resm{content:url("assets/logo-resm-light.png")}

/* Small corner control, page-level (not nested in any one screen) — lets anyone reaching this
   server's public URL (e.g. an ngrok tunnel) grab the desktop installers without needing to log
   in first, same reasoning as /downloads itself being unauthenticated. z-index above the
   login-view/revenue-centre-picker/workstation-setup overlays' own 70 so it stays reachable no
   matter which of those is currently covering the screen — including the very first thing a
   fresh install shows, the workstation-setup PIN screen, which sits on top of everything else. */
.dl-wrap{position:fixed;top:10px;right:10px;z-index:80}
.dl-btn{padding:6px 11px;border-radius:var(--radius-full);background:var(--panel-2);border:1px solid var(--line);color:var(--text-dim);font-family:inherit;font-size:11px;cursor:pointer;white-space:nowrap}
.dl-btn:hover{color:var(--text);border-color:var(--text-dim)}
.dl-menu{position:absolute;top:calc(100% + 8px);right:0;min-width:170px;background:var(--login-menu-bg);backdrop-filter:blur(6px);border:1px solid var(--line);border-radius:var(--radius-lg);padding:6px;box-shadow:0 20px 50px rgba(0,0,0,.5);display:flex;flex-direction:column;gap:2px}
.dl-menu[hidden]{display:none}
.dl-menu a{padding:9px 12px;border-radius:var(--radius-md);color:var(--text);text-decoration:none;font-size:13px;display:block}
.dl-menu a:hover{background:var(--panel-2)}

.login-card{width:100%;max-width:360px;padding:24px 24px 20px;background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);text-align:center;box-shadow:0 1px 2px rgba(24,35,56,.08);--unused-old:rgba(0,0,0,.5)}
/* .btn.ghost has no color of its own (see its own rule) since it sits on backgrounds the rest of
   the app doesn't share a class with (the login card here, the till's own check panel elsewhere
   for .check/.pay) — each context sets it explicitly rather than one value trying to fit both.
   var(--text) is correct in both themes here since the login card now tracks theme too. */
.login-card .btn.ghost{color:var(--text)}
.login-brand{margin-bottom:20px}
.login-brand b{display:block;font-size:22px;line-height:28px;font-weight:600;font-stretch:80%;letter-spacing:-.01em}
/* App name above the PIN prompt (owner, 2026-09-05): the name on its own line, the prompt under it. */
.login-brand .login-app{display:block;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-dim);margin-bottom:6px}
.login-brand span{display:block;font-size:11px;color:var(--text-dim);letter-spacing:.1em;text-transform:uppercase;margin-top:4px}
.country-card{max-width:380px}
.country-card .login-brand span{text-transform:none;letter-spacing:normal;font-size:12.5px;margin-top:6px;line-height:1.4}
.country-options{display:flex;flex-direction:column;gap:10px}
.country-opt{display:flex;align-items:center;gap:14px;width:100%;padding:16px 18px;border-radius:var(--radius-lg);background:var(--login-opt-bg);border:1px solid var(--line);color:var(--text);font-size:15px;font-weight:600;text-align:left;cursor:pointer}
.country-opt:hover{border-color:var(--brass);background:var(--login-opt-bg-hover)}
.country-flag{font-size:28px;line-height:1}
.pin-dots{display:flex;justify-content:center;gap:14px;margin-bottom:10px}
/* The login screen's outlet dropdown — same quiet glassy language as the login option rows. */
.login-rc-select{width:100%;margin-bottom:14px;padding:12px 14px;border-radius:var(--radius-lg);background:var(--login-opt-bg);border:1px solid var(--line);color:var(--text);font-family:inherit;font-size:14px;font-weight:600;text-align:center}
.login-rc-select:focus{border-color:var(--brass);outline:none}
.login-rc-select[hidden]{display:none}
.pin-dots span{width:14px;height:14px;border-radius:var(--radius-full);border:2px solid var(--line-strong);background:transparent}
.pin-dots span.filled{background:var(--pin);border-color:var(--pin)}
.pin-error{color:var(--stop);font-size:12px;font-weight:600;min-height:16px;margin-bottom:10px}
.pin-error[hidden]{visibility:hidden}
.pin-pad{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.pin-pad button{height:60px;padding:0;border-radius:var(--radius-md);background:var(--surface-raised);border:1px solid var(--line-strong);font-size:24px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--ink)}
.pin-pad button:active{background:var(--brand-soft)}
.pin-pad button:active{transform:scale(.96);border-color:var(--pin)}
.pin-pad button.ghost{font-size:15px;font-weight:600;color:var(--ink-muted);background:var(--surface-sunken);border-color:var(--surface-sunken)}
.revenue-centre-list{display:flex;flex-direction:column;gap:10px;margin-bottom:16px}
.revenue-centre-list button{padding:16px;border-radius:var(--radius-lg);background:var(--panel-2);border:1px solid var(--line);font-size:15px;text-align:left}

/* ---------- workstation setup (src/shared/workstationSetup.js) — reuses .pin-dots/.pin-pad as-is
   (6 dots instead of 4, same visual language as login) for the PIN entry; this is just the
   confirmation screen's centered name display. ---------- */
.ws-setup-name{text-align:center;font-size:28px;font-weight:700;color:var(--brass);letter-spacing:.01em;padding:18px 10px;word-break:break-word}

/* ================= CUSTOMER ORDER (order.html) =================
   Phone-first by default (customers are almost always on a phone), reusing
   .tile/.cats/.opt/.modal/.ln-* as-is for anything that isn't page layout.
   A desktop breakpoint below frames this same column as a floating card on
   a branded backdrop instead of stranding a bare phone-width layout in a
   sea of flat background — a guest who scans the QR code from a tablet or
   a laptop at the table still gets an intentional-looking page. */
.order-body{overflow-y:auto;display:flex;justify-content:center;background:var(--shell)}
.order-state{width:100%;max-width:520px;min-height:100dvh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;text-align:center}
.order-state[hidden]{display:none}
.order-spinner{display:flex;flex-direction:column;align-items:center}
.order-spinner h2{margin:0 0 8px;font-size:18px}
.order-spinner p{margin:0;color:var(--text-dim);font-size:13.5px;max-width:38ch}
.order-logo-lg{width:min(46vw,140px);height:auto;margin-bottom:18px;filter:drop-shadow(0 10px 22px rgba(0,0,0,.45))}
.order-app{width:100%;max-width:520px;margin:0 auto;display:flex;flex-direction:column;min-height:100dvh}
.order-app[hidden]{display:none}
@media (min-width:701px){
  .order-body{background:var(--login-bg)}
  .order-app,.order-state{max-width:560px;min-height:calc(100dvh - 48px);margin:24px auto;background:var(--shell);border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:0 30px 80px rgba(0,0,0,.35);overflow:hidden}
}
/* "Your order's ready" — fixed above everything (even the header) so it's seen no matter where
   on the page the guest is when it lands; stays until they dismiss it, not timed like a toast,
   since this is worth more than a few seconds' notice. See order.js's showReadyBanner. */
.order-ready-banner{position:fixed;top:0;left:0;right:0;z-index:90;display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 16px;padding-top:calc(12px + env(safe-area-inset-top, 0px));background:var(--brass);color: #fff;font-weight:600;font-size:13.5px;box-shadow:0 6px 20px rgba(0,0,0,.35)}
.order-ready-banner[hidden]{display:none}
.order-ready-banner button{flex:0 0 auto;width:26px;height:26px;border-radius:var(--radius-full);background:rgba(0,0,0,.12);border:0;color:inherit;font-size:13px;line-height:1;display:flex;align-items:center;justify-content:center;padding:0}
/* env(safe-area-inset-top) on the header (and the corner buttons/ready banner below): when this
   page runs as an installed Home Screen app, apple-mobile-web-app-status-bar-style
   black-translucent (see order.html) draws the page BEHIND the iPhone status bar/notch — without
   this padding the top strip of the header (the 🔔 bell, the theme toggle) sat invisible under
   the clock, and the whole page read as "bigger than the screen." Resolves to 0 in a normal
   browser tab, so nothing changes there. */
.order-hd{position:relative;padding:16px;padding-top:calc(16px + env(safe-area-inset-top, 0px));background:var(--panel);border-bottom:1px solid var(--line);flex:0 0 auto;display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center}
/* .brand span is shared with the till's topbar (10px there is fine at arm's length on a fixed
   till screen) — bumped past the 11px legibility floor here only, where a guest reads it one-handed
   on a phone, without touching the shared rule the till still uses. */
.order-hd .brand span{font-size:11.5px}
/* Sun/moon theme toggle, same convention as the desktop app: the icon shows what you GET by
   tapping — a sun while the page is dark, a moon while it's light. Flips /shared/theme.js's
   data-theme attribute; the guest's choice persists per phone via localStorage. */
.order-theme-toggle{position:absolute;top:calc(12px + env(safe-area-inset-top, 0px));right:12px;width:34px;height:34px;border-radius:var(--radius-full);background:var(--panel-2);border:1px solid var(--line);font-size:15px;line-height:1;display:flex;align-items:center;justify-content:center;padding:0}
.order-theme-toggle:active{transform:scale(.9)}
/* Mirrors .order-theme-toggle on the opposite corner — see order.js's subscribeToPush. */
.order-bell-toggle{position:absolute;top:calc(12px + env(safe-area-inset-top, 0px));left:12px;width:34px;height:34px;border-radius:var(--radius-full);background:var(--panel-2);border:1px solid var(--line);font-size:15px;line-height:1;display:flex;align-items:center;justify-content:center;padding:0}
.order-bell-toggle[hidden]{display:none}
.order-bell-toggle:active{transform:scale(.9)}
.order-logo{height:32px;width:auto}
.order-settle-link{font-size:11px;color:var(--text-dim);text-decoration:underline;background:none;border:none}
.order-settle-link[hidden]{display:none}
/* mask fade on the trailing edge hints there's more to scroll when a category list runs off-screen
   (e.g. an outlet with more than ~5 categories) — a guest who never tries a sideways swipe on a
   nav row would otherwise never discover the later categories exist. */
.order-app .cats{flex:0 0 auto;flex-direction:row;overflow-x:auto;padding:10px 12px;border-right:0;border-bottom:1px solid var(--line);-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent 100%);mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent 100%)}
.order-app .cat{flex:0 0 auto;white-space:nowrap}
/* touch-action pan-y on the menu: vertical scroll stays native, but double-tap zoom and other
   ambiguous gestures are off — so a SECOND finger tapping/scrolling here registers immediately
   while the first finger holds the mic (multi-touch ordering: browse with one hand, talk with
   the other). Pairs with order.js's pointercancel handling on the mic FAB. */
.order-app .grid{flex:1;padding-bottom:88px;touch-action:pan-y}
.order-app .tile,.order-app .cat,.dish-row{touch-action:manipulation}
.order-empty{padding:40px 16px;text-align:center;color:var(--text-dim);font-size:13px}
.order-bottombar{position:fixed;left:12px;right:12px;bottom:calc(14px + env(safe-area-inset-bottom, 0px));display:flex;gap:10px;z-index:30}
/* Deliberately NOT brass, unlike .order-paybar right next to it — "View order" is informational
   (nothing fires), "Send to Kitchen"/"Make Payment" actually commits something. Sharing the same
   fill made the two read as equally weighted, easy to mis-tap one for the other one-handed. */
.order-cartbar{flex:1;display:flex;align-items:center;gap:10px;padding:14px 16px;border-radius:var(--radius-full);background:var(--panel);color:var(--text);border:1px solid var(--line);font-weight:600;font-size:13.5px;box-shadow:0 10px 30px rgba(0,0,0,.2)}
.order-cartbar[hidden]{display:none}
.order-cartbar-cta{margin-left:auto;font-size:12px;text-decoration:underline;color:var(--brass)}
.order-paybar{flex:0 0 auto;padding:14px 18px;border-radius:var(--radius-full);background:var(--brass);color: #fff;font-weight:700;font-size:13.5px;box-shadow:0 10px 30px rgba(0,0,0,.35)}
.order-paybar[hidden]{display:none}
/* Floating shortcut back to the voice-ordering avatar, for a guest who declined it at the QR
   gate (or just wants it now) — parked above the cart/pay bar so the two never collide. */
.order-avatar-fab{
  /* Mic LEFT, avatar RIGHT — owner's layout call 2026-08-30 (was mic-right/avatar-left). */
  position:fixed; left:14px; bottom:92px; z-index:29;
  width:50px; height:50px; border-radius:var(--radius-full);
  background:var(--brass); color: #fff;
  display:flex; align-items:center; justify-content:center;
  font-size:21px; box-shadow:0 10px 24px rgba(0,0,0,.35);
  /* Press-and-hold to talk: without these, a real long-press on a phone triggers the browser's
     own text-selection/callout menu or a page scroll instead of reliably firing pointerdown/up
     on this button — confirmed needed the first time push-to-talk was tried on a real phone. */
  touch-action:none; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none;
}
.order-avatar-fab:active{transform:scale(.93)}
.order-avatar-fab[hidden]{display:none}
/* Moved off the bottom-right corner (owner, 10 Sep 2026: "it is covering part of the menu") to
   sit with the header's own corner icons instead — same size and top offset as
   .order-theme-toggle, stacked directly under it on the same top-right corner so the two never
   collide. z-index above .ov-panel's 60 on purpose: that panel takes over the ENTIRE top strip
   the moment Maro comes up (full width, top:0), which is exactly the region this button now
   lives in — without outranking it here, "call a waiter" would vanish the instant a guest starts
   talking to her, the one moment a guest asking for a human is most likely to reach for it
   instead. */
.order-waiter-fab{
  position:fixed; top:calc(12px + env(safe-area-inset-top, 0px) + 34px + 8px); right:12px; z-index:65;
  width:34px; height:34px; border-radius:var(--radius-full);
  background:var(--brass); color:#fff;
  display:flex; align-items:center; justify-content:center;
  font-size:15px; box-shadow:0 4px 14px rgba(0,0,0,.3);
  border:0; padding:0;
}
.order-waiter-fab:active{transform:scale(.9)}
.order-waiter-fab[hidden]{display:none}
/* Tap-again-to-confirm state (see order.js) — same idea as data-settle-cash's "confirming" class,
   a visual nudge rather than new markup: the emoji dims and a ring pulses while armed. */
.order-waiter-fab.confirming{animation:waiterFabPulse 1s ease-in-out infinite}
@keyframes waiterFabPulse{0%,100%{box-shadow:0 10px 24px rgba(0,0,0,.35),0 0 0 0 rgba(230,184,0,.6)}50%{box-shadow:0 10px 24px rgba(0,0,0,.35),0 0 0 8px rgba(230,184,0,0)}}
.order-cartrow{padding:9px 0;border-bottom:1px solid var(--line)}
.order-cartrow:last-child{border-bottom:0}
.order-cartrow-top{display:flex;gap:8px;justify-content:space-between;font-size:13.5px}
.order-cartrow-sub{margin-top:3px;font-size:11.5px;color:var(--text-dim)}
.order-cartrow-ctl{display:flex;align-items:center;gap:8px;margin-top:6px}
.order-cartrow-ctl button{padding:5px 10px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);font-size:13px}
.order-cartrow-ctl span{font-family:var(--mono);min-width:16px;text-align:center}
.order-cartrow-ctl button.danger{margin-left:auto;color:var(--stop);border-color:rgba(180,64,47,.4);font-size:11px}
.order-cartrow.sent{opacity:.68}
.order-sent-tag{font-style:italic}
.order-cartrow .ln-n em{font-style:normal;color:var(--text-dim);margin-left:4px;font-size:12px}
/* width:100% is load-bearing: .order-totals sits inside flex containers with align-items:center
   (e.g. .order-state), which shrinks block children to content width instead of stretching them —
   without this, .tr's justify-content:space-between has no extra width to distribute and the
   label/amount render jammed together ("Total due$18.87"). */
.order-totals{width:100%;margin-top:10px;padding-top:10px;border-top:1px dashed var(--line);font-family:var(--mono);font-size:12.5px}
.order-choice-actions{display:flex;flex-direction:column;gap:10px;margin:18px auto 0;width:100%;max-width:280px}
/* Stacked, full labels (MAK, 14 Sep 2026: "Pay for my …" was cut short with three in a row) */
.order-pay-choices{display:flex;flex-direction:column;gap:10px;margin:18px auto 0;width:100%;max-width:320px}
.order-pay-choices .btn{min-width:0;white-space:normal;padding:13px 16px;font-size:14px}
.order-settle-lines{text-align:left;width:100%;max-width:360px;margin-top:6px}
.mono{font-family:var(--mono)}
.order-qr-preview{display:flex;justify-content:center;padding:14px;background:#fff;border-radius:var(--radius-lg);margin:12px 0 4px}
.order-qr-preview img{display:block}
/* .tr.grand's default border-top is var(--ink-on-tape), meant for the till's light cheque tape —
   invisible on this page's dark modal, so give it the dark-theme line color instead. */
.order-totals .tr.grand{border-top-color:var(--line)}
.revenue-centre-list button:hover{border-color:var(--brass);color:var(--brass)}

/* ---------- menu item photo (Full Menu -> More… editor; see admin.js's drawMasterPriceForm) ---------- */
.mp-photo-row { display: flex; gap: 14px; align-items: flex-start; }
.mp-photo-preview {
  flex: none; width: 96px; height: 96px; border-radius:var(--radius-lg); overflow: hidden;
  background: var(--panel-2); border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-dim); font-size: 11px; text-align: center;
}
.mp-photo-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mp-photo-actions { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; }
.mp-photo-actions .a-hint { flex: 0 0 100%; }

/* Guest QR menu item photo — see order.js's renderGrid. Fixed square so a row of tiles keeps a
   straight baseline whatever each photo's own aspect ratio is, and so the grid's height doesn't
   jump as lazily-loaded photos arrive. */
/* A DEFINITE height, deliberately not aspect-ratio. The tile is a grid item AND a flex column,
   and with aspect-ratio the photo's height depends on the column width the grid is still busy
   resolving — a circular dependency the browser breaks by sizing the row as if the photo were
   zero-tall. The row came out at the tile's 96px minimum, the photo then laid out at its real
   height, and it spilled over the tiles below (worst on screens with many gaps, where short
   blank tiles set the row height). A fixed height removes the circularity outright: the row
   always accounts for the photo. flex:0 0 auto additionally stops the flex column squeezing it
   into a squashed strip. object-fit:cover keeps every photo filled and undistorted. */
.tile-img {
  width: 100%; height: 104px; border-radius:var(--radius-md); object-fit: cover;
  display: block; margin-bottom: 6px; background: var(--panel-2);
  flex: 0 0 auto;
}

/* ---------- the digital waiter, in-page on the QR menu (see order.html's #ovPanel) ----------
   A FULL-WIDTH TOP BANNER (owner's call 2026-08-31: "the upper banner that has the outlet name
   gets covered and the avatar shows in that area like a big screen — better than a small icon").
   While a voice session is open, the banner takes over the header zone: big face on the left,
   her words filling the middle, controls on the right — reads like a video call with the
   waiter. Opaque and pointer-events:auto (it genuinely covers the header, so taps must not
   leak through to the invisible theme/bell buttons beneath); the menu below stays fully
   tappable, and body:has() pushes the content down so nothing important hides under her. */
.ov-panel {
  position: fixed; left: 0; right: 0; top: 0; z-index: 60;
  /* Grid, not a single flex row: on a phone the 🌐 pill and ✕ were eating the bubble's width.
     Face spans both rows on the left; controls sit top-right; her words get the whole width
     beside the face. */
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px 12px;
  grid-template-areas: "face lang close" "face bubble bubble";
  align-items: start;
  padding: calc(env(safe-area-inset-top, 0px) + 10px) 12px 12px;
  background: var(--panel); border-bottom: 1px solid var(--line);
  box-shadow: 0 12px 30px rgba(0,0,0,.25);
  pointer-events: auto;
}
/* !important on purpose: the full-screen rule further down ([data-panel="full"] { display:flex }) has the
   same specificity and comes later, so without it hidden=true left her painted full screen while the
   session was already over (MAK, 15 Sep 2026: "she stayed and the X did nothing"). */
.ov-panel[hidden] { display: none !important; }
/* Push the page down while the banner is up, so the category nav and first menu rows aren't
   buried under her. Sized to the face clamp + padding; browsers without :has() just overlap. */
body:has(.ov-panel:not([hidden])) .order-app { padding-top: clamp(215px, calc(55vw + 45px), 325px); }
/* While she's up, the page's own intro collapses so the FIRST thing under the banner is the
   MENU (owner 2026-09-02: on Farrouj the hero photo + oversized brand block pushed Starters/
   Main Course a full screen down — "cannot browse the menu, it doesn't show fully"). The hero
   and welcome line go, the outlet name shrinks to one modest line, and the category nav lands
   right under her. Everything returns the moment the session closes. */
body:has(.ov-panel:not([hidden])) .world-hero { display: none; }
body:has(.ov-panel:not([hidden])) .world-welcome { display: none; }
body:has(.ov-panel:not([hidden])) .order-logo { display: none; }
body:has(.ov-panel:not([hidden])) .order-settle-link { display: none; }
body:has(.ov-panel:not([hidden])) .order-hd { padding-top: 8px; padding-bottom: 4px; }
body:has(.ov-panel:not([hidden])) .brand b { font-size: 18px !important; letter-spacing: .08em !important; text-indent: 0 !important; }
body:has(.ov-panel:not([hidden])) .brand span { display: none; }
body:has(.ov-panel:not([hidden])) .brand::after { display: none !important; }
/* Deliberately large: she is the feature, not a notification badge, and at 78px the face was
   too small to read as a person at arm's length — and far too small to show off lip-sync.
   Clamped so she still leaves room for the menu on a narrow phone. */
/* The face is a big RECTANGULAR video tile filling the banner's left side (owner drew the box:
   "I want the avatar to fill that box") — a video-call window, not a floating circle. */
.ov-face { grid-area: face; position: relative; width: clamp(180px, 55vw, 270px); aspect-ratio: 1; pointer-events: auto; }
.ov-photo {
  position: absolute; inset: 3px; width: calc(100% - 6px); height: calc(100% - 6px);
  border-radius:var(--radius-lg); object-fit: cover; background: var(--panel-2);
}
/* The "Calling your waiter…" opening state — fills the face circle with one calm message while
   the live avatar session connects, replacing the photo→flicker→blank→video load-in. The soft
   pulse says "working on it" without a spinner. */
.ov-calling {
  position: absolute; inset: 3px; z-index: 2;
  border-radius:var(--radius-lg);
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 14px;
  background: var(--panel-2); border: 1px solid var(--line);
  color: var(--text); font-family: var(--ui); font-size: 13px; line-height: 1.35;
  animation: ovCallingPulse 1.6s ease-in-out infinite;
}
.ov-calling[hidden] { display: none; }
@keyframes ovCallingPulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .ov-calling { animation: none; } }
/* The state ring — the only thing telling a guest whether they're being heard right now, so it
   carries listening/thinking/speaking the same way the standalone avatar page's ring does. */
.ov-ring { position: absolute; inset: 0; border-radius:var(--radius-lg); border: 2px solid transparent; transition: border-color .2s, box-shadow .2s; }
.ov-panel[data-mode="listening"] .ov-ring { border-color: var(--go); animation: ov-pulse 1.5s ease-out infinite; }
.ov-panel[data-mode="thinking"] .ov-ring { border-color: var(--line); border-top-color: var(--brass); animation: ov-spin 1.1s linear infinite; }
.ov-panel[data-mode="speaking"] .ov-ring { border-color: var(--brass); box-shadow: 0 0 22px rgba(201,162,39,.35); }
@keyframes ov-pulse { 0% { box-shadow: 0 0 0 0 rgba(47,127,91,.4); } 100% { box-shadow: 0 0 0 16px rgba(47,127,91,0); } }
@keyframes ov-spin { to { transform: rotate(360deg); } }
/* Tiny silence-countdown badge on the avatar face: seconds remaining before her reply, shown
   only once the guest pauses mid-listen (order.js hides/resets it whenever they speak again).
   Mono + tabular so the ticking digits don't wobble the badge width. */
.ov-countdown {
  position: absolute; bottom: 2px; right: 2px; z-index: 2;
  min-width: 30px; height: 30px; padding: 0 5px; border-radius:var(--radius-full);
  display: flex; align-items: center; justify-content: center;
  background: var(--go); color: #fff;
  font-family: var(--mono); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
  box-shadow: 0 4px 10px rgba(0,0,0,.3);
}
.ov-countdown[hidden] { display: none; }
/* Fixed white-on-black-text on purpose (MAK, 14 Sep 2026), not themed: this used to take its
   colors from var(--panel-2)/var(--text), which on the full-screen dark backdrop below rendered
   as dark-grey-on-dark-grey — "can't see anything" on a live test. A caption has to stay legible
   over WHATEVER is behind it (a light guest theme, a dark full-screen photo, anything), so it
   ignores the theme entirely instead of chasing every background it could land on. */
.ov-bubble {
  pointer-events: auto;
  grid-area: bubble; min-width: 0;
  max-height: clamp(140px, 45vw, 230px); overflow-y: auto;
  background: #fff; border: 1px solid var(--line); border-radius:var(--radius-lg);
  padding: 9px 12px; font-size: 13.5px; line-height: 1.45; color: #111;
}
.ov-bubble[hidden] { display: none; }
.ov-bubble .ov-heard { display: block; margin-top: 5px; font-size: 11.5px; color: #555; font-style: italic; }
.ov-close {
  pointer-events: auto; grid-area: close;
  width: 24px; height: 24px; border-radius:var(--radius-full); flex: none;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--text-dim); font-size: 11px;
}
/* Mid-session language switch — shows the language you GET by tapping (same convention as the
   theme toggle). Sits next to the ✕; flips guestLang for the next listen turn (see order.js). */
.ov-lang {
  pointer-events: auto; grid-area: lang; justify-self: end;
  padding: 4px 10px; border-radius:var(--radius-full); flex: none;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--text); font-size: 11.5px;
  font-family: var(--ui);
}
.ov-lang[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .ov-ring { animation: none !important; } }

/* Mic button state (see order.js's ovMode) — the button the guest's thumb is actually on has to
   show what's happening, not just the panel beside it. Green while listening (and the glyph
   becomes a stop square, since a second tap ends the turn early), muted while thinking so a
   double-tap plainly reads as "not now", accent while she's speaking. */
.order-avatar-fab[data-mode="listening"] { background: var(--go); animation: ov-pulse 1.5s ease-out infinite; }
.order-avatar-fab[data-mode="thinking"] { opacity: .55; }
.order-avatar-fab[data-mode="speaking"] { background: var(--brass); }
/* "Your turn" — the turn-taking cue (owner wanted guests to know WHEN to tap; a soft green
   breathing glow on the button itself + the pill below beat the red-arrow idea: signal in the
   "go" color, exactly where the action is, zero tutorial clutter). Shown only while a session
   is open and she's waiting for the guest (see ovMode). */
/* !important so the per-outlet theme skins (which restyle the FAB with higher specificity)
   can't swallow the turn signal — "your turn" must read green in every world. */
.order-avatar-fab[data-hint="turn"] { background: var(--go) !important; animation: micTurnBreathe 1.8s ease-in-out infinite; }
@keyframes micTurnBreathe {
  0%, 100% { box-shadow: 0 10px 24px rgba(0,0,0,.35), 0 0 0 0 rgba(47,127,91,.55); }
  50% { box-shadow: 0 10px 24px rgba(0,0,0,.35), 0 0 0 12px rgba(47,127,91,0); }
}
.mic-hint {
  position: fixed; left: 14px; bottom: 148px; z-index: 29;
  padding: 6px 12px; border-radius:var(--radius-full);
  background: var(--panel); border: 1px solid var(--line); color: var(--text);
  font-family: var(--ui); font-size: 12.5px; white-space: nowrap;
  box-shadow: 0 6px 18px rgba(0,0,0,.25);
  pointer-events: none;
}
.mic-hint[data-kind="turn"] { border-color: var(--go); color: var(--go); font-weight: 600; }
.mic-hint[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .order-avatar-fab[data-hint="turn"] { animation: none; } }

/* The live Simli stream, sitting exactly where the still photo does so the swap between them is
   invisible — same circle, same size, no reflow when she starts or stops speaking. */
.ov-video {
  position: absolute; inset: 3px; width: calc(100% - 6px); height: calc(100% - 6px);
  border-radius:var(--radius-lg); object-fit: cover; background: var(--panel-2);
}
.ov-video[hidden] { display: none; }
/* (banner layout: the bubble fills the middle of the top bar — no max-width cap needed) */

/* ================= Full-screen avatar (MAK, 13-14 Sep 2026) =================
   Two states, switched by .ov-panel's own [data-panel] attribute (order.js):
     data-panel="full"  set the instant a guest taps the mic: her face fills the whole screen,
                         mic/waiter/menu sit in a big row at the bottom.
     data-panel="menu"  set by tapping the Menu button: back to the ORIGINAL top-banner layout
                         above (owner's proven design, untouched) so the guest can browse/order
                         while she's still live in the strip. Tapping her face there flips back
                         to "full" (see order.js's click handler on #ovPanel) — a plain toggle,
                         nothing ends the session either way.

   Every rule below is scoped to [data-panel="full"] on purpose — "menu" needs ZERO new CSS, it
   just falls through to the banner rules above. An earlier version instead shrank the panel to a
   right-edge rail for "menu" and pushed .order-app over with padding, which needed every other
   full-screen sibling to separately know to make room for it — the bill/payment screen never got
   that treatment, so live testing (MAK, 14 Sep) showed the rail sitting on top of "Your bill" and
   clipping Total due / Full Pay / Back to menu. The banner already has that plumbing everywhere
   it's needed, so reusing it for "menu" removes the whole class of bug instead of chasing it
   sibling by sibling. */
/* ---- the video-call look (MAK, 14 Sep 2026: "I want her to look like you are on a video call") ----
   Her face full-bleed, a soft dark gradient top and bottom like a call app, her name and a live call
   timer at the top, live captions above a proper call bar (Waiter / Mic / Menu / red End, each
   with a label), and the opening "Calling…" state as a blurred ringing screen. The state ring is
   off here (a border pulsing at the screen edge reads as a glitch); the header status line and the
   mic button carry listening / thinking / speaking instead. */
.ov-panel[data-panel="full"] {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column;
  padding: 0; background: #0E1526; border-bottom: 0; box-shadow: none;
  grid-template-areas: none;
}
.ov-panel[data-panel="full"] .ov-face {
  grid-area: unset; flex: 1 1 auto; width: 100%; aspect-ratio: unset; min-height: 0; overflow: hidden;
}
.ov-panel[data-panel="full"] .ov-photo, .ov-panel[data-panel="full"] .ov-video { inset: 0; width: 100%; height: 100%; border-radius:0; }
.ov-panel[data-panel="full"] .ov-ring { display: none; }
/* a slow drift so the idle face reads as live video, not a poster. On the WRAPPER (.ov-media holds
   the photo, the live video and the portrait canvases), so the photo/video swap at the start of
   every reply stays at the same scale instead of snapping (captureIdleStill exists to make that
   swap pixel-identical). */
.ov-media { position: absolute; inset: 0; }
.ov-panel[data-panel="full"] .ov-media { animation: ov-kenburns 26s ease-in-out infinite alternate; transform-origin: 50% 38%; }
@keyframes ov-kenburns { from { transform: scale(1); } to { transform: scale(1.07); } }
@media (prefers-reduced-motion: reduce) { .ov-panel[data-panel="full"] .ov-media { animation: none; } }
/* the call app's gradients: readable name up top, readable captions and buttons down below */
.ov-panel[data-panel="full"] .ov-face::before, .ov-panel[data-panel="full"] .ov-face::after {
  content: ""; position: absolute; left: 0; right: 0; z-index: 1; pointer-events: none;
}
.ov-panel[data-panel="full"] .ov-face::before {
  top: 0; height: calc(env(safe-area-inset-top, 0px) + 160px);
  background: linear-gradient(180deg, rgba(6,10,22,.85) 0%, rgba(6,10,22,.7) 35%, rgba(6,10,22,.3) 70%, rgba(6,10,22,0) 100%);
}
.ov-panel[data-panel="full"] .ov-face::after {
  bottom: 0; height: calc(env(safe-area-inset-bottom, 0px) + 270px);
  background: linear-gradient(0deg, rgba(6,10,22,.9) 0%, rgba(6,10,22,.6) 42%, rgba(6,10,22,0) 100%);
}
/* her name + status line + timer, like the caller banner on a call */
.ov-callhd { display: none; }
.ov-panel[data-panel="full"] .ov-callhd {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  position: absolute; z-index: 3; left: 70px; right: 70px; top: calc(env(safe-area-inset-top, 0px) + 18px);
  text-align: center; color: #fff; text-shadow: 0 1px 10px rgba(0,0,0,.6); pointer-events: none;
}
.ov-callhd b { font-family: var(--ui); font-size: 23px; font-weight: 600; letter-spacing: .01em; }
.ov-callhd span { font-family: var(--ui); font-size: 13.5px; opacity: .92; font-variant-numeric: tabular-nums; display: inline-flex; align-items: center; gap: 7px; }
.ov-callhd span::before { content: ""; width: 8px; height: 8px; border-radius:var(--radius-full); background: var(--go); animation: ov-pulse 1.5s ease-out infinite; }
.ov-panel[data-mode="listening"] .ov-callhd span::before { background: #E53935; animation: ov-pulse-red .9s ease-out infinite; }
@keyframes ov-pulse-red { 0% { box-shadow: 0 0 0 0 rgba(229,57,53,.45); } 100% { box-shadow: 0 0 0 12px rgba(229,57,53,0); } }
.ov-panel[data-call="connecting"] .ov-callhd span::before { display: none; }
.ov-panel[data-call="ended"] .ov-callhd span::before { background: #9AA3AF; animation: none; }
/* language chip: a small translucent pill top-right, out of the way */
.ov-panel[data-panel="full"] .ov-lang {
  grid-area: unset; position: absolute; z-index: 3;
  top: calc(env(safe-area-inset-top, 0px) + 18px); right: 14px;
  background: rgba(255,255,255,.16); border-color: rgba(255,255,255,.28); color: #fff; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
/* live captions: white card, black text (MAK), sitting above the call bar */
.ov-panel[data-panel="full"] .ov-bubble {
  grid-area: unset; position: absolute; z-index: 3; left: 16px; right: 16px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 176px);
  max-height: 26vh; background: #fff; color: #111; border: 0; border-radius:var(--radius-lg);
  box-shadow: 0 10px 30px rgba(0,0,0,.35); font-size: 15px;
}
.ov-panel[data-panel="full"] .ov-countdown { bottom: auto; top: calc(env(safe-area-inset-top, 0px) + 22px); left: 14px; right: auto; }
/* "Calling your waiter…": the ringing screen, her face soft behind a blur */
.ov-panel[data-panel="full"] .ov-calling {
  inset: 0; border-radius:0; border: 0; z-index: 2;
  background: rgba(6,10,22,.5); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  color: #fff; font-size: 17px; letter-spacing: .01em; align-items: flex-end; padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 200px);
}
/* ---- the call bar: four round buttons with labels, fixed to the bottom ---- */
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-avatar-fab,
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-waiter-fab,
body:has(.ov-panel[data-panel="full"]:not([hidden])) .ov-menu-btn,
.ov-panel[data-panel="full"] .ov-close {
  grid-area: unset; position: fixed; top: auto; right: auto; z-index: 62;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 44px);
  width: 62px; height: 62px; border-radius:var(--radius-full); flex: none; padding: 0; margin: 0;
  display: flex; align-items: center; justify-content: center; font-size: 25px; line-height: 1;
  background: rgba(255,255,255,.16); border: 1px solid rgba(255,255,255,.22); color: #fff;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); box-shadow: 0 10px 24px rgba(0,0,0,.35);
}
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-avatar-fab:active,
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-waiter-fab:active,
body:has(.ov-panel[data-panel="full"]:not([hidden])) .ov-menu-btn:active,
.ov-panel[data-panel="full"] .ov-close:active { transform: scale(.93); }
/* labels under each button, from data-label so order.js can switch them to Arabic */
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-avatar-fab::after,
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-waiter-fab::after,
body:has(.ov-panel[data-panel="full"]:not([hidden])) .ov-menu-btn::after,
.ov-panel[data-panel="full"] .ov-close::after {
  content: attr(data-label); position: absolute; top: calc(100% + 7px); left: 50%; transform: translateX(-50%);
  width: 96px; text-align: center; font-family: var(--ui); font-size: 11.5px; font-weight: 500; letter-spacing: .01em;
  color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.6); pointer-events: none; white-space: nowrap;
}
/* four slots on centres -150 / -50 / +50 / +150 px (left = centre minus half the width) */
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-waiter-fab { left: calc(50% - 181px); }
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-avatar-fab {
  left: calc(50% - 86px); bottom: calc(env(safe-area-inset-bottom, 0px) + 40px);
  width: 72px; height: 72px; font-size: 30px; background: var(--go); border-color: rgba(255,255,255,.35);
  box-shadow: 0 0 0 6px rgba(47,127,91,.22), 0 14px 28px -6px rgba(0,0,0,.6);
}
/* while recording the base green pulse shows through (the 🔴 glyph, the red header dot and the
   "Tap when done" pill already say recording; a red circle next to the red End would say hang up);
   dimmed whenever a tap does nothing, so green means "a tap does something" */
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-avatar-fab[data-mode="thinking"],
body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-avatar-fab[data-mode="speaking"] { opacity: .7; }
body:has(.ov-panel[data-panel="full"]:not([hidden])) .ov-menu-btn { left: calc(50% + 19px); }
.ov-panel[data-panel="full"] .ov-close { left: calc(50% + 123px); width: 54px; height: 54px; font-size: 19px; background: var(--stop); border-color: rgba(255,255,255,.3); }
/* narrow phones: pull the outer two in a little */
@media (max-width: 380px) {
  body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-waiter-fab { left: calc(50% - 171px); }
  body:has(.ov-panel[data-panel="full"]:not([hidden])) .order-avatar-fab { left: calc(50% - 83px); }
  body:has(.ov-panel[data-panel="full"]:not([hidden])) .ov-menu-btn { left: calc(50% + 16px); }
  .ov-panel[data-panel="full"] .ov-close { left: calc(50% + 113px); }
}
/* the turn-taking pill sits centred above the bar instead of by the old corner mic */
body:has(.ov-panel[data-panel="full"]:not([hidden])) .mic-hint {
  left: calc(50% - 50px); transform: translateX(-50%); bottom: calc(env(safe-area-inset-bottom, 0px) + 128px); z-index: 63; /* centred over the mic slot */
  background: rgba(255,255,255,.94); color: #111; border: 0; box-shadow: 0 6px 18px rgba(0,0,0,.35);
}
body:has(.ov-panel[data-panel="full"]:not([hidden])) .mic-hint[data-kind="turn"] { color: var(--go); }
.ov-menu-btn span { display: none; } /* the label comes from data-label now, like the other three */
/* Hidden outside data-panel="full" — the banner grid above has no area for it, so this element
   only ever renders while the rules above turn it back on. */
.ov-menu-btn { display: none; }
.ov-menu-btn[hidden] { display: none; }
/* Her face is the door back to full screen while the banner's up — see order.js's click handler
   on #ovPanel, which checks for a tap on .ov-face specifically while data-panel="menu". */
.ov-panel[data-panel="menu"] .ov-face { cursor: pointer; }

/* Unsaved-changes marker in the screen editor header — screen edits are a draft until Save. */
.screen-dirty{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--stop);border:1px solid var(--stop);border-radius:var(--radius-full);padding:2px 8px;margin-left:8px;vertical-align:middle}

/* ---------- Screen Layout editor (Admin) ----------
   A working copy of the till grid: same auto-fill columns and tile proportions as .grid/.tile in
   the POS, so what's arranged here is what the kitchen-facing screen actually shows. Every cell
   is draggable; a "gap" is a real entry that holds its place and renders as nothing on the till. */
.layout-grid{display:grid;gap:10px;grid-template-columns:repeat(5,1fr);padding:12px;background:var(--shell);border:1px solid var(--line);border-radius:var(--r);max-height:62vh;overflow-y:auto}
.layout-cell{position:relative;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:12px;min-height:96px;display:flex;flex-direction:column;justify-content:space-between;cursor:grab}
.layout-cell:active{cursor:grabbing}
.layout-cell:hover{border-color:var(--brass)}
.layout-cell .nm{font-size:13px;line-height:1.25}
.layout-cell .pr{font-family:var(--mono);font-size:12px;color:var(--brass)}
.layout-num{position:absolute;top:6px;left:8px;font-family:var(--mono);font-size:10px;color:var(--text-dim)}
.layout-cell.tile-addon{border-style:dashed}
/* An empty cell — a drop target, nothing more. No content, no controls, nothing to drag out. */
.layout-empty{background:transparent;border-style:dashed;border-color:var(--line);cursor:default}
.layout-empty:hover{border-color:var(--brass);background:rgba(201,162,39,.06)}
.layout-x{position:absolute;top:4px;right:4px;width:22px;height:22px;border-radius:var(--radius-md);background:var(--panel-2);border:1px solid var(--line);color:var(--text-dim);font-size:11px;line-height:1;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .12s}
.layout-cell:hover .layout-x{opacity:1}
.layout-x:hover{border-color:var(--stop);color:var(--stop)}
/* The read-only preview shows gaps too, so it matches what Layout arranged. */
.snap-blank{background:repeating-linear-gradient(45deg,transparent,transparent 5px,rgba(255,255,255,.05) 5px,rgba(255,255,255,.05) 10px);border-style:dashed}
/* The till's own empty cell — holds its place, shows nothing, ignores taps. */
.tile-blank{background:transparent;border:1px dashed transparent;pointer-events:none}

/* The Layout editor runs at till proportions so what's arranged is what staff see. */
.modal-wide{max-width:990px}

/* Photos in the layout editor, so arranging a screen looks like the screen being arranged. */
.layout-cell.has-photo{padding-top:8px}
.layout-img{width:100%;height:56px;object-fit:cover;border-radius:var(--radius-md);display:block;margin-bottom:6px;background:var(--panel-2);flex:0 0 auto}

/* ---------- on screen keyboard (osk.js, the till only) ---------- */
#osk{position:fixed;left:0;right:0;bottom:0;z-index:60;background:var(--panel);border-top:1px solid var(--line);padding:6px 8px calc(8px + env(safe-area-inset-bottom,0px));box-shadow:0 -12px 30px rgba(0,0,0,.35);user-select:none;-webkit-user-select:none;touch-action:manipulation}
#osk .osk-bar{display:flex;justify-content:space-between;align-items:center;padding:0 4px 4px;font-size:12px;color:var(--text-dim)}
#osk .osk-close{background:transparent;border:1px solid var(--line);color:var(--text);border-radius:var(--radius-md);min-width:44px;min-height:30px;font-size:16px;cursor:pointer}
#osk .osk-row{display:flex;justify-content:center;gap:6px;margin:4px 0}
#osk .osk-key{flex:1 1 0;max-width:72px;min-height:48px;background:var(--panel-2);color:var(--text);border:1px solid var(--line);border-radius:var(--radius-md);font:500 19px/1 var(--sans, system-ui);cursor:pointer;padding:0}
#osk .osk-key:active{background:var(--brass);color:#fff}
#osk .osk-shift,#osk .osk-backspace,#osk .osk-sym,#osk .osk-abc,#osk .osk-lang{flex:1.5 1 0;max-width:110px;font-size:15px;color:var(--text-dim)}
#osk .osk-shift.on{background:var(--brass);color:#fff}
#osk .osk-space{flex:6 1 0;max-width:none}
#osk .osk-enter{flex:1.5 1 0;max-width:110px;background:var(--brass);color:#fff}
@media (max-width:700px){#osk .osk-key{min-height:42px;font-size:17px;max-width:none}}

/* ---------- first run screen: the country form inside the login card (17 Sep 2026) ---------- */
.country-card .a-field{text-align:left}
.country-card .a-hint{text-align:left;font-size:12.5px;color:var(--text-dim);margin:0 0 12px}
.country-card .a-formerr:empty{display:none}
.country-card .a-field label input[type=checkbox]{margin-right:8px;vertical-align:middle}
.country-card .a-field > label:has(input[type=checkbox]){text-transform:none;letter-spacing:0;font-size:13px;color:var(--text)}

/* KSA Phase 1: the ZATCA QR on the guest check drill view */
.a-zatca{display:flex;align-items:center;gap:14px;margin:8px 0 12px}
.a-zatca svg{width:120px;height:120px;flex:none;background:#fff;border-radius:var(--radius-md)}

/* KSA Phase 2: the E invoicing tab */
.a-card{max-width:820px;padding:16px 18px;margin:0 0 16px;border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--panel)}
.a-card h3{margin:0 0 8px;font-size:15px}
.a-ok{padding:10px 12px;border-radius:var(--radius-md);background:rgba(46,125,50,.12);border:1px solid #2e7d32;font-size:12.5px;margin-bottom:12px}
@media (max-width:1200px){.a-quick{grid-template-columns:1fr}.a-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}.a-home-cols{grid-template-columns:1fr}}
/* ===== Menu table and side panel (redesign step 7a, board BohMenu, 21 Sep 2026) ===== */
.a-filters{display:flex;align-items:center;gap:10px;margin-bottom:16px;flex-wrap:wrap}
.a-page-search input.search{width:300px}
.filt-select{white-space:nowrap;height:32px;padding:0 28px 0 10px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-raised);font:inherit;font-size:13px;font-weight:500;color:var(--ink);appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235a6577' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;background-size:16px;cursor:pointer}
.filt-select.on{border-color:var(--brand);background-color:var(--brand-soft);color:var(--brand)}
.a-filters-count{margin-left:auto;font-size:13px;color:var(--ink-muted);white-space:nowrap}
.a-range-row{padding:12px 16px;background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);align-items:flex-end}
.a-range-row .fld{width:120px}
.a-table-panel{overflow:visible}
.a-table tr.clickable{cursor:pointer}
.a-table tr.clickable:hover td{background:var(--surface)}
.a-table tr.sel td{background:var(--brand-soft);box-shadow:inset 3px 0 0 var(--brand)}
.a-table tr.inactive td{opacity:.55}
.a-table td.nowrap{white-space:nowrap}
.a-table td.a-ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:0}
.a-table{table-layout:fixed}
.a-table-panel{overflow:auto}
.a-headbtns{display:flex;gap:8px;align-items:center;flex-wrap:wrap;justify-content:flex-end}
.a-headbtns .btn{flex:0 0 auto}
.a-headbtns .seg{flex:0 0 auto}
.a-pull-pane{display:flex;flex-direction:column;gap:10px;flex:1;min-height:0}
.a-pull-search input.search{width:100%}
.a-pull-tools{display:flex;align-items:center;justify-content:space-between;gap:8px}
.a-pull-table td{padding:8px 10px}
.a-pull-table tr.sel td{background:var(--brand-soft);box-shadow:none}
.modal.side .a-pull-pane .a-table-panel{flex:1;min-height:0;overflow:auto}
.modal.side .a-pull-pane{padding-bottom:12px}
/* BohScreens (redesign 7d): list left in rail order, editor right with the till preview inline. */
.a-screens{display:grid;grid-template-columns:var(--split,300px) 12px minmax(0,1fr);gap:16px;align-items:start}
.a-screens-list{position:sticky;top:0}
.a-screens-rows{min-height:0;overflow-y:auto}
.a-screen-row{display:flex;align-items:center;gap:10px;padding:10px 12px 10px 16px;border-bottom:1px solid var(--line);cursor:pointer;position:relative;min-height:52px}
.a-screen-row:last-child{border-bottom:0}
.a-screen-row:hover{background:var(--surface-sunken)}
.a-screen-row.sel{background:var(--brand-soft)}
.a-screen-row.sel::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--brand)}
.a-screen-row.inactive .a-cell-stack{opacity:.55}
.a-screen-row .a-cell-stack{flex:1;min-width:0}
.a-screen-row .a-cell-stack b{overflow:hidden;text-overflow:ellipsis}
.a-screen-row .a-screen-meta{font-size:12px;color:var(--ink-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-screen-row .a-screen-name{display:flex;align-items:baseline;gap:8px;min-width:0}
.a-screen-row .a-screen-name .ar{font-weight:400;color:var(--ink-muted);direction:rtl;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.a-screen-grip{color:var(--ink-faint);display:inline-flex;flex:0 0 16px;cursor:grab}
.a-screen-row.sub .a-screen-grip{cursor:default}
.a-screen-grip svg{width:16px;height:16px}
.a-screen-fold{color:var(--ink-muted);min-height:32px;flex:0 0 32px;width:32px}
.a-screen-row .a-rowmenu-btn{opacity:0}
.a-screen-row:hover .a-rowmenu-btn,.a-screen-row.sel .a-rowmenu-btn{opacity:1}
.a-screens-editor{padding:20px}
.a-screens-empty{padding:48px 20px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:8px}
.a-screens-empty b{font-size:16px}
.a-screens-empty p{margin:0 0 8px;color:var(--ink-muted);font-size:13px}
.a-screens-empty .btn{width:auto}
.a-screens-ed-head{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.a-crumbs{display:flex;align-items:center;gap:6px;min-width:0;flex-wrap:wrap}
.a-crumbs h3{margin:0;font-size:22px;line-height:28px;font-weight:600;font-stretch:80%;letter-spacing:-.01em;white-space:nowrap}
.a-crumbs h3 .ar{font-size:15px;font-weight:500;color:var(--ink-muted);direction:rtl;display:inline-block;margin-left:6px}
.a-crumb-sep{color:var(--ink-faint);display:inline-flex}
.a-crumb-sep svg{width:14px;height:14px}
.a-screens-ed-sub{display:flex;align-items:center;gap:10px;margin:10px 0 16px;flex-wrap:wrap}
.a-screens-photo{display:flex;gap:14px;align-items:flex-start;margin:0 0 16px;padding:12px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-sunken)}
.a-screens-photo .mp-photo-actions .btn{width:auto}
.a-preview-label{display:flex;align-items:baseline;gap:10px;margin-bottom:8px;font-size:13px;font-weight:600}
.a-preview-label .a-meta{font-weight:400}
.a-till-grid{max-height:none;background:var(--surface-sunken);border-radius:var(--radius-md);grid-template-columns:repeat(5,minmax(0,1fr))}
.a-till-grid .layout-cell{border-radius:var(--radius-md);background:var(--surface-raised);min-height:88px;padding:10px 12px}
.a-till-grid .layout-cell .nm{font-size:13px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.a-till-grid .layout-cell .pr{font-size:12px;margin-top:6px}
.a-till-grid .layout-cell.tile-screen .pr{color:var(--brand);font-weight:600}
.a-till-grid .layout-empty{border:1px dashed var(--line-strong);background:transparent;display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink-faint)}
.a-till-grid .layout-empty:hover{border-color:var(--brand);background:var(--brand-soft);color:var(--brand)}
.a-till-grid .layout-x{opacity:0;width:22px;height:22px;top:4px;right:4px;background:var(--surface-raised);border-color:var(--line);align-items:center;justify-content:center;padding:0;cursor:pointer}
.a-till-grid .layout-x svg{width:12px;height:12px}
.a-till-grid .layout-cell:hover .layout-x{opacity:1}
.a-till-grid .layout-x:hover{border-color:var(--danger);color:var(--danger)}
.layout-open{position:absolute;top:4px;right:4px;height:22px;padding:0 8px;border-radius:var(--radius-sm);background:var(--surface-raised);border:1px solid var(--line);color:var(--brand);font:inherit;font-size:11px;font-weight:600;opacity:0;cursor:pointer}
.a-till-grid .layout-cell:hover .layout-open{opacity:1}
.a-not-on{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:14px}
.a-not-on .filt .a-mono{color:var(--ink-muted);font-size:12px}
.a-not-on .btn{width:auto}
.a-pick-ranges{display:flex;flex-direction:column;gap:4px}
.a-pick-ranges .screen-pick-range{margin:0}
.a-pick-ranges .btn{width:auto}
.a-pull-table td.a-mono{font-size:12px;color:var(--ink-muted)}
.a-pull-table tr.a-row-disabled td{opacity:.55}
.a-pick-table-wrap{flex:1;min-height:0;overflow:auto}
/* .pane.on wins over .a-pull-pane on specificity, so the picker panes (Add from catalogue, Add
   items) say it again: a column that fills the panel and scrolls its own table, never the panel. */
.modal.side .a-pull-pane.pane.on{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden}
.a-cell-stack{display:flex;flex-direction:column}
.a-cell-stack b{font-weight:600;white-space:nowrap}
.a-cell-stack .ar{font-size:13px;color:var(--ink-muted);white-space:nowrap;text-align:left;direction:rtl;display:inline-block}
.ph-img{width:40px;height:40px;border-radius:var(--radius-sm);object-fit:cover;display:block;background:var(--surface-sunken)}
.ph-img.inherited{opacity:.6}
.noph{width:40px;height:40px;border-radius:var(--radius-sm);border:1px dashed var(--line-strong);box-sizing:border-box;display:flex;align-items:center;justify-content:center;color:var(--line-strong)}
.noph svg{width:18px;height:18px}
.a-rowmenu-cell{width:44px;text-align:right}
.a-table td.a-rowmenu-cell{padding:0 6px 0 0}
.a-rowmenu-btn{color:var(--ink-muted);min-height:32px;flex:0 0 32px;width:32px}
.modal.rowmenu{width:200px;max-width:200px;padding:6px;border-radius:var(--radius-md);box-shadow:0 8px 24px -4px rgba(24,35,56,.16),0 2px 6px rgba(24,35,56,.08);background:var(--surface-raised)}
.a-rowmenu-item{display:block;width:100%;text-align:left;padding:9px 12px;border-radius:var(--radius-sm);font-size:14px;font-weight:500;color:var(--ink);background:none;border:0;font-family:inherit;cursor:pointer}
.a-rowmenu-item:hover{background:var(--surface-sunken)}
.a-rowmenu-item.danger{color:var(--danger)}
.a-rowmenu-item:disabled{opacity:.4;cursor:default}
.a-kpis-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.tile-k .v.a-success{color:var(--success)}
.tile-k .v.a-danger{color:var(--danger)}
.a-mono{font-family:ui-monospace,Consolas,monospace;font-size:13px}
.a-classes-strip{display:grid;grid-template-columns:repeat(3,minmax(0,1fr))}
.a-classes-strip .a-prow{border-right:1px solid var(--surface-sunken)}
.a-classes-strip .a-prow:nth-child(3n){border-right:0}
.a-person{display:flex;align-items:center;gap:10px}
.a-person .avatar{width:28px;height:28px;font-size:12px}
.a-cell-stack span{font-size:13px;color:var(--ink-muted);white-space:nowrap}
.a-callout{background:var(--brand-soft);border-radius:var(--radius-md);padding:12px 14px;font-size:13px;line-height:18px;color:var(--brand);margin:4px 0 16px}
.a-panel-head-line{border-bottom:1px solid var(--line);padding-bottom:16px;margin-bottom:16px}
/* the side panel head: photo, eyebrow, title, close */
.modal.side{max-width:440px;width:min(440px,100%)}
.a-panel-head{display:flex;align-items:flex-start;gap:12px;padding:20px 20px 8px}
.a-panel-head img,.a-panel-head .noph{width:56px;height:56px;border-radius:var(--radius-md);object-fit:cover;flex:0 0 56px}
.a-panel-title{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.a-panel-title h2{margin:0;font-size:20px;line-height:28px;font-weight:600;font-stretch:80%;letter-spacing:-.01em;white-space:normal}
.modal.side .pane{display:none;padding:0 20px}
.modal.side .pane.on{display:block}
.modal.side .pane .a-field,.modal.side .pane .mgroup,.modal.side .pane .a-hint,.modal.side .pane .a-formerr,.modal.side .pane .a-row2{margin-left:0;margin-right:0}
.modal.side>.a-field,.modal.side>.mgroup,.modal.side>.a-hint,.modal.side>.a-formerr,.modal.side>.a-row2{margin-left:20px;margin-right:20px}
.modal.side .panel-tabs{margin:4px 0 16px}
/* Printers table (redesign lane check, 21 Sep 2026): never wider than its panel, whatever the names. */
.a-printers-table{table-layout:fixed;width:100%;max-width:100%}
.a-printers-table td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.a-printers-table td.a-rowmenu-cell{overflow:visible}
.a-printers-table th{overflow:hidden;text-overflow:ellipsis}

/* ================= The till order screen (redesign, TillOrder board, 21 Sep 2026) =================
   The top bar, the 96px screen rail, the menu with its head, the cheque column with the tabs on
   top and the panel under them. Appended after the older till rules so it wins on order; the
   phone layout under 880px keeps its own rules further up. */
@media (min-width:881px){
.topbar{height:52px;padding:0 16px;gap:10px;background:var(--surface-raised);border-bottom:1px solid var(--line);align-items:center}
.topbar .brand{flex:0 0 auto}
.topbar .btn.sm{width:auto;flex:0 0 auto;height:32px;padding:0 12px;font-size:13px}
.topbar .btn.sm svg{width:16px;height:16px}
.topbar .btn[hidden]{display:none}
.session-bar{display:none}
/* the rail */
.cats-col{flex:0 0 96px;width:96px;max-width:96px;min-width:0;overflow:hidden;background:var(--surface-raised);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0;padding:8px 6px 8px}
.cats,.cats-col .cats{flex:1;padding:0;gap:6px;border-right:0;background:transparent;overflow-y:auto;min-height:0}
.cats-col #cats .cat{white-space:nowrap;display:flex;flex-direction:column;justify-content:center;min-height:40px;padding:5px 8px;border-radius:var(--radius-md);font-size:13px;line-height:16px;font-weight:600;color:var(--ink);overflow:hidden;border:0;text-align:left;background:transparent}
.cats-col #cats .cat small{font-size:11px;line-height:14px;font-weight:400;color:var(--ink-muted);text-align:left;opacity:1;margin-top:0;display:block;direction:rtl;overflow:hidden;text-overflow:ellipsis}
.cats-col #cats .cat:hover{background:var(--surface-sunken)}
.cats-col #cats .cat.on{background:var(--brand);color:var(--on-brand);box-shadow:inset 3px 0 0 var(--brand-strong)}
.cats-col #cats .cat.on small{color:#c9d4ee}
/* the menu */
.menu{flex:1;min-width:0;display:flex;flex-direction:column;padding:14px 16px 16px;gap:12px;min-height:0}
.menu .grid{flex:1;min-height:0;padding:0;gap:12px;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));grid-auto-rows:min-content;align-content:start;overflow-y:auto;background:transparent;border:0}
/* the cheque column */
.check-col{flex:0 0 var(--split,420px);width:var(--split,420px);display:flex;flex-direction:column;padding:14px 16px 16px 0;min-height:0;background:transparent;border:0;z-index:auto}
.cheque-tabs{flex:0 0 auto;display:flex;flex-direction:row;flex-wrap:wrap;gap:6px;align-items:flex-end;padding:0 0 0 4px;background:transparent;overflow:visible;min-height:0;position:static;width:auto;height:auto;border:0}
.check{position:static;flex:1;min-height:0;width:auto;max-width:none;background:var(--surface-raised);color:var(--ink);border:1px solid var(--line);border-radius:0 var(--radius-md) var(--radius-md) var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);display:flex;flex-direction:column;transform:none;transition:none;overflow:hidden}
.check.open{transform:none}
.check.folded .lines,.check.folded .totals{display:none}
}
/* The till look shared by every width (the layout above is desktop only, the handheld block below overrides it). */
.top-outlet{font-size:15px;line-height:20px;font-weight:700;font-stretch:80%;letter-spacing:-.01em;white-space:nowrap}
.top-spacer{flex:1 1 auto;min-width:8px}
.filt.static{cursor:default}
.filt.static svg{width:16px;height:16px}
.filt.user{gap:8px}
.filt.user .avatar{width:20px;height:20px;font-size:11px}
.top-chip{white-space:nowrap;display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border-radius:var(--radius-sm);font-size:13px;line-height:16px;font-weight:600}
.top-chip i{width:6px;height:6px;border-radius:var(--radius-full);background:currentColor;display:inline-block}
.top-chip.ok{background:var(--success-soft);color:var(--success)}
.top-chip.bad{background:var(--danger-soft);color:var(--danger)}
.top-clock{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
.sys-row{display:flex;flex-direction:column;gap:6px;align-items:center;padding-top:8px;border-top:1px solid var(--line);margin-top:6px}
.sys{width:44px;height:44px;border-radius:var(--radius-md);border:1px solid var(--line);background:var(--surface-raised);color:var(--ink-muted);display:flex;align-items:center;justify-content:center;padding:0;cursor:pointer}
.sys:hover{border-color:var(--line-strong);color:var(--ink)}
.sys[hidden]{display:none}
.sys svg{width:20px;height:20px}
.grid-head{display:flex;align-items:center;gap:12px;flex:0 0 auto}
.grid-head h2{margin:0;font-size:20px;line-height:28px;font-weight:600;font-stretch:80%;letter-spacing:-.01em;white-space:nowrap;display:flex;align-items:baseline;gap:8px}
.grid-head h2 .ar{font-size:16px;font-weight:400;color:var(--ink-muted);direction:rtl}
.grid-head .lbl{white-space:nowrap}
.grid-search{position:relative;display:flex;align-items:center;flex:0 0 auto}
.grid-search svg{position:absolute;left:12px;width:18px;height:18px;color:var(--ink-muted);pointer-events:none}
.grid-search input{height:44px;width:260px;padding:0 12px 0 38px;border:1px solid var(--line-strong);border-radius:var(--radius-md);font:inherit;font-size:15px;color:var(--ink);background:var(--surface-raised)}
.menu .tile{background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);padding:0;overflow:hidden;display:flex;flex-direction:column;justify-content:flex-start;text-align:left;cursor:pointer;font:inherit;color:inherit;position:relative;min-height:0}
.menu .tile:active{transform:scale(.98);border-color:var(--brand)}
.menu .tile .tile-img{width:100%;height:112px;object-fit:cover;display:block;margin:0;border-radius:0}
.menu .tile .nm{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:14px;line-height:20px;font-weight:500;padding:8px 10px 0;margin:0}
.menu .tile .nar{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:12px;line-height:18px;color:var(--ink-muted);padding:0 10px;margin:0;text-align:left;direction:rtl}
.menu .tile .pr{white-space:nowrap;font-size:14px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;color:var(--brand);padding:4px 10px 10px;margin:0;font-family:var(--ui)}
.menu .tile:not(:has(.tile-img)) .nm{padding-top:12px}
.menu .tile:not(:has(.tile-img)){min-height:96px}
.menu .tile .flag{position:absolute;top:8px;left:8px;z-index:1;height:22px;padding:0 8px;border-radius:var(--radius-sm);background:var(--ink);color:var(--surface);font-size:11px;line-height:22px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;border:0;right:auto}
.menu .tile-screen .pr,.menu .tile-back .pr{color:var(--brand)}
.menu .tile-back{background:var(--surface-sunken);border-style:dashed}
.menu .tile-addon{border-style:dashed;border-color:var(--line-strong)}
.menu .tile-addon .nm::before{content:none}
.menu .tile-blank{background:transparent;border:1px dashed transparent;box-shadow:none;pointer-events:none}
.tab{white-space:nowrap;display:inline-flex;align-items:center;gap:6px;height:40px;padding:0 14px;border-radius:var(--radius-md) var(--radius-md) 0 0;font:inherit;font-size:14px;font-weight:600;background:var(--surface-sunken);color:var(--ink-muted);border:1px solid var(--line);border-bottom:0;cursor:pointer;position:relative;margin-bottom:-1px}
.tab.on{background:var(--surface-raised);color:var(--ink);z-index:2}
.tab.new{background:var(--brand);color:var(--on-brand);border-color:var(--brand)}
.tab.new svg{width:16px;height:16px}
.tab.overdue{background:var(--danger);border-color:var(--danger);color:#fff;animation:overdue-pulse 1.6s ease-in-out infinite}
.tab.overdue.on{background:var(--danger);color:#fff}
.tab.locked{opacity:.55}
.tab .tab-pax{font-weight:500;color:var(--ink-muted)}
.tab.on .tab-pax{color:var(--ink-muted)}
.tab.new .tab-pax,.tab.overdue .tab-pax{color:inherit;opacity:.8}
.tab .cq-lock{display:inline-flex;margin-left:2px;position:static;font-size:inherit}
.tab.closed{border-radius:var(--radius-md);border-bottom:1px solid var(--line);height:36px;margin-bottom:2px}
.cheque-tabs .top-spacer{flex:1 1 auto;min-width:6px}
.check-hd{padding:14px 16px 10px;border-bottom:1px solid var(--line);display:flex;align-items:flex-start;justify-content:space-between;gap:8px}
.check-hd-main{display:flex;flex-direction:column;gap:2px;min-width:0}
.check-hd b#checkTitle{font-size:17px;line-height:24px;font-weight:600;font-stretch:80%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.check-hd-sub{display:flex;gap:6px;font-size:13px;line-height:18px;color:var(--ink-muted);white-space:nowrap;font-family:var(--ui);opacity:1}
.check-hd-sub>span{opacity:1;font-family:var(--ui);font-size:13px}
.check-hd-sub>span:empty{display:none}
.check-hd-sub>span+span:not(:empty)::before{content:"· ";}
.check-hd-chips{display:flex;gap:6px;flex-wrap:wrap;margin-top:6px;opacity:1}
.check-hd-chips:empty{display:none}
.check-hd .check-pax{font-family:var(--ui);font-size:12px;font-weight:600;height:22px;padding:0 8px;border-radius:var(--radius-sm);background:var(--surface-sunken);border:0;color:var(--ink-muted);opacity:1}
.check-hd .check-pax:hover{color:var(--brand);background:var(--brand-soft)}
.check-hd .check-overdue-btn{font-family:var(--ui);font-size:12px;font-weight:600;height:22px;padding:0 8px;border-radius:var(--radius-sm);background:var(--warning-soft);color:var(--warning);border:0}
.check-hd .btn.icon{width:36px;height:36px;flex:0 0 36px;color:var(--ink-muted)}
.check .lines{flex:1;overflow-y:auto;padding:0}
.check .empty{padding:40px 16px;text-align:center;font-size:14px;color:var(--ink-muted);line-height:1.6}
.check .ln{display:grid;grid-template-columns:36px minmax(0,1fr) auto;column-gap:10px;padding:10px 16px;border-bottom:1px solid var(--surface-sunken);align-items:start;border-radius:0;cursor:pointer}
.check .ln:hover{background:var(--surface)}
.check .ln:active{background:var(--surface-sunken)}
.check .ln.sent{opacity:1}
.check .ln.sent .ln-n::after{content:none}
.check .ln.sent .ln-ctl button:not(.rm){display:none}
.check .ln-q{width:36px;height:28px;border-radius:var(--radius-sm);border:1px solid var(--line-strong);display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:500;font-variant-numeric:tabular-nums;flex:none}
.check .ln-body{min-width:0}
.check .ln-n{font-size:14px;line-height:20px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:var(--ui)}
.check .ln-sub,.check .ln-rem,.check .ln-note{margin:0;font-size:13px;line-height:18px;color:var(--ink-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-style:normal}
.check .ln-rem{color:var(--danger);font-weight:600}
.check .ln-unsent{color:var(--warning);font-weight:600}
.check .ln-alg{margin:2px 0 0;font-size:11px;color:var(--danger);background:var(--danger-soft);display:inline-block;padding:0 6px;border-radius:var(--radius-sm);line-height:18px;font-weight:600}
.check .ln-comp{color:var(--success)}
.check .ln-p{font-size:15px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap;padding-top:4px}
.check .ln-ctl{grid-column:2;display:flex;gap:6px;margin:6px 0 0}
.check .ln-ctl button{width:28px;height:28px;border-radius:var(--radius-sm);background:var(--surface-sunken);color:var(--ink);font-size:16px;font-weight:600;border:0}
.check .ln-ctl button.rm{margin-left:auto;background:transparent;color:var(--danger);width:auto;padding:0 6px;font-size:12px}
.check .ln-extracharge{cursor:default;color:var(--success)}
.check .ln-extracharge .ln-n,.check .ln-extracharge .ln-p{font-style:normal;color:var(--success)}
.check .ln-extracharge .ln-q{border-color:transparent}
.check .totals{padding:10px 16px 12px;border-top:1px solid var(--line);font-family:var(--ui);font-size:14px;line-height:20px;color:var(--ink-muted);display:flex;flex-direction:column;gap:2px}
.check .tr{padding:0;font-variant-numeric:tabular-nums}
.check .tr.grand{font-size:15px;font-weight:600;color:var(--ink);padding-top:0;margin-top:4px;border-top:0;align-items:baseline}
.check .tr.grand span:last-child{font-size:21px;line-height:30px;font-weight:700;font-stretch:80%;letter-spacing:-.015em}
.check .tr.alt{justify-content:flex-end;opacity:1;font-size:14px}
.check .pay{padding:0 16px 14px;display:flex;flex-direction:column;gap:10px}
.check .pay-main{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.check .pay-main .btn{width:100%;height:56px;font-size:17px;padding:0 12px}
.check .btn.outline{background:var(--surface-raised);border:1px solid var(--brand);color:var(--brand)}
.check .btn.outline:disabled{border-color:var(--line);color:var(--ink-faint);background:var(--surface-raised)}
.check .pay-main .btn svg{width:20px;height:20px}
.check .pay-row{display:flex;gap:6px}
.check .pay-row .btn.sm{flex:1;height:36px;padding:0 8px;font-size:13px;border-color:var(--line);color:var(--ink-muted);font-weight:600}
.check .pay-row .btn.sm:hover{color:var(--ink);border-color:var(--line-strong)}
.check .pay-row .btn.sm.danger{color:var(--danger)}
.check .pay-row .btn[hidden]{display:none}
.check .pay-row[hidden]{display:none}
.check .btn.needs-send{opacity:.6}
/* The dialogs (redesign): a 10px card with a head, a body and a foot, no padding of its own. */
.modal.dlg{padding:0;max-width:560px;background:var(--surface-raised);backdrop-filter:none;border-radius:var(--radius-lg);box-shadow:0 8px 24px -4px rgba(24,35,56,.16),0 2px 6px rgba(24,35,56,.08);display:flex;flex-direction:column;overflow:hidden}
.dlg-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:20px 24px 12px}
.dlg-title{font-size:20px;line-height:28px;font-weight:600;font-stretch:80%;letter-spacing:-.01em;white-space:nowrap}
.dlg-head .btn.icon{width:36px;height:36px;flex:0 0 36px;color:var(--ink-muted)}
.dlg-foot{display:flex;gap:10px;padding:14px 24px 20px;border-top:1px solid var(--line)}
.dlg-foot .btn{width:auto;flex:0 0 auto;height:56px;font-size:17px;padding:0 18px}
.dlg-foot .btn.primary{flex:1 1 auto}
.dlg-table-body{padding:0 24px 16px;display:grid;grid-template-columns:minmax(0,1fr) 200px;gap:20px}
.dlg-table-num{display:flex;flex-direction:column;gap:12px}
.dlg-readout{background:var(--surface-sunken);border:1px solid var(--line);border-radius:var(--radius-md);padding:10px 14px;display:flex;flex-direction:column;gap:2px}
.dlg-readout-v{font-size:40px;line-height:44px;font-weight:700;font-stretch:80%;font-variant-numeric:tabular-nums;min-height:44px}
.dlg-keys{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.dlg-keys .key{height:56px}
.dlg-keys .key svg{vertical-align:middle}
.dlg-table-pax{display:flex;flex-direction:column;gap:8px}
.dlg-pax-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.dlg-pax-grid .opt{height:48px;min-height:48px;justify-content:center;font:inherit;font-size:15px;font-weight:600;cursor:pointer}
.dlg-free{font-size:12px;line-height:18px;color:var(--ink-muted);white-space:normal}
.dlg-table-pax .fld input{height:40px}
/* The guests choices and every option in a redesigned dialog: 48px, the .opt look, no 30px modal override. */
.modal.dlg .opt{height:48px;min-height:48px;padding:0 14px;font-size:15px;line-height:20px;font-weight:600;font-family:inherit;cursor:pointer;border-radius:var(--radius-md);border:1px solid var(--line-strong);background:var(--surface-raised);color:var(--ink);display:inline-flex;align-items:center;justify-content:space-between;gap:10px;box-sizing:border-box;white-space:nowrap;overflow:hidden}
.modal.dlg .opt.on{border-color:var(--brand);background:var(--brand-soft);color:var(--brand);box-shadow:inset 0 0 0 1px var(--brand)}
.modal.dlg .opt.rem.on{border-color:var(--danger);background:var(--danger-soft);color:var(--danger);text-decoration:line-through;box-shadow:inset 0 0 0 1px var(--danger)}
.modal.dlg .opt small{font-size:13px;font-weight:500;color:var(--ink-muted);font-variant-numeric:tabular-nums;font-family:inherit;opacity:1}
.modal.dlg .opt.on small{color:var(--brand)}
.modal.dlg .opt .opt-nm{min-width:0;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:baseline;gap:6px}
.modal.dlg .opt .a{font-size:12px;color:var(--ink-muted);opacity:1;direction:rtl}
.modal.dlg .opt.on .a{color:var(--brand)}
/* TillOptions: the item sheet. */
.modal.dlg-opts{max-width:720px}
.dlg-item-head{display:flex;gap:16px;align-items:center;padding:20px 24px 14px;border-bottom:1px solid var(--line)}
.dlg-item-img{width:72px;height:72px;border-radius:var(--radius-md);object-fit:cover;flex:0 0 72px;background:var(--surface-sunken)}
.dlg-item-title{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.dlg-item-title .dlg-title{overflow:hidden;text-overflow:ellipsis}
.dlg-item-title .sub{font-size:15px;color:var(--ink-muted);direction:rtl;text-align:left}
.dlg-qty{display:flex;align-items:center;border:1px solid var(--line-strong);border-radius:var(--radius-md);overflow:hidden;flex:0 0 auto}
.dlg-qty button{width:48px;height:48px;border:0;background:var(--surface-raised);color:var(--ink);font:inherit;font-size:22px;font-weight:600;cursor:pointer;padding:0}
.dlg-qty button:active{background:var(--surface-sunken)}
.dlg-qty span{width:48px;text-align:center;font-size:18px;font-weight:600;font-variant-numeric:tabular-nums;border-left:1px solid var(--line);border-right:1px solid var(--line);height:48px;display:flex;align-items:center;justify-content:center}
.dlg-opts-body{padding:16px 24px;display:flex;flex-direction:column;gap:16px;overflow-y:auto;max-height:calc(88dvh - 220px)}
.dlg-sec{display:flex;flex-direction:column;gap:8px}
.dlg-sec-head{display:flex;align-items:center;gap:8px}
.dlg-opts{display:grid;gap:8px}
.dlg-opts.cols2{grid-template-columns:repeat(2,minmax(0,1fr))}
.dlg-opts.cols3{grid-template-columns:repeat(3,minmax(0,1fr))}
.dlg-opts .opt{height:52px;min-height:52px}
.dlg-note-btn{justify-content:flex-start;height:44px;color:var(--ink-muted);border-style:dashed;width:100%;font-weight:500}
.dlg-opts-body .noteBox{min-height:72px;background:var(--surface-raised);border:1px solid var(--line-strong);border-radius:var(--radius-sm);font:inherit;font-size:14px;color:var(--ink);padding:10px 12px}
.dlg-opts-body .allergy{background:var(--warning-soft);border:1px solid transparent;color:var(--warning);font-size:14px;font-weight:600;padding:10px 12px;border-radius:var(--radius-md);gap:10px}
.dlg-opts-body .allergy input{width:16px;height:16px;accent-color:var(--warning)}
/* TillPay: the payment as a full screen card. */
.modal.dlg-pay{max-width:calc(100vw - 32px);width:calc(100vw - 32px);max-height:calc(100dvh - 32px);height:calc(100dvh - 32px);background:var(--surface)}
.pay-top{height:52px;flex:0 0 52px;display:flex;align-items:center;gap:10px;padding:0 16px;background:var(--surface-raised);border-bottom:1px solid var(--line)}
.pay-top .btn{width:auto;height:36px;padding:0 12px;font-size:14px}
.pay-title{font-size:16px;line-height:20px;font-weight:600;font-stretch:80%;white-space:nowrap}
.pay-grid{flex:1;min-height:0;display:grid;grid-template-columns:400px minmax(0,1fr);gap:16px;padding:16px}
.pay-cheque{background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);display:flex;flex-direction:column;min-height:0;overflow:hidden}
.pay-ph{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px 10px;border-bottom:1px solid var(--line)}
.pay-ph h3{margin:0;font-size:16px;line-height:24px;font-weight:600;font-stretch:80%;white-space:nowrap}
.pay-ph .btn{width:auto}
.pay-lines{flex:1;min-height:0;overflow-y:auto}
.pay-ln{display:grid;grid-template-columns:32px minmax(0,1fr) auto;column-gap:10px;padding:9px 16px;border-bottom:1px solid var(--surface-sunken);align-items:start;font-size:14px;line-height:20px}
.pay-ln .q{font-weight:600;font-variant-numeric:tabular-nums}
.pay-ln .n{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pay-ln .m{font-size:13px;line-height:18px;color:var(--ink-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pay-ln .p{font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap}
.pay-tots{padding:12px 16px 14px;border-top:1px solid var(--line);display:flex;flex-direction:column;gap:2px;font-size:14px;line-height:20px;color:var(--ink-muted);font-variant-numeric:tabular-nums}
.pay-tots .tot{display:flex;justify-content:space-between}
.pay-tots .tot.alt{justify-content:flex-end}
.pay-total{display:flex;justify-content:space-between;align-items:baseline;margin-top:4px;color:var(--ink)}
.pay-total span:first-child{font-size:15px;font-weight:600}
.pay-total span:last-child{font-size:24px;line-height:28px;font-weight:700;font-stretch:80%;letter-spacing:-.015em}
.pay-tools{padding:0 16px 16px;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.pay-tools .btn{width:100%;height:40px;font-size:14px;padding:0 8px}
.pay-side{background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);display:flex;flex-direction:column;gap:10px;padding:14px 20px 14px;min-height:0;overflow:hidden}
.pay-due-row{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap}
.pay-due{display:flex;flex-direction:column;gap:2px;min-width:0}
.pay-due-v{font-size:48px;line-height:52px;font-weight:700;font-stretch:80%;letter-spacing:-.02em;font-variant-numeric:tabular-nums;white-space:nowrap}
.pay-due .sub{font-size:16px;font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--ink-muted)}
.pay-tip{display:flex;flex-direction:column;align-items:flex-end;gap:6px}
.pay-tip-opts{display:flex;gap:6px;align-items:center}
.pay-tip-opts .opt{height:44px;min-height:44px;min-width:64px;justify-content:center;padding:0 12px}
.pay-tip-in{height:44px;width:96px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 12px;font:inherit;font-size:15px;color:var(--ink);background:var(--surface-raised);text-align:right;font-variant-numeric:tabular-nums}
.pay-tip-note{font-size:13px;color:var(--ink-muted);min-height:18px}
.pay-seg{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));height:44px;width:100%}
.pay-seg>button{justify-content:center;font:inherit;font-size:14px;font-weight:600;cursor:pointer;height:100%}
.pay-seg>button svg{width:18px;height:18px}
.pay-tender{flex:1;min-height:0;display:flex;flex-direction:column;gap:10px}
.pay-inner{flex:1;min-height:0;display:flex;flex-direction:column;gap:10px}
.pay-cash-side .key.quick{height:56px;min-height:56px;padding:0 8px;font-size:16px;line-height:1;width:100%}
.pay-cash-side .key.quick.near{background:var(--brand-soft);border-color:var(--brand);color:var(--brand)}
.pay-retccy{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.pay-retccy .opt{height:44px;min-height:44px;justify-content:center}
.pay-cash{flex:1;min-height:0;display:grid;grid-template-columns:minmax(0,1fr) 200px;gap:16px}
.pay-cash-main{display:flex;flex-direction:column;gap:10px;min-height:0}
.pay-cash-side{display:flex;flex-direction:column;gap:8px;min-height:0}
.pay-readouts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.pay-readout{background:var(--surface-sunken);border:1px solid var(--line);border-radius:var(--radius-md);padding:10px 14px;display:flex;flex-direction:column;gap:2px;min-width:0}
.pay-readout.change{border-color:transparent}
.pay-readout.change.ok{background:var(--success-soft)}
.pay-readout.change.ok .lbl,.pay-readout.change.ok .pay-readout-v{color:var(--success)}
.pay-readout.change.bad{background:var(--danger-soft)}
.pay-readout.change.bad .lbl,.pay-readout.change.bad .pay-readout-v{color:var(--danger)}
.pay-readout-v{font-size:30px;line-height:36px;font-weight:700;font-stretch:80%;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pay-readout-v small{font-size:15px;font-weight:500}
.pay-readout-in{font-size:30px;line-height:36px;font-weight:700;font-stretch:80%;font-variant-numeric:tabular-nums;border:0;background:transparent;padding:0;width:100%;color:var(--ink);font-family:inherit;outline:none;min-height:36px}
.pay-readout-in::placeholder{color:var(--ink-faint)}
.pay-keys{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;flex:1;min-height:0;align-content:start}
.pay-keys .key{height:56px}
.pay-cash-side .key.quick{height:56px;font-size:16px}
.pay-cash-side .key.exact{border-color:var(--brand);color:var(--brand)}
.pay-cash-side .ret-row{display:grid;grid-template-columns:1fr;gap:8px}
.pay-cash-side .ret-row label{display:flex;flex-direction:column;gap:4px;font-size:12px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-muted)}
.pay-cash-side .ret-row input{height:40px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 12px;font:inherit;font-size:15px;color:var(--ink);background:var(--surface-raised);font-variant-numeric:tabular-nums;text-align:right}
.pay-cash-side #retOut{font-size:12px;line-height:16px;color:var(--ink-muted);padding:4px 0 0}
.pay-foot{display:grid;grid-template-columns:1fr;gap:10px;padding-top:4px}
.pay-foot .btn{width:100%;height:56px;font-size:17px}
.pay-note{font-size:14px;line-height:20px;color:var(--ink-muted);padding:10px 14px;background:var(--surface-sunken);border-radius:var(--radius-md)}
.pay-note b{color:var(--ink)}
.dlg-pay .tender{display:flex;flex-direction:column;gap:10px}
.dlg-pay .mix-row{display:grid;grid-template-columns:minmax(0,1fr) 120px;gap:8px}
.dlg-pay .mix-row input,.dlg-pay .mix-row select{height:44px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 12px;font:inherit;font-size:15px;color:var(--ink);background:var(--surface-raised)}
.dlg-pay .change{font-size:14px;color:var(--ink-muted)}
.dlg-pay .whish-pay{display:flex;gap:16px;align-items:flex-start}
.dlg-pay .whish-qr{width:160px;height:160px;border-radius:var(--radius-md);background:#fff;object-fit:contain}
.dlg-pay .mgroup>p{font-size:12px;letter-spacing:.12em;color:var(--ink-muted)}
.dlg-pay .mgroup .opt{height:44px;min-height:44px}
/* TillFloor: the plan with 52px pins, the open table's card and the open tables beside it. */
.modal.dlg-floor{max-width:calc(100vw - 32px);width:calc(100vw - 32px);max-height:calc(100dvh - 32px);height:calc(100dvh - 32px);background:var(--surface)}
.floor-grid{flex:1;min-height:0;display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:16px;padding:16px}
.floor-main{min-height:0;position:relative;background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);overflow:auto;display:flex;align-items:flex-start;justify-content:center}
.floor-main .floor-map{max-height:100%;width:auto;line-height:0}
.floor-main .floor-map img{max-height:calc(100dvh - 96px);width:auto;max-width:100%;border-radius:0;display:block}
.floor-areas{height:36px;flex:0 1 auto;min-width:0;overflow-x:auto}
.floor-areas>button{padding:0 14px;font:inherit;font-size:14px;font-weight:600;cursor:pointer;border:0;background:transparent;color:var(--ink-muted);white-space:nowrap}
.floor-areas>button.on{background:var(--brand);color:var(--on-brand)}
.floor-map-empty{display:flex;align-items:center;justify-content:center;min-height:240px;padding:24px;color:var(--ink-muted);font-size:14px;line-height:20px;text-align:center}
.floor-hint{position:absolute;left:16px;bottom:16px;height:28px;padding:0 10px;border-radius:var(--radius-sm);background:var(--surface-raised);border:1px solid var(--line);font-size:12px;font-weight:600;color:var(--ink-muted);display:inline-flex;align-items:center;white-space:nowrap}
.dlg-floor .fp-marker{width:52px;height:52px;border-radius:var(--radius-md);border:1px solid var(--line-strong);background:var(--surface-raised);color:var(--ink);box-shadow:0 1px 2px rgba(24,35,56,.12);padding:0;cursor:pointer;font:inherit}
.dlg-floor .fp-marker .fp-num{font-family:var(--ui);font-size:18px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1}
.dlg-floor .fp-marker .fp-seats{display:none}
.dlg-floor .fp-marker.empty{border-style:solid}
.dlg-floor .fp-marker.occupied{background:var(--brand);border-color:var(--brand);color:var(--on-brand)}
.dlg-floor .fp-marker.overdue{background:var(--danger);border-color:var(--danger);color:#fff}
.dlg-floor .fp-marker.locked{background:var(--surface-sunken);border-color:var(--line);color:var(--ink-muted);opacity:1}
.dlg-floor .fp-marker.mine{box-shadow:0 0 0 3px var(--brand-soft),0 1px 2px rgba(24,35,56,.12)}
.dlg-floor .fp-marker .fp-lock{position:absolute;right:-4px;bottom:-4px;width:18px;height:18px;border-radius:var(--radius-full);background:var(--surface-raised);border:1px solid var(--line);color:var(--ink-muted);display:flex;align-items:center;justify-content:center;font-size:0}
.floor-side{display:flex;flex-direction:column;gap:12px;min-height:0}
.floor-card{background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);padding:14px 16px;display:flex;flex-direction:column;gap:10px}
.floor-card-head{display:flex;justify-content:space-between;align-items:baseline;gap:8px}
.floor-card-title{font-size:17px;font-weight:600;font-stretch:80%}
.floor-card-rows{display:flex;flex-direction:column;gap:4px;font-size:14px;line-height:20px;color:var(--ink-muted);font-variant-numeric:tabular-nums}
.floor-card-rows .tot{display:flex;justify-content:space-between;gap:10px}
.floor-card .btn{width:100%;height:44px}
.floor-list{flex:1;min-height:0;background:var(--surface-raised);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:0 1px 2px rgba(24,35,56,.08);display:flex;flex-direction:column;overflow:hidden}
.floor-list-head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--line)}
.floor-list-head h3{margin:0;font-size:16px;line-height:24px;font-weight:600;font-stretch:80%}
.top-chip.off{background:var(--surface-sunken);color:var(--ink-muted);height:24px;padding:0 8px;font-size:12px}
.floor-list-rows{flex:1;min-height:0;overflow-y:auto}
.floor-row{display:flex;align-items:center;gap:12px;padding:10px 16px;border:0;border-bottom:1px solid var(--surface-sunken);background:transparent;width:100%;text-align:left;font:inherit;font-size:14px;color:var(--ink);cursor:pointer}
.floor-row:hover{background:var(--surface)}
.floor-row.on{background:var(--brand-soft);box-shadow:inset 3px 0 0 var(--brand)}
.floor-row-n{font-weight:700;width:28px;font-variant-numeric:tabular-nums;flex:0 0 28px}
.floor-row .m{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ink-muted);font-size:13px}
.floor-row.overdue .m::before{content:"";display:inline-block;width:6px;height:6px;border-radius:9999px;background:var(--danger);margin-right:6px;vertical-align:middle}
.floor-row .num{font-weight:600;font-variant-numeric:tabular-nums}
.floor-list .empty{padding:24px 16px;color:var(--ink-muted);font-size:13px;text-align:center}
/* the open tables stacked as cards (TillFloor v11, the previous design back on MAK's word) */
.floor-list-head .lbl{margin:0}
.floor-stack{display:flex;flex-direction:column;gap:10px;padding:12px}
.floor-card-t{display:flex;flex-direction:column;gap:2px;padding:12px 14px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-raised);box-shadow:0 1px 2px rgba(24,35,56,.08);text-align:left;font:inherit;color:var(--ink);cursor:pointer;position:relative;width:100%}
.floor-card-t:hover{background:var(--surface)}
.floor-card-t.on{border-color:var(--brand);box-shadow:inset 3px 0 0 var(--brand),0 1px 2px rgba(24,35,56,.08)}
.floor-card-n{font-size:24px;line-height:28px;font-weight:700;font-stretch:80%;letter-spacing:-.015em;font-variant-numeric:tabular-nums}
.floor-card-who{font-size:14px;line-height:20px;color:var(--ink)}
.floor-card-m{font-size:13px;line-height:18px;color:var(--ink-muted)}
.floor-card-t.overdue .floor-card-m::before{content:"";display:inline-block;width:6px;height:6px;border-radius:9999px;background:var(--danger);margin-right:6px;vertical-align:middle}
.floor-card-amt{margin-top:4px;font-size:16px;line-height:20px;font-weight:700;font-variant-numeric:tabular-nums}
.dlg-pay .tip-custom-in{height:40px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:0 12px;font:inherit;font-size:14px;color:var(--ink);background:var(--surface-raised);width:100%;margin:4px 0}

.scrim:has(.modal.dlg){background:rgba(24,35,56,.4)}
/* ================= The handheld (redesign, TillHandheld board): portrait tablets and phones ===
   The screens as a strip under the top bar, three tiles across, the cheque as a bottom sheet.
   Written after the desktop block, so it wins under 880px. */
@media (max-width:880px){
  .topbar{height:56px;flex-wrap:nowrap;row-gap:0;gap:10px;padding:0 16px}
  .topbar .brand{flex:0 0 auto;flex-direction:row}
  .topbar .brand-logo{width:60px;height:26px;background-size:122px 41px;background-position:-31px -4px}
  #btnFloorMap{width:36px;padding:0;font-size:0;gap:0}
  #btnFloorMap svg{width:18px;height:18px}
  #btnOsk,#connChip,#wsNameSidebar,#topClock{display:none}
  #servingPeriodName{font-size:12px;padding:0 8px}
  #btnLogout{padding:0;border:0;background:transparent;width:32px;height:32px;font-size:0;gap:0;overflow:hidden}
  #btnLogout .avatar{width:32px;height:32px;font-size:13px}
  .main{flex-direction:column;overflow:hidden}
  .cats-col{flex:0 0 auto;flex-direction:row;align-items:center;border-right:0;border-bottom:1px solid var(--line);padding:12px 16px 8px;gap:8px;overflow:hidden}
  .cats,.cats-col .cats{flex:1 1 auto;flex-direction:row;gap:8px;overflow-x:auto;overflow-y:hidden;padding:0 0 4px;min-height:0;scrollbar-width:none}
  .cats::-webkit-scrollbar{display:none}
  .cats-col #cats .cat{flex:0 0 auto;flex-direction:row;height:44px;min-height:44px;padding:0 16px;border:1px solid var(--line-strong);border-radius:var(--radius-md);font-size:15px;background:var(--surface-raised)}
  .cats-col #cats .cat small{display:none}
  .cats-col #cats .cat.on{background:var(--brand-soft);color:var(--brand);border-color:var(--brand);box-shadow:inset 0 0 0 1px var(--brand)}
  .sys-row{display:flex;flex-direction:row;align-items:center;border-top:0;border-left:1px solid var(--line);margin:0;padding:0 0 4px 8px;gap:6px}
  .sys{width:44px;height:44px;border-radius:var(--radius-md);border:1px solid var(--line);background:var(--surface-raised);color:var(--ink-muted);display:flex;align-items:center;justify-content:center;padding:0;cursor:pointer}
  .sys[hidden]{display:none}
  .sys svg{width:20px;height:20px}
  .menu{padding:12px 16px 200px;gap:10px;overflow:hidden}
  .grid-head h2{font-size:20px}
  .grid-search input{width:180px;height:40px}
  .menu .grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;overflow-y:auto}
  .menu .tile .tile-img{height:120px}
  /* the bottom sheet */
  .check-col{position:fixed;left:0;right:0;bottom:0;width:auto;flex:none;padding:0;z-index:30;display:flex;flex-direction:column;max-height:82dvh;background:var(--surface-raised);border-top:1px solid var(--line);box-shadow:0 -8px 24px -4px rgba(24,35,56,.16),0 -2px 6px rgba(24,35,56,.08);border-radius:var(--radius-lg) var(--radius-lg) 0 0;overflow:hidden}
  .cheque-tabs{position:static;height:auto;flex:0 0 auto;display:none;flex-direction:row;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;border:0;padding:12px 16px 0;gap:6px;background:transparent}
  .check-col.expanded .cheque-tabs{display:flex}
  .check{position:static;inset:auto;transform:none;height:auto;max-height:none;width:auto;border:0;border-radius:0;box-shadow:none;background:transparent;display:flex;flex-direction:column;min-height:0;transition:none}
  .check.open{transform:none}
  .check-toggle{display:flex;align-items:center;gap:12px;padding:12px 16px 4px;cursor:pointer}
  .check-toggle .mob-main{display:flex;flex-direction:column;min-width:0;flex:1}
  .check-toggle .mob-main b{font-size:15px;line-height:22px;font-weight:600;font-stretch:80%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .check-toggle .mob-main span{font-size:13px;line-height:18px;color:var(--ink-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .check-toggle #mobTotal{font-size:21px;line-height:30px;font-weight:700;font-stretch:80%;font-variant-numeric:tabular-nums;white-space:nowrap}
  .check-toggle .mob-chev{width:44px;height:44px;border:1px solid var(--line-strong);border-radius:var(--radius-md);display:flex;align-items:center;justify-content:center;color:var(--ink);flex:0 0 44px;transition:transform .15s}
  .check-col.expanded .mob-chev{transform:rotate(180deg)}
  .check .check-hd,.check .lines,.check .totals{display:none}
  .check-col.expanded .check .check-hd{display:flex;padding-top:4px}
  .check-col.expanded .check .check-hd b#checkTitle,.check-col.expanded .check .check-hd-sub{display:none}
  .check-col.expanded .check .check-hd-chips{margin-top:0}
  .check-col.expanded .check .lines{display:block;flex:1;min-height:120px;max-height:40dvh}
  .check-col.expanded .check .totals{display:flex}
  .check .pay{padding:6px 16px 16px;gap:10px}
  .check .pay-main .btn{height:56px;font-size:17px}
  .check .pay-row{display:none}
  .check-col.expanded .check .pay-row{display:flex}
  .check-col.expanded .check .pay-row[hidden]{display:none}
  /* the dialogs fill the width */
  .modal.dlg{max-width:calc(100vw - 24px)}
  .modal.dlg-pay,.modal.dlg-floor{width:calc(100vw - 16px);max-width:calc(100vw - 16px);height:calc(100dvh - 16px);max-height:calc(100dvh - 16px)}
  .pay-grid{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr);overflow-y:auto}
  .pay-cheque{max-height:34dvh}
  .pay-lines{max-height:14dvh}
  .pay-due-v{font-size:36px;line-height:40px}
  .pay-cash{grid-template-columns:minmax(0,1fr) 160px}
  .floor-grid{grid-template-columns:1fr;grid-template-rows:minmax(0,1fr) auto}
  .floor-side{max-height:36dvh}
  .dlg-table-body{grid-template-columns:1fr}
  .dlg-opts .opt{height:48px;min-height:48px}
}

.a-rewards-table th{overflow:hidden;text-overflow:ellipsis}

/* The column divider (round 3): a 12px strip, a 2px line, a 20 by 40 handle; brand while hovered or dragged. */
/* BohFloor (round 3): the tables list | divider | the plan panel */
.a-fp{display:grid;grid-template-columns:var(--split,300px) 12px minmax(0,1fr);gap:16px;align-items:start}
.a-fp-list{position:sticky;top:0}
.a-fp-list .a-ph{padding:12px 14px}
.a-fp-list .filt-select{height:28px;font-size:12px;padding:0 24px 0 8px}
.a-fp-rows{min-height:0;overflow:auto}
.a-fp-row{display:flex;align-items:center;gap:10px;padding:0 6px 0 14px;min-height:44px;border-bottom:1px solid var(--surface-sunken);cursor:pointer;position:relative;outline:none}
.a-fp-row:last-child{border-bottom:0}
.a-fp-row:hover,.a-fp-row:focus-visible{background:var(--surface)}
.a-fp-row.on{background:var(--brand-soft)}
.a-fp-row.on::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--brand)}
.a-fp-n{width:32px;flex:0 0 32px;font-weight:700;font-size:14px;font-variant-numeric:tabular-nums;color:var(--ink)}
.a-fp-row .m{flex:1;min-width:0;font-size:13px;color:var(--ink-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-fp-row .a-rowmenu-btn{opacity:0}
.a-fp-row:hover .a-rowmenu-btn,.a-fp-row.on .a-rowmenu-btn,.a-fp-row:focus-within .a-rowmenu-btn{opacity:1}
.a-fp-plan{min-width:0}
.a-fp-plan-head{flex-wrap:wrap;gap:8px;padding:12px 16px}
.a-fp-plan-head h3{margin:0;font-size:15px;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.a-fp-dims{height:24px;font-size:12px;cursor:default;color:var(--ink-muted);font-variant-numeric:tabular-nums}
.a-fp-areas{height:32px;max-width:100%;overflow-x:auto}
.a-fp-areas>button{padding:0 12px;font:inherit;font-size:13px;font-weight:600;cursor:pointer;border:0;background:transparent;color:var(--ink-muted);border-radius:var(--radius-sm);white-space:nowrap;display:inline-flex;align-items:center;gap:6px}
.a-fp-areas>button.on{background:var(--brand);color:var(--on-brand)}
.a-fp-nopic{width:6px;height:6px;border-radius:var(--radius-full);background:var(--warning);display:inline-block}
.a-fp-areas>button.on .a-fp-nopic{background:var(--on-brand)}
.a-fp-zoom{height:32px}
.a-fp-zoom>button{padding:0 10px;font:inherit;font-size:13px;font-weight:600;cursor:pointer;border:0;background:transparent;color:var(--ink-muted);border-radius:var(--radius-sm)}
.a-fp-zoom>button.on{background:var(--brand);color:var(--on-brand)}
.a-fp-stage{position:relative;background:var(--surface-sunken)}
.a-fp-wrap{overflow:auto;min-height:240px}
.a-fp-canvas{width:100%;line-height:0;user-select:none}
.a-fp-canvas.zoomed{width:max-content;max-width:none}
.a-fp-canvas img{border-radius:0;display:block;width:100%;height:auto}
.a-fp-canvas.zoomed img{max-width:none}
.a-fp-canvas .fp-marker{width:44px;height:44px;border:1px solid var(--line-strong);border-radius:var(--radius-full);background:var(--surface-raised);color:var(--ink);box-shadow:0 1px 2px rgba(24,35,56,.12);padding:0;gap:0;font:inherit;touch-action:none}
.a-fp-canvas .fp-marker .fp-num{font-family:var(--ui);font-size:15px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1}
.a-fp-canvas .fp-marker.shape-square{border-radius:var(--radius-sm)}
.a-fp-canvas .fp-marker.shape-wide{width:68px}
.a-fp-canvas .fp-marker.busy{border-color:var(--brand);color:var(--brand)}
.a-fp-canvas .fp-marker.moved{box-shadow:0 0 0 3px var(--brand-soft),0 1px 2px rgba(24,35,56,.12)}
.a-fp-canvas .fp-marker.sel{background:var(--brand);border-color:var(--brand);color:var(--on-brand)}
.a-fp-hint{position:absolute;left:12px;bottom:12px;height:28px;padding:0 10px;border-radius:var(--radius-sm);background:var(--surface-raised);border:1px solid var(--line-strong);font-size:12px;font-weight:600;color:var(--ink-muted);display:inline-flex;align-items:center;white-space:nowrap;max-width:calc(100% - 24px);overflow:hidden;text-overflow:ellipsis;pointer-events:none}
.a-fp-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-top:1px solid var(--line)}
.a-fp-foot .a-hint{margin:0}
.a-fp-empty{padding:40px 24px}
.a-fp-empty p{margin:0 0 6px;font-size:14px;color:var(--ink)}
.a-fp-empty .a-hint{margin:0 auto;max-width:48ch}
.a-form-pane .fld .seg.a-fp-shape{grid-template-columns:repeat(3,minmax(0,1fr))}
.a-fp-note{padding:10px 12px;border-radius:var(--radius-sm);background:var(--warning-soft);color:var(--ink)}
/* the till floor draws the marker's shape */
.dlg-floor .fp-marker.shape-round{border-radius:var(--radius-full)}
.dlg-floor .fp-marker.shape-wide{width:76px}
.dlg-free b{font-weight:600;color:var(--ink)}
.a-split{position:relative;width:12px;align-self:stretch;cursor:col-resize;touch-action:none;user-select:none;outline:none;min-height:120px}
.a-split::before{content:"";position:absolute;left:5px;top:0;bottom:0;width:2px;background:var(--line);border-radius:1px;transition:background .12s,width .12s,left .12s}
.a-split-handle{position:absolute;left:50%;top:50%;width:20px;height:40px;margin:-20px 0 0 -10px;border-radius:var(--radius-md);background:var(--surface-raised);border:1px solid var(--line-strong);color:var(--ink-muted);display:flex;align-items:center;justify-content:center;box-sizing:border-box}
.a-split:hover::before,.a-split.dragging::before,.a-split:focus-visible::before{background:var(--brand);width:4px;left:4px}
.a-split:hover .a-split-handle,.a-split.dragging .a-split-handle,.a-split:focus-visible .a-split-handle{background:var(--brand);border-color:var(--brand);color:var(--on-brand)}
body.a-splitting{cursor:col-resize;user-select:none}
body.a-splitting *{pointer-events:none}
body.a-splitting .a-split{pointer-events:auto}
/* the table columns (splitter.js, second mode): the grab zone on each header's right edge and the
   brand line the height of the table while hovered or dragged */
.a-table th,.a-report-table th{position:relative}
.a-colgrip{position:absolute;top:0;right:-4px;width:8px;height:100%;cursor:col-resize;z-index:2;touch-action:none;user-select:none}
.a-table-panel,.a-report-table-wrap{position:relative}
.a-colline{position:absolute;top:0;left:0;width:2px;height:0;background:var(--brand);pointer-events:none;z-index:3;display:none;border-radius:1px}
.a-colline.on{display:block}
body.a-colsizing{cursor:col-resize;user-select:none}
body.a-colsizing *{pointer-events:none}
body.a-colsizing .a-colgrip{pointer-events:auto}
/* a narrow column clips its own text instead of spilling into the next cell */
.a-table[data-cols] td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.a-table[data-cols] td .a-cell-stack{min-width:0}
.a-table[data-cols] td .a-cell-stack>*{overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:100%}
.a-table[data-cols] th{overflow:visible}
.main>.a-split{flex:0 0 12px;margin:14px 0 16px}
@media (max-width:880px){.main>.a-split{display:none}}

/* ===== A guest is waiting (MAK, 22 Sep 2026: "calling a waiter from mobile is not showing anything
   on the till, only a banner"). The yellow strip stays as the alert; these are the MARK, which lives
   in shared state and so survives a reload, an outlet switch and a fresh login, and only leaves when
   a waiter takes the call. Warning amber, deliberately not the red of "items not sent": a guest
   waiting is not a mistake, and the two must not read as the same thing across a room. ===== */
.call-badge{display:inline-flex;align-items:center;gap:4px;height:20px;padding:0 6px;border-radius:var(--radius-full);background:var(--warning-soft);color:var(--warning);border:1px solid var(--warning);font-size:11px;font-weight:700;line-height:1;cursor:pointer;animation:overdue-pulse 1.8s ease-in-out infinite}
.call-badge.sm{height:18px;padding:0 4px;gap:0}
.call-badge b{font-weight:700;font-size:10px}
.call-badge.cash{background:color-mix(in srgb, var(--alert) 18%, transparent);color:var(--alert);border-color:var(--alert)}
/* The tab and the marker take an amber edge so the table reads as called from across the room,
   before anybody is close enough to see the badge itself. */
.tab.calling{border-color:var(--warning);box-shadow:inset 0 0 0 2px var(--warning)}
.tab.overdue.calling{box-shadow:inset 0 0 0 2px var(--warning)}
.fp-marker.calling{border-color:var(--warning);box-shadow:0 0 0 3px color-mix(in srgb, var(--warning) 45%, transparent)}
.fp-marker .call-badge{position:absolute;top:-8px;right:-8px;z-index:3}
/* The top bar chip: the only one of the three that is on screen whatever the waiter is looking at. */
.top-chip.calls{background:var(--warning-soft);color:var(--warning);border:1px solid var(--warning);cursor:pointer;font-weight:700}
.top-chip.calls.late{animation:overdue-pulse 1.4s ease-in-out infinite}
/* The list behind the chip. A row is a grid, not a wrapped line, so the columns line up down the
   list and the two buttons sit in the same place on every row (the set-on-a-grid rule). */
.calls-list{display:flex;flex-direction:column;gap:8px;max-height:52vh;overflow-y:auto;padding:4px 0}
.calls-row{display:grid;grid-template-columns:24px auto 1fr auto auto auto;align-items:center;gap:10px;padding:10px 12px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-sunken)}
.calls-row.late{border-color:var(--warning);background:var(--warning-soft)}
.calls-what{font-size:16px;text-align:center}
.calls-table{font-weight:700;white-space:nowrap}
.calls-why{color:var(--ink-muted);font-size:13px;white-space:nowrap}
.calls-wait{font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right;min-width:62px}
.calls-row.late .calls-why,.calls-row.late .calls-wait{color:var(--warning)}

.calls-row .btn{white-space:nowrap}

@media (min-width:881px){
/* ===== TillOrder v16 (design lane, released by MAK 23 Sep 2026): the open cheques are a 96px tab
   column down the right edge of the screen, and the cheque folds away behind the chevron in its own
   head. These rules come after the older wrapped-row block above and replace it on the desktop
   till; the handheld media query further down still turns the whole thing back into a bottom
   sheet, which is untouched. ===== */
/* The column in the flex row is ONLY the 96px tab strip. The cheque is not in the flow at all
   (see .check below), so the tile grid is measured once and never moves. */
.check-col{flex-direction:row;gap:0;padding:0;background:transparent}
/* The column itself: three parts, and only the middle one scrolls, so New table and Closed are
   always reachable however many tables are open. */
.cheque-tabs{flex:0 0 96px;width:96px;display:flex;flex-direction:column;flex-wrap:nowrap;align-items:stretch;gap:6px;padding:14px 8px 16px 8px;background:transparent;overflow:visible;min-height:0;position:static;height:auto;border:0}
.cheque-tabs .tabs-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:6px;padding:2px 0}
/* A tab is one 40px line: the table number, a middle dot, the guest count. Tabular figures and the
   80% stretch keep "7 · 2" and "124 · 12" the same shape down the column. */
.cheque-tabs .tab{width:100%;height:40px;flex:0 0 40px;justify-content:center;gap:3px;padding:0 6px;margin:0;border-radius:var(--radius-md);border:1px solid var(--line);border-bottom:1px solid var(--line)}
.cheque-tabs .tab .tab-n{font-size:17px;font-weight:700;font-stretch:80%;font-variant-numeric:tabular-nums;line-height:20px}
.cheque-tabs .tab .tab-pax{font-size:13px;font-weight:600;color:var(--ink-muted);font-variant-numeric:tabular-nums}
.cheque-tabs .tab.on{background:var(--brand-soft,var(--surface-raised));border-color:var(--brand);box-shadow:inset 3px 0 0 var(--brand);color:var(--ink)}
.cheque-tabs .tab.on .tab-pax{color:var(--ink-muted)}
.cheque-tabs .tab.new{flex:0 0 44px;height:44px;font-size:13px;gap:4px}
.cheque-tabs .tab.new svg{width:15px;height:15px}
/* Closed is pinned at the foot and stays quiet: it is a way back, not a thing to reach for. */
.cheque-tabs .tab.closed{flex:0 0 36px;height:36px;margin:0;border-style:dashed;font-size:12px;font-weight:600;color:var(--ink-muted);background:transparent}
/* Items not sent is a dot in the corner, not a whole red tab: at 40px a filled tab would shout
   louder than the open cheque itself, and every tab in a busy hour would be shouting. */
/* Warning amber, not danger red. The SAME fact reads amber everywhere else on this screen: the
   cheque line says "Not sent" in var(--warning) and the floor's own chip is the warning tint, so a
   red tab beside an amber line was one screen giving one state two colours. Danger red is kept for
   what is genuinely wrong, offline, a void, a locked cheque, not for a drink that has not reached
   the bar yet (design lane, 23 Sep 2026). */
.cheque-tabs .tab.overdue{background:var(--surface-sunken);border-color:var(--warning);color:var(--ink);animation:none}
/* Inline, right after the guest count, so a tab reads "12 · 4 •" and the top right corner is left
   free for the guest call badge. The two marks mean different things and must never share a corner. */
/* No pulse either: at 7px inline it is the only coloured thing on a 40px tab and does not need to
   move to be found. A column of twelve pulsing dots in a busy hour is the shouting MAK has spent
   the week taking out of this app. */
.cheque-tabs .tab.overdue::after{content:"";width:7px;height:7px;flex:0 0 7px;margin-left:3px;border-radius:var(--radius-full);background:var(--warning)}
.cheque-tabs .tab.overdue.on{background:var(--brand-soft,var(--surface-raised));color:var(--ink)}
.cheque-tabs .tab .cq-lock{position:absolute;top:4px;left:4px;margin:0;color:var(--ink-muted)}
.cheque-tabs .tab .call-badge{position:absolute;top:-7px;right:-7px;width:16px;height:16px;padding:0;justify-content:center;font-size:9px;line-height:1}
/* The cheque lies over the tiles, to the left of the tab column, and slides. Absolute against
   .main (which is already position:relative), so opening or hiding it changes NOTHING in the flow:
   the tiles are six across at 1366 whether a cheque is open or not. Width is still the splitter's,
   so a till that dragged it wider keeps that and simply covers more tiles. The shadow and the fade
   at its left edge are what say "this is lying on top" rather than "this is a column". */
.check{position:absolute;top:0;right:96px;bottom:0;width:var(--split,420px);max-width:calc(100% - 96px);z-index:30;transform:translateX(calc(100% + 96px));transition:transform .2s ease;box-shadow:-10px 0 28px -6px rgba(24,35,56,.22),-1px 0 0 var(--line);border-radius:0}
.check.open{transform:none}
/* The tab column has to sit above the cheque, or the cheque's own shadow would fall across it. */
.cheque-tabs{z-index:31;position:relative}
/* In the FLOW the column is only the 96px tab strip: the cheque is absolute and lies over the
   tiles, so it reserves nothing. This is what keeps the tile grid six across at 1366 whether a
   cheque is open or not, and it is the rule the v16 version got wrong (three across with a cheque
   open, which is what MAK saw on the demos this morning). */
.check-col{flex:0 0 96px;width:96px}
}

/* The booked table warning on the till (23 Sep 2026). A card, not a paragraph: a waiter reads this
   with a guest standing in front of them, so the time and the name have to land in one glance. */
.due-booking{display:flex;align-items:center;gap:14px;padding:14px 16px;border:1px solid var(--warning);background:var(--warning-soft);border-radius:var(--radius-md);margin:4px 0 14px}
.due-when{font-size:22px;font-weight:700;font-stretch:80%;font-variant-numeric:tabular-nums;color:var(--warning);white-space:nowrap}
.due-who{display:flex;flex-direction:column;gap:2px;min-width:0}
.due-who b{font-size:16px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.due-who span{font-size:13px;color:var(--ink-muted)}
.due-ask{margin:0 0 4px;font-size:15px;font-weight:600}
.due-more{margin:2px 0 0;font-size:13px;color:var(--ink-muted)}

/* "Not now" sits apart from the two real answers: it defers the question, it is not a third opinion
   about whose guests these are (MAK, 23 Sep 2026: "what the waiter will do in that case?"). */
.due-foot{display:flex;align-items:center;gap:8px}
.due-spacer{flex:1 1 auto}
/* The parked question on the table own tab: the booked time, amber like every other mark that means
   somebody is waiting on you. Tapping it asks again. No pulse: it is a reminder, not an alarm. */
.call-badge.booked{background:var(--warning-soft);color:var(--warning);border-color:var(--warning);font-variant-numeric:tabular-nums;animation:none;padding:0 5px;height:16px;font-size:9px;font-weight:700}

/* The two ways on when the guests are not the ones booked (MAK, 23 Sep 2026): move their booking,
   or carry on and tell the host. Cards rather than buttons, because each needs a line of
   explanation and a waiter is choosing between two courses of action, not confirming one. */
.due-choices{display:flex;flex-direction:column;gap:8px;margin:4px 0 14px}
.due-choice{display:flex;flex-direction:column;gap:2px;align-items:flex-start;text-align:left;padding:12px 14px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-sunken);cursor:pointer;font:inherit;color:var(--ink)}
.due-choice:hover{border-color:var(--brand);background:var(--surface-raised)}
.due-choice b{font-size:15px;font-weight:700}
.due-choice span{font-size:13px;color:var(--ink-muted)}
/* The free tables, on a grid so they all read the same size (the sets on a grid rule). */
.due-tables{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:8px;margin:4px 0 14px;max-height:40vh;overflow-y:auto}
.due-table{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;height:56px;border:1px solid var(--line);border-radius:var(--radius-md);background:var(--surface-sunken);font:inherit;font-size:16px;font-weight:700;color:var(--ink);cursor:pointer}
.due-table:hover{border-color:var(--brand);background:var(--brand-soft,var(--surface-raised))}
.due-table span{font-size:11px;font-weight:600;color:var(--ink-muted)}
