/* ===== My Kitchen Rules — 应用样式 ===== */
:root{
  --paper:#F6F2EC; --paper-2:#FBF8F3; --card:#FFFFFF;
  /* --ink-faint was #9A8F84 — 2.85:1 on paper, under the 4.5:1 AA floor, and it
     is used on interactive text ("Forgot password?"). #7C7168 clears it. */
  --ink:#211E1B; --ink-soft:#6F655B; --ink-faint:#7C7168;
  --line:rgba(33,30,27,.10); --line-2:rgba(33,30,27,.06);
  --accent:#C9612E; --accent-soft:#F4E2D5; --accent-ink:#9A4516;
  /* -ink is the readable text colour ON the matching -soft tint. It exists so
     no rule has to hardcode "the dark version of amber" — that is precisely the
     value that has to flip when the tint goes dark. */
  --green:#2F8F5B; --green-soft:#E9F6EE; --green-ink:#1D6A40;
  --red:#D8453C; --red-soft:#FDECEA; --red-ink:#922019;
  --amber:#E0A11B; --amber-soft:#FBF2DA; --amber-ink:#8A6410;
  --blue:#2B5BB5; --blue-soft:#E7EEFB; --blue-ink:#234A8F;
  --violet:#5B45A8; --violet-soft:#ECE7F9;
  --teal:#0F6F6C; --teal-soft:#DDEFEE;
  --radius:18px; --radius-lg:26px;
  --shadow:0 1px 2px rgba(33,30,27,.05), 0 16px 36px -20px rgba(33,30,27,.22);
  --shadow-soft:0 1px 2px rgba(33,30,27,.04), 0 8px 22px -16px rgba(33,30,27,.18);
  --sidebar:248px;
  /* Motion: strong custom easing curves (built-in CSS easings are too weak) */
  --ease-out:cubic-bezier(0.23,1,0.32,1);
  --ease-in-out:cubic-bezier(0.77,0,0.175,1);
}

/* ---------- dark mode ----------
   Every colour in this file already goes through a token, so the dark theme is
   the token block again with different values — no per-component overrides.

   One rule, keyed on an attribute, rather than a @media copy plus an override
   copy: the tiny script in index.html resolves "auto" against the OS before
   first paint and writes the attribute, so there is exactly one place a colour
   is defined. (No JS, no app at all — this file is never the fallback.)

   Three things are deliberately not just "inverted":
   · The -soft tints are re-mixed rather than darkened. A pale tint darkened by
     a filter goes muddy and the status colours stop being distinguishable,
     which is the one thing they exist to do.
   · The accent lightens (#C9612E -> #E08050). Terracotta at its light-mode
     value is 3.1:1 on a dark ground; it carries the primary button and the
     active nav item, so it has to clear 4.5:1.
   · --ink-grad inverts outright. It paints the primary button and the active
     nav pill, so leaving it near-black hides the main action on a dark page. */
:root[data-theme="dark"]{
  --paper:#17161A; --paper-2:#1E1D22; --card:#25242A;
  --ink:#F0EDE8; --ink-soft:#B0A9A1; --ink-faint:#8E877F;
  --line:rgba(240,237,232,.14); --line-2:rgba(240,237,232,.08);
  --accent:#E08050; --accent-soft:#3A2A21; --accent-ink:#F0A87E;
  --green:#5FC489; --green-soft:#1C3226; --green-ink:#7FD6A3;
  --red:#F0736A; --red-soft:#3A2220; --red-ink:#FF9B93;
  --amber:#E8B44A; --amber-soft:#332812; --amber-ink:#F0C868;
  --blue:#7BA3E8; --blue-soft:#1E2739; --blue-ink:#9FBEF2;
  --violet:#A392E0; --violet-soft:#272138;
  --teal:#5FBFB9; --teal-soft:#12302F;
  --fp-floor:#221F1B; --fp-floor-2:#2C2823; --fp-wall:#4A5A4C;
  --ink-grad:linear-gradient(152deg,#F5F2ED,#DCD7CE);
  --green-grad:linear-gradient(140deg,#6FD199,#4FB37B);
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 16px 36px -20px rgba(0,0,0,.7);
  --shadow-soft:0 1px 2px rgba(0,0,0,.3), 0 8px 22px -16px rgba(0,0,0,.55);
  color-scheme:dark;
}
*{box-sizing:border-box;margin:0;padding:0}
/* The document element stays the scroll container. Putting height:100% on the
   body as well (with overflow-x:hidden further down) made the BODY the scroller,
   which on iOS means the URL bar never collapses and the scroll position is not
   restored on back. min-height keeps the full-height login page working. */
html{height:100%}
body{min-height:100%}
body{
  font-family:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--paper); color:var(--ink); line-height:1.55;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
.serif{font-family:"Playfair Display",serif}

/* ---------- per-language typography ----------
   Pin ONE script-appropriate family per language. Latin glyphs come from Inter;
   Han / Hangul / Thai glyphs then resolve from a single family, so the characters
   a Traditional string shares with Simplified never split across two different
   fonts — the whole line renders in one consistent typeface. */
html[lang="zh-CN"] body{font-family:"Inter","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans SC",sans-serif}
html[lang="zh-CN"] .serif{font-family:"Playfair Display","PingFang SC","Microsoft YaHei","Noto Sans SC",serif}
html[lang="zh-TW"] body{font-family:"Inter","PingFang TC","Hiragino Sans CNS","Microsoft JhengHei","Noto Sans TC",sans-serif}
html[lang="zh-TW"] .serif{font-family:"Playfair Display","PingFang TC","Microsoft JhengHei","Noto Sans TC",serif}
html[lang="ko"] body{font-family:"Inter","Apple SD Gothic Neo","Malgun Gothic","Noto Sans KR",sans-serif}
html[lang="ko"] .serif{font-family:"Playfair Display","Apple SD Gothic Neo","Malgun Gothic","Noto Sans KR",serif}
html[lang="th"] body{font-family:"Inter","Sukhumvit Set","Thonburi","Leelawadee UI","Noto Sans Thai",sans-serif}
html[lang="th"] .serif{font-family:"Playfair Display","Sukhumvit Set","Thonburi","Leelawadee UI","Noto Sans Thai",serif}
/* Vietnamese is Latin-script; Inter already carries the diacritics. */
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
input,select,textarea{font-family:inherit;font-size:16px}
img{max-width:100%;display:block}
.hidden{display:none !important}

/* ---------- buttons (>=48px touch) ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  min-height:48px;padding:0 22px;border-radius:14px;font-weight:600;font-size:15px;
  white-space:nowrap;transition:transform .16s var(--ease-out), box-shadow .2s, background .2s, opacity .2s;}
.btn:active{transform:scale(.97)}
.btn-dark{background:var(--ink);color:var(--paper);box-shadow:var(--shadow-soft)}
@media (hover:hover) and (pointer:fine){ .btn-dark:hover{transform:translateY(-1px)} }
.btn-accent{background:var(--accent);color:#fff;box-shadow:var(--shadow-soft)}
.btn-ghost{background:var(--card);border:1px solid var(--line)}
.btn-ghost:hover{background:var(--paper-2)}
.btn-danger{background:var(--red);color:#fff}
.btn-green{background:var(--green);color:#fff}
.btn-sm{min-height:48px;padding:0 16px;font-size:14px;border-radius:12px}
.btn-block{display:flex;width:100%}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none}

/* ---------- generic ---------- */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-soft)}
.muted{color:var(--ink-soft)}
.faint{color:var(--ink-faint)}
.row{display:flex;gap:14px}
.col{display:flex;flex-direction:column;gap:14px}
.between{justify-content:space-between}
.center{align-items:center}
.wrap{flex-wrap:wrap}
.grow{flex:1}
.gap8{gap:8px}.gap6{gap:6px}
.mt8{margin-top:8px}.mt12{margin-top:12px}.mt16{margin-top:16px}.mt24{margin-top:24px}
.tag{font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);font-weight:700}

.pill{display:inline-flex;align-items:center;gap:5px;font-size:12.5px;font-weight:600;padding:5px 11px;border-radius:999px;white-space:nowrap}
.pill.ok{background:var(--green-soft);color:var(--green)}
.pill.warn{background:var(--amber-soft);color:var(--amber-ink)}
.pill.danger{background:var(--red-soft);color:var(--red)}
.pill.info{background:var(--blue-soft);color:var(--blue)}
.pill.ghost{background:var(--paper-2);color:var(--ink-soft);border:1px solid var(--line)}

.field{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
.field label{font-size:13px;font-weight:600;color:var(--ink-soft)}
.input{height:48px;padding:0 14px;border-radius:12px;border:1px solid var(--line);background:var(--paper-2);width:100%;color:var(--ink)}
textarea.input{height:auto;padding:12px 14px;resize:vertical;min-height:80px}
.input:focus{outline:none;border-color:var(--accent);background:var(--card)}
/* iOS gives date and time fields a fixed minimum width of their own, so two
   side by side ran past the edge of a phone-width form and the whole sheet
   panned sideways. Let them shrink like any other field. */
.row > .grow{min-width:0}
input.input[type=date], input.input[type=time], input.input[type=datetime-local], input.input[type=month]{
  min-width:0;-webkit-appearance:none;appearance:none;text-align:left}
.input::-webkit-date-and-time-value{text-align:left}
/* The show / hide eye inside a password field (js/util.js dressPasswords). */
.pw-wrap{position:relative;display:block}
.pw-wrap > .input{padding-right:50px}
.pw-eye{position:absolute;right:5px;top:50%;transform:translateY(-50%);width:40px;height:40px;min-height:0;padding:0;
  display:grid;place-items:center;border:none;border-radius:10px;background:none;color:var(--ink-faint);cursor:pointer}
.pw-eye .ic{width:20px;height:20px}
.pw-eye:hover, .pw-eye[aria-pressed="true"]{color:var(--ink-soft)}
.pw-eye:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
select.input{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%236F655B' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 14px center}
/* Room for the arrow, so a long option never runs under it. */
select.input{padding-right:38px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}

.disclaimer{font-size:12.5px;color:var(--ink-soft);background:var(--paper-2);border:1px dashed var(--line);border-radius:12px;padding:11px 14px;display:flex;gap:9px;align-items:flex-start}
.disclaimer>span{flex-shrink:0;display:inline-flex;align-items:center;margin-top:1px}
.disclaimer .ic{width:16px;height:16px;color:var(--ink-faint)}
/* Most notes are an icon then a sentence with a bold word or a link in it.
   As flex items, every bare run of text and every <b> became its own column
   on a phone. The icon hangs in the margin instead and the sentence flows. */
.disclaimer:has(> span:first-child){display:block;position:relative;padding-left:39px}
.disclaimer:has(> span:first-child) > span:first-child{position:absolute;left:14px;top:11px}

.alert{display:flex;gap:11px;align-items:flex-start;padding:13px 15px;border-radius:14px;border:1px solid;font-size:14px}
.alert.red{background:var(--red-soft);border-color:color-mix(in srgb,var(--red) 35%,transparent);color:var(--red-ink)}
.alert.green{background:var(--green-soft);border-color:color-mix(in srgb,var(--green) 35%,transparent);color:var(--green-ink)}
.alert.amber{background:var(--amber-soft);border-color:color-mix(in srgb,var(--amber) 40%,transparent);color:var(--amber-ink)}
.alert.info{background:var(--blue-soft);border-color:color-mix(in srgb,var(--blue) 35%,transparent);color:var(--blue-ink)}

/* ---------- login ---------- */
.login-wrap{min-height:100vh;display:grid;place-items:center;padding:24px;background:
  radial-gradient(900px 520px at 12% -8%, rgba(201,97,46,.14), transparent 55%),
  radial-gradient(900px 520px at 90% 108%, rgba(47,143,91,.10), transparent 55%),
  linear-gradient(180deg, var(--paper-2), var(--paper))}
.login-card{width:100%;max-width:440px;padding:54px 30px 26px;border-radius:24px;
  box-shadow:0 2px 6px rgba(33,30,27,.06), 0 30px 60px -28px rgba(33,30,27,.30);
  animation:pop .4s var(--ease-out)}
.login-logo{width:54px;height:54px;border-radius:16px;color:var(--paper);
  /* Both ends of the gradient and the glow follow the brand — a hardcoded
     second stop leaves one orange corner on a venue that is not orange. */
  background:linear-gradient(150deg,var(--accent),var(--accent-ink));
  box-shadow:0 8px 20px -8px color-mix(in srgb, var(--accent) 60%, transparent);
  display:grid;place-items:center;font-weight:900;font-size:27px;font-family:"Playfair Display",serif}
.role-pick{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin:18px 0}
.role-pick button{padding:14px 8px;border-radius:14px;border:1px solid var(--line);background:var(--paper-2);
  font-weight:600;font-size:13.5px;display:flex;flex-direction:column;align-items:center;gap:6px;min-height:48px}
.role-pick button .em{font-size:22px;display:inline-flex}
.role-pick button .ic{width:22px;height:22px}
.preview-box b .ic{width:16px;height:16px;vertical-align:-3px;margin-right:2px}
.preview-box .btn .ic{width:16px;height:16px}
.role-pick button.sel{border-color:var(--ink);background:var(--ink);color:var(--paper)}
.seed-hint{font-size:12px;color:var(--ink-soft);background:var(--paper-2);border-radius:12px;padding:10px 12px;margin-top:14px}
.seed-hint code{background:var(--card);border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-size:11.5px}

/* ---------- app shell ---------- */
.shell{display:grid;grid-template-columns:var(--sidebar) 1fr;min-height:100vh}
.sidebar{background:var(--paper-2);border-right:1px solid var(--line-2);padding:20px 16px;display:flex;flex-direction:column;gap:6px;position:sticky;top:0;height:100vh;overflow:auto}
.side-brand{display:flex;align-items:center;gap:10px;padding:6px 8px 16px}
.side-brand .logo{width:36px;height:36px;border-radius:11px;background:var(--ink);color:var(--paper);display:grid;place-items:center;font-weight:900;font-family:"Playfair Display",serif}
.side-brand .logo .ic{width:21px;height:21px;stroke-width:1.7}
/* An owner's logo is a button: the mark in the corner is the one place it shows
   on every screen, so it is where they look to change it. The camera badge only
   shows on hover / focus so the sidebar isn't wearing an icon it doesn't need. */
.side-brand .logo.has-img{overflow:hidden;padding:0}
.logo-btn{position:relative;border:none;padding:0;cursor:pointer;font:inherit;overflow:hidden}
.logo-edit{position:absolute;inset:0;display:grid;place-items:center;opacity:0;
  background:color-mix(in srgb,var(--ink) 62%,transparent);color:#fff;transition:opacity .18s}
.logo-edit .ic{width:16px;height:16px}
.logo-btn:focus-visible .logo-edit{opacity:1}
@media (hover:hover) and (pointer:fine){ .logo-btn:hover .logo-edit{opacity:1} }
@media (hover:none){ .logo-btn .logo-edit{opacity:0} }
/* A venue called "My Kitchen · Melbourne" wrapped to three lines and shoved the
   fold button off the row. One line, elided. */
.side-brand b{font-size:16px;font-family:"Playfair Display",serif;letter-spacing:-.01em;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.side-brand small{display:block;font-size:11px;color:var(--ink-soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nav-item{display:flex;align-items:center;gap:12px;padding:11px 12px;border-radius:12px;font-weight:600;font-size:14.5px;color:var(--ink-soft);min-height:48px;transition:background .15s}
.nav-item .em{font-size:18px;width:22px;text-align:center}
.nav-item:hover{background:var(--card)}
.nav-item.active{background:var(--ink);color:var(--paper)}
.nav-item .badge{margin-left:auto;background:var(--red);color:#fff;font-size:11px;font-weight:700;border-radius:999px;padding:1px 7px;min-width:18px;text-align:center}
.nav-item.active .badge{background:var(--accent)}
.nav-sep{margin:14px 12px 6px;padding-top:12px;border-top:1px solid var(--line-2);
  font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-faint)}
.side-foot{margin-top:auto;padding-top:14px;border-top:1px solid var(--line-2)}

.main{display:flex;flex-direction:column;min-width:0}
.topbar{position:sticky;top:0;z-index:20;background:color-mix(in srgb,var(--paper) 85%,transparent);backdrop-filter:blur(12px);border-bottom:1px solid var(--line-2);
  display:flex;align-items:center;gap:14px;padding:14px 26px;min-height:64px}
.topbar h1{font-size:20px;font-weight:800}
.topbar .sub{font-size:12.5px;color:var(--ink-soft)}
.topbar-title{min-width:0}
.topbar-title h1{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.topbar-right{margin-left:auto;display:flex;align-items:center;gap:10px;flex-shrink:0}
.content{padding:26px;max-width:1180px;width:100%;margin:0 auto;flex:1}

/* network light */
.netlight{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--ink-soft);
  background:var(--card);border:1px solid var(--line);border-radius:999px;padding:7px 13px;min-height:40px}
.netlight .lamp{width:10px;height:10px;border-radius:50%;transition:background .3s, box-shadow .3s}
.netlight.online .lamp{background:var(--green);box-shadow:0 0 0 4px rgba(47,143,91,.16)}
.netlight.offline .lamp{background:var(--amber);box-shadow:0 0 0 4px rgba(224,161,27,.2)}
/* On phones, collapse the status pill to just its dot so the language switch fits */
@media(max-width:560px){ .topbar .netlight{font-size:0;gap:0;padding:11px} }
.netlight.syncing .lamp{background:var(--blue);box-shadow:0 0 0 4px rgba(43,91,181,.18)}

.who{display:flex;align-items:center;gap:9px}
.who .ava{width:36px;height:36px;border-radius:11px;background:var(--accent-soft);color:var(--accent-ink);display:grid;place-items:center;font-weight:700}

/* ---------- dashboard bits ---------- */
.grid{display:grid;gap:16px}
.g2{grid-template-columns:1fr 1fr}.g3{grid-template-columns:repeat(3,1fr)}.g4{grid-template-columns:repeat(4,1fr)}
.stat{padding:18px 20px}
.stat .k{font-size:12.5px;color:var(--ink-soft);display:flex;align-items:center;gap:6px}
.stat .v{font-family:"Playfair Display",serif;font-size:30px;font-weight:900;margin-top:6px}
.stat .v small{font-size:14px;color:var(--ink-soft);font-weight:400;font-family:"Inter"}
.delta{font-size:12.5px;font-weight:600;margin-top:2px}
.delta.up{color:var(--green)}.delta.down{color:var(--red)}.delta.flat{color:var(--ink-soft)}
.bar{height:8px;background:var(--line);border-radius:99px;overflow:hidden;margin-top:10px}
.bar i{display:block;height:100%;background:var(--accent);border-radius:99px;transition:width .4s}

/* flex-start + gap, not space-between: a leading icon is its own flex item, and
   space-between would shove it to one end and the words to the other. The
   trailing hint that space-between used to place is pushed right explicitly. */
.section-title{font-size:13px;font-weight:700;letter-spacing:.03em;color:var(--ink-soft);margin:4px 0 12px;text-transform:uppercase;display:flex;align-items:center;justify-content:flex-start;gap:7px}
.section-title>span:last-child,.section-title>b:last-child{margin-left:auto}
.section-title>span.st-count{margin-left:0}
.section-title>.ic{width:16px;height:16px;flex-shrink:0;color:var(--ink-faint)}
/* On a phone there is no room for a title and its hint side by side — both end
   up four words tall. The hint drops onto its own line instead. */
@media(max-width:560px){
  .section-title{flex-wrap:wrap}
  .section-title>span:last-child,.section-title>b:last-child{margin-left:0;flex-basis:100%}
  .section-title>span.st-count{flex-basis:auto}
}

.list{display:flex;flex-direction:column}
.li{display:flex;align-items:center;gap:13px;padding:13px 4px;border-bottom:1px solid var(--line-2)}
.li:last-child{border-bottom:none}
.li .ava{width:40px;height:40px;border-radius:12px;background:var(--accent-soft);color:var(--accent-ink);display:grid;place-items:center;font-weight:700;font-size:14px;flex-shrink:0}
.li .meta{flex:1;min-width:0}
.li .meta b{font-size:14.5px;font-weight:600;display:block}
.li .meta span{font-size:12.5px;color:var(--ink-soft)}

.section-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:18px;flex-wrap:wrap;gap:12px}
.section-head h2{font-size:22px;font-weight:800}
.section-head p{font-size:13.5px;color:var(--ink-soft)}

/* ---------- POS ---------- */
.pos{display:grid;grid-template-columns:1fr 360px;gap:18px;align-items:start}
.menu-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:12px}
.menu-item{padding:16px 14px;text-align:left;border-radius:16px;border:1px solid var(--line);background:var(--card);min-height:84px;display:flex;flex-direction:column;justify-content:space-between;transition:transform .12s,border-color .15s}
.menu-item:hover{border-color:var(--accent);transform:translateY(-2px)}
.menu-item .nm{font-weight:700;font-size:15px}
.menu-item .pr{color:var(--accent);font-weight:700;margin-top:8px}
.cat-tabs{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.cat-tabs button{min-height:40px;padding:0 14px;border-radius:999px;border:1px solid var(--line);background:var(--card);font-weight:600;font-size:13.5px}
.cat-tabs button.active{background:var(--ink);color:var(--paper)}
.cart{position:sticky;top:84px}
.cart-lines{max-height:46vh;overflow:auto;margin:4px 0}
.cart-line{display:flex;gap:10px;padding:11px 2px;border-bottom:1px solid var(--line-2);align-items:flex-start}
.cart-line .qty{display:flex;align-items:center;gap:8px}
.cart-line .qty button{width:30px;height:30px;border-radius:8px;border:1px solid var(--line);background:var(--paper-2);font-weight:700;font-size:16px}
.cart-line .note{font-size:12px;color:var(--accent);margin-top:2px;cursor:pointer}
.cart-total{display:flex;justify-content:space-between;align-items:baseline;margin:14px 0;font-weight:700}
.cart-total .v{font-family:"Playfair Display",serif;font-size:26px}

/* cash counter */
.cash-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px}
.denom{background:var(--paper-2);border:1px solid var(--line-2);border-radius:14px;padding:12px;text-align:center}
.denom b{font-size:17px;display:block}
.denom .ct{display:flex;align-items:center;justify-content:center;gap:10px;margin-top:8px}
.denom .ct button{width:34px;height:34px;border-radius:9px;background:var(--card);border:1px solid var(--line);font-weight:700;font-size:17px}
.denom .ct span{min-width:24px;font-weight:700;font-size:16px}
.denom .ct .cash-input{width:46px;height:34px;text-align:center;font-weight:700;font-size:16px;border:1px solid var(--line);border-radius:9px;background:var(--card);padding:0;-moz-appearance:textfield}
.denom .ct .cash-input::-webkit-outer-spin-button,.denom .ct .cash-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.denom .ct .cash-input:focus{outline:none;border-color:var(--accent)}
.total-box{background:var(--ink);color:var(--paper);border-radius:16px;padding:16px 20px;display:flex;align-items:baseline;justify-content:space-between;margin-top:12px}
.total-box .v{font-family:"Playfair Display",serif;font-size:28px;font-weight:900}

/* ---------- KDS ---------- */
.kds-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:16px}
.ticket{border-radius:18px;border:1px solid var(--line);background:var(--card);overflow:hidden;box-shadow:var(--shadow-soft)}
.ticket-head{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:var(--ink);color:var(--paper)}
.ticket-head .t{font-weight:800}
.ticket-head .timer{font-family:"Playfair Display",serif;font-weight:700}
.ticket.warn .ticket-head{background:var(--accent)}
.ticket.late .ticket-head{background:var(--red)}
.ticket-body{padding:14px 16px}
.ticket-line{display:flex;justify-content:space-between;gap:8px;padding:7px 0;border-bottom:1px solid var(--line-2);font-size:15px}
.ticket-line:last-child{border-bottom:none}
.ticket-line .q{font-weight:800;color:var(--accent);min-width:30px}
.ticket-line .note{display:block;font-size:12.5px;color:var(--red);font-weight:600}

/* ---------- roster ---------- */
.roster{display:grid;grid-template-columns:repeat(7,1fr);gap:8px}
.roster .hd{font-size:12px;color:var(--ink-soft);text-align:center;font-weight:700;padding-bottom:4px}
.roster .cell{background:var(--paper-2);border:1px solid var(--line-2);border-radius:12px;min-height:118px;padding:8px;cursor:pointer;transition:border-color .15s}
.roster .cell:hover{border-color:var(--accent)}
.roster .cell .d{font-weight:700;font-size:13px;color:var(--ink-soft);display:flex;justify-content:space-between}
.roster .cell.wknd .d{color:var(--accent)}
.shift-chip{display:block;margin-top:5px;padding:4px 7px;border-radius:8px;font-size:11.5px;font-weight:600;line-height:1.35;position:relative}
.shift-chip.a{background:var(--blue-soft);color:var(--blue)}
.shift-chip.b{background:var(--accent-soft);color:var(--accent-ink)}
.shift-chip.x{background:var(--red-soft);color:var(--red)}
.shift-chip.breach{background:var(--red-soft);color:var(--red);outline:2px solid var(--red)}
.shift-chip .rm{position:absolute;right:4px;top:3px;opacity:.5;cursor:pointer}

/* ---------- tasks ---------- */
.task-item{display:flex;gap:13px;align-items:center;padding:14px;border:1px solid var(--line);border-radius:14px;background:var(--card);margin-bottom:10px}
.task-check{width:30px;height:30px;border-radius:9px;border:2px solid var(--line);display:grid;place-items:center;cursor:pointer;flex-shrink:0;font-size:16px;color:#fff}
.task-check.done{background:var(--green);border-color:var(--green)}
/* The tick is a real button now (it was a div, so a keyboard could not reach it
   and a screen reader did not know it could be pressed). The box stays 30px;
   the finger target around it is 44px, for gloved and wet hands. */
.task-check{position:relative;padding:0}
.task-check::after{content:"";position:absolute;inset:-7px}
.task-check:focus-visible{outline:3px solid var(--accent);outline-offset:3px}
.task-item.done{opacity:.7}
.thumb{width:44px;height:44px;border-radius:10px;object-fit:cover;border:1px solid var(--line)}

/* A collapsible .alert: the marker sits inline with the headline so a folded
   block reads as one line, not as a heading with a stray triangle. */
details.alert>summary{display:flex;align-items:flex-start;gap:10px;cursor:pointer;list-style:none;
  font-weight:600}
details.alert>summary::-webkit-details-marker{display:none}
details.alert>summary::after{content:'▸';margin-left:auto;opacity:.55;transition:transform .18s var(--ease-out)}
details.alert[open]>summary::after{transform:rotate(90deg)}
details.alert>summary:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:8px}
.fc-how-body{margin-top:8px;padding-left:28px}
details.disclaimer>summary{cursor:pointer;list-style:none}
details.disclaimer>summary::-webkit-details-marker{display:none}
details.disclaimer>summary::after{content:'▸';margin-left:6px;opacity:.55;display:inline-block;
  transition:transform .18s var(--ease-out)}
details.disclaimer[open]>summary::after{transform:rotate(90deg)}

/* ---------- modal / toast ---------- */
/* The page behind a sheet must not scroll — see U.modal(). */
body.modal-open{overflow:hidden}
/* Above the assistant panel and its button (300/301): a modal is a blocking
   dialog, so nothing may sit on top of it. Only showed up once the assistant
   started opening one of its own. */
.modal-back{position:fixed;inset:0;background:rgba(33,30,27,.42);backdrop-filter:blur(2px);display:grid;place-items:center;z-index:400;padding:20px;animation:fade .2s}
.modal{background:var(--card);border-radius:22px;box-shadow:var(--shadow);width:100%;max-width:460px;max-height:88vh;overflow:auto;overflow-x:hidden;animation:pop .24s var(--ease-out)}
.modal.wide{max-width:680px}
.modal-head{padding:20px 22px 0;display:flex;justify-content:space-between;align-items:flex-start}
.modal-head h3{font-size:18px;font-weight:800}
.modal-body{padding:16px 22px 22px}
/* Desktop: the buttons sit at the foot of the dialog, after the body. */
.modal > .modal-actions{padding:0 22px 22px;gap:10px;flex-wrap:wrap}
.modal:has(> .modal-actions) > .modal-body{padding-bottom:16px}
/* Two fields side by side line their boxes up along the bottom, even when one
   label runs to two lines. */
.row > .field{justify-content:flex-end}
.x{font-size:24px;line-height:1;color:var(--ink-soft);cursor:pointer;background:none}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes pop{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
.toast-wrap{pointer-events:none;position:fixed;bottom:22px;left:16px;right:16px;z-index:200;display:flex;flex-direction:column;gap:8px;align-items:center}
.toast{background:var(--ink);color:var(--paper);padding:12px 18px;border-radius:999px;font-size:14px;font-weight:500;box-shadow:var(--shadow);animation:pop .22s var(--ease-out);max-width:min(440px, 100%);
  transition:opacity .25s, transform .25s var(--ease-out)}
.toast.out{opacity:0;transform:translateY(6px) scale(.97)}
/* Done / went wrong / heads up: a light card, dark words, a coloured mark. */
.toast.green,.toast.red,.toast.amber{display:flex;align-items:center;gap:10px;padding:10px 18px 10px 10px;border-radius:18px;
  background:var(--card);color:var(--ink);font-weight:600;font-size:15px;
  box-shadow:0 0 0 .5px var(--line), 0 10px 30px rgba(33,30,27,.16), 0 2px 6px rgba(33,30,27,.08)}
.toast-mark{flex:none;display:grid;place-items:center;width:28px;height:28px;border-radius:50%;color:#fff}
.toast-mark svg{width:16px;height:16px;stroke-width:2.6}
.toast.green .toast-mark{background:var(--green)}
.toast.red .toast-mark{background:var(--red)}
.toast.amber .toast-mark{background:var(--amber)}
.toast-msg{min-width:0}

.clickable{text-decoration:none;color:inherit;cursor:pointer;transition:transform .14s var(--ease-out),box-shadow .2s}
@media (hover:hover) and (pointer:fine){ .clickable:hover{transform:translateY(-2px);box-shadow:var(--shadow)} }
.clickable:active{transform:scale(.99)}

/* ---------- 顾客端扫码点餐 ---------- */
.cust-wrap{max-width:560px;margin:0 auto;min-height:100vh;background:var(--paper);padding-bottom:90px}
.cust-head{position:sticky;top:0;z-index:10;background:var(--ink);color:var(--paper);padding:18px 20px;border-radius:0 0 22px 22px;display:flex;align-items:center;justify-content:space-between;gap:12px}
.cust-head .btn-ghost{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.25);color:var(--paper);flex:none}
.cust-brand{font-family:"Playfair Display",serif;font-weight:900;font-size:22px}
.cust-table{font-size:13px;opacity:.8;margin-top:2px}
.cust-cats{position:sticky;top:0;display:flex;gap:8px;overflow-x:auto;padding:14px 16px;background:var(--paper);z-index:9}
.cust-cats button{flex:0 0 auto;min-height:42px;padding:0 16px;border-radius:999px;border:1px solid var(--line);background:var(--card);font-weight:600;font-size:14px;white-space:nowrap}
.cust-cats button.active{background:var(--ink);color:var(--paper)}
.cust-menu{padding:4px 16px}
.cust-item{display:flex;align-items:center;justify-content:space-between;gap:12px;background:var(--card);border:1px solid var(--line);border-radius:16px;padding:14px 16px;margin-bottom:10px}
.cust-item .ci-info b{font-size:16px;display:block}
.ci-price{color:var(--accent);font-weight:700;font-size:15px}
.ci-add{flex:0 0 auto;width:42px;height:42px;border-radius:12px;background:var(--accent);color:#fff;font-size:24px;font-weight:700;line-height:1}
.cust-bar{position:fixed;bottom:0;left:0;right:0;max-width:560px;margin:0 auto;padding:12px 16px env(safe-area-inset-bottom);transition:transform .12s;pointer-events:none}
.cust-bar.show{pointer-events:auto}
.cust-cart-btn{display:none}
.cust-bar.show .cust-cart-btn{display:flex;width:100%;align-items:center;justify-content:space-between;gap:10px;background:var(--ink);color:var(--paper);min-height:56px;border-radius:16px;padding:0 20px;font-size:16px;font-weight:700;box-shadow:var(--shadow)}
.cust-cart-btn .go{background:var(--accent);padding:8px 16px;border-radius:999px;font-size:14px}
.cust-lines{max-height:48vh;overflow:auto}
.cust-line{display:flex;gap:10px;align-items:flex-start;padding:12px 2px;border-bottom:1px solid var(--line-2)}
.cust-line .qty{display:flex;align-items:center;gap:10px}
.cust-line .qty button{width:34px;height:34px;border-radius:9px;border:1px solid var(--line);background:var(--paper-2);font-size:18px;font-weight:700}
.ci-note{font-size:12.5px;color:var(--accent);margin-top:3px}
.ci-note.add-note{cursor:pointer;opacity:.85}
.cust-done{text-align:center;padding:60px 20px}
.cust-done .em{font-size:56px}
.cust-done h2{font-size:24px;margin-top:10px}
.cust-done .stars [data-star]{transition:opacity .12s,transform .12s}
.cust-done .stars [data-star]:active{transform:scale(1.2)}
@keyframes urgePulse{0%,100%{box-shadow:0 0 0 0 rgba(216,69,60,.0)}50%{box-shadow:0 0 0 6px rgba(216,69,60,.18)}}
.urge-flash{animation:urgePulse 1.1s ease-in-out infinite}

/* ---------- login: divider + Google button ---------- */
.or-divider{display:flex;align-items:center;gap:12px;margin:16px 0;color:var(--ink-faint);font-size:12.5px}
.or-divider::before,.or-divider::after{content:"";flex:1;height:1px;background:var(--line)}
.btn-google{gap:10px;font-weight:600}
.btn-google svg{flex:0 0 auto}

/* ---------- KPI callout (large stat) ---------- */
.kpi-callout{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;
  background:var(--ink-grad);color:var(--paper);border-radius:var(--radius-lg);
  padding:26px 30px;box-shadow:var(--shadow)}
.kpi-main{display:flex;flex-direction:column;gap:2px;min-width:200px}
.kpi-label{font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:color-mix(in srgb,var(--paper) 72%,transparent)}
.kpi-value{font-family:"Playfair Display",serif;font-weight:900;font-size:clamp(40px,7vw,64px);line-height:1.02}
.kpi-sub{font-size:13px;color:color-mix(in srgb,var(--paper) 76%,transparent);margin-top:4px}
.kpi-side{display:flex;gap:12px;flex-wrap:wrap}
.kpi-mini{background:color-mix(in srgb,var(--paper) 12%,transparent);border-radius:14px;padding:12px 16px;min-width:120px}
.kpi-mini span{display:block;font-size:11.5px;color:color-mix(in srgb,var(--paper) 72%,transparent)}
.kpi-mini b{font-family:"Playfair Display",serif;font-size:24px;color:var(--paper)}

/* ---------- menu item image (POS) ---------- */
.menu-item.has-img{padding-top:0;overflow:hidden}
.menu-item .mi-img{width:calc(100% + 28px);height:84px;object-fit:cover;margin:-1px -14px 8px;border-bottom:1px solid var(--line)}

/* ---------- menu admin grid ---------- */
.menu-admin-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:16px}
.menu-admin-card{overflow:hidden;display:flex;flex-direction:column}
.ma-thumb{height:130px;background:var(--paper-2);display:grid;place-items:center;overflow:hidden}
.ma-thumb img{width:100%;height:100%;object-fit:cover}
.ma-noimg{font-size:38px;opacity:.4}
.ma-body{padding:14px 16px}
.ma-body b{font-size:15px}

/* ---------- image upload drop ---------- */
.img-drop{display:block;cursor:pointer}
.img-preview{border:1.5px dashed var(--line);border-radius:14px;min-height:120px;display:grid;place-items:center;
  background:var(--paper-2);color:var(--ink-soft);font-size:13.5px;overflow:hidden;text-align:center;padding:10px}
.img-preview img{width:100%;max-height:200px;object-fit:contain;border-radius:10px}
.img-drop:hover .img-preview{border-color:var(--accent)}
/* A photo the delivery can't be signed without. The border alone would be a
   colour-only signal, so the label above it says "required" in words too. */
.img-drop.needs .img-preview{border-color:var(--red);border-style:solid;background:var(--red-soft)}

/* Category shelves. A horizontal strip that scrolls on its own rather than
   wrapping into three rows on a phone and pushing the stock off the screen. */
.catbar{display:flex;gap:6px;overflow-x:auto;padding:12px 0 4px;scrollbar-width:none}
.catbar::-webkit-scrollbar{display:none}
.catchip{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);
  background:var(--paper);color:var(--ink);border-radius:999px;padding:6px 13px;font-size:13px;
  font-weight:600;cursor:pointer;white-space:nowrap}
.catchip:hover{border-color:var(--accent)}
.catchip.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.catchip.ghost{font-weight:500;color:var(--ink-soft);border-style:dashed}
.catchip-n{font-size:11.5px;font-weight:600;opacity:.65}

/* Branch switcher in the sidebar header. Styled to read as the venue's subtitle
   rather than as a form control — it sits where the role name used to. */
.branch-pick{appearance:none;-webkit-appearance:none;border:none;background:transparent;
  color:var(--ink-soft);font:inherit;font-size:11.5px;font-weight:600;padding:1px 16px 1px 0;
  max-width:100%;cursor:pointer;border-radius:6px;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-faint) 50%),linear-gradient(135deg,var(--ink-faint) 50%,transparent 50%);
  background-position:calc(100% - 6px) 55%, calc(100% - 2px) 55%;
  background-size:4px 4px, 4px 4px; background-repeat:no-repeat}
.branch-pick:hover{color:var(--accent-ink);background-color:var(--accent-soft)}
.branch-pick:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
body.side-mini .branch-pick{display:none}

/* Signature pad. `touch-action:none` is what stops a finger stroke scrolling
   the page instead of drawing — without it the pad is unusable on the tablet
   it exists for. */
.sigpad{border:1.5px dashed var(--line);border-radius:14px;background:var(--paper-2);height:130px;overflow:hidden}
.sigpad canvas{width:100%;height:100%;display:block;touch-action:none;cursor:crosshair}
.sigpad img{width:100%;height:100%;object-fit:contain}

/* ---------- onboarding checklist ---------- */
.onb-item{display:flex;align-items:center;gap:12px;padding:13px 0;border-bottom:1px solid var(--line-2)}
.onb-item:last-of-type{border-bottom:none}
.onb-ic{width:34px;height:34px;border-radius:10px;display:grid;place-items:center;font-size:16px;flex-shrink:0;
  background:var(--paper-2);border:1px solid var(--line)}
.onb-item.done .onb-ic{background:var(--green);color:#fff;border-color:var(--green);font-weight:800}

/* ---------- customer menu image ---------- */
.cust-item .ci-img{width:64px;height:64px;border-radius:12px;object-fit:cover;flex:0 0 auto;border:1px solid var(--line)}

.lang-toggle{position:fixed;left:14px;bottom:14px;z-index:300;background:var(--ink);color:var(--paper);border:none;border-radius:999px;padding:9px 15px;font-size:13px;font-weight:600;box-shadow:var(--shadow);opacity:.88;min-height:auto}
.lang-toggle:hover{opacity:1;transform:translateY(-1px)}
@media(max-width:880px){.lang-toggle{bottom:78px}}

.empty{text-align:center;color:var(--ink-soft);padding:40px 20px}
.empty .em{font-size:40px;opacity:.5}

/* offline banner */
.offbar{background:var(--amber-soft);color:var(--amber-ink);text-align:center;font-size:13px;font-weight:600;padding:8px;border-bottom:1px solid color-mix(in srgb,var(--amber) 40%,transparent)}

/* mobile nav */
.mobile-nav{display:none}
.navsheet-back{display:none}

/* ---------- "More" sheet (phones only) ----------
   The pages the bottom bar has no room for. The sidebar that carries them is
   hidden under 880px, so without this they have no entry point on a phone. */
@media(max-width:880px){
  .navsheet-back:not(.hidden){display:flex;position:fixed;inset:0;z-index:40;align-items:flex-end;
    background:rgba(33,30,27,.4);backdrop-filter:blur(2px);animation:fade .2s ease}
  /* The grip stays put at the top; only the list under it scrolls. */
  .navsheet{width:100%;max-height:82vh;display:flex;flex-direction:column;overflow:hidden;background:var(--card);
    border-radius:26px 26px 0 0;padding-top:8px;
    box-shadow:0 -10px 40px -18px rgba(33,30,27,.5);animation:sheetUp .26s var(--ease-out)}
  .navsheet-grip{flex:0 0 auto;width:40px;height:4px;border-radius:99px;background:var(--line);margin:6px auto 8px}
  .navsheet-body{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
    padding:6px 16px calc(18px + env(safe-area-inset-bottom))}
  .navsheet-list{display:flex;flex-direction:column}
  .ns-item{display:flex;align-items:center;gap:14px;min-height:56px;padding:8px 4px;
    font-size:15px;font-weight:600;border-bottom:1px solid var(--line-2)}
  .ns-item:last-child{border-bottom:none}
  .ns-ic{display:grid;place-items:center;width:38px;height:38px;border-radius:12px;flex-shrink:0;
    background:var(--tone-soft,var(--paper-2));color:var(--tone,var(--ink-soft))}
  .ns-ic .ic{width:20px;height:20px}
  .ns-item.on{color:var(--accent)}
  .ns-badge{margin-left:auto;background:var(--red);color:#fff;font-size:11.5px;font-weight:800;
    border-radius:999px;padding:2px 8px;min-width:22px;text-align:center}
  .navsheet-foot{display:flex;gap:10px;margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}
  .navsheet-foot .ic{width:17px;height:17px}
}
/* Delete my account: under the account buttons in the sidebar and the More
   sheet. Easy to find, never the thing a thumb lands on by accident. */
.del-acct{display:block;text-align:center;font-size:12px;font-weight:600;margin-top:10px;text-decoration:underline}
.del-acct:hover{color:var(--red)}
@keyframes sheetUp{from{transform:translateY(18px);opacity:.4}to{transform:none;opacity:1}}
@media(max-width:880px){
  .shell{grid-template-columns:1fr}
  .sidebar{display:none}
  .pos{grid-template-columns:1fr}
  .cart{position:static}
  .g3,.g4{grid-template-columns:1fr 1fr}
  .content{padding:18px 16px 90px}
  .topbar{padding:12px 16px}
  .roster{grid-template-columns:repeat(7,1fr);gap:4px}
  .roster .cell{min-height:84px;padding:5px}
  .cash-grid{grid-template-columns:1fr 1fr}
  .mobile-nav{display:flex;position:fixed;bottom:0;left:0;right:0;z-index:30;background:var(--card);border-top:1px solid var(--line);justify-content:space-around;padding:6px 4px env(safe-area-inset-bottom)}
  .mobile-nav a,.mobile-nav button{display:flex;flex-direction:column;align-items:center;gap:2px;font-size:10.5px;font-weight:600;color:var(--ink-soft);padding:6px 10px;min-width:56px;min-height:48px;justify-content:center}
  .mobile-nav a.active,.mobile-nav button.active{color:var(--accent)}
  .mobile-nav a .em,.mobile-nav button .em{font-size:20px;position:relative}
  .mn-badge{position:absolute;top:-5px;left:12px;min-width:16px;height:16px;padding:0 4px;border-radius:999px;
    background:var(--red);color:#fff;font-size:10px;font-weight:800;line-height:16px;text-align:center;
    border:1.5px solid var(--card)}
}
@media(max-width:520px){.g2,.g3,.g4{grid-template-columns:1fr}.cash-grid{grid-template-columns:1fr 1fr}.role-pick{grid-template-columns:1fr}}

/* ===== System language switch (英 / 中) ===== */
.lang-switch{display:inline-flex;gap:0;border:1px solid var(--line);border-radius:999px;overflow:hidden;background:var(--card);flex-shrink:0}
.lang-switch button{appearance:none;border:none;background:transparent;cursor:pointer;font:inherit;font-size:13px;font-weight:600;color:var(--ink-soft);padding:6px 14px;min-height:36px;line-height:1}
.lang-switch button.active{background:var(--accent);color:#fff}
.lang-switch button:not(.active):hover{background:var(--paper-2)}
.login-card .lang-switch{position:absolute;top:16px;right:16px}
/* ---------- simplified owner home ("Today") — action-first, low-clutter ---------- */
.today-label{font-size:12.5px;font-weight:700;color:var(--ink-soft);letter-spacing:.05em;text-transform:uppercase;margin:2px 0 12px}
.today-acts{display:flex;flex-direction:column;gap:12px}
.today-act{display:flex;align-items:center;gap:14px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;transition:transform .16s var(--ease-out),box-shadow .2s}
@media (hover:hover) and (pointer:fine){ .today-act:hover{transform:translateY(-2px);box-shadow:var(--shadow-soft)} }
.today-act-ic{width:46px;height:46px;border-radius:13px;display:flex;align-items:center;justify-content:center;font-size:24px;flex-shrink:0}
.today-act-body{flex:1;min-width:0}
.today-act-body b{display:block;font-size:16px;font-weight:700;color:var(--ink)}
.today-act-body span{display:block;font-size:13.5px;color:var(--ink-soft);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.today-act-n{background:var(--ink);color:var(--paper);font-size:14px;font-weight:800;min-width:26px;height:26px;border-radius:999px;display:flex;align-items:center;justify-content:center;padding:0 8px;flex-shrink:0}
.today-act-chev{color:var(--ink-faint);font-size:22px;flex-shrink:0}
.ic{width:20px;height:20px;flex-shrink:0;vertical-align:-4px}
.btn .ic{width:16px;height:16px;vertical-align:0}
.today-act-ic .ic{width:24px;height:24px}
.today-clear-ic .ic{width:26px;height:26px}
.today-foot-head .ic{width:16px;height:16px;color:var(--green);flex-shrink:0}
.today-clear{display:flex;flex-direction:column;align-items:center;text-align:center;padding:40px 24px;gap:5px}
.today-clear-ic{width:56px;height:56px;border-radius:50%;background:var(--green-soft);color:var(--green);font-size:28px;display:flex;align-items:center;justify-content:center;margin-bottom:6px}
.today-clear b{font-size:18px;color:var(--ink)}
.today-clear span{font-size:14px;color:var(--ink-soft)}
.today-foot{margin-top:26px;padding-top:18px;border-top:1px solid var(--line)}
.today-foot-head{display:flex;align-items:center;gap:8px;font-size:13.5px;color:var(--ink-soft);margin-bottom:14px}
.today-foot-metrics{display:flex;flex-wrap:wrap;gap:10px}
.today-foot-metrics a{display:flex;flex-direction:column;gap:2px;background:var(--paper-2);border:1px solid var(--line-2);border-radius:14px;padding:10px 16px;min-width:92px}
.today-foot-metrics a span{font-size:12px;color:var(--ink-faint)}
.today-foot-metrics a b{font-size:17px;font-weight:800;color:var(--ink)}
@media (hover:hover) and (pointer:fine){ .today-foot-metrics a:hover{background:var(--card);border-color:var(--line)} }

/* compact summary strip — replaces stacked stat cards across pages */
/* Cells grow into the row they land on, so a wrapped last cell fills the width
   instead of sitting there as a narrow orphan. A fixed column count can't do
   this — it would leave the same gap at some other width. */
.statline{display:flex;flex-wrap:wrap;gap:10px;margin:4px 0 18px}
.statcell{flex:1 1 96px;display:flex;flex-direction:column;gap:1px;background:var(--paper-2);border:1px solid var(--line-2);border-radius:12px;padding:8px 16px;min-width:0}
.statcell b{font-size:18px;font-weight:800;color:var(--ink);line-height:1.1}
.statcell i{font-size:11.5px;color:var(--ink-faint);font-style:normal}
/* A figure never breaks across lines ("$120.0 / 0"): a cell too narrow for
   its number moves to the next row instead. */
.statcell b{white-space:nowrap;font-variant-numeric:tabular-nums}
.statcell{min-width:max-content}
@media (max-width:600px){ .statcell{padding:10px 14px} .statcell i{line-height:1.3} }
@media (hover:hover) and (pointer:fine){ .statcell.warn:hover{background:var(--card)} }

/* staff home — today's shift + the one action (clock in) */
.staff-today{display:flex;flex-direction:column;align-items:flex-start;padding:22px 22px 24px}
.staff-today-top{display:flex;align-items:center;justify-content:space-between;width:100%;gap:10px}
.staff-today-label{font-size:12.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--accent)}
.staff-today-date{font-size:13px;color:var(--ink-faint)}
.staff-today-time{font-family:"Playfair Display",serif;font-weight:900;font-size:clamp(30px,7vw,42px);line-height:1.05;color:var(--ink);margin-top:8px}
.staff-today-hrs{font-size:14px;color:var(--ink-soft);margin-bottom:16px}
.staff-clock-btn{min-height:54px;font-size:17px;padding:0 40px;width:100%;max-width:300px}
.staff-today-status{font-size:15px;padding:10px 0}
.staff-today-status.ok{color:var(--green)}
.staff-today-status.late{color:var(--red)}

/* Language <select> — replaces the old EN|中 toggle; scales to N languages */
.lang-select{appearance:none;-webkit-appearance:none;border:1px solid var(--line);border-radius:999px;
  background:var(--card) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236F655B' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 12px center;
  color:var(--ink);font:inherit;font-size:13px;font-weight:600;padding:8px 32px 8px 14px;min-height:36px;cursor:pointer;flex-shrink:0}
.lang-select:hover{background-color:var(--paper-2)}
.login-card .lang-select{position:absolute;top:16px;right:16px;z-index:2}
.login-card{position:relative}

/* ===== Login tabs (Sign in / Apply) ===== */
.login-tabs{display:flex;gap:6px;background:var(--paper-2);border:1px solid var(--line);border-radius:12px;padding:4px}
.login-tabs button{flex:1;appearance:none;border:none;background:transparent;cursor:pointer;font:inherit;font-size:13px;font-weight:600;color:var(--ink-soft);padding:9px 8px;border-radius:9px;line-height:1.2}
.login-tabs button.active{background:var(--card);color:var(--ink);box-shadow:var(--shadow-soft)}

/* ===== Approved-restaurant logo strip on login ===== */
.logo-strip{margin-top:16px;border-top:1px solid var(--line-2);padding-top:12px}
.logo-strip>.faint{font-size:11px;text-transform:uppercase;letter-spacing:.08em}
.logo-strip-row{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.logo-strip-row img{width:38px;height:38px;border-radius:10px;object-fit:cover;border:1px solid var(--line);background:var(--card)}

/* ===== Restaurant logo in Super Admin lists ===== */
.kit-logo{width:40px;height:40px;border-radius:12px;object-fit:cover;border:1px solid var(--line);flex-shrink:0}

/* ===== Role segmented control (owner: change role) ===== */
.role-seg{display:flex;gap:8px;margin-top:6px}
.role-seg button{flex:1;appearance:none;border:1px solid var(--line);background:var(--paper-2);cursor:pointer;font:inherit;font-size:14px;font-weight:600;color:var(--ink-soft);padding:14px 8px;border-radius:14px}
.role-seg button.active{border-color:var(--ink);background:var(--ink);color:var(--paper)}

/* ===== AI assistant (floating chat) ===== */
.ai-fab{position:fixed;right:18px;bottom:18px;z-index:300;width:56px;height:56px;border-radius:50%;
  background:var(--ink);color:var(--paper);font-size:24px;box-shadow:var(--shadow);display:grid;place-items:center;
  border:none;cursor:pointer;transition:transform .15s,background .2s}
.ai-fab:hover{transform:translateY(-2px)}
.ai-fab.open{background:var(--accent)}
.ai-fab .ic{width:24px;height:24px;stroke-width:2}
/* On a phone the bottom bar already carries AI, so the floating button was a
   second door to the same room — one that sat on top of the content on every
   single page. Desktop keeps it; there the sidebar link is further away. */
/* The assistant used to be desktop-only. It cannot be: the guided onboarding
   conversation is for someone's first morning, and that person is holding a
   phone. So it stays — lifted clear of the bottom nav rather than hidden. */
@media(max-width:880px){.ai-fab{bottom:calc(72px + env(safe-area-inset-bottom));width:50px;height:50px}}
.ai-panel{position:fixed;right:18px;bottom:84px;z-index:301;width:min(380px,calc(100vw - 36px));max-height:min(560px,calc(100vh - 120px));
  background:var(--card);border:1px solid var(--line);border-radius:20px;box-shadow:var(--shadow);
  display:none;flex-direction:column;overflow:hidden;animation:pop .2s ease}
.ai-panel.show{display:flex}
@media(max-width:880px){.ai-panel{bottom:140px;right:12px;left:12px;width:auto}}
.ai-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;background:var(--paper-2);border-bottom:1px solid var(--line-2)}
.ai-head b{font-size:15px}
.ai-x{font-size:22px;line-height:1;color:var(--ink-soft);background:none;cursor:pointer}
.ai-log{flex:1;overflow:auto;padding:14px 14px 4px;display:flex;flex-direction:column;gap:10px}
.ai-msg{max-width:88%;padding:10px 13px;border-radius:14px;font-size:14px;line-height:1.5;word-wrap:break-word;overflow-wrap:anywhere}
.ai-msg.bot{background:var(--paper-2);border:1px solid var(--line-2);align-self:flex-start;border-bottom-left-radius:5px}
/* A guided-onboarding bubble carries a form, not a sentence — it gets the whole
   panel width, and its own inline validation line. */
.ai-msg.ai-form{max-width:100%;width:100%}
.ai-msg.ai-form .field{margin-bottom:8px}
.ob-warn{color:var(--red);font-size:12px;margin-top:6px}
/* Signature pad. touch-action:none so a finger drawing a signature draws
   instead of scrolling the modal out from under it. Always white with dark
   ink: it becomes a page on paper, dark mode or not. */
.sig-pad{display:block;width:100%;height:190px;border:1.5px dashed var(--line);border-radius:14px;background:#fff;touch-action:none;cursor:crosshair}
.sig-decl{background:var(--paper-2);border:1px solid var(--line-2);border-radius:14px;padding:14px 16px}
.ai-msg.user{background:var(--ink);color:var(--paper);align-self:flex-end;border-bottom-right-radius:5px}
.ai-msg b{font-weight:700}
.ai-jump{display:inline-block;margin-top:6px;color:var(--accent);font-weight:700;cursor:pointer}
.ai-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.ai-chip{background:var(--card);border:1px solid var(--line);border-radius:999px;padding:6px 12px;font-size:12.5px;font-weight:600;color:var(--ink);cursor:pointer}
.ai-chip:hover{border-color:var(--accent);color:var(--accent-ink)}
.ai-input-row{display:flex;gap:8px;padding:12px 14px;border-top:1px solid var(--line-2)}
.ai-input-row .input{height:44px}
.ai-input-row .btn{min-height:44px;padding:0 16px}
.ai-dots{display:inline-flex;gap:4px}
.ai-dots i{width:6px;height:6px;border-radius:50%;background:var(--ink-faint);animation:aiBlink 1s infinite}
.ai-dots i:nth-child(2){animation-delay:.2s}.ai-dots i:nth-child(3){animation-delay:.4s}
@keyframes aiBlink{0%,100%{opacity:.3}50%{opacity:1}}

/* The assistant as the app's home screen rather than a corner panel: the
   conversation fills the page and the composer sits at the bottom of it.
   It reuses .ai-log / .ai-msg / .ai-input-row wholesale — only the frame and
   the reading width differ, because a message that is comfortable in a 380px
   panel runs the full width of a desktop and stops being readable. */
.ai-page{display:flex;flex-direction:column;height:100%;min-height:min(70vh,680px);
  background:var(--card);border:1px solid var(--line-2);border-radius:var(--radius);overflow:hidden}
.ai-page .ai-log{flex:1;padding:20px 20px 8px;gap:12px}
.ai-page .ai-msg{max-width:min(68ch,86%)}
.ai-page .ai-input-row{padding:14px 18px}
/* Suggestions after a replayed conversation — a hint, not a message, so it
   carries no bubble and sits flush with the thread. */
.ai-page .ai-suggest{align-self:flex-start;max-width:100%}
.ai-page .ai-suggest .ai-chips{margin-top:0}

/* On the assistant's own page the shell stops scrolling and the conversation
   scrolls inside it. Without this the thread grows the page, the composer
   rides down with it, and answering a long conversation means scrolling to the
   bottom to find the box. `min-height:0` on each flex link is what lets the
   log shrink instead of pushing the composer off. */
body.ai-fullpage .main{height:100vh;overflow:hidden}
body.ai-fullpage .content{display:flex;min-height:0;overflow:hidden}
body.ai-fullpage .ai-page{flex:1;min-height:0;height:auto}
@media(max-width:880px){
  /* dvh, because the phone's address bar collapsing must not leave the composer
     under the fold. The bottom bar still needs its own room. */
  body.ai-fullpage .main{height:100dvh}
  body.ai-fullpage .content{padding-bottom:calc(66px + env(safe-area-inset-bottom))}
}
@media(max-width:880px){
  /* Edge to edge on a phone, and tall enough that the keyboard opening does not
     leave the conversation as a two-line slot. */
  .ai-page{border:none;border-radius:0;min-height:calc(100vh - 210px);background:transparent}
  .ai-page .ai-log{padding:6px 2px 4px}
  .ai-page .ai-msg{max-width:92%}
  .ai-page .ai-input-row{padding:12px 2px}
}

/* A supplier whose docket the reader has learned. */
.sup-learned{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:12px;background:var(--green-soft);color:var(--ink);grid-column:1/-1}
.sup-learned > .ic{color:var(--green)}
.sup-learned div{flex:1;display:flex;flex-direction:column;font-size:13px}
.sup-learned span{color:var(--ink-soft);font-size:12px}

/* Cash-up: one row per note and coin. The ones that stay in the till as the
   float are marked, so the person counting can see which pile is which. */
.cu-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px 14px}
.cu-row{display:grid;grid-template-columns:52px 1fr 76px;align-items:center;gap:8px;padding:4px 0}
.cu-den{font-weight:700;font-variant-numeric:tabular-nums}
.cu-row.keep .cu-den{color:var(--green)}
.cu-legend{color:var(--green);font-weight:600}
/* A phone counts two piles side by side, so the whole drawer fits in a thumb's
   reach instead of eleven rows of scrolling. The subtotal sits under the box. */
@media(max-width:560px){
  .cu-grid{grid-template-columns:1fr 1fr;gap:4px 12px}
  .cu-row{grid-template-columns:42px 1fr;gap:6px;padding:2px 0}
  .cu-sub{grid-column:2;text-align:left;font-size:11.5px;margin-top:-2px}
  .cu-sub:empty{display:none}
}
.cu-row .input{padding:8px 10px}
.cu-sub{font-size:12.5px;color:var(--ink-soft);text-align:right;font-variant-numeric:tabular-nums}

/* The home page: the dashboard on top and the conversation under it. The chat
   is a fixed-height panel, so a long thread scrolls inside it and the numbers
   above stay where they are. */
.home-chat{margin-top:22px}
.home-chat-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 2px 10px}
.home-chat-head b{font-size:15px}
.home-chat-head .faint{font-size:12.5px;flex-basis:100%;margin-left:26px;margin-top:-4px}
.home-chat .ai-page{height:min(62vh,560px);min-height:360px}
.home-fold{display:none}
.home-chat-size{display:none}
/* A computer has the width for both: the numbers on the left, the conversation
   a column beside them that stays put while the numbers scroll. */
@media(min-width:1200px){
  .home-split{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:22px;align-items:start}
  .home-chat{margin-top:0;position:sticky;top:84px;height:calc(100vh - 120px);display:flex;flex-direction:column}
  /* A preview or offline bar above the topbar pushes the column down until it scrolls away. */
  .main:has(> .offbar:not(.hidden)) .home-chat{height:calc(100vh - 160px)}
  .home-chat-head .faint{display:none}
  #homeChat{flex:1;min-height:0;display:flex}
  .home-chat .ai-page{flex:1;height:auto;min-height:0}
  .home-chat .ai-page .ai-log{padding:14px 14px 6px}
  .home-chat .ai-page .ai-msg{max-width:92%}
  .home-chat .ai-page .ai-input-row{padding:10px 10px}
  .home-split.chat-wide{grid-template-columns:minmax(0,1fr) minmax(0,1.5fr)}
  .home-chat-size{display:inline-flex;align-items:center;justify-content:center;margin-left:auto;width:32px;height:32px;
    border:1px solid var(--line-2);border-radius:10px;background:var(--card);color:var(--ink-soft);cursor:pointer;padding:0}
  .home-chat-size:hover{color:var(--accent);border-color:var(--accent)}
  .home-chat-size .ic{width:16px;height:16px}
}
@media(max-width:880px){
  /* Phone: the chat is the home screen; the numbers are one tap away. */
  .home-fold{display:flex;align-items:center;gap:8px;width:100%;padding:10px 14px;border-radius:var(--radius);
    border:1px solid var(--line-2);background:var(--card);font-weight:600;font-size:14px;color:var(--ink);cursor:pointer}
  .home-fold span{flex:1;text-align:left}
  .home-fold .ic:last-child{transition:transform .2s}
  .show-dash .home-fold .ic:last-child{transform:rotate(90deg)}
  .home-dash{display:none}
  .show-dash > .home-dash{display:block;margin-top:10px}
  .home-chat{margin-top:10px}
  .home-chat-head .faint{display:none}
  .home-chat .ai-page{height:calc(100dvh - 300px - env(safe-area-inset-bottom));min-height:300px;border:1px solid var(--line-2);border-radius:var(--radius);background:var(--card)}
  .home-chat .ai-page .ai-log{padding:12px 12px 4px}
  .home-chat .ai-page .ai-input-row{padding:10px 10px}
}

/* ===== Dashboard v2 (icons, charts, count-up) ===== */
.ic{width:18px;height:18px;flex:0 0 auto;vertical-align:-3px}
.pad20{padding:20px}
.ds-hero{display:grid;grid-template-columns:1.1fr 1fr;gap:24px;padding:24px;background:
  radial-gradient(120% 140% at 100% 0%, rgba(201,97,46,.10), transparent 55%), var(--card)}
.ds-hero-label{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:600;color:var(--ink-soft)}
.ds-hero-value{font-family:"Playfair Display",serif;font-weight:900;font-size:46px;line-height:1.05;display:block;margin:4px 0 2px;letter-spacing:-.5px}
.ds-hero-sub{font-size:13px;color:var(--ink-faint)}
.ds-mini-row{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}
.ds-mini{flex:1 1 120px;background:var(--paper-2);border:1px solid var(--line-2);border-radius:12px;padding:10px 12px}
.ds-mini span{display:block;font-size:11.5px;color:var(--ink-soft)}
.ds-mini b{font-size:17px}
.ds-hero-chart{display:flex;flex-direction:column;justify-content:flex-end}
.ds-chart-cap{font-size:11.5px;font-weight:600;color:var(--ink-soft);margin-bottom:8px}
.ds-bars{display:flex;align-items:flex-end;gap:8px;height:96px}
.ds-bar-wrap{flex:1;height:100%;display:flex;align-items:flex-end}
.ds-bar{width:100%;height:0;min-height:3px;border-radius:6px 6px 3px 3px;background:linear-gradient(180deg,var(--accent),#e08a5a);
  transition:height .55s var(--ease-out)}
.ds-bar-wrap:last-child .ds-bar{background:linear-gradient(180deg,var(--ink),#4a443d)}
.ds-bars-x{display:flex;gap:8px;margin-top:6px}
.ds-bars-x span{flex:1;text-align:center;font-size:10.5px;color:var(--ink-faint)}
.ds-tile{display:flex;align-items:center;gap:14px;padding:16px 18px}
.ds-ico{width:42px;height:42px;flex:0 0 auto;border-radius:13px;background:var(--accent-soft);color:var(--accent-ink);display:grid;place-items:center}
.ds-ico .ic{width:21px;height:21px}
.ds-tile-body{display:flex;flex-direction:column;min-width:0}
.ds-tile-label{font-size:12.5px;color:var(--ink-soft);font-weight:500}
.ds-tile-val{font-family:"Playfair Display",serif;font-weight:900;font-size:26px;line-height:1.15}
.ds-tile-val small{font-size:14px;font-family:inherit}
.ds-tile-delta{font-size:11.5px;color:var(--ink-faint);font-weight:600}
.ds-tile-delta.up{color:var(--green)}.ds-tile-delta.down{color:var(--red)}
.bestlist{display:flex;flex-direction:column;gap:12px;margin-top:6px}
.bestrow{display:grid;grid-template-columns:120px 1fr 28px;align-items:center;gap:12px}
.bestnm{font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.besttrack{height:10px;background:var(--paper-2);border-radius:99px;overflow:hidden}
.bestfill{height:100%;width:0;border-radius:99px;background:linear-gradient(90deg,var(--accent),#e08a5a);transition:width .6s var(--ease-out)}
.bestq{font-weight:800;font-size:14px;text-align:right;font-family:"Playfair Display",serif}
.gauge-val{font-family:"Playfair Display",serif;font-weight:900;font-size:34px;margin:6px 0 10px}
.gauge-val small{font-size:16px}
.gauge{position:relative;height:14px;background:var(--paper-2);border-radius:99px;overflow:hidden}
.gauge-fill{height:100%;width:0;border-radius:99px;transition:width .6s var(--ease-out)}
.gauge-line{position:absolute;top:-3px;width:2px;height:20px;background:var(--ink);border-radius:2px}
.gauge-legend{display:flex;justify-content:space-between;font-size:11.5px;color:var(--ink-soft);margin-top:8px}
/* An item can carry a photo of the actual thing. Small, square, and never
   required — the name is still the item, the picture only makes it faster to
   find on a shelf you're standing in front of. */
.itm-nm{display:inline-flex;align-items:center;gap:8px}
.itm-ph{width:30px;height:30px;border-radius:8px;object-fit:cover;flex:none;background:var(--paper-2)}
.ds-li-ic .itm-ph{width:100%;height:100%;border-radius:inherit}
.ds-li-ic{width:40px;height:40px;flex:0 0 auto;border-radius:12px;background:var(--accent-soft);color:var(--accent-ink);display:grid;place-items:center}
.ds-li-ic .ic{width:20px;height:20px}
/* Severity as a tinted chip rather than a 🔴/🟠/🔵 emoji: an emoji circle is
   colour and nothing else, and it renders differently on every OS. */
.ds-li-ic.sev-red{background:var(--red-soft);color:var(--red-ink)}
.ds-li-ic.sev-amber{background:var(--amber-soft);color:var(--amber-ink)}
.ds-li-ic.sev-info{background:var(--blue-soft);color:var(--blue-ink)}
@media(max-width:760px){ .ds-hero{grid-template-columns:1fr} }

/* ===== Accessibility: respect reduced motion (keep opacity, drop movement) ===== */
@media (prefers-reduced-motion: reduce){
  *{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.05ms !important;scroll-behavior:auto !important}
  .btn:active{transform:none}
  .clickable:hover,.clickable:active,.btn-dark:hover{transform:none}
  @keyframes pop{from{opacity:0}to{opacity:1}}
  .urge-flash{animation:none}
}

/* ===== Nav icons (SVG replaces emoji) ===== */
.nav-item .em{display:inline-flex;align-items:center;justify-content:center;width:22px}
.nav-item .em svg{width:19px;height:19px}
.mobile-nav a .em{display:inline-flex;align-items:center;justify-content:center}
.mobile-nav a .em svg{width:22px;height:22px}

/* ===== Membership / loyalty / QR ===== */
.mem-box{margin-bottom:12px}
.mem-card{display:flex;align-items:center;gap:12px;padding:12px 14px;border:1px solid var(--line-2);border-radius:14px;background:var(--accent-soft)}
.earn-hint{font-size:12.5px}
.qr{display:block;border-radius:10px}
.qr-fallback{display:flex;align-items:center;justify-content:center;border:2px dashed var(--line);border-radius:12px;background:#fff;text-align:center;padding:8px}
.qr-fallback span{font-family:ui-monospace,Menlo,monospace;font-weight:700;font-size:18px;letter-spacing:2px;word-break:break-all}
.mem-detail{display:flex;gap:18px;align-items:flex-start;flex-wrap:wrap}
.qr-wrap{display:flex;flex-direction:column;align-items:center;gap:6px}
.qr-code{font-family:ui-monospace,Menlo,monospace;font-weight:700;letter-spacing:2px;font-size:14px}
.mem-detail .kv{background:var(--paper);border:1px solid var(--line-2);border-radius:11px;padding:8px 12px;min-width:78px}
.mem-detail .kv .muted{font-size:11.5px}
.mem-detail .kv b{font-size:16px;display:block;margin-top:2px}
@media(max-width:520px){.mem-detail{flex-direction:column;align-items:stretch}}

/* ===== Design polish pass (cohesive across all portals) ===== */
/* Smooth page transition on every navigation */
@keyframes viewIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.view-enter{animation:viewIn .30s var(--ease-out)}

/* Interactive list rows feel responsive (subtle, even on static lists) */
.li{padding:13px 10px;margin:0 -2px;border-radius:12px;transition:background .15s}
@media (hover:hover) and (pointer:fine){ .li:hover{background:var(--paper-2)} }

/* Stat tiles: aligned figures + a clearer interactive cue when clickable */
.stat .v{font-variant-numeric:tabular-nums;letter-spacing:-.4px}
.ds-tile-val,.ds-hero-value{font-variant-numeric:tabular-nums}
.stat.clickable:hover{border-color:var(--accent)}

/* Cards that act as buttons get a hairline accent on hover */
@media (hover:hover) and (pointer:fine){
  .card.clickable:hover,.menu-item:hover{border-color:var(--accent)}
}

/* Refined empty states — a soft "drop-zone" panel instead of bare text */
.empty{border:1.5px dashed var(--line);border-radius:16px;background:var(--paper-2)}
.empty .em{font-size:34px;opacity:.6;display:inline-grid;place-items:center;width:64px;height:64px;
  margin:0 auto 6px;border-radius:50%;background:var(--card);box-shadow:var(--shadow-soft)}
.empty .em .ic{width:28px;height:28px;color:var(--ink-faint)}
.empty p{font-size:13.5px}

/* Sidebar: clearer active state + crisper icons */
.nav-item{transition:background .15s,color .15s}
.nav-item.active{box-shadow:var(--shadow-soft)}
.nav-item .em svg{transition:transform .15s}
@media (hover:hover) and (pointer:fine){ .nav-item:hover .em svg{transform:scale(1.08)} }

/* Accessible keyboard focus everywhere */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:8px}
.input:focus-visible{outline:none}

/* Honor reduced-motion */
@media (prefers-reduced-motion:reduce){
  .view-enter{animation:none}
  .nav-item:hover .em svg{transform:none}
}

/* ===== Sold-out / 86 states ===== */
.menu-item.is-soldout{opacity:.5;cursor:not-allowed;filter:grayscale(.5)}
.menu-item.is-soldout .pr{color:var(--red);font-weight:700}
.menu-admin-card.is-soldout{opacity:.7}
.ma-thumb{position:relative}
.soldout-tag{position:absolute;top:8px;left:8px;background:var(--red);color:#fff;font-size:11px;font-weight:700;
  padding:3px 9px;border-radius:999px;letter-spacing:.02em}
.cust-item.is-soldout{opacity:.55}
.cust-item.is-soldout .ci-price{color:var(--red);font-weight:700}
.ci-sold{font-size:12px;font-weight:700;color:var(--red);padding:0 10px;white-space:nowrap}

/* ===== Receipt / print ===== */
.receipt{font-family:ui-monospace,Menlo,Consolas,monospace;max-width:300px;margin:0 auto;color:#111}
.rc-head{text-align:center;margin-bottom:10px}
.rc-head b{font-family:"Playfair Display",serif;font-size:20px;display:block}
.rc-sub{font-size:11px;color:var(--ink-soft)}
.rc-meta{font-size:11.5px;color:var(--ink-soft);text-align:center;border-bottom:1px dashed var(--line);padding-bottom:10px;margin-bottom:10px;line-height:1.5}
.rc-row{display:flex;justify-content:space-between;font-size:13px;gap:10px;padding:2px 0}
.rc-row i{color:var(--ink-soft);font-style:italic}
.rc-items{border-bottom:1px dashed var(--line);padding-bottom:8px;margin-bottom:8px}
.rc-grand{font-weight:800;font-size:15px;border-top:1px solid var(--line);margin-top:6px;padding-top:6px}
.rc-member{margin-top:12px;padding:9px 10px;background:var(--accent-soft);border-radius:10px;font-size:12.5px;text-align:center}
.rc-foot{text-align:center;font-size:12px;color:var(--ink-soft);margin-top:12px}

#print-area{display:none}
@media print{
  /* Paper is white whatever the screen is doing. Without this a venue printing
     a docket in dark mode gets light-on-dark tokens on white paper — a page
     that looks blank. */
  :root{
    --paper:#FFFFFF; --paper-2:#F8F6F2; --card:#FFFFFF;
    --ink:#211E1B; --ink-soft:#5A524A; --ink-faint:#6E665D;
    --line:rgba(33,30,27,.18); --line-2:rgba(33,30,27,.10);
    --accent:#C9612E; --accent-soft:#F4E2D5; --accent-ink:#9A4516;
    --green:#2F8F5B; --green-soft:#E9F6EE; --green-ink:#1D6A40;
    --red:#D8453C; --red-soft:#FDECEA; --red-ink:#922019;
    --amber:#E0A11B; --amber-soft:#FBF2DA; --amber-ink:#8A6410;
    --blue:#2B5BB5; --blue-soft:#E7EEFB; --blue-ink:#234A8F;
    color-scheme:light;
  }
  body{background:#fff}
  body *{visibility:hidden}
  #print-area, #print-area *{visibility:visible}
  #print-area{display:block;position:absolute;left:0;top:0;width:100%;padding:10px}
  .receipt{max-width:none}
}

/* ============================================================
   ===== Visual refresh v2 — cohesive premium pass (all portals) =====
   Elevates the shared design tokens + key components. Structure-safe:
   overrides only finish (depth, gradients, motion), not layout.
   ============================================================ */
:root{
  /* Layered, softer-yet-present shadows = real depth */
  --shadow:0 1px 2px rgba(33,30,27,.06), 0 6px 16px -6px rgba(33,30,27,.12), 0 28px 52px -30px rgba(33,30,27,.32);
  --shadow-soft:0 1px 2px rgba(33,30,27,.05), 0 8px 20px -14px rgba(33,30,27,.22);
  /* Derived from --accent so a venue's own colour reaches the primary buttons
     and the sign-in mark. Hardcoded stops here meant the brand applied to
     tags and avatars but every main button stayed the default orange. */
  --accent-grad:linear-gradient(140deg, var(--accent), var(--accent-ink));
  --ink-grad:linear-gradient(152deg,#2B2723,#161310);
  --green-grad:linear-gradient(140deg,#37A468,#258A51);
}

/* Page: a whisper of warmth instead of a flat fill */
body{
  background:
    radial-gradient(1100px 620px at 6% -8%, rgba(201,97,46,.055), transparent 60%),
    radial-gradient(1000px 600px at 100% 0%, rgba(47,143,91,.045), transparent 55%),
    var(--paper);
  background-attachment:fixed;
}

/* Buttons: gradient primaries + a smoother, more tactile lift */
.btn{font-weight:650;letter-spacing:.01em}
.btn-dark{background:var(--ink-grad)}
.btn-accent{background:var(--accent-grad)}
.btn-green{background:var(--green-grad)}
@media (hover:hover) and (pointer:fine){
  .btn-dark:hover,.btn-accent:hover,.btn-green:hover{transform:translateY(-1.5px);box-shadow:0 12px 26px -12px rgba(33,30,27,.5)}
}

/* Cards: a touch more lift + responsive hover */
.card{transition:box-shadow .22s var(--ease-out),transform .22s var(--ease-out),border-color .2s}

/* Inputs: rounded a hair more + a soft focus ring */
.input{border-radius:13px;transition:border-color .15s,background .15s,box-shadow .18s}
.input:focus{box-shadow:0 0 0 3px var(--accent-soft)}

/* Sidebar active + brand mark = the gradient ink */
.nav-item.active{background:var(--ink-grad)}
.side-brand .logo{background:var(--ink-grad);box-shadow:0 6px 16px -8px rgba(33,30,27,.5)}

/* Crisper headings */
.topbar h1,.section-head h2{letter-spacing:-.015em}

/* Login: richer brand mark + deeper card */
.login-logo{background:var(--accent-grad);box-shadow:0 12px 26px -10px color-mix(in srgb, var(--accent) 55%, transparent)}
.login-card{border-radius:26px}

/* Stat / dashboard tiles: gentle hover so cards feel alive */
@media (hover:hover) and (pointer:fine){
  .stat:hover,.ds-tile:hover{box-shadow:var(--shadow-soft)}
}

/* ===== 全能助手 · AI Admin agent ===== */
.ai-admin{max-width:760px;margin:0 auto;display:flex;flex-direction:column;height:calc(100vh - 140px);min-height:420px}
.aa-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:14px;border-bottom:1px solid var(--line-2);margin-bottom:14px}
.aa-orb{width:42px;height:42px;border-radius:14px;display:grid;place-items:center;font-size:20px;
  background:var(--ink-grad);color:var(--paper);box-shadow:var(--shadow-soft)}
.aa-log{flex:1;overflow:auto;display:flex;flex-direction:column;gap:12px;padding:4px 2px 10px}
.aa-msg{max-width:86%;padding:13px 16px;border-radius:16px;font-size:14.5px;line-height:1.6;word-wrap:break-word;overflow-wrap:anywhere}
.aa-msg.bot{align-self:flex-start;background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow-soft);border-bottom-left-radius:6px}
.aa-msg.user{align-self:flex-end;background:var(--ink);color:var(--paper);border-bottom-right-radius:6px}
.aa-msg b{font-weight:700}
.aa-confirm{font-size:14.5px}
.aa-chips{display:flex;gap:8px;flex-wrap:wrap;padding:10px 0}
.aa-chip{font-size:13px;padding:8px 13px;border-radius:999px;border:1px solid var(--line);background:var(--card);color:var(--ink-soft);white-space:nowrap}
.aa-chip:hover{border-color:var(--accent);color:var(--accent-ink)}
.aa-input{display:flex;gap:8px;align-items:center;padding-top:10px;border-top:1px solid var(--line-2)}
.aa-input .input{flex:1;height:50px;border-radius:14px}
.aa-input .btn{height:50px;width:50px;padding:0;border-radius:14px;flex:none}
@media(max-width:520px){ .ai-admin{height:calc(100vh - 170px)} }

/* ==========================================================================
   Stock · deliveries · training · rostering — components added with the
   time-saving back-of-house rebuild.
   ========================================================================== */

/* ---------- overflow menu (⋯) ----------
   The occasional actions, folded away so the everyday one can lead. <details>
   does the open/close, so there is no state to keep and nothing to unbind. */
.omenu{position:relative;flex-shrink:0}
.omenu>summary{list-style:none;padding:0 14px}
.omenu>summary::-webkit-details-marker{display:none}
.omenu>summary .ic{width:19px;height:19px}
.omenu[open]>summary{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.omenu-pop{position:absolute;right:0;top:calc(100% + 6px);z-index:25;min-width:200px;padding:6px;
  background:var(--card);border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow);
  display:flex;flex-direction:column;animation:pop .16s var(--ease-out)}
.omenu-pop button{display:flex;align-items:center;gap:10px;width:100%;min-height:48px;padding:0 12px;
  border-radius:11px;font-size:14px;font-weight:600;text-align:left;color:var(--ink)}
.omenu-pop button:hover{background:var(--paper-2)}
.omenu-pop .ic{width:18px;height:18px;color:var(--ink-soft);flex-shrink:0}

/* ---------- tab bar (Stock page) ----------
   A fade on the right edge is the only honest signal that a scroller has more
   in it — a tab cut off mid-word just looks like a rendering fault. */
.tabbar{position:relative;display:flex;gap:6px;flex-wrap:wrap;border-bottom:1px solid var(--line-2);margin-bottom:4px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.tabbar::-webkit-scrollbar{display:none}
.tabbar .tab{display:inline-flex;align-items:center;gap:7px;appearance:none;border:none;background:transparent;font:inherit;font-size:14px;font-weight:600;color:var(--ink-soft);
  padding:11px 15px;min-height:46px;border-radius:12px 12px 0 0;border-bottom:2px solid transparent;cursor:pointer;white-space:nowrap}
.tabbar .tab .ic{width:17px;height:17px}
/* Hover only where there is a pointer: on a phone :hover sticks to wherever
   the finger last was, and after the page redraws that is a different tab —
   a grey box on one tab while another is selected. */
@media (hover:hover) and (pointer:fine){ .tabbar .tab:hover{background:var(--paper-2);color:var(--ink)} }
.tabbar .tab.active{color:var(--ink);border-bottom-color:var(--accent);background:var(--card)}
/* A page's own buttons under its tabs (Stock): they differ from tab to tab, and
   above the tabs they pushed the tab bar up and down on every switch. */
.tab-actions{margin:14px 0 2px}
.tab-actions:empty{display:none}
/* Every stock tab starts the same distance under the tabs (or its buttons). */
#stockBody > :first-child{margin-top:16px!important}
/* Buttons on the left here, so the ⋯ menu opens rightward, onto the screen. */
.tab-actions .omenu-pop{right:auto;left:0}
.tab-actions{align-items:center}
/* The row's last control sits at the right end: kitchen / list after Add items,
   Export after the period switch. */
.tab-actions > :last-child:not(:first-child){margin-left:auto}
@media (max-width:430px){
  /* One row on a phone: the switch drops its icons to fit beside Add items. */
  .tab-actions{flex-wrap:nowrap}
  .tab-actions .viewswitch button{padding:0 12px;min-height:44px}
  .tab-actions .viewswitch button .ic{display:none}
}

/* ---------- data tables ---------- */
/* Wide tables scroll inside their own box so the page itself never scrolls sideways. */
.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:0 -4px;padding:0 4px}
table.dtable{border-collapse:separate;border-spacing:0;width:100%;min-width:520px;font-size:13.5px}
.dtable th,.dtable td{padding:10px 12px;border-bottom:1px solid var(--line-2);vertical-align:top;text-align:left}
.dtable thead th{font-size:12px;font-weight:700;color:var(--ink-soft);text-transform:uppercase;letter-spacing:.04em;white-space:nowrap;
  background:var(--paper-2);position:sticky;top:0;z-index:1}
.dtable tbody tr:last-child td{border-bottom:none}
.dtable tfoot td{padding:10px 12px;border-top:2px solid var(--line);font-weight:700}
.dtable .num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.dtable .input{height:38px;padding:6px 10px;font-size:13.5px}
@media (hover:hover) and (pointer:fine){ .dtable tbody tr:hover{background:var(--paper-2)} }

/* Entry tables (stocktake, waste) are filled in on a phone while walking the
   shelves, so on a narrow screen they stack instead of scrolling sideways —
   sideways-scrolling to reach the box you have to type in is the wrong
   interaction. The label spans are plain text nodes so they translate like
   everything else; they're redundant with the header on desktop, hence hidden. */
.dtable .cell-l{display:none}
@media(max-width:520px){
  table.dtable.entry{min-width:0}
  .dtable.entry, .dtable.entry tbody, .dtable.entry tr, .dtable.entry td{display:block;width:100%}
  .dtable.entry thead{display:none}
  .dtable.entry tbody tr{border-bottom:1px solid var(--line-2);padding:10px 0}
  .dtable.entry tbody tr:last-child{border-bottom:none}
  .dtable.entry td{border-bottom:none;padding:3px 0;text-align:left}
  .dtable.entry td.num{text-align:left}
  .dtable.entry .cell-l{display:block;font-size:11.5px;font-weight:600;color:var(--ink-soft);margin-bottom:3px}
  .dtable.entry td .input{width:100%;text-align:left!important}
}
.linkish{appearance:none;border:none;background:transparent;padding:0;font:inherit;cursor:pointer}

/* ---------- roster grid ---------- */
.rgrid-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.rgrid{border-collapse:separate;border-spacing:0;width:100%;min-width:780px;font-size:12.5px}
.rgrid th,.rgrid td{border-bottom:1px solid var(--line-2);border-right:1px solid var(--line-2);padding:6px 8px;vertical-align:top}
.rgrid thead th{background:var(--paper-2);position:sticky;top:0;z-index:3;text-align:center;font-weight:700;white-space:nowrap}
.rgrid .rg-date{font-weight:500;font-size:10.5px;color:var(--ink-faint)}
/* Running cost under the dish cost card editor. */
.dm-total{padding:10px 14px;border-radius:12px;background:var(--paper-2);
  border:1px solid var(--line-2);font-size:13.5px;color:var(--ink-soft)}

/* Running total under the stocktake table — the gap as it is being typed. */
.stk-running{margin-top:10px;padding:10px 14px;border-radius:12px;background:var(--paper-2);
  border:1px solid var(--line-2);font-size:13px;color:var(--ink-soft)}
.stk-running.short{background:var(--red-soft);border-color:var(--red);color:var(--red-ink)}
.stk-running.over{background:var(--green-soft);border-color:var(--green);color:var(--green-ink)}

/* A public holiday is information, not a status, so it takes the module's
   own colour rather than a warning colour. */
.rgrid .rg-hol{display:inline-block;max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-weight:700;font-size:10px;color:var(--accent-ink);background:var(--accent-soft);
  border-radius:6px;padding:1px 6px;margin-top:3px}
.rgrid td.rg-cell.hol{background:color-mix(in srgb, var(--accent-soft) 45%, transparent)}
.rgrid td.rg-cell.hol.today{background:var(--accent-soft)}
.rgrid th.rg-name,.rgrid td.rg-name{position:sticky;left:0;background:var(--card);z-index:2;text-align:left;min-width:150px;max-width:172px}
.rgrid thead th.rg-name{z-index:4;background:var(--paper-2)}
.rgrid td.rg-cell{min-width:90px;cursor:pointer}
.rgrid td.rg-cell.today{background:var(--accent-soft)}
.rgrid td.rg-cell:hover{background:var(--paper-2)}
.rgrid td.rg-cell.dragover{outline:2px dashed var(--accent);outline-offset:-2px}
.rgrid tr.rg-bandrow td{padding:7px 10px;font-weight:800;letter-spacing:.3px}
.rgrid td.rg-total{text-align:center;font-weight:800;white-space:nowrap;background:var(--card);min-width:60px;font-variant-numeric:tabular-nums}
.rg-person{display:flex;align-items:center;gap:7px}
.rg-person .ava{width:26px;height:26px;font-size:13px;flex:none}
.rg-person b{display:block;font-size:12.5px}
.rg-person .faint{font-size:11px}
.rg-chip{display:inline-flex;align-items:center;gap:5px;margin:2px;padding:3px 8px;border-radius:8px;font-weight:700;white-space:nowrap;border:1px solid;cursor:grab;line-height:1.3}
.rg-chip .rg-x{cursor:pointer;opacity:.5;font-weight:800}
.rg-chip .rg-x:hover{opacity:1}
.rg-empty{color:var(--ink-faint);font-size:12px}

/* ---------- week switcher ---------- */
/* nowrap: the arrows are square and fixed, the week label takes what is left.
   With flex-wrap the two text pills queued up and folded onto three rows. */
.weekbar{display:flex;align-items:center;gap:10px;background:var(--card);border:1px solid var(--line);
  border-radius:var(--radius);padding:10px 14px;margin-bottom:4px}
.weekbar-arrow{width:48px;min-width:48px;padding:0;flex-shrink:0}
.weekbar-arrow .ic{width:20px;height:20px}
.weekbar-mid{flex:1;min-width:0;text-align:center;line-height:1.35}
.weekbar-mid b{display:block;font-size:15px}
.weekbar-mid .faint{font-size:12px}

/* ---------- skills ---------- */
.skill-row{display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap;padding:10px 0;border-bottom:1px solid var(--line-2)}
.skill-row:last-child{border-bottom:none}
.skill-row>b{min-width:110px;font-size:14px;padding-top:5px}
.skill-chip{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;color:var(--ink-soft);
  border:1px solid var(--line);background:var(--card);border-radius:999px;padding:6px 11px;min-height:36px;cursor:pointer;white-space:nowrap}
.skill-chip input{width:16px;height:16px;margin:0}
.skill-chip:has(input:checked){border-color:var(--accent);background:var(--accent-soft);color:var(--accent-ink)}

/* ---------- SOP steps ---------- */
.sop-video{position:relative;padding-top:56.25%;border-radius:12px;overflow:hidden;background:#000}
.sop-video iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.sop-steps{margin:14px 0 0;padding-left:22px;display:flex;flex-direction:column;gap:10px}
.sop-steps li{font-size:14.5px;line-height:1.6;padding-left:4px}
.sop-steps li::marker{font-weight:800;color:var(--accent)}

/* ==========================================================================
   Fluid layout — the app should be usable at any window width, not just at
   the two old breakpoints. Grids reflow on available space, the sidebar
   narrows before it disappears, and nothing pushes the page sideways.
   ========================================================================== */
/* Only the body: an overflow on <html> stops it propagating to the viewport and
   hands the scrolling to <body> instead. See the html/body rules at the top. */
body{overflow-x:hidden}
img,svg,video{max-width:100%}
.content{max-width:min(1180px, 100%)}
/* Break only words that genuinely don't fit — never mid-word on ordinary text. */
.card,.li,.alert,.aa-msg{overflow-wrap:break-word}
.dtable td,.dtable th{overflow-wrap:normal}
.section-head{flex-wrap:wrap;gap:12px}

/* Stat/tile grids size themselves to the space they're given rather than to a
   fixed column count, so every width in between the breakpoints looks right. */
@media(min-width:521px){
  .g2{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
  .g3{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
  .g4{grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}
}

/* Tablet / small laptop: keep the sidebar, just make it slimmer. */
@media(min-width:881px) and (max-width:1180px){
  :root{--sidebar:210px}
  .nav-item{font-size:13.5px;gap:9px;padding:10px}
  .content{padding:20px}
  .topbar{padding:12px 20px}
}
/* Narrow desktop windows: collapse to an icon rail rather than squeezing the
   labels into an unreadable column. Nav labels are bare text nodes, so they are
   hidden with font-size:0 and the icon's size is restored on the child.
   Every rule is skipped once the owner has pressed » to keep the menu open
   (body.side-full) — an explicit choice always beats the automatic one. */
@media(min-width:881px) and (max-width:1000px){
  body:not(.side-full){--sidebar:72px}
  body:not(.side-full) .sidebar{padding:16px 8px;align-items:center;overflow-x:hidden}
  body:not(.side-full) .nav-item{position:relative;justify-content:center;padding:11px 0;width:100%;font-size:0;gap:0}
  /* Folded to an icon rail there is no room for the word — the rule stays. */
  body:not(.side-full) .nav-sep{font-size:0;margin:12px 6px 8px;padding-top:10px}
  body:not(.side-full) .nav-item .em{font-size:18px;width:auto}
  body:not(.side-full) .nav-item .badge{position:absolute;top:4px;right:8px;font-size:10px;padding:0 5px;min-width:16px}
  body:not(.side-full) .side-brand{padding:6px 0 16px;justify-content:center}
  body:not(.side-full) .side-brand div{display:none}
  body:not(.side-full) .side-foot .who div{display:none}
  body:not(.side-full) .side-foot .who{justify-content:center}
  body:not(.side-full) .side-foot .row{flex-direction:column;gap:6px}
  body:not(.side-full) .side-foot .btn{font-size:0;padding:0;min-width:44px}
  /* The label is hidden with font-size:0, so the folded button needs a glyph of
     its own. ::first-letter can't supply one — these buttons are flex
     containers and ::first-letter only applies to block containers, which left
     them rendering as two blank pills. */
  body:not(.side-full) #pwBtn::before{content:'🔑';font-size:15px}
  body:not(.side-full) #logoutBtn::before{content:'⏻';font-size:16px;font-weight:700}
  /* Explicitly opened at this width: the labels come back and the content just
     gets a little narrower. */
  body.side-full{--sidebar:210px}
  body.side-full .nav-item{font-size:13.5px;gap:9px;padding:10px}
}
@media(max-width:880px){
  /* The bar used to be 90px of a 812px screen carrying one clipped marketing
     line. It is now the iOS pattern: a slim persistent title, with the page's
     own large heading scrolling underneath it. */
  .topbar{min-height:52px;padding:8px 14px;gap:10px}
  .topbar h1{font-size:17px}
  .weekbar{padding:10px}
  .modal{width:min(560px,94vw)}
}
@media(max-width:520px){
  .content{padding:16px 12px 90px}
  .section-head h2{font-size:20px}
  .stat .v{font-size:25px}
  /* Only once they actually scroll do the two chip rows get their edge fade —
     a tab or a category clipped mid-word otherwise reads as a rendering fault. */
  /* Every tab and category on show: a row that scrolls sideways hid half the
     Stock tabs and the category Edit button, with nothing to say they were there. */
  .tabbar,.catbar{flex-wrap:wrap;overflow:visible}
  .tabbar .tab{padding:10px 12px;font-size:13px}
  /* Switch + primary + ⋯ come to 364px at 375px wide, so the menu dropped to a
     line of its own. Eight pixels off each side of the switch and they fit. */
  .viewswitch button{padding:0 11px}
  .omenu>summary{padding:0 11px}
  .skill-row>b{min-width:100%}
}

/* ---------- local preview entry on the login page ---------- */
.preview-box{margin-top:14px;padding:14px 16px;border:1px dashed var(--line);border-radius:16px;background:var(--paper-2)}
.preview-box b{font-size:13.5px;display:block}
.preview-box p{font-size:12.5px;color:var(--ink-soft);margin:4px 0 10px;line-height:1.5}
.preview-box .btn{flex:1;min-width:96px}

/* ===== The row of ways to show one screen (Blocks / Floor / List) ===== */
.home-switch{display:flex;justify-content:flex-end;margin-bottom:4px}
.viewswitch{display:inline-flex;border:1px solid var(--line);border-radius:999px;overflow:hidden;background:var(--card);flex-shrink:0}
.viewswitch button{display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:13.5px;font-weight:600;color:var(--ink-soft);padding:0 14px;min-height:48px;line-height:1;white-space:nowrap;transition:background .2s,color .2s}
.viewswitch button .ic{width:17px;height:17px}
.viewswitch button.on{background:var(--ink);color:var(--paper)}

/* A docket can take as many photos as it takes: two pages of invoice and a
   picture of the broken crate is three, and picking one of them is how the
   evidence for a claim goes missing. */
.shots{display:flex;flex-wrap:wrap;gap:8px;padding:8px;border:1px dashed var(--line);
  border-radius:var(--radius);background:var(--paper-2);min-height:66px;align-items:center}
.shots.needs{border-color:var(--red);background:var(--red-soft)}
.shot{position:relative;width:74px;height:74px;flex:none}
.shot img{width:100%;height:100%;object-fit:cover;border-radius:10px;display:block}
.shot-x{position:absolute;top:-7px;right:-7px;width:24px;height:24px;border-radius:999px;
  background:var(--ink);color:var(--paper);font-size:15px;line-height:1;
  display:grid;place-items:center;border:2px solid var(--paper);box-shadow:var(--shadow-soft)}
.shot-empty{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--ink-faint);padding:0 4px}
.shot-empty .ic{width:16px;height:16px}

/* Waiting deliveries, grouped by week. The date column is the point of the
   block, so it leads the row instead of hiding in the second line. */
.dlv-week + .dlv-week{margin-top:10px}
.dlv-week-head{display:flex;align-items:baseline;gap:8px;padding:10px 0 2px;
  font-size:13px;font-weight:800;letter-spacing:-.01em}
.dlv-week-head span{font-size:12px;font-weight:600;color:var(--ink-faint)}
.dlv-week-head.late{color:var(--red)}
.dlv-when{flex:none;min-width:92px;font-size:12.5px;font-weight:700;line-height:1.25;color:var(--ink-soft)}
.dlv-when i{display:block;font-style:normal;font-size:11.5px;font-weight:600;color:var(--ink-faint)}
.dlv-when.now{color:var(--accent-ink)}
.dlv-when.late{color:var(--red)}
@media(max-width:560px){ .dlv-when{min-width:74px;font-size:12px} }

/* ===== Calendar (owner) =====
   A month you can read at arm's length. The grid is the whole page: no side
   panel, no agenda column — a cell is a day, a chip is a thing happening, and
   tapping the number puts something new on that day. */
.cal-bar{display:flex;align-items:center;gap:8px;margin:16px 0 10px}
.cal-title{font-family:"Playfair Display",serif;font-size:22px;font-weight:900;letter-spacing:-.01em;
  min-width:190px;text-align:center}
.cal-bar #calToday{margin-left:auto}

.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-soft)}
.cal-dow{background:var(--paper-2);padding:8px 10px;font-size:11.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-faint)}
.cal-cell{background:var(--card);min-height:116px;padding:6px 6px 8px;display:flex;flex-direction:column;gap:4px;
  /* Grid items refuse to shrink under their content by default, which on a
     phone pushed Saturday and Sunday off the edge of the month. */
  min-width:0}
.cal-off{background:var(--paper-2)}
/* Today is a ring on the date, not a tinted cell: a whole coloured column reads
   as "something is wrong here" on a calendar. */
.cal-cell.is-today .cal-day{background:var(--ink);color:var(--paper)}
.cal-day{align-self:flex-start;min-width:26px;height:26px;border-radius:50%;font:inherit;font-size:13px;
  font-weight:700;color:var(--ink-soft);display:grid;place-items:center;
  transition:background .16s,color .16s}
@media (hover:hover) and (pointer:fine){ .cal-day:hover{background:var(--paper-2);color:var(--ink)} }
.cal-items{display:flex;flex-direction:column;gap:3px;overflow:hidden}
.cal-chip{display:flex;align-items:center;gap:5px;width:100%;min-width:0;padding:3px 6px;border-radius:7px;
  font:inherit;font-size:11.5px;font-weight:700;line-height:1.3;text-align:left;color:var(--tone,var(--ink));
  background:var(--tone-soft,var(--paper-2));border:1px solid transparent;transition:border-color .16s}
.cal-chip span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.cal-chip .ic{width:12px;height:12px;flex:none}
@media (hover:hover) and (pointer:fine){ .cal-chip:hover{border-color:var(--tone,var(--line))} }

/* On a phone seven columns of 116px is a wall of nothing. Keep the grid — the
   month shape is the point — but let a day be as tall as what's in it. */
@media(max-width:700px){
  .cal-cell{min-height:74px;padding:4px 3px 6px}
  .cal-day{min-width:22px;height:22px;font-size:12px}
  .cal-chip{padding:2px 4px;font-size:10px;gap:3px}
  .cal-chip .ic{display:none}
  .cal-dow{padding:6px 4px;font-size:10px;text-align:center}
  .cal-title{font-size:18px;min-width:0;flex:1}
}

/* ===== The restaurant floor (owner home) =====
   Rooms you walk into instead of a list you read. Flat vector, no assets. */
:root{
  --fp-floor:#E8DFCC; --fp-floor-2:#DFD4BD; --fp-wall:#3C4A3E;
}
.fp-hello{display:flex;align-items:flex-end;gap:16px;flex-wrap:wrap;margin-top:8px}
.fp-hello h2{font-size:30px;line-height:1.15;letter-spacing:-.02em}
.fp-hello .fp-count{font-size:15px;color:var(--ink-soft);margin-top:6px;font-weight:600}
.fp-hello .btn{margin-left:auto}

/* progress across the six rooms */
.fp-prog{margin-top:16px;padding:14px 18px;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.fp-prog-copy{display:flex;align-items:baseline;gap:10px;flex-shrink:0}
.fp-prog-copy span{font-size:12.5px;color:var(--ink-soft)}
.fp-prog-copy strong{font-size:17px}
.fp-prog-track{flex:1;min-width:140px;height:9px;border-radius:999px;background:var(--paper);overflow:hidden}
.fp-prog-track span{display:block;height:100%;border-radius:999px;
  background:linear-gradient(90deg,var(--accent),#E4A15C);transition:width .7s var(--ease-out)}
.fp-prog-goal{font-size:12px;color:var(--ink-faint);flex-shrink:0}

/* the room itself */
/* A quiet tile grid, not a 45° chequerboard — the chequer reads as the
   transparency placeholder every image editor uses, i.e. as a broken asset. */
.fp-floor{position:relative;margin-top:16px;padding:68px 20px 30px;border-radius:var(--radius-lg);
  border:5px solid var(--fp-wall);
  background-color:var(--fp-floor);
  background-image:
    repeating-linear-gradient(90deg,var(--fp-floor-2) 0 1px,transparent 1px 46px),
    repeating-linear-gradient(0deg,var(--fp-floor-2) 0 1px,transparent 1px 46px);
  box-shadow:var(--shadow)}
.fp-floor-label{position:absolute;top:14px;left:18px;right:18px;max-width:max-content;background:var(--card);border-radius:14px;
  padding:8px 14px;box-shadow:var(--shadow-soft);line-height:1.3}
.fp-floor-label span{display:block;font-size:13.5px;font-weight:700}
.fp-floor-label small{font-size:11.5px;color:var(--ink-soft)}

.fp-rooms{display:grid;grid-template-columns:repeat(3,1fr);gap:122px 18px}

/* a room card */
.rm{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  min-height:132px;padding:16px 12px;border-radius:16px;text-align:center;
  background:var(--card);border:2px solid var(--line);
  transition:transform .18s var(--ease-out), box-shadow .2s, border-color .2s}
.rm b{font-size:14.5px;font-weight:700}
.rm small{font-size:11.5px;color:var(--ink-soft)}
/* Same icon chip as the room's block on the home screen — one module, one look. */
.rm-ic{display:grid;place-items:center;width:44px;height:44px;border-radius:14px;margin-bottom:3px;
  background:var(--tone-soft,var(--paper-2));color:var(--tone,var(--ink))}
.rm-ic .ic{width:23px;height:23px}
.rm:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){ .rm:hover{transform:translateY(-2px);box-shadow:var(--shadow)} }
/* a room that wants you gets its own colour on the wall; a clear one goes quiet */
.rm-live{border-color:color-mix(in srgb,var(--tone,var(--accent)) 55%,transparent)}
.rm-done{opacity:.75}
.rm-done .rm-ic{background:var(--paper-2);color:var(--ink-faint)}
/* Three states, the same three the home blocks use: clear · worth a look ·
   do it today. Never the room's own colour — that is identity, not status. */
.rm-badge{position:absolute;top:-11px;right:-9px;min-width:26px;height:26px;padding:0 7px;border-radius:999px;
  color:#fff;font-size:13px;font-weight:800;line-height:26px;text-align:center;
  box-shadow:0 2px 6px -1px rgba(33,30,27,.35)}
.rm-badge .ic{width:15px;height:15px;stroke-width:3;vertical-align:middle;margin-top:-2px}
.rm.is-ok .rm-badge,.rm-badge.ok{background:var(--green)}
.rm.is-warm .rm-badge{background:var(--amber);color:#4a3405}
.rm.is-hot .rm-badge{background:var(--red)}

/* the boss stands in the middle and points at the first room */
.fp-boss{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;pointer-events:none;z-index:2}
.fp-think{background:var(--card);border-radius:999px;padding:6px 14px;font-size:12px;font-weight:600;
  box-shadow:var(--shadow-soft);white-space:nowrap;max-width:270px;overflow:hidden;text-overflow:ellipsis;
  margin-bottom:6px;animation:fpBob 3.2s var(--ease-in-out) infinite}
@keyframes fpBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
.fp-body{display:flex;align-items:center;justify-content:center;width:52px;height:38px;margin-top:-2px;
  border-radius:12px 12px 8px 8px;background:var(--fp-wall);color:var(--paper);
  font-size:10px;font-weight:800;letter-spacing:.06em;
  box-shadow:0 6px 12px -6px rgba(33,30,27,.5)}
/* the one line of context under the floor */
.fp-insight{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:16px;padding:16px 18px;
  border-radius:var(--radius);background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow-soft)}
.fp-insight-ic{flex-shrink:0;display:grid;place-items:center;width:38px;height:38px;border-radius:12px;
  background:var(--accent-soft);color:var(--accent-ink)}
.fp-insight-ic .ic{width:20px;height:20px}

/* Legal/plumbing copy that has to exist but does not have to be on the home
   screen every single visit. */
.disclaimer-fold{font-size:12.5px;color:var(--ink-soft);background:var(--paper-2);
  border:1px dashed var(--line);border-radius:12px;padding:10px 14px}
.disclaimer-fold summary{cursor:pointer;font-weight:600;list-style:none}
.disclaimer-fold summary::-webkit-details-marker{display:none}
.disclaimer-fold summary::after{content:' ›';display:inline-block;transition:transform .2s}
.disclaimer-fold[open] summary::after{transform:rotate(90deg)}
.disclaimer-fold p{margin-top:8px;line-height:1.55}
.fp-insight div{flex:1;min-width:200px}
.fp-insight b{font-size:13.5px}
.fp-insight p{font-size:13px;color:var(--ink-soft);margin-top:3px;line-height:1.5}

@media(max-width:880px){
  .fp-hello h2{font-size:24px}
  .fp-hello .btn{margin-left:0;width:100%}
  .fp-floor{padding:86px 14px 26px}
  .fp-rooms{gap:112px 12px}
}
@media(max-width:560px){
  .fp-rooms{grid-template-columns:repeat(2,1fr);gap:14px}
  .rm{min-height:112px;padding:14px 8px}
  .rm b{font-size:13px}
  .rm small{font-size:10.5px}
  .rm-em{font-size:23px}
  /* two columns leaves no middle aisle — the boss stands at the door instead */
  .fp-boss{position:static;transform:none;flex-direction:row;align-items:center;gap:10px;
    margin-top:18px;justify-content:center}
  .fp-think{margin-bottom:0;order:3;max-width:none}
  .fp-body{width:40px;height:30px;margin-top:0}
  .fp-deco{display:none}
  .fp-prog-goal{display:none}
}

/* ==========================================================================
   Collapsible sidebar
   The « button folds the menu down to an icon rail and back. It's a per-device
   preference, not a per-page one: the class is set on <body> before the shell
   paints, so the menu never renders wide and then snaps narrow.
   Below 881px the sidebar is replaced by the bottom bar, so the button goes.
   ========================================================================== */
.side-toggle{margin-left:auto;flex:none;width:28px;height:28px;border-radius:9px;
  border:1px solid var(--line);background:var(--card);color:var(--ink-soft);
  display:grid;place-items:center;transition:background .15s,color .15s,border-color .15s}
.side-toggle::before{content:'«';font-size:14px;font-weight:800;line-height:1}
.side-toggle:hover{background:var(--ink);color:var(--paper);border-color:var(--ink)}
body.side-mini .side-toggle::before{content:'»'}

@media(min-width:881px){
  body.side-mini{--sidebar:76px}
  body.side-mini .sidebar{padding:16px 8px;align-items:center;overflow-x:hidden}
  body.side-mini .side-brand{flex-direction:column;gap:9px;padding:6px 0 14px;justify-content:center}
  body.side-mini .side-brand div{display:none}
  body.side-mini .side-toggle{margin:0}
  /* Same trick as the automatic rail above: the nav label is a bare text node. */
  body.side-mini .nav-item{position:relative;justify-content:center;padding:11px 0;width:100%;font-size:0;gap:0}
  body.side-mini .nav-sep{font-size:0;margin:12px 6px 8px;padding-top:10px}
  body.side-mini .nav-item .em{font-size:18px;width:auto}
  body.side-mini .nav-item .badge{position:absolute;top:4px;right:8px;font-size:10px;padding:0 5px;min-width:16px}
  body.side-mini .side-foot .who div{display:none}
  body.side-mini .side-foot .who{justify-content:center}
  body.side-mini .side-foot .row{flex-direction:column;gap:6px}
  body.side-mini .side-foot .btn{font-size:0;padding:0;min-width:44px}
  /* Same as the automatic rail: a glyph via ::before, because ::first-letter
     does nothing on a flex container. */
  body.side-mini #pwBtn::before{content:'🔑';font-size:15px}
  body.side-mini #logoutBtn::before{content:'⏻';font-size:16px;font-weight:700}
}
@media(max-width:880px){ .side-toggle{display:none} }

/* ==========================================================================
   Home tiles — the springboard
   Every page in the app as a tile the owner can add, drop and re-order, the
   way a tablet home screen works. Edit mode wobbles the tiles and puts a −
   on each one; the rest of the time a tile is just a big tap target.
   ========================================================================== */
.tiles-wrap{margin-top:8px}
/* Greeting, today's count and Edit on one line — the springboard used to stack
   a greeting, a "Your home screen" heading and a hint before the first block. */
/* The greeting can sit on a photo of the venue's own kitchen. With no photo
   this is the plain two-line header it has always been — the band only exists
   once somebody uploads one. */
.tiles-head{display:flex;align-items:flex-end;gap:12px;margin-bottom:16px}
.tiles-head.has-hero{position:relative;overflow:hidden;border-radius:var(--radius-lg);
  padding:26px 22px;min-height:150px;align-items:flex-end;
  background:var(--paper-2);box-shadow:var(--shadow-soft)}
.tiles-head.has-hero::before{content:"";position:absolute;inset:0;z-index:0;
  background-image:var(--hero);background-size:cover;background-position:center}
/* The text has to stay readable over whatever photo they picked, so the page
   colour is washed across it from the left rather than dimming the whole image. */
.tiles-head.has-hero::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(90deg,var(--paper) 8%,color-mix(in srgb,var(--paper) 72%,transparent) 46%,transparent 92%)}
.tiles-head.has-hero>*{position:relative;z-index:2}
@media(max-width:560px){
  .tiles-head.has-hero{padding:18px 16px;min-height:132px}
  .tiles-head.has-hero::after{background:linear-gradient(90deg,var(--paper) 20%,color-mix(in srgb,var(--paper) 82%,transparent) 70%,color-mix(in srgb,var(--paper) 40%,transparent) 100%)}
}
.tiles-head h2{font-size:30px;line-height:1.15;letter-spacing:-.02em}
.tiles-head .fp-count{font-size:15px;color:var(--ink-soft);margin-top:6px;font-weight:600}
.tiles-head .btn{margin-left:auto;flex:none}
@media(max-width:560px){ .tiles-head h2{font-size:24px} .tiles-head .fp-count{font-size:13.5px} }

/* Two up on a phone, so a block is a comfortable thumb target and has room for
   its own status line — a 4-across springboard of tiny icons reads as a launcher,
   not as the six things the venue has to get done today. */
.tiles-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px;align-items:stretch;max-width:1160px}
.tile{position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:10px;
  padding:16px 16px 14px;min-height:132px;border-radius:var(--radius-lg);text-align:left;
  background:var(--card);border:1px solid var(--line);box-shadow:var(--shadow-soft);
  font:inherit;color:inherit;-webkit-tap-highlight-color:transparent;
  transition:transform .18s var(--ease-out),box-shadow .18s,border-color .2s}
.tile-ic{display:grid;place-items:center;width:52px;height:52px;border-radius:50%;
  background:var(--tone-soft,var(--paper-2));color:var(--tone,var(--ink));flex-shrink:0}
.tile-ic .ic{width:26px;height:26px}
.tile-label{font-size:15px;font-weight:700;line-height:1.25}
/* The number is the thing you cross the kitchen to read, so it gets the size and
   a line of its own; the unit under it says what it counts. "All clear" is a
   real state and takes the same slot rather than leaving a hole. */
.tile-n{margin-top:auto;font-size:30px;font-weight:900;font-family:"Playfair Display",serif;
  line-height:1.05;letter-spacing:-.01em}
.tile-unit{font-size:12.5px;font-weight:600;color:var(--ink-soft);line-height:1.2;margin-top:3px}
.tile-n.tile-ok{font-size:24px;color:var(--green);margin-bottom:18px}
/* A card with a number on it is not obviously a door. The chevron is the whole
   difference between "here is a statistic" and "tap here to deal with it". */
.tile-go{position:absolute;right:14px;bottom:20px;font-size:20px;line-height:1;
  color:var(--ink-faint);transition:transform .18s var(--ease-out),color .18s}
.tile:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){ .tile:hover .tile-go{transform:translateX(3px);color:var(--tone,var(--ink-soft))} }
.tile-n,.tile-unit{padding-right:20px}

/* Under the blocks: what today looks like on the left, the verbs on the right.
   The blocks say what needs you; these two say what is going on and what you
   can start. */
.home-panels{display:grid;gap:16px;max-width:1160px;margin-top:16px}
.panel{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-soft);padding:15px 18px 8px}
.panel-head{font-size:15px;font-weight:800;letter-spacing:-.01em;margin-bottom:2px}

/* Across, not down: five short columns read in one sweep where five stacked
   rows made the owner scan a list to find the one number they came for. */
.ov-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));padding:8px 0 14px}
.ov{display:flex;align-items:center;gap:12px;padding:8px 16px 8px 0;color:inherit}
.ov+.ov{border-left:1px solid var(--line-2);padding-left:16px}
.ov-ic{display:grid;place-items:center;width:44px;height:44px;border-radius:14px;flex:none;
  background:var(--tone-soft,var(--paper-2));color:var(--tone,var(--ink))}
.ov-ic .ic{width:22px;height:22px}
.ov-label{display:block;font-size:13px;font-weight:600;color:var(--ink-soft);line-height:1.25}
.ov-n{font-family:"Playfair Display",serif;font-size:26px;font-weight:900;line-height:1.15}
@media(max-width:560px){ .ov+.ov{border-left:none;padding-left:0} }

/* Quick actions — icon over label, so four of them fit a phone two-up without
   the words wrapping. */
.qa-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;padding-bottom:10px}
.qa{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  padding:15px 8px;border-radius:var(--radius);background:var(--paper-2);border:1px solid transparent;
  font-weight:700;font-size:13px;text-align:center;color:inherit;line-height:1.2;
  transition:transform .18s var(--ease-out),background .18s,border-color .18s}
.qa-ic{display:grid;place-items:center;width:42px;height:42px;border-radius:14px;flex:none;
  background:var(--tone-soft,var(--accent-soft));color:var(--tone,var(--accent-ink))}
.qa-ic .ic{width:20px;height:20px}
.qa:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){ .qa:hover{background:var(--card);border-color:var(--line)} }

.home-foot{text-align:center;color:var(--ink-faint);font-size:12px;margin:22px 0 76px}
@media(max-width:880px){ .home-foot{margin-bottom:22px} }
@media (hover:hover) and (pointer:fine){ .tile:hover{transform:translateY(-3px);box-shadow:var(--shadow)} }

/* One module, one colour — set once here, read by the icon chip and the border. */
.t-blue{--tone:var(--blue);--tone-soft:var(--blue-soft)}
.t-green{--tone:var(--green);--tone-soft:var(--green-soft)}
.t-amber{--tone:var(--amber-ink);--tone-soft:var(--amber-soft)}
.t-red{--tone:var(--red);--tone-soft:var(--red-soft)}
.t-violet{--tone:var(--violet);--tone-soft:var(--violet-soft)}
.t-teal{--tone:var(--teal);--tone-soft:var(--teal-soft)}
.t-accent{--tone:var(--accent-ink);--tone-soft:var(--accent-soft)}
.t-ink{--tone:var(--ink-soft);--tone-soft:var(--paper-2)}

/* Three states, the same three everywhere: clear · worth a look · do it today.
   They colour the NUMBER, not the whole card: a wall of tinted cards is a wall,
   and the one that actually wants you today stops standing out. Identity is the
   icon chip, status is the number, and nothing else carries either. */
.tile.is-warm .tile-n{color:var(--amber-ink)}
.tile.is-hot  .tile-n{color:var(--red)}
.tile.is-hot{border-color:color-mix(in srgb,var(--red) 34%,transparent)}

/* edit mode */
/* Only while arranging does a finger on a block drag it; the rest of the time
   it scrolls the page like anything else (touch-action:none on every block
   left a home screen of blocks that could not be scrolled at all). */
.tiles-edit .tile{touch-action:none}
.tiles-edit .tile{animation:tile-wobble .28s ease-in-out infinite alternate}
.tiles-edit .tile:nth-child(even){animation-delay:-.14s}
.tiles-edit .tile-add{animation:none}
@keyframes tile-wobble{ from{transform:rotate(-1.1deg)} to{transform:rotate(1.1deg)} }
@media (prefers-reduced-motion:reduce){ .tiles-edit .tile{animation:none} }
.tile-x{position:absolute;top:-9px;left:-9px;z-index:3;width:28px;height:28px;border-radius:999px;
  background:var(--ink);color:var(--paper);line-height:1;
  display:grid;place-items:center;border:2px solid var(--paper);box-shadow:var(--shadow-soft)}
.tile-x .ic{width:16px;height:16px;stroke-width:2.6}
/* Same badge, other corner: one to take the block off, one to give it a
   picture. Only ever visible while arranging. */
.tile-cam{position:absolute;top:-9px;right:-9px;z-index:3;width:28px;height:28px;border-radius:999px;
  background:var(--card);color:var(--ink);line-height:1;
  display:grid;place-items:center;border:2px solid var(--paper);box-shadow:var(--shadow-soft)}
.tile-cam .ic{width:15px;height:15px;stroke-width:2.2}
.tile-artx{right:24px;background:var(--red-soft);color:var(--red)}

/* The venue's own picture on a block: a watermark behind the number, never in
   front of it. Bottom-right, because that corner is the only one that carries
   nothing — the chevron sits above it and the number runs along the left. */
.tile.has-art::after{content:"";position:absolute;right:0;bottom:0;width:56%;height:64%;
  background-image:var(--art);background-size:cover;background-position:center;
  border-radius:0 0 var(--radius-lg) 0;opacity:.16;pointer-events:none;
  -webkit-mask-image:linear-gradient(300deg,#000 30%,transparent 78%);
          mask-image:linear-gradient(300deg,#000 30%,transparent 78%)}
:root[data-theme="dark"] .tile.has-art::after{opacity:.22}
.tile-dragging{opacity:.95;z-index:5;animation:none!important;transform:scale(1.04);box-shadow:var(--shadow)}
.tile-add{align-items:center;justify-content:center;background:transparent;box-shadow:none;
  border:2px dashed var(--line);color:var(--ink-faint)}
.tile-add .tile-ic{background:transparent}
.tile-add .tile-label{font-size:13px}
.tiles-empty{padding:26px 18px;border-radius:var(--radius);background:var(--paper-2);
  border:1px dashed var(--line);text-align:center;font-size:13.5px;color:var(--ink-soft)}
/* The picker is a chooser, not a dashboard — icon and name only, packed tighter. */
.tiles-pick{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:10px}
.tiles-pick .tile{min-height:96px;padding:14px 10px;align-items:center;text-align:center;gap:8px}
.tiles-pick .tile-ic{width:44px;height:44px;border-radius:14px}
.tiles-pick .tile-label{font-size:12.5px}
@media(max-width:560px){
  .tiles-grid{grid-template-columns:repeat(2,1fr);gap:12px}
  .tile{min-height:124px;padding:14px 13px 12px;border-radius:22px}
  .tile-ic{width:46px;height:46px;border-radius:50%}
  .tile-label{font-size:14px}
}

/* ==========================================================================
   Kitchen room — the same daily checklist drawn as the kitchen
   Stations along the wall, a dot per outstanding job. Tap the station, tick
   the job. Identical data to the list; no points, no walking about.
   ========================================================================== */
/* Stock · kitchen view (js/kitchen-game.js): one summary card, then the
   shelves as a grouped list — what each holds and what needs topping up. */
.kv{margin-top:14px}
.kv-bar{display:block;height:6px;border-radius:99px;background:color-mix(in srgb,var(--ink) 8%,transparent);overflow:hidden}
.kv-bar i{display:block;height:100%;border-radius:inherit;background:var(--green);transition:width .4s var(--ease-out)}
.kv-sum{background:var(--card);border:1px solid var(--line-2);border-radius:var(--radius-lg);padding:16px 18px 18px;box-shadow:var(--shadow-soft)}
.kv-sum-n{display:flex;align-items:baseline;gap:8px}
.kv-sum-n b{font-size:34px;font-weight:800;line-height:1;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.kv-sum-n span{font-size:15px;font-weight:600;color:var(--ink-soft)}
.kv-sum.hot .kv-sum-n b{color:var(--red)}
.kv-sum.ok .kv-sum-n b{color:var(--green)}
.kv-sum-of{font-size:13px;color:var(--ink-soft);margin:6px 0 10px}
.kv-head{display:flex;align-items:center;justify-content:space-between;margin:22px 4px 8px}
.kv-head > span{font-size:13px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-soft)}
.kv-edit{display:inline-flex;align-items:center;gap:6px;border:none;background:none;padding:6px 4px;min-height:0;
  font:inherit;font-size:14px;font-weight:600;color:var(--accent-ink);cursor:pointer}
.kv-edit .ic{width:15px;height:15px}
.kv-group{background:var(--card);border:1px solid var(--line-2);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-soft)}
.kv-row{display:flex;align-items:center;gap:14px;width:100%;padding:14px 14px 14px 16px;border:none;background:none;
  font:inherit;color:var(--ink);text-align:left;cursor:pointer;position:relative;-webkit-tap-highlight-color:transparent}
.kv-row + .kv-row::before{content:"";position:absolute;top:0;left:70px;right:0;border-top:1px solid var(--line-2)}
.kv-row:active{background:var(--paper-2)}
@media (hover:hover) and (pointer:fine){ .kv-row:hover{background:var(--paper-2)} }
.kv-row-ic{display:grid;place-items:center;width:40px;height:40px;border-radius:12px;flex:none;
  background:var(--tone-soft,var(--paper-2));color:var(--tone,var(--ink-soft))}
.kv-row-ic .ic{width:21px;height:21px}
.kv-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.kv-row-main b{font-size:15.5px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.kv-row-main small{font-size:12.5px;color:var(--ink-soft)}
.kv-row-main .kv-bar{height:4px;margin-top:6px;max-width:180px}
.kv-row.live .kv-bar i{background:color-mix(in srgb,var(--green) 85%,transparent)}
.kv-state{display:inline-flex;align-items:center;gap:4px;flex:none;font-size:12.5px;font-weight:700;
  padding:5px 10px;border-radius:99px;white-space:nowrap}
.kv-state.hot{background:var(--red-soft);color:var(--red)}
.kv-state.ok{background:var(--green-soft);color:var(--green)}
.kv-state .ic{width:13px;height:13px;stroke-width:3}
.kv-go{width:16px;height:16px;flex:none;color:var(--ink-faint)}
.kv-hint{font-size:12.5px;color:var(--ink-faint);margin:10px 4px 0}
.kv-list .li{cursor:pointer}
/* Stock · Edit shelves: the items to move, one ticked row each. */
.cm-items{max-height:260px;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;
  border:1px solid var(--line-2);border-radius:var(--radius);background:var(--card)}
.cm-item{display:flex;align-items:center;gap:12px;min-height:46px;padding:8px 14px;cursor:pointer}
.cm-item + .cm-item{border-top:1px solid var(--line-2)}
.cm-item input{width:20px;height:20px;flex:none;margin:0}
.cm-item b{flex:1;min-width:0;font-size:14.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cm-item span{flex:none;font-size:12.5px;max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kv-tick{width:30px;height:30px;flex:none;border-radius:10px;border:2px solid var(--line);
  display:grid;place-items:center}
.kv-tick.on{background:var(--green);border-color:var(--green);color:#fff}

/* ==========================================================================
   Purchases — the wall of dockets
   A purchase is the piece of paper that came with the delivery, so it's drawn
   as one: off-white stock, monospace, dashed rules, a torn bottom edge. The
   card in the wall is the same component as the full-size one, just clipped to
   its first few lines.
   ========================================================================== */
.dkt-filters{display:flex;gap:10px;flex-wrap:wrap;margin-top:18px}
.dkt-filters .input{flex:1 1 190px;min-width:0}
.dkt-wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:22px 18px;
  margin-top:18px;align-items:start}
.dkt-card{display:block;width:100%;padding:0;border:none;background:none;text-align:left;
  font:inherit;color:inherit;cursor:pointer}
.dkt-card .dkt{transition:transform .18s var(--ease-out),box-shadow .18s}
@media (hover:hover) and (pointer:fine){ .dkt-card:hover .dkt{transform:translateY(-4px) rotate(-.35deg);box-shadow:var(--shadow)} }
.dkt-card:active .dkt{transform:translateY(0) scale(.99)}
.dkt-none{padding:26px 18px;text-align:center;color:var(--ink-soft);font-size:13.5px}

.dkt{position:relative;max-width:340px;margin:0 auto;padding:18px 18px 20px;
  background:#FFFDF7;border-radius:5px 5px 0 0;box-shadow:var(--shadow-soft);
  font-family:ui-monospace,Menlo,Consolas,monospace;color:#211E1B}
/* the torn-off bottom edge */
.dkt::after{content:"";position:absolute;left:0;right:0;bottom:-9px;height:10px;
  background:linear-gradient(-45deg,#FFFDF7 34%,transparent 34%) 0 0/13px 10px repeat-x,
             linear-gradient(45deg,#FFFDF7 34%,transparent 34%) 0 0/13px 10px repeat-x}
.dkt-head{text-align:center;padding-bottom:12px}
.dkt-head b{display:block;font-family:"Playfair Display",serif;font-size:16px;line-height:1.25;letter-spacing:.01em}
.dkt-head span{display:block;margin-top:3px;font-size:9px;letter-spacing:.16em;text-transform:uppercase;color:#9A8F84}
.dkt-meta{display:grid;grid-template-columns:1fr 1fr;gap:7px 12px}
.dkt-meta span{display:block;font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;color:#9A8F84}
.dkt-meta b{font-size:11.5px;font-weight:700;line-height:1.3;word-break:break-word}
.dkt-rule{border-top:1px dashed #CDC2B4;margin:12px 0}
.dkt-line + .dkt-line{margin-top:10px}
.dkt-line-top{display:flex;justify-content:space-between;align-items:baseline;gap:10px;font-size:12.5px}
.dkt-line-top b{font-weight:700;white-space:nowrap}
.dkt-name{font-weight:700;line-height:1.3}
.dkt-line-sub{display:flex;justify-content:space-between;align-items:baseline;gap:8px;
  font-size:10px;color:#8A8078;margin-top:2px;flex-wrap:wrap}
.dkt-move{white-space:nowrap}
.dkt-move.up{color:var(--red);font-weight:700}
.dkt-move.down{color:var(--green);font-weight:700}
.dkt-more{margin-top:9px;text-align:center;font-size:10px;color:#8A8078}
.dkt-sum div{display:flex;justify-content:space-between;gap:12px;font-size:11.5px;padding:1.5px 0}
.dkt-sum .dkt-total{margin-top:7px;padding-top:7px;border-top:1.5px solid #211E1B;font-size:14px;font-weight:800}
.dkt-note{margin-top:11px;padding:7px 9px;border-radius:7px;background:var(--amber-soft);
  font-size:10.5px;line-height:1.45}
.dkt-foot{margin-top:13px;text-align:center;font-size:9px;line-height:1.6;color:#9A8F84}
.dkt-photo img{display:block;width:100%;border-radius:12px;margin-top:10px;border:1px solid var(--line)}
.dkt-runtotal{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:12px;
  padding:11px 15px;border-radius:14px;background:var(--paper-2);border:1px solid var(--line)}
.dkt-runtotal b{font-size:17px}
@media(max-width:560px){
  .dkt-wall{grid-template-columns:1fr;gap:24px}
  .dkt{max-width:none}
}

/* Price watch — the movers table */
.pw-cheap{margin-top:4px;font-size:11.5px;color:var(--green);font-weight:600}
.pw-worse{color:var(--red)}
.pw-better{color:var(--green)}
.pw-spark{width:72px}
.spark{display:block;overflow:visible}

/* Supplier cards — the page you open with the phone already in your hand */
/* Suppliers · master–detail. The list is the lookup, the panel is the supplier.
   Past three or four suppliers a wall of cards stops being scannable, and the
   panel can hold everything about one of them without any card growing taller
   than its neighbours. */
.sup-split{display:grid;grid-template-columns:minmax(300px,4fr) 6fr;gap:16px;align-items:start}
.sup-list{padding:0;overflow:hidden}
.sup-search{display:flex;gap:8px;padding:14px 16px 10px}
.sup-search .input{min-height:40px;font-size:13.5px}
.sup-search #supQ{flex:1;min-width:0}
.sup-search #supF{flex:0 0 auto;width:auto;max-width:46%}
.sup-count{padding:0 16px 8px;font-size:12px;color:var(--ink-faint)}
/* A row, not a table: the master column is narrow by definition and four
   columns truncate in it. Name and last delivery are the two facts you scan
   for; who to ask and which days ride under the name. */
.sup-rows{display:flex;flex-direction:column}
.sup-row{display:flex;align-items:center;gap:10px;width:100%;text-align:left;font:inherit;color:inherit;
  padding:11px 16px;background:none;border:none;border-top:1px solid var(--line-2);cursor:pointer}
.sup-row:first-child{border-top:1px solid var(--line)}
.sup-row .grow{flex:1;min-width:0}
.sup-row b{display:inline;font-size:13.5px;font-weight:700}
.sup-row i{display:block;font-style:normal;font-size:11.5px;color:var(--ink-faint);margin-top:2px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sup-row .pill{margin-left:7px;font-size:10.5px}
.sup-row-last{flex:none;text-align:right}
.sup-row-last b{font-size:12.5px;font-weight:600;color:var(--ink-soft)}
.sup-row-last i{font-size:10px;margin-top:1px}
.sup-row:hover{background:var(--paper-2)}
.sup-row.on{background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}
.sup-row.on b{color:var(--ink)}
.sup-row:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.sup-foot{padding:11px 16px;border-top:1px solid var(--line-2);font-size:12px;color:var(--ink-faint)}
.sup-detail{padding:20px}
.sup-d-head{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.sup-d-head h3{margin:0;font-size:19px;letter-spacing:-.01em}
.sup-d-head .btn{margin-left:auto;flex:none}
/* Facts on the left, the four counts on the right — the panel is wide enough
   that stacking them would leave half of it empty. */
.sup-d-grid{display:grid;grid-template-columns:1.35fr 1fr;gap:18px;align-items:start}
.sup-d-stats{margin-top:0;display:grid;grid-template-columns:1fr 1fr;gap:8px}
.sup-d-stats span{flex:none}
.sup-last{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:16px;padding:12px 14px;
  border:1px solid var(--line);border-radius:var(--radius);background:var(--paper-2)}
.sup-last span{display:block;font-size:11px;color:var(--ink-faint)}
.sup-last b{font-size:13px}
.sup-last-amt{margin-left:auto;font-family:"Playfair Display",serif;font-size:17px}
@media(max-width:880px){
  .sup-split{grid-template-columns:1fr}
  .sup-d-grid{grid-template-columns:1fr}
  .sup-d-stats{grid-template-columns:repeat(4,1fr)}
}
@media(max-width:520px){ .sup-d-stats{grid-template-columns:1fr 1fr} .sup-search{flex-wrap:wrap} .sup-search #supF{max-width:100%} }

.sup-grid{display:grid;gap:16px;align-items:start;
  grid-template-columns:repeat(auto-fill,minmax(360px,1fr))}
.sup-card{display:flex;flex-direction:column}
.sup-actions{margin-top:auto;padding-top:14px}
.sup-actions .btn{flex:1 1 auto}
.sup-links{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.sup-links .btn{min-height:40px}
.sup-facts{display:grid;grid-template-columns:1fr 1fr;gap:10px 16px}
.sup-fact span{display:block;font-size:11px;color:var(--ink-faint)}
.sup-fact b{font-size:13px;font-weight:600;line-height:1.35;word-break:break-word}
.sup-stats{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.sup-stats span{flex:1 1 92px;background:var(--paper-2);border:1px solid var(--line);border-radius:14px;
  padding:9px 12px;display:flex;flex-direction:column;gap:1px}
.sup-stats b{font-size:16px;line-height:1.2}
.sup-stats i{font-style:normal;font-size:10.5px;color:var(--ink-faint)}
.sup-stats .hot{background:var(--red-soft);border-color:color-mix(in srgb,var(--red) 35%,transparent)}
.sup-stats .hot b{color:var(--red)}
.sup-items{margin-top:16px;display:flex;flex-wrap:wrap;gap:7px}
.sup-items-h{flex:1 0 100%;font-size:12px;color:var(--ink-faint);margin-bottom:2px}

/* A chip: a small tappable label. Used for linked items and day pickers. */
.chip{font:inherit;font-size:12.5px;font-weight:600;line-height:1;padding:8px 11px;border-radius:999px;
  border:1px solid var(--line);background:var(--card);color:var(--ink);cursor:pointer;
  transition:background .15s,color .15s,border-color .15s,transform .15s}
.chip i{font-style:normal;font-weight:500;color:var(--ink-faint);margin-left:3px}
.chip:active{transform:scale(.96)}
@media (hover:hover) and (pointer:fine){ .chip:hover{border-color:var(--ink)} }
.chip.on{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.chip.on i{color:color-mix(in srgb,var(--paper) 72%,transparent)}
.chip-hot{background:var(--amber-soft);border-color:color-mix(in srgb,var(--amber) 40%,transparent);color:var(--amber-ink)}
.chip-hot i{color:var(--amber-ink);opacity:.8}
.daypick{display:flex;gap:6px;flex-wrap:wrap}
@media(max-width:520px){ .sup-facts{grid-template-columns:1fr} }

/* Forecast — showing the working */
.fc-formula{display:block;margin:8px 0;padding:8px 11px;border-radius:9px;background:color-mix(in srgb,var(--card) 55%,transparent);
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12.5px;line-height:1.5}
.fc-worked{margin-top:16px;padding:18px;border-radius:var(--radius);background:var(--card);
  border:1px solid var(--line);box-shadow:var(--shadow-soft)}
.fc-worked>b{font-size:14px}
.fc-worked p{margin-top:12px;font-size:13.5px;color:var(--ink-soft)}
.fc-sum{display:flex;align-items:stretch;gap:10px;flex-wrap:wrap;margin-top:12px}
.fc-sum span{flex:1 1 120px;background:var(--paper-2);border:1px solid var(--line);border-radius:14px;padding:10px 13px}
.fc-sum i{display:block;font-style:normal;font-size:11px;color:var(--ink-faint);line-height:1.35}
.fc-sum b{font-size:16px}
.fc-sum em{display:flex;align-items:center;font-style:normal;font-weight:800;font-size:17px;color:var(--ink-faint)}
.fc-sum .hot{background:var(--accent-soft);border-color:color-mix(in srgb,var(--accent) 35%,transparent)}
.fc-sum .hot b{color:var(--accent-ink)}
@media(max-width:560px){ .fc-sum span{flex:1 1 100%} .fc-sum em{justify-content:center} }

/* Adding stock in bulk — paste the list, check the table */
.bulk-ta{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:13.5px;line-height:1.6;
  min-height:150px;resize:vertical;margin-top:12px}
.bulk-common{margin-top:16px;padding:12px 14px;border-radius:14px;background:var(--paper-2);
  border:1px solid var(--line)}
.bulk-common summary{cursor:pointer;font-size:13px;font-weight:600;color:var(--ink-soft)}
.bulk-common[open] summary{margin-bottom:12px}
.bulk-common>div{margin-top:10px}
.bulk-group{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.bulk-group>span{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);
  width:100%;margin-bottom:-2px}
.bulk-group .chip{font-size:12px;padding:7px 10px}
.bulk-prev table{min-width:660px}
.bulk-prev td:first-child{min-width:170px}
.bulk-prev .input{min-height:42px;padding:8px 10px;font-size:13px}
.bulk-prev .input.num{text-align:right}
.bulk-bad .input[data-f="name"]{border-color:var(--red);background:var(--red-soft)}

/* Delivery ⇄ docket: the same event seen from either end */
.dkt-flag{margin-top:3px;font-size:10px;font-weight:700;color:var(--red)}
.dkt-stamp{margin-top:12px;padding:8px 10px;border-radius:8px;border:1.5px dashed rgba(47,143,91,.5);
  background:color-mix(in srgb,var(--green-soft) 70%,transparent);text-align:center}
.dkt-stamp b{display:block;font-size:10.5px;letter-spacing:.04em;color:#1d6a40}
.dkt-stamp span{display:block;margin-top:2px;font-size:9.5px;color:#4b7c60;line-height:1.4}
.dkt-stamp.plain{border-color:rgba(33,30,27,.18);background:rgba(33,30,27,.03)}
.dkt-stamp.plain b{color:var(--ink-soft)}
.dkt-stamp.plain span{color:var(--ink-faint)}
.dlv-amt{white-space:nowrap;font-size:14px}
/* the back-door check sheet: never let the condition column get crushed */
.dc-row td:last-child{min-width:132px}
/* The back-door checklist: a tick per line, and a camera per line for the one
   that arrived broken. A ticked row dims a little so what's left stands out. */
.dc-bar{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-bottom:8px;font-size:13px;color:var(--ink-soft)}
.dc-check{display:flex;align-items:flex-start;gap:8px}
.dc-tick{flex:none;width:28px;height:28px;border-radius:9px;border:2px solid var(--line);background:var(--card);color:transparent;display:grid;place-items:center;cursor:pointer}
.dc-tick .ic{width:16px;height:16px;stroke-width:3}
.dc-row.ticked .dc-tick{background:var(--green);border-color:var(--green);color:#fff}
.dc-row.ticked .c-item b{color:var(--ink-soft)}
.dc-cam{display:flex;align-items:center;gap:6px;margin-top:6px}
.dc-cam .btn{padding:4px 8px}
.dc-thumb img,.dc-thumb-img{width:36px;height:36px;object-fit:cover;border-radius:8px;display:block}
.dc-thumb-img{margin-top:6px}

/* Skill glyphs (can open / can close / kitchen / bar / shift lead) — inline with
   the name they sit next to, so a roster row reads as one line. */
.skill-ic{width:15px;height:15px;vertical-align:-2px;color:var(--ink-soft)}
.skill-chip .skill-ic{margin:0 2px}
.rg-name .skill-ic{width:13px;height:13px;opacity:.75}

/* Icons that sit inline with a label rather than in a chip of their own —
   stat-card keys, supplier buttons, chat, the AI send button. */
.stat .k .ic{width:15px;height:15px;flex-shrink:0}
.btn .ic{width:17px;height:17px;flex-shrink:0}
.tab .ic{width:16px;height:16px}
.pill .ic{width:13px;height:13px}
.ai-head .ic,.aa-head .ic{width:17px;height:17px}
.ai-input-row .btn .ic{width:18px;height:18px}
.ai-msg .ic,.aa-msg .ic{width:14px;height:14px;vertical-align:-2px}
.dkt-flag .ic,.dkt-stamp .ic{width:12px;height:12px;vertical-align:-1px}
.li .meta .ic,.meta span .ic{width:13px;height:13px;vertical-align:-2px}
.offbar .ic{width:15px;height:15px;vertical-align:-3px;margin-right:3px}
.img-preview .ic{width:22px;height:22px;margin-bottom:4px}
.ai-chip .ic{width:13px;height:13px}

/* Rating: five icons filled to the score, rather than a repeated ★ character —
   a text star can't be styled per-state and reads as noise to a screen reader. */
.stars{display:inline-flex;gap:1px;vertical-align:-2px}
.stars .ic{width:14px;height:14px;color:var(--line)}
.stars .on .ic{color:var(--amber);fill:var(--amber)}
/* Leaderboard rank: one medal icon plus the number. */
.bestnm .ic,.li b .ic{width:14px;height:14px;vertical-align:-2px}
.onb-ic .ic{width:17px;height:17px}
.task-check .ic,.kv-tick .ic{width:15px;height:15px;stroke-width:3}
.aa-orb .ic{width:21px;height:21px}
.role-seg .ic{width:16px;height:16px}
/* A draft the assistant filled in from one sentence — an SOS, a task. It sits in
   an .ai-form bubble, so it already has the panel's full width. */
.ai-card{margin-top:10px;padding:12px 12px 10px;border:1px solid var(--line);border-radius:12px;background:var(--card)}
.ai-card-head{display:flex;align-items:center;gap:6px;margin-bottom:8px}
.ai-card-note{font-size:12px;margin-top:6px}
/* The camera beside the assistant's input — owner and manager only — and the
   photo it sends, shown small in the bubble and on the filing card. */
.ai-attach{display:inline-flex;align-items:center;justify-content:center;flex:0 0 44px;height:44px;border:1px solid var(--line);border-radius:12px;background:var(--card);color:var(--ink-soft);cursor:pointer}
.ai-attach:hover{color:var(--accent);border-color:var(--accent)}
.ai-attach .ic{width:20px;height:20px}
.ai-att{display:block;max-width:180px;max-height:140px;border-radius:10px;margin:2px 0 8px;object-fit:cover}

/* Sidebar footer: "Change password" and "Log out" do not fit side by side in
   a 248px sidebar, which pushed "Log out" off the edge. Stack them. */
.row:has(> #pwBtn){flex-wrap:wrap}
#pwBtn,#logoutBtn{flex:1 1 100%}

/* "Photo" / "Add photo" buttons are a <label> wrapping a hidden file input.
   `hidden` is display:none, which also takes the input out of the tab order, so
   nobody on a keyboard could attach a photo. Keep it invisible but reachable,
   and show the focus on the button it sits in. */
label.btn{position:relative}
label.btn > input[type="file"][hidden]{display:block !important;position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}
label.btn:focus-within{outline:3px solid var(--accent);outline-offset:2px}

/* Read by screen readers, not shown. */
.sr-only{position:absolute !important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* ---------- first-run guide: one question per screen ---------- */
.guide{max-width:560px;margin:8px auto 40px}
.guide-top{display:flex;justify-content:space-between;align-items:center;gap:10px;font-size:13px}
.guide-phase{font-weight:700;letter-spacing:.02em}
.guide .bar{margin:8px 0 22px}
.guide-hero{font-size:44px;line-height:1;margin:18px 0 12px;letter-spacing:6px}
.guide-q{font-size:26px;line-height:1.2;margin:0 0 6px;letter-spacing:-.01em}
.guide-sub{color:var(--ink-soft);margin:0 0 18px;font-size:14.5px;line-height:1.5}
.guide-prep{padding:16px 18px}
.guide-li{display:flex;gap:12px;align-items:flex-start;padding:8px 0;font-size:14.5px}
.guide-li > span{font-size:20px;line-height:1.2;flex:none;width:26px;text-align:center}
.guide-actions{display:flex;gap:10px;margin-top:22px;flex-wrap:wrap}
.guide-actions .btn{min-height:48px}
.guide-photo{display:flex;align-items:center;gap:12px;padding:12px 14px;border:1.5px dashed var(--line);border-radius:14px;margin-bottom:16px;font-size:13.5px}
.guide-photo .faint{font-size:12px;margin-top:2px}
.guide-have{font-size:13px;color:var(--ink-soft);margin:0 0 12px;display:flex;gap:6px;align-items:center}
.guide-logo .img-preview{height:88px}
.guide-nudge{display:flex;align-items:center;gap:14px;padding:14px 18px;margin-bottom:16px;border-color:var(--amber);background:var(--amber-soft)}
.guide-nudge-ic{font-size:24px}
@media (max-width:520px){ .guide-photo{flex-wrap:wrap} .guide-q{font-size:23px} }
.guide .rep-row .input.grow{min-width:150px}
.guide .btn-link{background:none;border:none;box-shadow:none;color:var(--ink-soft);text-decoration:underline;padding:8px 0;min-height:44px;cursor:pointer}
.guide-tries{display:grid;gap:10px}
.guide-try{display:flex;align-items:center;gap:14px;padding:16px 18px;text-align:left;font:inherit;font-size:15px;color:var(--ink);cursor:pointer;min-height:60px}
.guide-try > span{font-size:24px}
.guide-try:hover{border-color:var(--accent)}
.guide-try:focus-visible{outline:3px solid var(--accent);outline-offset:2px}
.ob-prep > div:not(.faint){font-size:13.5px;padding:2px 0}
a.ai-chip{text-decoration:none;display:inline-flex;align-items:center}

/* ---------- assistant: voice ---------- */
.ai-input-row .input{flex:1 1 auto;min-width:0}
.ai-mic{display:inline-flex;align-items:center;justify-content:center;flex:0 0 44px;height:44px;border:1px solid var(--line);border-radius:12px;background:var(--card);color:var(--ink-soft);cursor:pointer;padding:0}
.ai-mic .ic{width:20px;height:20px}
.ai-mic:hover{color:var(--accent);border-color:var(--accent)}
.ai-mic:focus-visible{outline:3px solid var(--accent);outline-offset:2px}
.ai-mic.listening{color:#fff;background:var(--red);border-color:var(--red);animation:mic-pulse 1.2s ease-in-out infinite}
@keyframes mic-pulse{0%,100%{box-shadow:0 0 0 0 rgba(216,69,60,.45)}50%{box-shadow:0 0 0 8px rgba(216,69,60,0)}}
@media (prefers-reduced-motion: reduce){ .ai-mic.listening{animation:none} }
@media (max-width:420px){ .ai-input-row{gap:6px} .ai-mic,.ai-attach{flex-basis:40px;height:40px} }

/* ---------- wide tables become cards on a phone ---------- */
@media (max-width:600px){
  /* Forecast: the item across the top, then three figures side by side, with
     days of cover as a bar — two weeks fills it. */
  .dtable.stack.fc-table tr{grid-template-columns:repeat(3,minmax(0,1fr))!important;gap:10px 12px}
  .fc-table td:nth-child(1){grid-column:1/-1}
  .fc-table td:nth-child(1) .faint{font-size:12px!important;margin-top:2px}
  .fc-table td:nth-child(4) b{font-size:20px}
  /* Prices: name and the move on top, this period's price big beneath, last
     period's and the cost to you as the small print. */
  .dtable.stack.pw-table tr{grid-template-columns:minmax(0,1fr) auto!important;
    grid-template-areas:"item move" "this cost" "prev spark";gap:8px 14px;padding:16px 2px}
  .pw-table td:nth-child(1){grid-area:item;grid-column:auto!important}
  .pw-table td:nth-child(2){grid-area:prev}
  .pw-table td:nth-child(3){grid-area:this}
  .pw-table td:nth-child(3) b{font-size:20px}
  .pw-table td:nth-child(4){grid-area:move;align-self:start}
  .pw-table td:nth-child(4)::before, .pw-table td:nth-child(6)::before{display:none!important}
  .pw-table td:nth-child(5){grid-area:cost;text-align:right!important}
  .pw-table td:nth-child(6){grid-area:spark;justify-self:end;align-self:end}
  .pw-table td:nth-child(1) b{font-size:16px}
  .tablewrap:has(> table.dtable.stack){overflow:visible}
  .dtable.stack, .dtable.stack tbody{display:block;width:100%;min-width:0!important}
  .dtable.stack tr{grid-template-columns:minmax(0,1fr) minmax(0,1fr)!important}
  .dtable.stack td{overflow-wrap:anywhere}
  .dtable.stack thead{display:none}
  .dtable.stack tr{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px;padding:14px 2px;border-bottom:1px solid var(--line-2)}
  .dtable.stack tr:last-child{border-bottom:none}
  .dtable.stack td{display:block;padding:0;border:none;text-align:left;min-width:0;width:auto!important}
  .dtable.stack td:first-child{grid-column:1/-1}
  .dtable.stack td[data-label]:not([data-label=""]):not(:first-child)::before{content:attr(data-label);display:block;font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);margin-bottom:4px}
  .dtable.stack td .input, .dtable.stack td select{width:100%;max-width:none;text-align:left!important}
  .dtable.stack td:last-child:empty{display:none}
}

/* ---------- phone: sheets rise from the bottom ---------- */
@media (max-width:600px){
  .modal-back{place-items:end center;padding:0}
  .modal,.modal.wide{max-width:none;border-radius:22px 22px 0 0;max-height:94vh;animation:sheet-up .26s var(--ease-out);
    padding-bottom:env(safe-area-inset-bottom,0px)}
  /* The sheet is a column: the title, the form scrolling under it, and the
     buttons fixed at the foot — just clear of the home indicator. Nothing in
     the form can scroll beneath them, because they are not in the scroller. */
  .modal:has(> .modal-actions){display:flex;flex-direction:column;overflow:hidden;padding-bottom:0}
  .modal:has(> .modal-actions) > .modal-head{flex:none;padding-bottom:12px;border-bottom:1px solid var(--line-2)}
  .modal:has(> .modal-actions) > .modal-head + .modal-body{padding-top:14px}
  .modal:has(> .modal-actions) > .modal-body{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}
  .modal > .modal-actions{flex:none;background:var(--card);margin:0;
    padding:10px 22px max(12px, calc(env(safe-area-inset-bottom,0px) - 10px));flex-wrap:nowrap}
  .modal .modal-actions .btn{flex:1 1 0;min-height:48px}
}
@keyframes sheet-up{from{transform:translateY(40px);opacity:.6}to{transform:none;opacity:1}}
@media (prefers-reduced-motion: reduce){ .modal{animation:none} }

/* ---------- phone: the delivery sign-off, two lines per item ----------
   Name and what was ordered on top; what came and its state underneath. */
@media (max-width:600px){
  .dtable.dc tr{grid-template-columns:minmax(0,1fr) minmax(0,1fr)!important;grid-template-areas:"item ord" "rec cond" "price price";gap:8px 12px;padding:12px 0}
  .dtable.dc td.c-item{grid-area:item;grid-column:auto}
  .dtable.dc td.c-item .faint{display:inline;margin-left:6px}
  .dtable.dc td.c-ord{grid-area:ord;text-align:right!important;align-self:center}
  .dtable.dc td.c-ord::before{display:inline!important;margin:0 6px 0 0!important}
  .dtable.dc td.c-rec{grid-area:rec}
  .dtable.dc td.c-cond{grid-area:cond}
  .dtable.dc td.c-price{grid-area:price}
  .dtable.dc td.c-rec::before,.dtable.dc td.c-cond::before,.dtable.dc td.c-price::before{font-size:10.5px;margin-bottom:3px}
}

/* ============================================================
   ===== Glass — the navigation layer as a translucent material =====
   Apple's rule for Liquid Glass, applied here: glass is for the chrome that
   floats ABOVE the content — the top bar, the tab bar, sheets, the floating
   button, toasts, the view switch — never for the content itself. Cards, lists
   and forms stay solid, because text read at arm's length in a busy kitchen
   must not sit on something that changes colour as the page scrolls under it.
   · Bigger surfaces are thicker: sheets blur harder and are more opaque than bars.
   · Colour lives on solid layers: status toasts and the preview banner stay solid.
   · Controls on glass (inputs, the language select) stay solid — never glass on glass.
   · Everything falls back to solid for Reduce Transparency, Increase Contrast,
     and browsers without backdrop-filter.
   ============================================================ */
:root{
  --glass:rgba(255,252,247,.56);                 /* bars */
  --glass-thick:rgba(255,252,247,.97);           /* sheets: thick enough that the page behind never reads through their text */
  --glass-blur:blur(22px) saturate(180%);
  --glass-blur-thick:blur(36px) saturate(190%);
  --glass-rim:rgba(255,255,255,.85);             /* the bright top edge where light catches */
  --glass-edge:rgba(33,30,27,.09);               /* hairline that separates it from white */
  --glass-shadow:0 1px 1px rgba(33,30,27,.04), 0 12px 32px -14px rgba(33,30,27,.28);
  --glass-lens:color-mix(in srgb, var(--ink) 86%, transparent);   /* dark lens: FAB, toast */
  --glass-pill:color-mix(in srgb, var(--accent) 15%, transparent); /* selected tab */
  --glass-liquid:rgba(255,253,250,.14);          /* the tab bar: clearer than the other bars */
  --glass-blur-liquid:blur(10px) saturate(220%) brightness(1.08);
  --glass-sheen:rgba(255,255,255,.40);           /* light across the top half */
  --nav-float:max(10px, calc(env(safe-area-inset-bottom) - 18px)); /* capsule's gap to the bottom: just above the home indicator */
}
:root[data-theme="dark"]{
  --glass:rgba(38,36,42,.55);
  --glass-thick:rgba(34,33,39,.97);
  --glass-rim:rgba(255,255,255,.12);
  --glass-edge:rgba(0,0,0,.45);
  --glass-shadow:0 1px 1px rgba(0,0,0,.35), 0 14px 34px -14px rgba(0,0,0,.75);
  --glass-pill:color-mix(in srgb, var(--accent) 24%, transparent);
  --glass-liquid:rgba(40,38,44,.30);
  --glass-blur-liquid:blur(16px) saturate(190%) brightness(.92);
  --glass-sheen:rgba(255,255,255,.07);
}

/* Solid when the person or the device asks for it. `mkr-solid` is set by the
   iOS app from the system's Reduce Transparency switch, which WebKit does not
   expose as a media query. */
@media (prefers-reduced-transparency: reduce){
  :root, :root[data-theme="dark"]{ --glass:var(--card); --glass-thick:var(--card); --glass-liquid:var(--card); --glass-sheen:transparent; --glass-blur-liquid:none; --glass-blur:none; --glass-blur-thick:none; --glass-lens:var(--ink) }
}
html.mkr-solid, html.mkr-solid[data-theme="dark"]{ --glass:var(--card); --glass-thick:var(--card); --glass-liquid:var(--card); --glass-sheen:transparent; --glass-blur-liquid:none; --glass-blur:none; --glass-blur-thick:none; --glass-lens:var(--ink) }
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  :root, :root[data-theme="dark"]{ --glass:var(--card); --glass-thick:var(--card); --glass-liquid:var(--card); --glass-sheen:transparent; --glass-blur-liquid:none; --glass-lens:var(--ink) }
}
@media (prefers-contrast: more){
  :root, :root[data-theme="dark"]{ --glass:var(--card); --glass-thick:var(--card); --glass-liquid:var(--card); --glass-sheen:transparent; --glass-blur-liquid:none; --glass-blur:none; --glass-blur-thick:none;
    --glass-lens:var(--ink); --glass-edge:var(--ink-soft); --glass-rim:transparent }
}
html.mkr-contrast, html.mkr-contrast[data-theme="dark"]{ --glass:var(--card); --glass-thick:var(--card); --glass-liquid:var(--card); --glass-sheen:transparent; --glass-blur-liquid:none; --glass-blur:none; --glass-blur-thick:none;
  --glass-lens:var(--ink); --glass-edge:var(--ink-soft); --glass-rim:transparent }

/* Something for the glass to catch: the page's warm wash, a touch stronger. */
body{
  background:
    radial-gradient(900px 560px at 0% -6%, color-mix(in srgb, var(--accent) 11%, transparent), transparent 62%),
    radial-gradient(820px 520px at 100% 8%, color-mix(in srgb, var(--green) 8%, transparent), transparent 58%),
    radial-gradient(760px 520px at 50% 108%, color-mix(in srgb, var(--amber) 8%, transparent), transparent 60%),
    var(--paper);
  background-attachment:fixed;
}

/* ---- Top bar: a glass strip the page scrolls under ---- */
.topbar{
  background:var(--glass);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border-bottom:0;
  box-shadow:inset 0 -1px 0 var(--glass-edge);
}
.topbar h1{letter-spacing:-.02em}

/* ---- View switch (Floor / Blocks / List): a glass track, the choice solid on it ---- */
.viewswitch{
  background:var(--glass);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  border:1px solid var(--glass-edge);
  box-shadow:inset 0 1px 0 var(--glass-rim), var(--glass-shadow);
  padding:3px; gap:2px;
}
.viewswitch button{border-radius:999px;min-height:42px}
.viewswitch button.on{background:var(--ink-grad);box-shadow:0 4px 12px -6px rgba(33,30,27,.5)}

/* ---- Floating button: a dark lens ---- */
.ai-fab{
  background:var(--glass-lens);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), inset 0 0 0 .5px rgba(255,255,255,.14), var(--glass-shadow);
}
.ai-fab.open{background:var(--accent)}
.ai-fab:active{transform:scale(.94);transition:transform .1s ease-out}

/* ---- Toasts: plain messages are a lens; status colours stay solid ---- */
.toast:not(.green):not(.red):not(.amber){
  background:var(--glass-lens);
  -webkit-backdrop-filter:var(--glass-blur); backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18), var(--glass-shadow);
}

/* ---- Dialogs: thick glass; the fields and the scrim stay as they were ---- */
/* Sheets are near-solid and carry no backdrop blur: on iOS a blurred box with
   a scrolling inside paints the part scrolled past as blank, leaving a big
   empty band at the top of a long list. The dimmed backdrop does the blurring. */
.modal{
  background:var(--glass-thick);
  box-shadow:inset 0 1px 0 var(--glass-rim), 0 0 0 .5px var(--glass-edge), var(--shadow);
}
.modal-back{background:rgba(33,30,27,.32);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
/* One thing on screen at a time: the floating button showed through open dialogs. */
body.modal-open .ai-fab{display:none}

@media (max-width:880px){
  /* ---- Tab bar: a floating Liquid Glass capsule, as on iOS 26 ----
     Clearer than the other bars so the page reads through it as it scrolls
     under: a thin tint, a strong blur that lifts the colour behind, a bright
     rim along the top, a softer one along the bottom, and a sheen across the
     upper half where the light lands. */
  .mobile-nav{
    left:12px; right:12px; bottom:var(--nav-float);
    padding:5px; border-radius:32px; border-top:0;
    justify-content:space-between;
    background:var(--glass-liquid);
    -webkit-backdrop-filter:var(--glass-blur-liquid); backdrop-filter:var(--glass-blur-liquid);
    box-shadow:
      inset 0 1px 0 var(--glass-rim),
      inset 0 -1px 0 color-mix(in srgb, var(--glass-rim) 45%, transparent),
      inset 0 0 0 .5px color-mix(in srgb, var(--glass-rim) 50%, transparent),
      0 0 0 .5px var(--glass-edge), var(--glass-shadow);
    isolation:isolate;
  }
  .mobile-nav::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:-1;
    background:linear-gradient(to bottom, var(--glass-sheen) 0%, transparent 55%)}
  .mobile-nav a,.mobile-nav button{
    flex:1 1 0; min-width:0; min-height:52px; padding:5px 4px; border-radius:27px;
    transition:background .2s var(--ease-out), color .2s, transform .1s ease-out;
  }
  /* The selected tab sits in a lens of brighter glass, tinted by the accent. */
  .mobile-nav a.active,.mobile-nav button.active{background:var(--glass-pill);color:var(--accent-ink);font-weight:700;
    box-shadow:inset 0 1px 0 color-mix(in srgb, var(--glass-rim) 70%, transparent), inset 0 0 0 .5px color-mix(in srgb, var(--glass-rim) 40%, transparent)}
  :root[data-theme="dark"] .mobile-nav a.active,:root[data-theme="dark"] .mobile-nav button.active{color:var(--accent)}
  /* Feedback on the press itself, not on release. */
  .mobile-nav a:active,.mobile-nav button:active{transform:scale(.94)}

  /* The scroll edge under the capsule, as iOS 26 draws it: nothing shows in
     the strip between the capsule and the bottom of the screen, and the page
     fades out as it slides under the glass rather than ending in sharp text. */
  /* Only the strip under the capsule is filled — behind the capsule itself the
     page has to show, or the glass is just a white slab. */
  .shell:has(> .mobile-nav)::after{content:"";position:fixed;left:0;right:0;bottom:0;z-index:29;pointer-events:none;
    height:calc(var(--nav-float) + 22px);
    background:linear-gradient(to top, var(--paper) 0, var(--paper) var(--nav-float), color-mix(in srgb, var(--paper) 0%, transparent))}
  html.mkr-kb .shell::after{display:none}

  /* Room under the page for the capsule (its height is 64px). */
  .content{padding-bottom:calc(var(--nav-float) + 84px)}
  body.ai-fullpage .content{padding-bottom:calc(var(--nav-float) + 70px)}
  .ai-fab{bottom:calc(var(--nav-float) + 76px)}
  .toast-wrap{bottom:calc(var(--nav-float) + 76px)}

  /* ---- The More sheet: thick glass, floating clear of the screen edges ---- */
  /* Rises from the bottom edge like every other sheet, not floating above it. */
  .navsheet{
    margin:0; width:100%; border-radius:22px 22px 0 0;
    background:var(--glass-thick);
    box-shadow:inset 0 1px 0 var(--glass-rim), 0 0 0 .5px var(--glass-edge), 0 -10px 40px -18px rgba(33,30,27,.5);
  }
  .navsheet-body{padding-bottom:max(14px, env(safe-area-inset-bottom))}
  /* Change password / Log out: two rows at the foot, like Settings, not two
     pill buttons side by side. */
  .navsheet-foot{flex-direction:column;gap:0;margin-top:8px;padding-top:0;border-top:none;
    background:color-mix(in srgb,var(--ink) 4%,transparent);border-radius:16px;overflow:hidden}
  .navsheet-foot .btn{justify-content:flex-start;gap:14px;width:100%;min-height:50px;padding:0 16px;border:none;border-radius:0;
    background:none;box-shadow:none;font-size:15px;font-weight:600}
  .navsheet-foot .btn + .btn{border-top:1px solid var(--line-2)}
  .navsheet-foot .btn .ic{width:19px;height:19px}
  .navsheet-foot #logoutBtnM{color:var(--red)}
  .navsheet-back:not(.hidden){background:rgba(33,30,27,.30);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
  .ns-item{border-bottom-color:var(--glass-edge)}
  .ns-item:active{transform:scale(.985)}
  /* The floating button sat on top of the open sheet, over its rows. */
  body:has(.navsheet-back:not(.hidden)) .ai-fab{display:none}
}

@media (max-width:600px){
  /* The button bar is the sheet's own material, not a second layer on it. */
  .modal > .modal-actions{background:transparent}
}

/* ---- Large titles (js/router.js largeTitle): the top bar's small title stays
   out of the way while the page's own heading says the same thing, and fades
   in once that heading has scrolled up under the bar. ---- */
.topbar-title h1{transition:opacity .22s var(--ease-out), transform .22s var(--ease-out)}
.topbar.large-title:not(.scrolled-title) .topbar-title h1{opacity:0;transform:translateY(6px)}
@media (prefers-reduced-motion: reduce){ .topbar.large-title:not(.scrolled-title) .topbar-title h1{transform:none} }

/* A logo image (the venue's, or the app's own) fills the tile edge to edge. */
.login-logo:has(img){background:none;padding:0;overflow:hidden;box-shadow:0 10px 22px -12px rgba(33,30,27,.45)}

/* The need the assistant offers to pass on to the team: what it heard, set
   apart so the owner can see exactly what would be sent before saying yes. */
.ai-need{display:flex;gap:10px;align-items:flex-start;margin-top:10px;padding:10px 12px;border-radius:12px;
  background:var(--card);border:1px solid var(--line-2)}
.ai-need > .ic{color:var(--accent);flex:0 0 auto;margin-top:2px}
.ai-need span{display:flex;flex-direction:column;gap:2px;font-weight:600}
.ai-need small{font-weight:400;color:var(--ink-soft);font-size:12.5px}
.napp-chat .ai-need{border:none;border-radius:14px}
/* The conversation a request came from, on the super admin's Requests page. */
.req-convo{margin-top:6px;font-size:12.5px}
.req-convo summary{cursor:pointer;color:var(--accent-ink);font-weight:600}
.req-convo p{margin:4px 0 0;padding:6px 10px;border-radius:10px;background:var(--paper-2);white-space:pre-wrap}
.req-convo p.user{background:var(--accent-soft)}

/* Starting a restaurant by chatting (js/signup-chat.js). On the website it
   sits in the sign-in card's tab; the iOS app gives it the chat screen. */
.su-web .ai-page{height:min(520px,64vh);min-height:360px;margin-top:16px}
.su-web .ai-log{padding:14px 12px 6px}
.su-sum{margin-top:8px;display:flex;flex-direction:column;gap:2px;background:var(--card);border-radius:12px;padding:6px 12px;border:1px solid var(--line-2)}
.su-row{display:flex;justify-content:space-between;gap:12px;padding:6px 0;font-size:13.5px}
.su-row + .su-row{border-top:1px solid var(--line-2)}
.su-row span{color:var(--ink-soft);flex:0 0 auto}
.su-row b{text-align:right;overflow-wrap:anywhere}
.ai-chip.su-go{background:var(--accent);border-color:var(--accent);color:#fff}
.su-swatch{display:inline-block;width:14px;height:14px;border-radius:50%;vertical-align:-2px;margin-left:2px;box-shadow:0 0 0 1px rgba(0,0,0,.12)}
.su-logo{width:34px;height:34px;object-fit:contain;border-radius:8px;background:#fff;vertical-align:middle}
.napp-mark.has-logo{background:#fff}
.napp-mark.has-logo img{width:100%;height:100%;object-fit:contain}
/* A choice that can be one of several: picked ones fill in and carry a tick. */
.ai-chip.su-pick.on{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-ink)}
.ai-chip.su-pick.on::before{content:"✓ ";font-weight:700}
/* An answer can be changed: a pencil in front of it, and the answer it
   replaced stays in the thread, crossed out. */
.ai-msg.user[data-step]{position:relative}
.su-edit{position:absolute;right:calc(100% + 6px);top:50%;transform:translateY(-50%);width:30px;height:30px;
  display:inline-flex;align-items:center;justify-content:center;padding:0;border:none;border-radius:50%;
  background:var(--paper-2);color:var(--ink-soft);cursor:pointer;min-height:0}
.su-edit .ic{width:15px;height:15px}
.su-edit:active{transform:translateY(-50%) scale(.92)}
.ai-msg.user.su-old{opacity:.45;text-decoration:line-through}
.su-eye{flex:0 0 auto;width:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;
  padding:0;border:none;border-radius:50%;background:transparent;color:var(--ink-soft);cursor:pointer;min-height:0}
.su-eye[hidden]{display:none}
.su-eye[aria-pressed="true"]{color:var(--accent)}
.su-eye .ic{width:20px;height:20px}
.napp-chat .ai-chip.su-pick.on{background:var(--accent-soft);box-shadow:0 0 0 1.5px var(--accent)}
.ai-chip:disabled{opacity:.55;pointer-events:none}
/* Clocking on and the day's checklist, live inside a chat message (js/chat-widgets.js). */
.ai-widget{margin-top:8px;background:var(--card);border:1px solid var(--line);border-radius:14px;padding:12px}
.cw-clock{display:flex;flex-direction:column;gap:8px}
.cw-clock.off{gap:2px}
.cw-clock > b{font-size:15px;display:flex;align-items:center;gap:6px}
.cw-status{font-size:14px;font-weight:600}
.cw-status.ok{color:var(--green)}
.cw-status.late{color:var(--red)}
.cw-head{display:flex;justify-content:space-between;align-items:baseline}
.cw-tasks .bar{margin:6px 0 4px}
.cw-task{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--line)}
.cw-task:last-of-type{border-bottom:none}
.cw-task .grow{min-width:0}
.cw-task .grow b{font-size:14px;overflow-wrap:anywhere}
.cw-task .grow .faint{font-size:12px}
.cw-task.done .grow b{text-decoration:line-through;color:var(--ink-faint)}
.cw-temp{width:72px;flex:0 0 auto;text-align:right}
.cw-cam{flex:0 0 auto;cursor:pointer}
.cw-cam.need{border-color:var(--accent);color:var(--accent)}
.cw-thumb{width:40px;height:40px;object-fit:cover;border-radius:8px;flex:0 0 auto}
.cw-warn{margin-top:6px;color:var(--red)}
/* A shelf photo's count in the chat: one line per item, the figure to check on the right. */
.ai-count-row{align-items:center;padding:4px 0;border-bottom:1px solid var(--line)}
.ai-count-row label{font-size:13.5px;min-width:0;overflow-wrap:anywhere}
.ai-count-row .input{width:92px;flex:0 0 auto;text-align:right}
/* The owner's set-up chat (js/owner-setup.js): one row per part of the app,
   tapped on or off — a chip is too small to say what each one does. */
.os-parts{display:flex;flex-direction:column;gap:6px;margin:4px 0 8px}
.os-part{display:flex;align-items:center;gap:10px;width:100%;text-align:left;padding:9px 12px;border-radius:12px;border:1px solid var(--line);background:var(--card);color:var(--ink);font:inherit;cursor:pointer}
.os-part .grow{display:flex;flex-direction:column;gap:1px;min-width:0}
.os-part .grow b{font-size:14px}
.os-part .grow .faint{font-size:12px;line-height:1.35}
.os-ic{font-size:20px;flex:0 0 auto}
.os-tick{width:22px;height:22px;border-radius:50%;border:1.5px solid var(--line);flex:0 0 auto;display:grid;place-items:center;color:transparent}
.os-tick .ic{width:14px;height:14px;stroke-width:3}
.os-part.on{border-color:var(--accent);background:var(--accent-soft)}
.os-part.on .os-tick{background:var(--accent);border-color:var(--accent);color:#fff}
.os-part:disabled{opacity:.7;cursor:default}
.ai-form .os-text, .ai-form .os-more{width:100%;margin:2px 0 6px}
/* One row per person: name and email take the room, access and job sit after. */
.os-people{display:flex;flex-direction:column;gap:8px;margin:4px 0 6px}
.os-person{display:grid;grid-template-columns:1fr 1.4fr auto;gap:8px 6px;align-items:center;padding:8px;border:1px solid var(--line);border-radius:14px;background:var(--card)}
.os-person .os-pn{grid-column:1;grid-row:1}.os-person .os-pe{grid-column:2;grid-row:1}.os-person .os-px{grid-column:3;grid-row:1}
.os-person .input{min-width:0;padding:8px 10px;font-size:14px}
/* Access: a two-way switch. Job: chips in one row that scrolls sideways. */
.os-seg{grid-column:1 / -1;justify-self:start;display:inline-flex;gap:2px;padding:3px;border-radius:999px;background:var(--paper-2)}
.os-seg button{min-height:34px;padding:0 16px;border:none;border-radius:999px;background:transparent;color:var(--ink-soft);
  font:inherit;font-size:13.5px;font-weight:600;cursor:pointer;transition:background .18s var(--ease-out),color .18s}
.os-seg button.on{background:var(--card);color:var(--ink);box-shadow:0 1px 3px rgba(33,30,27,.16)}
.os-jobs{grid-column:1 / -1;display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;margin:0 -8px;padding:0 8px 2px;
  -webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
.os-jobs::-webkit-scrollbar{display:none}
.os-job{flex:0 0 auto;min-height:34px;padding:0 13px;border:1px solid var(--line);border-radius:999px;background:var(--card);
  color:var(--ink);font:inherit;font-size:13.5px;font-weight:500;white-space:nowrap;cursor:pointer;
  transition:background .18s var(--ease-out),border-color .18s,color .18s}
.os-job.on{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.os-seg button:active,.os-job:active{transform:scale(.96)}
.os-person.is-mgr .os-jobs{display:none}
.os-paste{margin:6px 0;font-size:13px}.os-paste summary{cursor:pointer;color:var(--ink-soft)}
.os-paste .os-text{margin-top:6px}
.ai-form textarea.os-text{resize:vertical;min-height:84px;font-family:inherit;line-height:1.5}
.napp-chat .ai-chip.su-go{background:var(--accent);color:#fff}
.napp-back{width:38px;height:38px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;border:none;background:transparent;color:var(--accent);padding:0;cursor:pointer}
.napp-back .ic{width:24px;height:24px;stroke-width:2.2}
.napp-chat .su-sum{border:none}

/* Start-up: the venue's logo and a welcome, until the first screen is drawn. */
.boot{min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  background:var(--paper);padding:24px;text-align:center;animation:bootIn .4s var(--ease-out)}
.boot-mark{width:92px;height:92px;border-radius:24px;overflow:hidden;background:#fff;margin-bottom:10px;
  box-shadow:0 0 0 .5px rgba(0,0,0,.08), 0 14px 34px -14px rgba(0,0,0,.3)}
.boot-mark img{width:100%;height:100%;object-fit:cover;display:block}
.boot-hi{font-size:26px;font-weight:700;letter-spacing:-.4px;color:var(--ink)}
.boot-sub{font-size:15px;color:var(--ink-soft)}
.boot-dots{display:inline-flex;gap:5px;margin-top:18px}
.boot-dots i{width:6px;height:6px;border-radius:50%;background:var(--ink-faint);animation:aiBlink 1s infinite}
.boot-dots i:nth-child(2){animation-delay:.2s}.boot-dots i:nth-child(3){animation-delay:.4s}
@keyframes bootIn{from{opacity:0;transform:scale(.97)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){ .boot{animation:none} .boot-dots i{animation:none} }

/* ===== The iOS app (html.mkr-native, js/native-app.js) =====
   One screen, drawn the way iOS 26 draws a messaging app: a white page, the
   conversation running edge to edge, and the chrome — the venue bar on top,
   the composer below — as Liquid Glass floating over it, so messages slide
   underneath and show through. Glass only on chrome, never glass on glass:
   the field inside the composer and the rows inside the sheet stay solid.
   Reduce Transparency / Increase Contrast turn the glass solid (mkr-solid /
   mkr-contrast, set by NativeFeel.swift). */
html.mkr-native{
  --paper:#FFFFFF; --paper-2:#F2F2F7; --card:#FFFFFF;
  --n-fill:#E9E9EB;                       /* system grey: bot bubble, inputs */
  --n-sep:rgba(60,60,67,.18);
  --n-glass:rgba(255,255,255,.62);
  --n-glass-thick:rgba(250,250,252,.82);
  --n-glass-blur:blur(24px) saturate(190%);
  --n-glass-rim:inset 0 1px 0 rgba(255,255,255,.95), inset 0 0 0 .5px rgba(255,255,255,.7);
  --n-glass-edge:0 0 0 .5px rgba(0,0,0,.07);
  --n-glass-lift:0 8px 28px -10px rgba(0,0,0,.18), 0 1px 3px rgba(0,0,0,.06);
}
html.mkr-native[data-theme="dark"]{
  --paper:#000000; --paper-2:#1C1C1E; --card:#1C1C1E;
  --n-fill:#26252A; --n-sep:rgba(84,84,88,.6);
  --n-glass:rgba(40,40,44,.58); --n-glass-thick:rgba(30,30,33,.86);
  --n-glass-rim:inset 0 1px 0 rgba(255,255,255,.14), inset 0 0 0 .5px rgba(255,255,255,.08);
  --n-glass-edge:0 0 0 .5px rgba(0,0,0,.5);
  --n-glass-lift:0 8px 28px -10px rgba(0,0,0,.7);
}
html.mkr-native.mkr-solid, html.mkr-native.mkr-contrast{ --n-glass:var(--card); --n-glass-thick:var(--card); --n-glass-blur:none }
html.mkr-native, html.mkr-native body{background:var(--paper);
  font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","PingFang SC","Hiragino Sans GB",system-ui,sans-serif;-webkit-font-smoothing:antialiased}
html.mkr-native .ai-fab, html.mkr-native .ai-panel{display:none !important}
/* Only the full-screen chat (.napp, the sign-up conversation) locks the page:
   it scrolls its own thread. Every page in the shell scrolls the document,
   same as the website — a lock here left long pages like Add people stuck. */
html.mkr-native:has(.napp), html.mkr-native:has(.napp) body{height:100%;overflow:hidden}

/* "Easier on a computer" — advice at the top of a wide page, never a link out
   (js/native-app.js desktopNote). */
.desk-note{display:flex;align-items:flex-start;gap:10px;margin:0 0 14px;padding:11px 12px;border-radius:14px;
  background:var(--blue-soft);color:var(--blue);font-size:13.5px;line-height:1.4}
.desk-note > .ic{width:20px;height:20px;flex:0 0 auto;margin-top:1px}
.desk-note b{display:block;font-weight:600}
.desk-note .grow > div{color:var(--ink-soft);margin-top:2px}
.desk-note .grow > div b{display:inline;color:var(--ink)}
.desk-note-x{border:none;background:none;color:inherit;font-size:22px;line-height:1;padding:0 2px;min-height:0;cursor:pointer;opacity:.7}

/* The shared recipe: translucent fill, blur + saturation behind it, a bright
   rim where the light catches, a hairline, and a soft lift off the page. */
.napp-glass, .napp-bar, .napp-sheet{
  background:var(--n-glass);-webkit-backdrop-filter:var(--n-glass-blur);backdrop-filter:var(--n-glass-blur);
  box-shadow:var(--n-glass-rim), var(--n-glass-edge), var(--n-glass-lift)}

.napp{position:fixed;inset:0;background:var(--paper)}
/* The scroll edge: where the thread runs under the bars it fades and blurs
   out, the way iOS 26 does it, instead of showing sharp text in the gaps
   between the floating glass pieces. */
.napp::before,.napp::after{content:"";position:absolute;left:0;right:0;z-index:2;pointer-events:none;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.napp::before{top:0;height:84px;
  background:linear-gradient(to bottom, var(--paper) 30%, color-mix(in srgb, var(--paper) 0%, transparent));
  -webkit-mask-image:linear-gradient(to bottom,#000 55%,transparent);mask-image:linear-gradient(to bottom,#000 55%,transparent)}
.napp::after{bottom:0;height:calc(78px + env(safe-area-inset-bottom));
  background:linear-gradient(to top, var(--paper) 35%, color-mix(in srgb, var(--paper) 0%, transparent));
  -webkit-mask-image:linear-gradient(to top,#000 55%,transparent);mask-image:linear-gradient(to top,#000 55%,transparent)}
html.mkr-kb .napp::after{height:72px}
/* Venue bar: a glass capsule floating at the top. */
.napp-bar{position:absolute;top:6px;left:10px;right:10px;z-index:3;display:flex;align-items:center;gap:10px;
  padding:6px 6px 6px 7px;border-radius:26px}
.napp-mark{width:38px;height:38px;border-radius:12px;overflow:hidden;flex:0 0 auto;background:#fff;box-shadow:0 0 0 .5px rgba(0,0,0,.1)}
.napp-mark img{width:100%;height:100%;object-fit:cover;display:block}
.napp-title{flex:1;min-width:0;line-height:1.15}
.napp-title b{display:block;font-size:16px;font-weight:600;letter-spacing:-.3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.napp-title .netlight{font-size:12px;gap:5px;padding:0;margin-top:2px;min-height:0;height:auto;line-height:1.2;background:none;border:none;box-shadow:none;color:var(--ink-soft)}
.napp-title .netlight .lamp{width:6px;height:6px;box-shadow:none !important}
.napp-sub{display:flex;align-items:center;gap:4px;margin-top:2px;font-size:12px;font-weight:500;color:var(--accent-ink);min-width:0}
.napp-sub span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.napp-sub .ic{width:13px;height:13px;flex:0 0 auto}
.napp-ava{width:38px;height:38px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;
  background:color-mix(in srgb, var(--accent) 14%, transparent);color:var(--accent-ink);font-weight:600;font-size:14px;border:none;cursor:pointer;padding:0}
.napp-ava:active{transform:scale(.92)}
.napp-ava.big{width:56px;height:56px;font-size:20px}
.napp-note{position:absolute;top:70px;left:50%;transform:translateX(-50%);z-index:3;display:flex;align-items:center;gap:6px;white-space:nowrap;
  font-size:12px;font-weight:600;padding:5px 12px;border-radius:99px;color:var(--accent-ink);
  background:var(--n-glass);-webkit-backdrop-filter:var(--n-glass-blur);backdrop-filter:var(--n-glass-blur);box-shadow:var(--n-glass-rim), var(--n-glass-edge)}
.napp-note.warn{color:var(--amber-ink)}
.napp-note.warn:not(.hidden) ~ .napp-note{display:none}
.napp-note.hidden{display:none}
.napp-note .ic{width:14px;height:14px}

/* The conversation runs the full height; the glass sits over its ends. */
.napp-chat{position:absolute;inset:0;display:flex;flex-direction:column}
.napp-chat .ai-page{flex:1;min-height:0;height:auto;border:none;border-radius:0;background:transparent;position:relative}
.napp-chat .ai-page .ai-log{position:absolute;inset:0;padding:80px 14px calc(68px + env(safe-area-inset-bottom));gap:6px;overflow:auto;-webkit-overflow-scrolling:touch}
.napp:has(.napp-note:not(.hidden)) .napp-chat .ai-page .ai-log{padding-top:110px}
.napp-chat .ai-msg{max-width:80%;font-size:16.5px;line-height:1.34;letter-spacing:-.2px;padding:8px 13px;border-radius:20px;border:none;box-shadow:none}
.napp-chat .ai-msg.bot{background:var(--n-fill);color:var(--ink);border-bottom-left-radius:6px}
.napp-chat .ai-msg.user{background:var(--accent);color:#fff;border-bottom-right-radius:6px;margin-top:6px}
.napp-chat .ai-msg.ai-form{max-width:100%}
.napp-chat .ai-msg b{font-weight:600}
/* A card in a bubble is a small grouped form: white on the grey bubble. */
.napp-chat .ai-card{border:none;border-radius:14px;background:var(--card);padding:12px}
.napp-chat .ai-card .input{background:var(--paper-2);border:none;border-radius:10px;height:42px;font-size:16px}
.napp-chat .ai-card .btn{border-radius:12px;min-height:40px}
.napp-chat .ai-chips{gap:6px;margin-top:10px}
.napp-chat .ai-chip{font-size:14.5px;font-weight:500;padding:8px 14px;border:none;border-radius:99px;
  background:var(--card);color:var(--accent-ink);box-shadow:0 0 0 .5px rgba(0,0,0,.06)}
.napp-chat .ai-chip:active{transform:scale(.96)}
.napp-chat .ai-suggest .ai-chip{background:var(--n-fill)}
.napp-chat .ai-jump{color:var(--accent-ink)}
/* A page link leaves the app for the website — say so. */
.napp-chat .ai-jump::after{content:"\00a0\2197\FE0E";font-weight:600}

/* Composer, drawn like Messages: a round glass "+" (camera / photos) and a
   glass capsule beside it holding the field, with the mic at its right end.
   Once there is something typed, the mic gives way to a round send arrow
   inside the capsule. It floats over the bottom of the thread, sitting on the
   home indicator — or on the keyboard, which the app shrinks the page above.
   (js/native-app.js wraps the field, mic and send into .napp-field.) */
.napp-chat .ai-page .ai-input-row{position:absolute;left:12px;right:12px;bottom:calc(6px + env(safe-area-inset-bottom));z-index:3;
  gap:8px;align-items:flex-end;padding:0;border-top:none;border-radius:0;
  background:none;-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none}
html.mkr-kb .napp-chat .ai-page .ai-input-row{bottom:8px}
.napp-chat .ai-attach, .napp-field{
  background:var(--n-glass);-webkit-backdrop-filter:var(--n-glass-blur);backdrop-filter:var(--n-glass-blur);
  box-shadow:var(--n-glass-rim), var(--n-glass-edge), 0 6px 20px -8px rgba(0,0,0,.16)}
.napp-chat .ai-attach{flex:0 0 44px;width:44px;height:44px;border:none;border-radius:50%;color:var(--ink)}
.napp-chat .ai-attach .ic{width:22px;height:22px;stroke-width:2.2}
.napp-chat .ai-attach:active{transform:scale(.92)}
.napp-field{flex:1;min-width:0;display:flex;align-items:center;gap:2px;min-height:44px;border-radius:22px;padding:3px 4px 3px 16px}
.napp-field .input{flex:1;min-width:0;height:38px;padding:0;border:none;border-radius:0;background:transparent;box-shadow:none;font-size:17px;letter-spacing:-.3px}
.napp-field .input:focus{background:transparent;box-shadow:none}
.napp-field .input::placeholder{color:rgba(60,60,67,.45)}
.napp-field .ai-mic{flex:0 0 36px;width:36px;height:36px;border:none;border-radius:50%;background:transparent;color:rgba(60,60,67,.6);padding:0}
.napp-field .ai-mic .ic{width:21px;height:21px}
.napp-field .ai-mic.listening{color:#fff;background:#FF3B30}
.napp-field .btn{display:none;flex:0 0 32px;width:32px;min-height:32px;height:32px;padding:0;margin:0 2px;border-radius:50%;
  background:var(--accent);color:#fff;border:none;box-shadow:none;place-items:center}
.napp-field .btn .ic{width:18px;height:18px;stroke-width:2.6}
.napp-field .btn:active{transform:scale(.9)}
.ai-input-row.has-text .napp-field .btn{display:grid;animation:nappPop .18s var(--ease-out)}
.ai-input-row.has-text .napp-field .ai-mic{display:none}
@keyframes nappPop{from{transform:scale(.4);opacity:0}to{transform:none;opacity:1}}

/* Account sheet: thick glass, grouped white rows, like Settings. */
/* Every sheet rises from the bottom edge and sits on it — this one too. */
.napp-sheet-back{position:fixed;inset:0;z-index:50;display:flex;align-items:flex-end;padding:0;
  background:rgba(0,0,0,.18);animation:nappFade .2s ease}
.napp-sheet-back.hidden{display:none}
.napp-sheet{width:100%;max-height:88%;overflow:auto;background:var(--paper);border-radius:22px 22px 0 0;
  -webkit-backdrop-filter:none;backdrop-filter:none;
  padding:8px 14px max(16px, env(safe-area-inset-bottom));animation:nappUp .38s var(--ease-out)}
@keyframes nappUp{from{transform:translateY(105%)}to{transform:none}}
@keyframes nappFade{from{opacity:0}to{opacity:1}}
.napp-grip{width:36px;height:5px;border-radius:99px;background:rgba(0,0,0,.18);margin:2px auto 12px}
.napp-who{display:flex;flex-direction:column;align-items:center;text-align:center;gap:8px;padding:4px 4px 16px}
.napp-who b{font-size:20px;font-weight:600;letter-spacing:-.3px}
.napp-who .faint{font-size:13.5px;margin-top:1px}
.napp-group{background:var(--card);border-radius:20px;overflow:hidden;margin-bottom:12px}
.napp-row{display:flex;align-items:center;gap:12px;width:100%;min-height:50px;padding:0 16px;border:none;background:none;
  font:inherit;font-size:17px;letter-spacing:-.3px;color:var(--ink);text-align:left;cursor:pointer;position:relative}
.napp-row:active{background:rgba(0,0,0,.05)}
.napp-row + .napp-row::before{content:"";position:absolute;top:0;left:50px;right:0;border-top:.5px solid var(--n-sep)}
.napp-row > .ic:first-child{width:22px;height:22px;color:var(--accent)}
.napp-row span{flex:1}
.napp-row > .ic:last-child:not(:first-child){width:15px;height:15px;color:rgba(60,60,67,.3)}
.napp-row select{border:none;background:none;font:inherit;font-size:17px;color:var(--ink-soft);text-align:right;max-width:52%;position:static;appearance:none;-webkit-appearance:none;box-shadow:none;padding:0;height:auto}
.napp-row.danger, .napp-row.danger .ic{color:#FF3B30 !important}
.napp-switch{appearance:none;-webkit-appearance:none;width:51px;height:31px;border-radius:99px;background:rgba(120,120,128,.16);position:relative;transition:background .2s;flex:0 0 auto;margin:0;cursor:pointer}
.napp-switch::after{content:"";position:absolute;top:2px;left:2px;width:27px;height:27px;border-radius:50%;background:#fff;box-shadow:0 3px 8px rgba(0,0,0,.15),0 1px 1px rgba(0,0,0,.16);transition:transform .25s var(--ease-out)}
.napp-switch:checked{background:#34C759}
.napp-switch:checked::after{transform:translateX(20px)}
.napp-del{display:block;margin:2px auto 0;border:none;background:none;font:inherit;font-size:14px;color:var(--ink-faint);cursor:pointer}

/* Sign-in: a white first screen with the mark as an app icon, an iOS
   segmented control, filled fields and capsule buttons. */
html.mkr-native .login-wrap{display:block;min-height:100%;height:100%;overflow:auto;padding:0;background:var(--paper)}
html.mkr-native .login-card{max-width:none;min-height:100%;border-radius:0;box-shadow:none;border:none;background:var(--paper);
  padding:60px 20px calc(28px + env(safe-area-inset-bottom));animation:none}
html.mkr-native .login-card .lang-select{top:10px;right:14px;border:none;border-radius:99px;font-size:15px;
  background-color:var(--n-glass);-webkit-backdrop-filter:var(--n-glass-blur);backdrop-filter:var(--n-glass-blur);box-shadow:var(--n-glass-rim), var(--n-glass-edge), 0 4px 14px -6px rgba(0,0,0,.15)}
html.mkr-native .login-card > .row.center{flex-direction:column;text-align:center;gap:14px;margin-bottom:6px}
html.mkr-native .login-card > .row.center b{font-family:inherit !important;font-size:30px !important;font-weight:700;letter-spacing:-.6px !important}
html.mkr-native .login-logo{width:84px;height:84px;border-radius:22px;background:#fff !important;
  box-shadow:0 0 0 .5px rgba(0,0,0,.08), 0 10px 30px -12px rgba(0,0,0,.28) !important}
html.mkr-native .login-tabs, html.mkr-native .seed-hint{display:none}
html.mkr-native .role-pick{display:flex;gap:0;padding:2px;margin:26px 0 20px;background:rgba(118,118,128,.12);border-radius:9px}
html.mkr-native .role-pick button{flex:1;flex-direction:row;justify-content:center;gap:6px;padding:7px 4px;min-height:0;border:none;border-radius:7px;
  background:transparent;font-size:14px;font-weight:500;color:var(--ink);box-shadow:none}
html.mkr-native .role-pick button .em, html.mkr-native .role-pick button .ic{display:none}
html.mkr-native .role-pick button.sel{background:var(--card);font-weight:600;box-shadow:0 3px 8px rgba(0,0,0,.12), 0 3px 1px rgba(0,0,0,.04)}
html.mkr-native .login-card .field label{font-size:13px;font-weight:500;color:var(--ink-soft);margin-left:4px}
html.mkr-native .login-card .input{height:50px;font-size:17px;border-radius:14px;background:var(--paper-2);border:none;box-shadow:none}
html.mkr-native .login-card .input:focus{background:var(--paper-2);box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent)}
html.mkr-native .login-card .btn-block{height:54px;border-radius:15px;font-size:17px;font-weight:600}
html.mkr-native .login-card .btn-block:active{transform:scale(.98)}
html.mkr-native .preview-box{margin-top:26px;background:transparent;border:none;padding:0;text-align:center}
html.mkr-native .preview-box p{display:none}
html.mkr-native .preview-box > b{display:block;font-size:13px;color:var(--ink-soft);font-weight:500;margin-bottom:10px}
html.mkr-native .preview-box .row{justify-content:center;gap:10px;flex-wrap:nowrap}
html.mkr-native .preview-box .row .btn{flex:1 1 0;min-width:0;padding:0 8px;gap:6px}
html.mkr-native .preview-box .btn{border:none;border-radius:14px;background:var(--paper-2);font-weight:500;box-shadow:none}
.native-apply{text-align:center;margin-top:10px;font-size:13px;font-weight:600}

/* ===== Phone home: the assistant OR the workbench, never one under the other =====
   With the workbench folded the conversation is the whole home screen — the
   shell stops scrolling and the composer sits just above the tab bar, like
   the assistant's own page. Opened, the workbench takes the screen and scrolls;
   the chat steps aside rather than trailing at the bottom of a long page. */
@media(max-width:880px){
  .show-dash > .home-chat{display:none}
  body:has(.home-split:not(.show-dash)) .main{height:100dvh;overflow:hidden}
  body:has(.home-split:not(.show-dash)) .content{display:flex;flex-direction:column;min-height:0;overflow:hidden;
    padding-bottom:calc(var(--nav-float) + 72px)}
  .home-split:not(.show-dash){flex:1;min-height:0;display:flex;flex-direction:column}
  .home-split:not(.show-dash) > .home-chat{flex:1;min-height:0;display:flex;flex-direction:column}
  .home-split:not(.show-dash) #homeChat{flex:1;min-height:0;display:flex}
  .home-split:not(.show-dash) .home-chat .ai-page{flex:1;height:auto;min-height:0}
  /* The conversation gets the whole screen: no top bar saying "Home" over it
     and no heading inside it — the Dashboard row is the only thing above. The
     bar comes back with the workbench and on every other page. */
  body:has(.home-split:not(.show-dash)) .topbar{display:none}
  .home-split:not(.show-dash) .home-chat-head{display:none}
  .home-split:not(.show-dash) > .home-chat{margin-top:8px}
  /* No tab bar under the conversation either: the Dashboard row is the way
     out, and the bar comes back with the workbench (in the iPhone app the
     native bar follows the same rule — js/native-app.js). The composer drops
     to the bottom edge, just clear of the home indicator. */
  body:has(.home-split:not(.show-dash)) .mobile-nav{display:none}
  .shell:has(.home-split:not(.show-dash))::after{display:none}
  body:has(.home-split:not(.show-dash)) .content{padding-bottom:max(10px, env(safe-area-inset-bottom))}

  /* The conversation, drawn like Messages: no box around it, filled bubbles,
     and a composer of round buttons beside a capsule field. */
  .home-chat .ai-page{border:none;border-radius:0;background:transparent}
  .home-chat .ai-page .ai-log, .ai-page .ai-log{padding:8px 2px 6px;gap:8px}
  .ai-page .ai-msg{font-size:15.5px;line-height:1.42;padding:9px 14px;border-radius:20px;max-width:84%}
  .ai-page .ai-msg.bot{background:var(--paper-2);border:none;border-bottom-left-radius:6px}
  .ai-page .ai-msg.user{border-bottom-right-radius:6px}
  .ai-page .ai-msg.ai-form{max-width:100%}
  .ai-page .ai-chip:not(.su-go){border:none;background:var(--paper-2);padding:8px 14px;font-size:13.5px}
  .ai-page .ai-msg.bot .ai-chip:not(.su-go){background:var(--card)}
  .home-chat .ai-page .ai-input-row, .ai-page .ai-input-row{border-top:none;padding:8px 0 4px;gap:8px;align-items:center}
  .ai-page .ai-attach, .ai-page .ai-mic{flex:0 0 42px;width:42px;height:42px;border:none;border-radius:50%;background:var(--paper-2);color:var(--ink-soft)}
  .ai-page .ai-input-row .input{height:44px;border:none;border-radius:22px;background:var(--paper-2);padding:0 16px;font-size:16px}
  .ai-page .ai-input-row .input:focus{background:var(--paper-2);box-shadow:0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent)}
  .ai-page .ai-input-row .btn{flex:0 0 44px;width:44px;min-height:44px;height:44px;padding:0;border-radius:50%;display:grid;place-items:center}
  .home-chat-head{margin:6px 2px 4px}
}

/* ===== Purchases: six months of spend, dockets by month, a docket to swipe ===== */
.dkt-chart{background:var(--card);border:1px solid var(--line-2);border-radius:var(--radius-lg);padding:16px 16px 12px;box-shadow:var(--shadow-soft)}
.dkt-chart-top{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.dkt-chart-now span{display:block;font-size:13px;color:var(--ink-soft);font-weight:600}
.dkt-chart-now b{display:block;font-size:30px;font-weight:800;letter-spacing:-.02em;line-height:1.1;margin-top:2px}
.dkt-delta{display:flex;flex-direction:column;align-items:flex-end;font-size:15px;font-weight:800;padding:4px 10px;border-radius:12px}
.dkt-delta small{font-size:11px;font-weight:600;opacity:.8}
.dkt-delta.up{background:var(--red-soft);color:var(--red)}
.dkt-delta.down{background:var(--green-soft);color:var(--green)}
.dkt-bars{display:grid;grid-template-columns:repeat(6,1fr);gap:8px;height:150px;margin-top:14px}
.dkt-bar{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:0;min-height:0;padding:0;border:none;background:none;font:inherit;cursor:pointer}
.dkt-bar:disabled{cursor:default}
.dkt-bar-v{font-size:10.5px;font-weight:700;color:var(--ink-soft);white-space:nowrap;height:14px}
.dkt-bar-col{flex:1;width:100%;max-width:38px;display:flex;align-items:flex-end;border-radius:8px;background:color-mix(in srgb,var(--ink) 5%,transparent)}
.dkt-bar-col i{display:block;width:100%;border-radius:8px;background:color-mix(in srgb,var(--accent) 45%,transparent);transition:height .4s var(--ease-out)}
.dkt-bar.now .dkt-bar-col i, .dkt-bar.on .dkt-bar-col i{background:var(--accent)}
.dkt-bar.on em{color:var(--accent-ink);font-weight:800}
.dkt-bar em{font-style:normal;font-size:12px;font-weight:600;color:var(--ink-soft)}
.dkt-chart-foot{display:flex;justify-content:space-between;gap:10px;margin-top:12px;padding-top:10px;border-top:1px solid var(--line-2);font-size:12.5px;color:var(--ink-soft)}
.dkt-wall.dkt-rows{display:block;background:var(--card);border:1px solid var(--line-2);border-radius:var(--radius-lg);overflow:hidden;margin-top:14px}
.dkt-month{display:flex;justify-content:space-between;align-items:baseline;padding:12px 16px 6px;background:var(--paper-2);
  font-size:13px;font-weight:700;color:var(--ink-soft)}
.dkt-month b{color:var(--ink);font-variant-numeric:tabular-nums}
.dkt-row{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px 12px 16px;border:none;background:none;font:inherit;color:var(--ink);text-align:left;cursor:pointer}
.dkt-row + .dkt-row{border-top:1px solid var(--line-2)}
.dkt-row:active{background:var(--paper-2)}
.dkt-row-ic{display:grid;place-items:center;width:36px;height:36px;flex:none;border-radius:10px;background:var(--paper-2);color:var(--ink-soft)}
.dkt-row-ic.bad{background:var(--amber-soft,#FBF1DA);color:var(--amber,#B7791F)}
.dkt-row-ic .ic{width:18px;height:18px}
.dkt-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.dkt-row-main b{font-size:15px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dkt-row-main small{font-size:12.5px;color:var(--ink-soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dkt-row-amt{flex:none;font-size:15px;font-weight:700;font-variant-numeric:tabular-nums}
.dkt-go{width:15px;height:15px;flex:none;color:var(--ink-faint)}
.dkt-pager{display:flex;align-items:center;justify-content:center;gap:14px;margin:-4px 0 12px;font-size:13.5px;font-weight:700;color:var(--ink-soft);font-variant-numeric:tabular-nums}
.dkt-step{display:grid;place-items:center;width:38px;height:38px;min-height:0;padding:0;border:1px solid var(--line-2);border-radius:50%;background:var(--card);color:var(--ink);cursor:pointer}
.dkt-step:disabled{opacity:.3;cursor:default}
.dkt-step .ic{width:17px;height:17px}
.dkt-page.from-right{animation:dktIn .22s var(--ease-out)}
.dkt-page.from-left{animation:dktInL .22s var(--ease-out)}
@keyframes dktIn{from{transform:translateX(24px);opacity:.3}to{transform:none;opacity:1}}
@keyframes dktInL{from{transform:translateX(-24px);opacity:.3}to{transform:none;opacity:1}}
@media (prefers-reduced-motion:reduce){ .dkt-page.from-right,.dkt-page.from-left{animation:none} }
@media (max-width:880px){
  /* The month filter is the bar chart now; supplier and search share a row. */
  .dkt-filters{flex-wrap:nowrap;gap:8px;margin-top:14px}
  .dkt-filters #fMon{display:none}
  .dkt-filters .input{flex:1 1 0;height:44px;font-size:15px}
}

/* Forecast: days of cover as a bar (two weeks fills it). */
.fc-cover{display:block;height:5px;border-radius:99px;margin-top:6px;background:color-mix(in srgb,var(--ink) 8%,transparent);overflow:hidden;min-width:44px}
.fc-cover i{display:block;height:100%;border-radius:inherit;background:var(--green)}
.fc-cover.mid i{background:var(--amber)}
.fc-cover.short i{background:var(--red)}

/* New delivery: on a phone each line is one row — item, quantity, remove —
   instead of a table wider than the sheet. */
@media (max-width:600px){
  .dl-table, .dl-table tbody{display:block;width:100%;min-width:0!important}
  .dl-table thead{display:none}
  .dl-table tr{display:flex;align-items:center;gap:8px;padding:6px 0;border:none}
  .dl-table td{display:block;padding:0!important;border:none!important}
  .dl-table td:first-child{flex:1;min-width:0}
  .dl-table td:nth-child(2){flex:0 0 84px}
  .dl-table td:nth-child(2) .input{padding:0 10px}
  .dl-table td:last-child .btn{width:44px;padding:0}
}

/* ===== Suppliers as a contact book ===== */
.sup-ava{display:grid;place-items:center;width:40px;height:40px;flex:none;border-radius:50%;
  background:color-mix(in srgb,var(--accent) 14%,transparent);color:var(--accent-ink);font-size:14px;font-weight:700;letter-spacing:.02em}
.sup-ava.big{width:56px;height:56px;font-size:19px}
.sup-d-head{align-items:center}
.sup-d-name{min-width:0}
.sup-d-name h3{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sup-d-name span{display:block;font-size:13.5px;color:var(--ink-soft);margin-top:2px}
.sup-acts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:2px 0 16px}
.sup-acts a, .sup-acts button{display:flex;flex-direction:column;align-items:center;gap:5px;padding:10px 4px;min-height:0;
  border:none;border-radius:14px;background:var(--paper-2);color:var(--accent-ink);font:inherit;font-size:12px;font-weight:600;text-decoration:none;cursor:pointer}
.sup-acts span{display:grid;place-items:center}
.sup-acts .ic{width:21px;height:21px}
.sup-acts a:active, .sup-acts button:active{transform:scale(.96)}
/* The phone/email pill buttons say the same as the round actions. */
.sup-acts ~ .sup-links a[href^="tel:"], .sup-acts ~ .sup-links a[href^="mailto:"]{display:none}
.sup-letter{position:sticky;top:0;z-index:1;padding:6px 16px;font-size:12.5px;font-weight:800;color:var(--ink-soft);
  background:var(--paper-2);border-top:1px solid var(--line-2)}
@media (max-width:880px){
  /* The list is the page; a supplier opens as a card over it. */
  .sup-split{display:block}
  .sup-split > .sup-detail{display:none}
  .sup-row{gap:12px;padding:10px 16px;min-height:60px}
  .sup-row:first-child, .sup-letter + .sup-row{border-top:none}
  .sup-row b{font-size:15.5px}
  .sup-row i{font-size:12.5px}
  .sup-row.on{background:none;box-shadow:none}
  .sup-count, .sup-foot{display:none}
  /* Contact card: the facts as a grouped list, a label over each value. */
  .sup-sheet .sup-facts{grid-template-columns:1fr;gap:0;background:var(--paper-2);border-radius:14px;overflow:hidden}
  .sup-sheet .sup-fact{padding:10px 14px}
  .sup-sheet .sup-fact + .sup-fact{border-top:1px solid var(--line-2)}
  .sup-sheet .sup-fact b{font-size:15px}
  .sup-sheet .modal-head h3{visibility:hidden}
}

/* A page heading with its buttons beside it (Points settings, Float rules,
   AI auto-roster + ⋯): on a phone they sit at the right of the title, and the
   line under the title runs full width beneath both — not on rows of their own. */
@media (max-width:600px){
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child){display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:4px 10px}
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > div:first-child{display:contents}
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > div:first-child > h2{grid-column:1;grid-row:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > div:first-child > p{grid-column:1 / -1;grid-row:2}
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > :last-child{grid-column:2;grid-row:1;flex-wrap:nowrap;gap:6px}
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > :last-child .btn,
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > .btn:last-child{min-height:40px;padding:0 13px;font-size:13.5px}
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > :last-child summary.btn{width:40px;padding:0;justify-content:center}
}

/* Settings on a phone: a list of sections, one opened at a time (owner.js settingsIndex). */
.set-index{background:var(--card);border:1px solid var(--line-2);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-soft)}
.set-row{display:flex;align-items:center;gap:14px;width:100%;min-height:56px;padding:8px 14px 8px 14px;border:none;background:none;
  font:inherit;font-size:16px;font-weight:600;color:var(--ink);text-align:left;cursor:pointer;position:relative}
.set-row + .set-row::before{content:"";position:absolute;top:0;left:62px;right:0;border-top:1px solid var(--line-2)}
.set-row:active{background:var(--paper-2)}
.set-ic{display:grid;place-items:center;width:34px;height:34px;flex:none;border-radius:9px;background:var(--accent);color:#fff}
.set-ic .ic{width:19px;height:19px}
.set-row:nth-child(6n+2) .set-ic{background:#5E8BD8}
.set-row:nth-child(6n+3) .set-ic{background:#4FAE7B}
.set-row:nth-child(6n+4) .set-ic{background:#8E7CC3}
.set-row:nth-child(6n+5) .set-ic{background:#D9A23A}
.set-row:nth-child(6n+6) .set-ic{background:#6B7280}
.set-name{flex:1;min-width:0}
.set-go{width:15px;height:15px;color:var(--ink-faint)}
.set-back{display:inline-flex;align-items:center;gap:4px;margin:0 0 12px -6px;padding:6px 8px;min-height:0;border:none;background:none;
  font:inherit;font-size:16px;font-weight:600;color:var(--accent-ink);cursor:pointer}
.set-back .ic{width:20px;height:20px}

/* Availability: a day per line — the day, then one segmented control. */
#avlist{display:flex;flex-direction:column}
.av-row{display:grid;grid-template-columns:44px minmax(0,1fr);align-items:center;gap:8px 10px;padding:10px 0}
.av-row + .av-row{border-top:1px solid var(--line-2)}
.av-day{font-size:15px;font-weight:700}
.av-segs{display:flex;padding:3px;border-radius:12px;background:color-mix(in srgb,var(--ink) 6%,transparent);gap:2px}
.av-seg{flex:1 1 0;min-width:0;min-height:38px;padding:0 4px;border:none;border-radius:9px;background:none;
  font:inherit;font-size:14px;font-weight:600;color:var(--ink-soft);cursor:pointer;display:grid;place-items:center}
.av-seg .ic{width:17px;height:17px}
.av-seg.on{background:var(--card);color:var(--ink);box-shadow:0 1px 3px rgba(0,0,0,.12)}
.av-seg.on:not(.off){color:var(--accent-ink)}
.av-own{display:none;grid-column:2;align-items:center;gap:8px}
.av-row.is-custom .av-own{display:flex}
.av-own .input{flex:1;min-width:0;height:40px}

/* Switch view: managers or staff, then the person. */
.sw-roles{width:100%}
.sw-roles button{flex:1;justify-content:center}
.sw-people{background:var(--card);border:1px solid var(--line-2);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-soft)}
.sw-person{display:flex;align-items:center;gap:12px;width:100%;min-height:62px;padding:10px 16px;border:none;background:none;font:inherit;color:var(--ink);text-align:left;cursor:pointer}
.sw-person + .sw-person{border-top:1px solid var(--line-2)}
.sw-person:active{background:var(--paper-2)}
.sw-p-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.sw-p-main b{font-size:15.5px;font-weight:700}
.sw-p-main small{font-size:12.5px;color:var(--ink-soft)}
.sw-go{width:18px;height:18px;color:var(--ink-faint)}

/* Home floor (js/game-map.js): drawn as the stock kitchen view is. */
.gm-row{text-decoration:none}
.kv-state.warm{background:var(--amber-soft);color:var(--amber-ink)}
.fp .gm-sum{margin-top:14px}
.fp-hello .btn-accent{white-space:nowrap}
@media (max-width:600px){
  .fp-hello{flex-direction:column;align-items:stretch;gap:12px}
  .fp-hello .btn-accent{width:100%;justify-content:center}
  .fp-insight{flex-wrap:wrap}
}

/* My calendar: what is yours — your shifts, a job with your name on it — is outlined. */
.cal-chip.cal-mine{box-shadow:inset 0 0 0 1.5px var(--tone,var(--accent));font-weight:700}
.cal-day:disabled{cursor:default;opacity:1}

/* Sign-up chat: Google is a plain white button with the G, like everywhere else. */
.ai-chip.su-google{background:var(--card)!important;color:var(--ink)!important;font-weight:600;display:inline-flex;align-items:center;gap:8px;
  box-shadow:0 0 0 1px var(--line)!important}

/* The venue's logo at the left of the top bar on a phone, on every page —
   the bar was empty there until the page title scrolled up into it. */
.topbar-mark{display:none}
@media (max-width:880px){
  .topbar-title{display:flex;align-items:center;gap:10px}
  .topbar-mark{display:block;width:34px;height:34px;flex:none;border-radius:10px;overflow:hidden;background:#fff;box-shadow:0 0 0 .5px rgba(0,0,0,.1)}
  .topbar-mark img{width:100%;height:100%;object-fit:cover;display:block}
}

/* Share sheet (U.share): the link, then the apps as a grid of icons. */
.sh-link{display:flex;align-items:center;gap:10px;padding:8px 8px 8px 14px;border-radius:14px;background:var(--paper-2);margin-bottom:16px}
.sh-link span{flex:1;min-width:0;font-size:13px;color:var(--ink-soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sh-link .btn{flex:none;min-height:38px}
.sh-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px 8px}
.sh-app{display:flex;flex-direction:column;align-items:center;gap:6px;padding:0;min-height:0;border:none;background:none;
  font:inherit;font-size:12px;font-weight:600;color:var(--ink);text-decoration:none;cursor:pointer;text-align:center}
.sh-app span:last-child{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sh-ic{display:grid;place-items:center;width:54px;height:54px;border-radius:15px;box-shadow:0 2px 6px rgba(0,0,0,.12)}
.sh-app:active .sh-ic{transform:scale(.92)}

/* ===== The venue's colour, everywhere it should show =====
   --accent comes from the venue's logo (js/brand.js), already checked to carry
   white text. Bubbles, selections, today, sheets and the top bar take it —
   tinted, never loud — so the app looks like this restaurant's own. */
:root{
  --brand-wash: color-mix(in srgb, var(--accent) 6%, var(--paper));   /* top bar, sheets */
  --brand-tint: color-mix(in srgb, var(--accent) 10%, var(--card));   /* fills inside sheets */
}
.topbar{background:var(--glass-bar)}
.napp-sheet{background:var(--brand-wash)!important}
.navsheet-foot, .sh-link{background:var(--brand-tint)!important}
/* Later in the file than the scrims' own rules, so no !important: that would
   outrank the colour fade the sheets open with (below). */
.modal-back, .navsheet-back:not(.hidden){background:color-mix(in srgb, var(--accent) 18%, rgba(33,30,27,.32))}
/* What you said, in the venue's colour. */
.ai-msg.user{background:var(--accent);color:#fff}
.ai-msg.user a, .ai-msg.user .ai-jump{color:#fff}
/* What is chosen. */
.viewswitch button.on{background:var(--accent)!important;color:#fff!important;box-shadow:0 4px 12px -6px color-mix(in srgb, var(--accent) 60%, transparent)!important}
.catchip.on{background:var(--accent);border-color:var(--accent);color:#fff}
.cal-cell.is-today .cal-day{background:var(--accent);color:#fff}
.av-seg.on{color:var(--accent-ink)}
.set-row:nth-child(n) .set-ic{background:var(--accent)}
.set-row:nth-child(2n) .set-ic{background:color-mix(in srgb, var(--accent) 70%, #1f2937)}
/* The app mark in the top bar sits on the venue's soft colour. */
.topbar-mark{background:var(--accent-soft)}
/* On a phone the top bar always says which page this is, next to the logo —
   it used to stay blank until the page's own heading scrolled up into it. */
@media (max-width:880px){
  .topbar.large-title:not(.scrolled-title) .topbar-title h1{opacity:1;transform:none}
}

/* Switch view: on a phone the role buttons go under the venue's name — side by
   side they left the name a one-letter column. */
@media (max-width:600px){
  .sv-li{flex-wrap:wrap}
  .sv-li .sv-roles{flex-basis:100%;min-width:0}
  .sv-li .sv-roles .btn{flex:1 1 0;min-width:0;justify-content:center}
}

/* ===== Sheets: Liquid Glass =====
   Everything that slides up over the page — every dialog, and the More
   sheet — is glass tinted with the venue's colour, the page blurred through
   it. Thick, so the text behind never reads through the text on it; the
   fields and grouped rows on it stay solid (never glass on glass).
   Three WebKit rules decide how it is built:
   · The blur is a layer of its own (::before) beside the part that scrolls,
     never on a box with a scroller inside: iOS paints the scrolled-past part
     of a blurred scroller blank. So a dialog never scrolls itself — its body
     does, under a title and buttons that stay put.
   · Nothing over the page may blur, fade (opacity) or filter while a sheet is
     up, or the sheet's blur sees only that layer instead of the page. The
     scrim tints without blurring and fades its colour, not its opacity; the
     sheet rises and sinks without fading.
   · Reduce Transparency, Increase Contrast and no backdrop-filter: solid. */
:root{
  /* Thin enough that the page shows through as colour and shape; the blur,
     not the tint, is what keeps the text behind from reading through. */
  --glass-sheet:color-mix(in srgb, var(--brand-wash) 52%, transparent);
  --glass-blur-sheet:blur(30px) saturate(210%) brightness(1.04);
  --glass-bar:color-mix(in srgb, var(--brand-wash) 58%, transparent);   /* the top bar */
  --glass-scrim:color-mix(in srgb, var(--accent) 8%, rgba(33,30,27,.16));
}
:root[data-theme="dark"]{ --glass-sheet:color-mix(in srgb, var(--brand-wash) 62%, transparent); --glass-blur-sheet:blur(30px) saturate(180%) brightness(.9);
  --glass-bar:color-mix(in srgb, var(--brand-wash) 66%, transparent); --glass-scrim:rgba(0,0,0,.34) }
@media (prefers-reduced-transparency: reduce){ :root, :root[data-theme="dark"]{ --glass-sheet:var(--brand-wash); --glass-blur-sheet:none; --glass-bar:var(--brand-wash) } }
@media (prefers-contrast: more){ :root, :root[data-theme="dark"]{ --glass-sheet:var(--brand-wash); --glass-blur-sheet:none; --glass-bar:var(--brand-wash) } }
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){ :root, :root[data-theme="dark"]{ --glass-sheet:var(--brand-wash); --glass-bar:var(--brand-wash) } }
html.mkr-solid, html.mkr-solid[data-theme="dark"], html.mkr-contrast, html.mkr-contrast[data-theme="dark"]{ --glass-sheet:var(--brand-wash); --glass-blur-sheet:none; --glass-bar:var(--brand-wash) }

.modal, .navsheet{position:relative;isolation:isolate;background:transparent!important}
.modal::before, .navsheet::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;pointer-events:none;
  /* Light lands on the top edge and falls across the upper part, as on the tab bar. */
  background:linear-gradient(to bottom, var(--glass-sheen), transparent 140px), var(--glass-sheet);
  -webkit-backdrop-filter:var(--glass-blur-sheet); backdrop-filter:var(--glass-blur-sheet);
  box-shadow:inset 0 1px 0 var(--glass-rim), inset 0 0 0 .5px color-mix(in srgb, var(--glass-rim) 55%, transparent),
    inset 0 -1px 0 color-mix(in srgb, var(--glass-rim) 30%, transparent)}

/* A dialog is a column: the title, the body scrolling under it, the buttons. */
.modal{display:flex;flex-direction:column;overflow:hidden}
.modal > .modal-head, .modal > .modal-actions{flex:none}
.modal > .modal-body{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}

/* The scrim: a tint, no blur, faded by its colour. */
.modal-back, .navsheet-back:not(.hidden){-webkit-backdrop-filter:none;backdrop-filter:none;animation:scrimIn .22s ease}
@keyframes scrimIn{from{background-color:transparent}}

/* In and out by movement alone. */
.modal{animation:glassPop .24s var(--ease-out)}
@keyframes glassPop{from{transform:translateY(14px) scale(.97)}to{transform:none}}
@keyframes glassRise{from{transform:translateY(100%)}to{transform:none}}
@media (max-width:600px){ .modal, .modal.wide{animation:glassRise .34s var(--ease-out)} }
@media (max-width:880px){ .navsheet{animation:glassRise .34s var(--ease-out)} }
.modal-back.closing{background-color:transparent!important;transition:background-color .2s ease;pointer-events:none}
.modal-back.closing .modal{transform:translateY(14px) scale(.97);opacity:0;transition:transform .2s ease-in, opacity .2s ease-in}
@media (max-width:600px){ .modal-back.closing .modal{transform:translateY(100%);opacity:1;transition:transform .22s cubic-bezier(.4,0,1,1)} }
@media (prefers-reduced-motion: reduce){
  .modal, .modal.wide, .navsheet{animation:none}
  .modal-back.closing .modal{transform:none;opacity:0;transition:opacity .15s}
}

/* ===== Page changes =====
   MKR.util.morph (js/util.js) keeps the old page up while the next one is
   drawn, then fades the new one in over it, in place. The old page stays solid
   underneath — fading both at once left a moment where neither was, and the
   page dipped. Nothing is lifted out as its own layer: a bar taken out on its
   own is pictured without its glass blur and flickered, while inside the one
   picture anything that hasn't changed (the top bar, the tabs) simply holds
   still. */
::view-transition-old(root), ::view-transition-new(root){mix-blend-mode:normal}
::view-transition-old(root){animation:none}
::view-transition-new(root){animation:vtIn .2s ease-out both}
@keyframes vtIn{from{opacity:0}}
@media (prefers-reduced-motion: reduce){
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*){animation:none!important}
}

/* Scan a list (stock → add in bulk): busy while the phone reads the photo. */
.bulk-scan.is-busy{opacity:.6;pointer-events:none}
/* The page under a sheet is dimmed only a little, so the glass has colour to
   carry; a heavy scrim left it nothing but its own tint. */
.modal-back, .navsheet-back:not(.hidden){background:var(--glass-scrim)}
/* iPhone app: the phone draws the tab bar (js/native-app.js MKR.nativeTabs);
   the web one stays in the page, unseen, as what that bar reads from. */
html.mkr-native-tabs .mobile-nav{visibility:hidden!important;pointer-events:none!important}

/* Delivery log: the amount, any claim and the status sit together at the end
   of the row; on a phone they go under the supplier, so the name keeps the
   width instead of breaking a word to a line. */
.dlv-end{display:flex;align-items:center;gap:8px;flex:0 0 auto}
@media (max-width:600px){
  .dlv-li{flex-wrap:wrap}
  .dlv-li .dlv-end{flex-basis:100%;padding-left:53px;flex-wrap:wrap}
}
/* A page heading with two or more buttons: on a phone the buttons take their
   own row under the title and share it, rather than squeezing the title down
   to its first letter. One button still sits beside the title. */
@media (max-width:880px){
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > .row:last-child:has(> .btn + .btn){grid-column:1 / -1;grid-row:3;margin-top:8px}
  .section-head:has(> div:first-child > h2):has(> :nth-child(2):last-child) > .row:last-child:has(> .btn + .btn) > .btn{flex:1 1 0;min-width:0}
}


/* ===== Switches that slide (js/util.js) =====
   One thumb carries the choice and slides between the options; the buttons go
   clear over it. Held and dragged, the thumb turns into a glass lens — clear,
   bright-rimmed, a size larger — and the option under it lifts, then it
   settles on the nearest one in the venue's colour. */
/* The switch takes the finger: a sideways drag on it moves the thumb, never scrolls. */
.viewswitch{position:relative;isolation:isolate;touch-action:none}
.vs-thumb{position:absolute;top:3px;bottom:3px;left:0;z-index:0;border-radius:999px;pointer-events:none;
  background:var(--accent);box-shadow:0 4px 12px -6px color-mix(in srgb, var(--accent) 60%, transparent);
  transition:transform .3s cubic-bezier(.25,.8,.25,1), width .3s cubic-bezier(.25,.8,.25,1),
    background .25s, box-shadow .25s, scale .25s cubic-bezier(.3,1.35,.45,1), opacity .2s}
.viewswitch.has-thumb > button{position:relative;z-index:1;background:transparent!important;box-shadow:none!important;
  transition:color .25s, transform .25s cubic-bezier(.3,1.35,.45,1)}
.viewswitch.has-thumb > button.on{color:#fff!important}
.vs-thumb.lens{scale:1.14;background:rgba(255,255,255,.3);
  -webkit-backdrop-filter:blur(1px) saturate(190%) brightness(1.1); backdrop-filter:blur(1px) saturate(190%) brightness(1.1);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95), inset 0 -1px 1px rgba(255,255,255,.5), inset 0 0 0 .5px rgba(255,255,255,.7),
    0 8px 22px -8px rgba(33,30,27,.45)}
/* As specific as the .on rule above: held, the option the thumb left is plain
   grey like the rest, not white text on the light track (a washed-out ghost). */
.viewswitch.has-thumb.dragging > button{color:var(--ink-soft)!important}
.viewswitch.has-thumb.dragging > button.under{color:var(--ink)!important;transform:scale(1.08)}
:root[data-theme="dark"] .vs-thumb.lens{background:rgba(255,255,255,.14)}
@media (prefers-reduced-motion: reduce){ .vs-thumb{transition:opacity .2s} }

/* Language, with the account rows (More sheet, sidebar foot) — not in the top bar. */
.acct-lang{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:14px;font-weight:600;color:var(--ink-soft);margin-bottom:10px}
.acct-lang > span{display:inline-flex;align-items:center;gap:8px}
.acct-lang .ic{width:17px;height:17px}
@media (max-width:880px){
  .navsheet-foot .acct-lang{margin:0;min-height:50px;padding:0 16px;color:var(--ink);font-size:15px;border-bottom:1px solid var(--line-2)}
  .navsheet-foot .acct-lang .ic{width:19px;height:19px}
  .navsheet-foot .acct-lang > span{gap:14px}
}
/* Super admin, one restaurant: four counts — two by two on a phone. */
.sa-stats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr))}
.sa-stats .statcell{min-width:0}
@media (max-width:600px){ .sa-stats{grid-template-columns:repeat(2,minmax(0,1fr))} }
.section-head h2 .pill{font-size:12px;vertical-align:4px;margin-left:4px}
/* …and its name, which can be long, gets the whole width on a phone: the
   buttons go on the row under it. */
@media (max-width:880px){
  .section-head.sa-head{display:flex!important;flex-direction:column!important;align-items:stretch!important;gap:10px!important}
  .section-head.sa-head > div:first-child{display:block!important}
  .section-head.sa-head h2{white-space:normal!important;overflow:visible!important}
  .section-head.sa-head > .row{display:flex;gap:8px}
  .section-head.sa-head > .row > .btn{flex:1 1 0;min-height:44px}
}
/* Home, list view: the four "running fine" numbers share one row on a phone. */
@media (max-width:600px){
  .today-foot-metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}
  .today-foot-metrics a{min-width:0;padding:9px 10px;border-radius:12px}
  .today-foot-metrics a span{font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .today-foot-metrics a b{font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
}
/* A page's tabs on a phone: one row that scrolls sideways, the tab you are on
   underlined — not three ragged rows. Fades at the right edge to say there is
   more. */
@media (max-width:600px){
  .tabbar{flex-wrap:nowrap;gap:2px;overflow-x:auto;overflow-y:hidden;
    -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 28px), transparent);mask-image:linear-gradient(to right, #000 calc(100% - 28px), transparent)}
  .tabbar .tab{flex:0 0 auto;padding:10px 12px;min-height:44px;background:transparent!important}
  .tabbar .tab.active{background:transparent!important}
  .tabbar.at-end{-webkit-mask-image:none;mask-image:none}
}

/* ===== Pickers (js/util.js) =====
   On a phone a <select> is a button in its place; a tap opens a sheet of the
   options. The button keeps the select's own look (its classes come across). */
select.pick-native{display:none!important}
.pick-btn{display:flex;align-items:center;text-align:left;cursor:pointer;font:inherit;color:var(--ink);min-width:0}
.pick-btn.input{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%236F655B' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;padding-right:38px}
.pick-btn .pick-val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pick-btn:disabled{opacity:.55;cursor:default}
.pick-list{display:flex;flex-direction:column;background:color-mix(in srgb, var(--card) 88%, transparent);border-radius:16px;overflow:hidden;margin-bottom:6px}
.pick-opt{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:52px;padding:0 16px;border:none;background:none;
  font:inherit;font-size:16px;color:var(--ink);text-align:left;cursor:pointer;border-bottom:1px solid var(--line-2)}
.pick-opt:last-child{border-bottom:none}
.pick-opt:active{background:var(--paper-2)}
.pick-opt.on{color:var(--accent);font-weight:650}
.pick-opt .ic{width:19px;height:19px;color:var(--accent);flex:none}
.pick-opt:disabled{color:var(--ink-faint)}
.pick-group{font-size:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-faint);padding:14px 16px 6px}

/* Photos: a thumbnail big enough to see what it is, and a tap shows it whole. */
.thumb{cursor:zoom-in}
.task-item img.thumb{width:60px;height:60px;border-radius:12px;flex:none;box-shadow:0 1px 3px rgba(33,30,27,.12)}
.photo-view{position:fixed;inset:0;z-index:600;display:grid;place-items:center;padding:max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
  background:rgba(12,10,9,.92);animation:fade .2s ease;cursor:zoom-out}
.photo-view img{max-width:100%;max-height:100%;object-fit:contain;border-radius:12px;box-shadow:0 20px 60px -20px rgba(0,0,0,.6);animation:pop .22s var(--ease-out)}
.photo-view.out{opacity:0;transition:opacity .2s}
.photo-x{position:absolute;top:max(14px, env(safe-area-inset-top));right:14px;width:40px;height:40px;border-radius:50%;border:none;
  background:rgba(255,255,255,.16);color:#fff;font-size:24px;line-height:1;display:grid;place-items:center;cursor:pointer}
/* The page never pans sideways on a phone: a row that scrolls sideways (tabs,
   chips) scrolls inside itself, and anything a few pixels too wide is cut off
   rather than letting a swipe drag the whole page. */
@media (max-width:880px){ .main, .content{overflow-x:clip} }


/* ===== The guide (js/tour.js) =====
   The screen dims around the one thing being explained; a card beside it. */
.tour{position:fixed;inset:0;z-index:800;animation:fade .25s ease}
.tour.out{opacity:0;transition:opacity .2s}
.tour-hole{position:fixed;left:50%;top:50%;width:0;height:0;border-radius:16px;pointer-events:none;
  box-shadow:0 0 0 200vmax rgba(14,11,9,.62);
  /* No slide between steps: the dim around it is one screen-sized shadow, and
     moving it repaints the whole screen every frame — the guide stuttered. */
  transition:none}
.tour-hole.on{outline:2px solid rgba(255,255,255,.95);outline-offset:2px}
.tour-card{position:fixed;left:16px;right:16px;max-width:400px;margin:0 auto;padding:18px 18px 14px;border-radius:22px;
  background:var(--card);color:var(--ink);box-shadow:0 24px 60px -18px rgba(0,0,0,.55), inset 0 1px 0 var(--glass-rim);
  transition:opacity .14s ease}
.tour-card.swap{opacity:0}
.tour-n{font-size:12px;font-weight:700;letter-spacing:.04em;color:var(--accent)}
.tour-t{font-size:19px;font-weight:800;margin:4px 0 6px;letter-spacing:-.01em}
.tour-p{font-size:15px;line-height:1.5;color:var(--ink-soft);margin:0}
.tour-act{display:flex;align-items:center;gap:8px;margin-top:16px}
.tour-act .grow{flex:1}
.tour-skip{border:none;background:none;font:inherit;font-size:14px;font-weight:600;color:var(--ink-faint);padding:8px 2px;cursor:pointer}
.tour-act .btn{min-height:44px}
.tour-next{min-width:96px}
/* While the guide points at the tab bar, it is the page's own (the iPhone app's
   native bar steps aside), and it shows even under the home chat. */
@media (max-width:880px){
  html.mkr-tour-nav .mobile-nav{display:flex!important;visibility:visible!important;pointer-events:none!important}
  .navsheet-foot .acct-guide{justify-content:flex-start}
}
/* Under the guide's dim nothing needs to be glass: the blur behind the sheet,
   the bars and the tab bar is the heaviest thing on the screen, and it is all
   covered anyway. Solid while the guide is up. */
html.mkr-touring .navsheet::before, html.mkr-touring .modal::before{-webkit-backdrop-filter:none;backdrop-filter:none;background:var(--brand-wash)}
html.mkr-touring .topbar, html.mkr-touring .mobile-nav{-webkit-backdrop-filter:none;backdrop-filter:none}
html.mkr-touring .mobile-nav{background:var(--card)}



/* ===== Settings (js/prefs.js) ===== grouped rows, as in iOS Settings. */
.pf-label{font-size:12.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-faint);margin:22px 4px 8px}
.pf-group{margin-bottom:4px}
.pf-row{position:relative;text-decoration:none;color:var(--ink);font:inherit;text-align:left;cursor:pointer}
.pf-row .set-name{flex:1;min-width:0;display:flex;flex-direction:column;font-size:15.5px;font-weight:600}
.pf-row .set-name small{font-size:12.5px;font-weight:500;color:var(--ink-soft);margin-top:1px}
.pf-row .lang-select{flex:none}
/* Notifications: an on/off switch per kind, as in iOS Settings. */
.pf-bare + .pf-row::before, .pf-row + .pf-bare::before{left:14px}
.pf-state{display:inline-flex;align-items:center;gap:5px;flex:none;font-size:14px;font-weight:600;color:var(--green-ink)}
.pf-state .ic{width:16px;height:16px}
.pf-dim{opacity:.55}
.pf-switch{appearance:none;-webkit-appearance:none;flex:none;position:relative;width:51px;height:31px;margin:0;border-radius:999px;
  background:var(--line);cursor:pointer;transition:background .2s}
.pf-switch::after{content:"";position:absolute;top:2px;left:2px;width:27px;height:27px;border-radius:50%;background:#fff;
  box-shadow:0 2px 6px rgba(0,0,0,.18), 0 0 0 .5px rgba(0,0,0,.04);transition:transform .22s var(--ease-out)}
.pf-switch:checked{background:var(--green)}
.pf-switch:checked::after{transform:translateX(20px)}
.pf-switch:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.pf-danger, .pf-danger .set-name{color:var(--red)}
.pf-danger .set-ic{background:var(--red)!important}
.pf-theme{flex:none}
.pf-theme button{min-height:34px;padding:0 12px;font-size:13px}
.side-foot .who{margin-bottom:0}

/* Phone home, workbench open: the Dashboard row is the only header (as in the
   chat), and Floor / Blocks / List is one full-width switch under it, three
   equal parts — not a second bar plus a switch hanging off the right edge. */
@media (max-width:880px){
  body:has(.home-split.show-dash) .topbar{display:none}
  .home-split.show-dash .home-switch{display:block;margin:12px 0 18px}
  .home-split.show-dash .home-switch .viewswitch{display:flex;width:100%}
  .home-split.show-dash .home-switch .viewswitch button{flex:1 1 0;justify-content:center;min-width:0}
}

/* ===== A venue's own colours (js/brand.js) =====
   With a logo uploaded the app wears up to three of its colours: the main one
   (--accent) on whatever is selected — the tab you are on, the switch, badges;
   the second on the buttons and your own chat bubbles; the third, faintly,
   behind the page. Without one, the app keeps its own dark buttons. */
html.mkr-branded .btn-dark{background:var(--brand-2);color:var(--brand-2-text);
  box-shadow:0 6px 16px -10px color-mix(in srgb, var(--brand-2) 70%, transparent)}
html.mkr-branded .ai-msg.user{background:var(--brand-2);color:var(--brand-2-text)}
html.mkr-branded .ai-msg.user a, html.mkr-branded .ai-msg.user .ai-jump{color:var(--brand-2-text)}
html.mkr-branded .nav-item.active{background:var(--accent);color:#fff}
html.mkr-branded body{
  background:
    radial-gradient(900px 560px at 0% -6%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 62%),
    radial-gradient(820px 520px at 100% 8%, color-mix(in srgb, var(--brand-2) 10%, transparent), transparent 58%),
    radial-gradient(760px 520px at 50% 108%, color-mix(in srgb, var(--brand-3) 12%, transparent), transparent 60%),
    var(--paper);
  background-attachment:fixed;
}
html.mkr-branded .login-wrap{background:
  radial-gradient(900px 520px at 12% -8%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 55%),
  radial-gradient(900px 520px at 90% 108%, color-mix(in srgb, var(--brand-3) 12%, transparent), transparent 55%),
  linear-gradient(180deg, var(--paper-2), var(--paper))}

/* The alerts bell, top right of every page (js/router.js shell). On a phone
   it takes the place of the connection light, which only shows when there is
   something to say — offline, or catching up (js/net.js). */
.topbar-title{display:flex;align-items:center;gap:10px}
.topbar-right{display:flex;align-items:center;gap:10px}
@media (max-width:880px){ .topbar-right:has(.topbar-bell) .netlight.online{display:none} }
.topbar-bell{position:relative;display:grid;place-items:center;flex:none;width:38px;height:38px;border-radius:12px;
  color:var(--ink);background:var(--card);box-shadow:0 0 0 .5px var(--line), 0 1px 3px rgba(33,30,27,.06);text-decoration:none}
.topbar-bell .ic{width:20px;height:20px}
.topbar-bell.on{background:var(--accent-soft);color:var(--accent-ink)}
.topbar-bell:active{transform:scale(.94)}
/* The count sits on the bell's shoulder, inside the button — not hanging off
   its corner over the edge. */
.tb-badge{position:absolute;top:3px;left:50%;margin-left:1px;min-width:17px;height:17px;padding:0 4px;border-radius:999px;
  background:var(--red);color:#fff;font-size:10.5px;font-weight:800;line-height:13px;text-align:center;border:2px solid var(--card)}
.home-top .topbar-bell{display:none}
@media (max-width:880px){
  .home-top{display:flex;align-items:stretch;gap:8px}
  .home-top .home-fold{flex:1;min-width:0}
  .home-top .topbar-bell{display:grid;width:46px;height:auto;min-height:44px;border-radius:var(--radius)}
}

/* New delivery (js/deliveries.js newModal): the lines as rows of equal height. */
.dl-new label .faint{font-weight:500}
.dl-head{display:flex;justify-content:space-between;padding:0 62px 6px 2px;font-size:12.5px;font-weight:600;color:var(--ink-soft)}
.dl-lines{display:flex;flex-direction:column;gap:8px}
.dl-row{display:flex;align-items:center;gap:8px}
.dl-row .dl-item{flex:1;min-width:0;height:48px}
.dl-row .dl-ord{flex:none;width:76px;height:48px;text-align:center;padding:0 8px}
.dl-del{flex:none;display:grid;place-items:center;width:44px;height:48px;border:none;border-radius:12px;background:transparent;color:var(--ink-faint);cursor:pointer}
.dl-del .ic{width:18px;height:18px}
.dl-del:active{background:var(--red-soft);color:var(--red)}
.dl-add{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;min-height:46px;margin:10px 0 14px;
  border:1.5px dashed var(--line);border-radius:14px;background:transparent;font:inherit;font-size:14.5px;font-weight:600;color:var(--accent-ink);cursor:pointer}
.dl-add .ic{width:17px;height:17px}

/* Counting-up numbers (js/util.js): fixed-width digits, so the number doesn't
   jitter sideways as it runs. */
.odo-run{font-variant-numeric:tabular-nums;white-space:nowrap}

/* The page's add button, top right beside the title (js/util.js). Anything
   else the header carries goes on a line of its own underneath. */
.section-head.has-corner{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;column-gap:12px;row-gap:4px}
/* The title shares the top line with the button, at the button's height, and
   the line under it runs the full width — so a tab with no add button (Prices,
   Counts) has the same header as one with, and nothing below it moves. */
.section-head.has-corner > div:first-child{display:contents}
.section-head.has-corner > div:first-child > h2{grid-column:1;grid-row:1;min-height:40px;display:flex;align-items:center;min-width:0}
.section-head.has-corner > div:first-child > :not(h2){grid-column:1 / -1}
.section-head.has-corner > :not(:first-child):not(.sh-corner){grid-column:1 / -1;margin-top:8px}
.section-head.has-corner > .row:empty{display:none}
.sh-corner{grid-column:2;grid-row:1;display:flex;align-items:center;gap:8px}
.sh-corner .omenu summary{min-height:36px;padding:0 10px}
/* A switch left on its own in a row runs the full width, in equal parts. */
.tab-actions > .viewswitch:only-child{display:flex;width:100%}
.tab-actions > .viewswitch:only-child > button{flex:1 1 0;justify-content:center}
.sh-add{white-space:nowrap}

/* Small square icon buttons for row actions (rename, remove). */
.icon-btn{display:inline-grid;place-items:center;width:40px;height:40px;border-radius:12px;border:1px solid var(--line);
  background:var(--card);color:var(--ink-soft);cursor:pointer;flex:none}
.icon-btn .ic{width:18px;height:18px}
.icon-btn.danger{color:var(--red)}
.icon-btn:active{transform:scale(.94)}
/* A ⋯ menu as a sheet: the icon leads each row. */
.pick-opt.pick-act{justify-content:flex-start;gap:12px}
.pick-opt.pick-act .ic{width:20px;height:20px;color:var(--ink-soft)}


/* ===== Restaurant settings → Features & access (views/owner.js settings) =====
   One row per feature: its name, then On · Managers · Staff in fixed columns,
   so a glance down a column answers "what can staff see". */
.mod-table{margin:0 -4px 14px}
.mod-table:last-child{margin-bottom:0}
.mod-row{display:grid;grid-template-columns:minmax(0,1fr) 58px 64px 52px;align-items:center;column-gap:4px;padding:10px 4px;border-top:1px solid var(--line-2)}
.mod-row.mod-head{border-top:none;padding:4px 4px 6px;font-size:12px;font-weight:700;color:var(--ink-faint);letter-spacing:.02em}
.mod-row.mod-head .mod-name{font-size:12.5px;text-transform:uppercase;letter-spacing:.05em}
.mod-name{min-width:0;display:flex;flex-direction:column;gap:4px}
.mod-name b{font-size:14.5px;font-weight:600;line-height:1.3}
.mod-row.off .mod-name b{color:var(--ink-soft)}
.mod-cell{display:flex;justify-content:center;align-items:center;text-align:center}
.mod-tick{width:22px;height:22px;margin:0;accent-color:var(--accent);cursor:pointer}
.mod-tick:disabled{opacity:.3;cursor:default}
.mod-row .pf-switch{transform:scale(.85)}
.mod-hidden{display:flex;flex-wrap:wrap;gap:4px}
.mod-note{font-size:12px;line-height:1.35}

/* Swipe from the left edge to go back (js/swipe-back.js, iOS app): what is
   leaving casts a shadow on what it uncovers, as an iOS page does. */
.swipe-back-on{box-shadow:-10px 0 28px -8px rgba(0,0,0,.28)}

/* ===== Under the clock (iOS app) =====
   The page runs up under the status bar (WebViewController pins the web view
   to the top of the screen). Everything in the page starts below the clock;
   the band behind the clock is the top bar's own glass over the same page
   background, so the two read as one bar for any venue's colours. A page
   without a top bar (the chat, sign-in) simply continues up under it. */
html.mkr-native body{padding-top:env(safe-area-inset-top)}
html.mkr-native .topbar{top:env(safe-area-inset-top)}
html.mkr-native .napp{top:env(safe-area-inset-top)}
html.mkr-native body::before{content:"";position:fixed;top:0;left:0;right:0;height:env(safe-area-inset-top);
  z-index:21;pointer-events:none}
html.mkr-native.mkr-bar body::before{background:var(--glass-bar);
  -webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur)}
/* Screens sized to the whole screen are now the screen less the clock. */
html.mkr-native .login-wrap, html.mkr-native .shell, html.mkr-native .boot{min-height:calc(100dvh - env(safe-area-inset-top))}
html.mkr-native body.ai-fullpage .main{height:calc(100dvh - env(safe-area-inset-top))}
@media (max-width:880px){
  html.mkr-native body:has(.home-split:not(.show-dash)) .main{height:calc(100dvh - env(safe-area-inset-top))}
}

/* The join page on a phone: the form near the top, not in the middle of a
   screen the keyboard is about to cover half of. */
@media (max-width:560px){
  .join-wrap{place-items:start center;padding-top:max(20px, env(safe-area-inset-top))}
  .join-wrap .login-card{margin-bottom:45vh}       /* room to scroll the last field above the keyboard */
}

/* The guide's "Ask the assistant" step can be tried for real (js/tour.js):
   taps reach the box in the hole, and while typing the guide steps aside. */
.tour.tour-live{pointer-events:none}
.tour.tour-live .tour-card{pointer-events:auto}
.tour.tour-typing .tour-card{opacity:0;pointer-events:none}
.tour.tour-typing .tour-hole{box-shadow:none;outline-color:transparent}

/* Starter chat, "When you can work" (js/onboard-chat.js): a row per day, four
   choices each, the one picked filled in. */
.ob-week{display:flex;flex-direction:column;gap:6px}
.ob-dayrow{display:flex;align-items:center;gap:8px}
.ob-dayname{flex:0 0 34px;font-size:13.5px;font-weight:700;color:var(--ink)}
.ob-slots{flex:1;display:grid;grid-template-columns:repeat(4,1fr);gap:4px;min-width:0}
.ob-slot{min-height:36px;padding:0 2px;border-radius:10px;border:1px solid var(--line);background:var(--card);
  font:inherit;font-size:12.5px;font-weight:600;color:var(--ink-soft);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ob-slot.on{background:var(--accent);border-color:var(--accent);color:#fff}
.ob-slot[data-s="off"].on{background:var(--paper-2);border-color:var(--line);color:var(--ink-faint)}

/* The bell: every item opens the page it is about (views/owner.js alerts). */
.al-go{color:inherit;text-decoration:none;cursor:pointer;min-width:0}
.al-go:active{opacity:.7}
.al-arrow{font-weight:700;opacity:.6;margin-left:2px}

/* A grid column or a select never wider than the screen: a long option
   ("经理 —— 管排班、库存和团队") used to push the Add people card past the
   right edge on a phone, fields and all. */
.grid > *{min-width:0}
select.input{max-width:100%;min-width:0;text-overflow:ellipsis}

/* Rostering: tap a day (js/roster-view.js dayModal) — a row per person, their
   word on that day, what they're already on, and a button per shift. */
.rg-dayhead{cursor:pointer;text-decoration:underline dotted;text-underline-offset:4px}
.dayroster{display:flex;flex-direction:column;gap:10px}
.dr-row{padding:10px 0;border-top:1px solid var(--line-2)}
.dr-row:first-of-type{border-top:none}
.dr-row.dr-dim .dr-who b{color:var(--ink-soft)}
.dr-who{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
.dr-on{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}
.dr-slots{display:flex;flex-wrap:wrap;gap:6px}
/* A banner directly under the clock (preview, offline, viewing as someone):
   the strip is that banner's colour, so the two read as one band. */
html.mkr-native.mkr-banner-top body::before{background:var(--clock-bg);-webkit-backdrop-filter:none;backdrop-filter:none}

/* Documents to sign (js/staff-docs.js) */
.doc-text{max-height:42vh;overflow:auto;padding:12px 14px;border:1px solid var(--line-2);border-radius:12px;background:var(--paper-2);font-size:14px;line-height:1.6;margin-bottom:10px}
.doc-img{display:block;max-width:100%;border-radius:10px;border:1px solid var(--line-2);margin-bottom:10px}
